diff options
Diffstat (limited to 'WebKitTools')
97 files changed, 4199 insertions, 429 deletions
diff --git a/WebKitTools/CMakeListsEfl.txt b/WebKitTools/CMakeListsEfl.txt new file mode 100644 index 0000000..b9086ac --- /dev/null +++ b/WebKitTools/CMakeListsEfl.txt @@ -0,0 +1,56 @@ +SET(EWebLauncher_SOURCES + ${WebKit_THEME} + ${WEBKITTOOLS_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 () + +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/WebKitTools/ChangeLog b/WebKitTools/ChangeLog index 905a8e2..aa525b5 100644 --- a/WebKitTools/ChangeLog +++ b/WebKitTools/ChangeLog @@ -1,3 +1,894 @@ +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. diff --git a/WebKitTools/DumpRenderTree/AccessibilityTextMarker.cpp b/WebKitTools/DumpRenderTree/AccessibilityTextMarker.cpp new file mode 100644 index 0000000..d84ee80 --- /dev/null +++ b/WebKitTools/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/WebKitTools/DumpRenderTree/AccessibilityTextMarker.h b/WebKitTools/DumpRenderTree/AccessibilityTextMarker.h new file mode 100644 index 0000000..aeb078d --- /dev/null +++ b/WebKitTools/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/WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp b/WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp index e09eb35..22bbbaa 100644 --- a/WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp +++ b/WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp @@ -406,6 +406,62 @@ static JSValueRef removeSelectionCallback(JSContextRef context, JSObjectRef func 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 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 @@ -662,6 +718,42 @@ static JSValueRef removeNotificationListenerCallback(JSContextRef context, JSObj return JSValueMakeUndefined(context); } +// Implementation + +#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; +} + +#endif + // Destruction static void finalize(JSObjectRef thisObject) @@ -774,6 +866,12 @@ JSClassRef AccessibilityUIElement::getJSClass() { "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 }, { 0, 0, 0 } }; diff --git a/WebKitTools/DumpRenderTree/AccessibilityUIElement.h b/WebKitTools/DumpRenderTree/AccessibilityUIElement.h index 13415cd..2606795 100644 --- a/WebKitTools/DumpRenderTree/AccessibilityUIElement.h +++ b/WebKitTools/DumpRenderTree/AccessibilityUIElement.h @@ -26,6 +26,7 @@ #ifndef AccessibilityUIElement_h #define AccessibilityUIElement_h +#include "AccessibilityTextMarker.h" #include <JavaScriptCore/JSObjectRef.h> #include <wtf/Platform.h> #include <wtf/Vector.h> @@ -40,8 +41,8 @@ typedef struct objc_object* PlatformUIElement; #undef _WINSOCKAPI_ #define _WINSOCKAPI_ // Prevent inclusion of winsock.h in windows.h -#include <oleacc.h> #include <WebCore/COMPtr.h> +#include <oleacc.h> typedef COMPtr<IAccessible> PlatformUIElement; #elif PLATFORM(GTK) @@ -183,6 +184,14 @@ public: // 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*); + AccessibilityUIElement accessibilityElementForTextMarker(AccessibilityTextMarker*); + int textMarkerRangeLength(AccessibilityTextMarkerRange*); + // Notifications // Function callback should take one argument, the name of the notification. bool addNotificationListener(JSObjectRef functionCallback); diff --git a/WebKitTools/DumpRenderTree/DumpRenderTree.gypi b/WebKitTools/DumpRenderTree/DumpRenderTree.gypi index a525532..b39fd2a 100644 --- a/WebKitTools/DumpRenderTree/DumpRenderTree.gypi +++ b/WebKitTools/DumpRenderTree/DumpRenderTree.gypi @@ -26,6 +26,8 @@ 'chromium/NotificationPresenter.cpp', 'chromium/PlainTextController.cpp', 'chromium/PlainTextController.h', + 'chromium/Task.h', + 'chromium/Task.cpp', 'chromium/TestEventPrinter.h', 'chromium/TestEventPrinter.cpp', 'chromium/TestNavigationController.cpp', diff --git a/WebKitTools/DumpRenderTree/DumpRenderTree.sln b/WebKitTools/DumpRenderTree/DumpRenderTree.sln index 3647a2a..196f872 100644 --- a/WebKitTools/DumpRenderTree/DumpRenderTree.sln +++ b/WebKitTools/DumpRenderTree/DumpRenderTree.sln @@ -2,12 +2,21 @@ 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
diff --git a/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj b/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj index c92c704..c01ca4e 100644 --- a/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj +++ b/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj @@ -43,6 +43,9 @@ 1AC77DCF120605B6005C19EF /* NPRuntimeRemoveProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC77DCE120605B6005C19EF /* NPRuntimeRemoveProperty.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 */; }; 5185F6B210714E07007AA393 /* HistoryDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5185F69F10714A57007AA393 /* HistoryDelegate.mm */; }; @@ -202,6 +205,9 @@ 1AC77DCE120605B6005C19EF /* NPRuntimeRemoveProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NPRuntimeRemoveProperty.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>"; }; @@ -389,6 +395,9 @@ 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 */, @@ -585,6 +594,7 @@ BC9D90260C97472E0099A4A3 /* WorkQueueItem.h in Headers */, 5185F6B310714E12007AA393 /* HistoryDelegate.h in Headers */, E1B7816711AF31C3007E1BC2 /* MockGeolocationProvider.h in Headers */, + 29CFBA10122736E600BC30C0 /* AccessibilityTextMarker.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -758,6 +768,8 @@ 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; }; diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp index 44fafa1..5002400 100644 --- a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp +++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp @@ -690,7 +690,9 @@ static bool testPostURLFile(PluginObject* obj, const NPVariant* args, uint32_t a if (!tempFile) return false; - fwrite(contentsString.UTF8Characters, contentsString.UTF8Length, 1, tempFile); + if (!fwrite(contentsString.UTF8Characters, contentsString.UTF8Length, 1, tempFile)) + return false; + fclose(tempFile); NPError error = browser->posturl(obj->npp, url, target, pathString.UTF8Length, path, TRUE); diff --git a/WebKitTools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp b/WebKitTools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp index ba1edd7..a9a891b 100644 --- a/WebKitTools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp +++ b/WebKitTools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp @@ -43,8 +43,7 @@ using namespace WebKit; DRTDevToolsAgent::DRTDevToolsAgent() - : m_callMethodFactory(this) - , m_drtDevToolsClient(0) + : m_drtDevToolsClient(0) , m_webView(0) { static int devToolsAgentCounter = 0; @@ -56,7 +55,7 @@ DRTDevToolsAgent::DRTDevToolsAgent() void DRTDevToolsAgent::reset() { - m_callMethodFactory.RevokeAll(); + m_taskList.revokeAll(); } void DRTDevToolsAgent::setWebView(WebView* webView) @@ -70,10 +69,6 @@ void DRTDevToolsAgent::sendMessageToInspectorFrontend(const WebKit::WebString& d m_drtDevToolsClient->asyncCall(DRTDevToolsCallArgs(data)); } -void DRTDevToolsAgent::forceRepaint() -{ -} - void DRTDevToolsAgent::runtimePropertyChanged(const WebKit::WebString& name, const WebKit::WebString& value) { // FIXME: Implement. @@ -89,10 +84,9 @@ WebDevToolsAgentClient::WebKitClientMessageLoop* DRTDevToolsAgent::createClientM return webkit_support::CreateDevToolsMessageLoop(); } -void DRTDevToolsAgent::asyncCall(const DRTDevToolsCallArgs &args) +void DRTDevToolsAgent::asyncCall(const DRTDevToolsCallArgs& args) { - webkit_support::PostTaskFromHere( - m_callMethodFactory.NewRunnableMethod(&DRTDevToolsAgent::call, args)); + postTask(new AsyncCallTask(this, args)); } void DRTDevToolsAgent::call(const DRTDevToolsCallArgs &args) @@ -137,9 +131,9 @@ void DRTDevToolsAgent::detach() m_drtDevToolsClient = 0; } -void DRTDevToolsAgent::frontendLoaded() { - webkit_support::PostTaskFromHere( - m_callMethodFactory.NewRunnableMethod(&DRTDevToolsAgent::delayedFrontendLoaded)); +void DRTDevToolsAgent::frontendLoaded() +{ + postTask(new DelayedFrontendLoadedTask(this)); } bool DRTDevToolsAgent::setTimelineProfilingEnabled(bool enabled) diff --git a/WebKitTools/DumpRenderTree/chromium/DRTDevToolsAgent.h b/WebKitTools/DumpRenderTree/chromium/DRTDevToolsAgent.h index 8747cea..c988fa1 100644 --- a/WebKitTools/DumpRenderTree/chromium/DRTDevToolsAgent.h +++ b/WebKitTools/DumpRenderTree/chromium/DRTDevToolsAgent.h @@ -31,7 +31,8 @@ #ifndef DRTDevToolsAgent_h #define DRTDevToolsAgent_h -#include "base/task.h" // FIXME: remove this +#include "DRTDevToolsCallArgs.h" +#include "Task.h" #include "public/WebDevToolsAgentClient.h" #include <wtf/HashMap.h> #include <wtf/Noncopyable.h> @@ -46,7 +47,6 @@ struct WebDevToolsMessageData; } // namespace WebKit -class DRTDevToolsCallArgs; class DRTDevToolsClient; class DRTDevToolsAgent : public WebKit::WebDevToolsAgentClient @@ -61,7 +61,6 @@ public: // WebDevToolsAgentClient implementation. virtual void sendMessageToInspectorFrontend(const WebKit::WebString&); virtual int hostIdentifier() { return m_routingID; } - virtual void forceRepaint(); virtual void runtimePropertyChanged(const WebKit::WebString& name, const WebKit::WebString& value); virtual WebKit::WebCString debuggerScriptSource(); virtual WebKitClientMessageLoop* createClientMessageLoop(); @@ -74,6 +73,7 @@ public: bool evaluateInWebInspector(long callID, const std::string& script); bool setTimelineProfilingEnabled(bool enable); + TaskList* taskList() { return &m_taskList; } private: void call(const DRTDevToolsCallArgs&); @@ -81,7 +81,21 @@ private: static void dispatchMessageLoop(); WebKit::WebDevToolsAgent* webDevToolsAgent(); - ScopedRunnableMethodFactory<DRTDevToolsAgent> m_callMethodFactory; + 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; diff --git a/WebKitTools/DumpRenderTree/chromium/DRTDevToolsClient.cpp b/WebKitTools/DumpRenderTree/chromium/DRTDevToolsClient.cpp index 42f3724..a53f0db 100644 --- a/WebKitTools/DumpRenderTree/chromium/DRTDevToolsClient.cpp +++ b/WebKitTools/DumpRenderTree/chromium/DRTDevToolsClient.cpp @@ -45,8 +45,7 @@ using namespace WebKit; DRTDevToolsClient::DRTDevToolsClient(DRTDevToolsAgent* agent, WebView* webView) - : m_callMethodFactory(this) - , m_drtDevToolsAgent(agent) + : m_drtDevToolsAgent(agent) , m_webView(webView) { m_webDevToolsFrontend.set(WebDevToolsFrontend::create(m_webView, @@ -59,14 +58,14 @@ 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_callMethodFactory.RevokeAll(); + m_taskList.revokeAll(); if (m_drtDevToolsAgent) m_drtDevToolsAgent->detach(); } void DRTDevToolsClient::reset() { - m_callMethodFactory.RevokeAll(); + m_taskList.revokeAll(); } void DRTDevToolsClient::sendFrontendLoaded() { @@ -107,8 +106,7 @@ void DRTDevToolsClient::undockWindow() void DRTDevToolsClient::asyncCall(const DRTDevToolsCallArgs& args) { - webkit_support::PostTaskFromHere( - m_callMethodFactory.NewRunnableMethod(&DRTDevToolsClient::call, args)); + postTask(new AsyncCallTask(this, args)); } void DRTDevToolsClient::call(const DRTDevToolsCallArgs& args) diff --git a/WebKitTools/DumpRenderTree/chromium/DRTDevToolsClient.h b/WebKitTools/DumpRenderTree/chromium/DRTDevToolsClient.h index 37b1e9d..f7c8fbf 100644 --- a/WebKitTools/DumpRenderTree/chromium/DRTDevToolsClient.h +++ b/WebKitTools/DumpRenderTree/chromium/DRTDevToolsClient.h @@ -31,7 +31,8 @@ #ifndef DRTDevToolsClient_h #define DRTDevToolsClient_h -#include "base/task.h" // FIXME: remove this +#include "DRTDevToolsCallArgs.h" +#include "Task.h" #include "public/WebDevToolsFrontendClient.h" #include <wtf/Noncopyable.h> #include <wtf/OwnPtr.h> @@ -45,7 +46,6 @@ class WebView; } // namespace WebKit -class DRTDevToolsCallArgs; class DRTDevToolsAgent; class DRTDevToolsClient : public WebKit::WebDevToolsFrontendClient @@ -68,11 +68,20 @@ public: 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; + }; - ScopedRunnableMethodFactory<DRTDevToolsClient> m_callMethodFactory; + TaskList m_taskList; WebKit::WebView* m_webView; DRTDevToolsAgent* m_drtDevToolsAgent; WTF::OwnPtr<WebKit::WebDevToolsFrontend> m_webDevToolsFrontend; diff --git a/WebKitTools/DumpRenderTree/chromium/DumpRenderTree.cpp b/WebKitTools/DumpRenderTree/chromium/DumpRenderTree.cpp index 726e412..6e180d0 100644 --- a/WebKitTools/DumpRenderTree/chromium/DumpRenderTree.cpp +++ b/WebKitTools/DumpRenderTree/chromium/DumpRenderTree.cpp @@ -47,6 +47,7 @@ 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 void runTest(TestShell& shell, TestParams& params, const string& testName, bool testShellMode) { @@ -109,6 +110,8 @@ int main(int argc, char* argv[]) allowExternalPages = true; else if (argument == optionStartupDialog) startupDialog = true; + else if (argument == optionCheckLayoutTestSystemDeps) + exit(checkLayoutTestSystemDependencies() ? EXIT_SUCCESS : EXIT_FAILURE); else if (argument.size() && argument[0] == '-') fprintf(stderr, "Unknown option: %s\n", argv[i]); else diff --git a/WebKitTools/DumpRenderTree/chromium/EventSender.cpp b/WebKitTools/DumpRenderTree/chromium/EventSender.cpp index 49421f6..c2ba380 100644 --- a/WebKitTools/DumpRenderTree/chromium/EventSender.cpp +++ b/WebKitTools/DumpRenderTree/chromium/EventSender.cpp @@ -244,8 +244,7 @@ enum KeyLocationCode { }; EventSender::EventSender(TestShell* shell) - : m_methodFactory(this) - , m_shell(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 @@ -322,7 +321,7 @@ void EventSender::reset() timeOffsetMs = 0; touchModifiers = 0; touchPoints.clear(); - m_methodFactory.RevokeAll(); + m_taskList.revokeAll(); } WebView* EventSender::webview() @@ -750,14 +749,29 @@ void EventSender::contextClick(const CppArgumentList& arguments, CppVariant* res pressedButton = WebMouseEvent::ButtonNone; } +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(); - - webkit_support::PostTaskFromHere(m_methodFactory.NewRunnableMethod( - &EventSender::mouseDown, arguments, static_cast<CppVariant*>(0))); - webkit_support::PostTaskFromHere(m_methodFactory.NewRunnableMethod( - &EventSender::mouseUp, arguments, static_cast<CppVariant*>(0))); + postTask(new MouseDownTask(this, arguments)); + postTask(new MouseUpTask(this, arguments)); } void EventSender::beginDragWithFiles(const CppArgumentList& arguments, CppVariant* result) @@ -895,7 +909,10 @@ void EventSender::handleMouseWheel(const CppArgumentList& arguments, CppVariant* event.wheelTicksY = static_cast<float>(vertical); event.deltaX = event.wheelTicksX; event.deltaY = event.wheelTicksY; - if (!continuous) { + if (continuous) { + event.wheelTicksX /= scrollbarPixelsPerTick; + event.wheelTicksY /= scrollbarPixelsPerTick; + } else { event.deltaX *= scrollbarPixelsPerTick; event.deltaY *= scrollbarPixelsPerTick; } diff --git a/WebKitTools/DumpRenderTree/chromium/EventSender.h b/WebKitTools/DumpRenderTree/chromium/EventSender.h index 0d8fe5d..399a132 100644 --- a/WebKitTools/DumpRenderTree/chromium/EventSender.h +++ b/WebKitTools/DumpRenderTree/chromium/EventSender.h @@ -38,7 +38,7 @@ #define EventSender_h #include "CppBoundClass.h" -#include "base/task.h" +#include "Task.h" #include "public/WebDragOperation.h" #include "public/WebInputEvent.h" #include "public/WebPoint.h" @@ -108,6 +108,8 @@ public: CppVariant wmSysDeadChar; #endif + TaskList* taskList() { return &m_taskList; } + private: // Returns the test shell's webview. WebKit::WebView* webview(); @@ -141,7 +143,7 @@ private: // Handle a request to send a wheel event. void handleMouseWheel(const CppArgumentList&, CppVariant*, bool continuous); - ScopedRunnableMethodFactory<EventSender> m_methodFactory; + TaskList m_taskList; // Non-owning pointer. The EventSender is owned by the TestShell. TestShell* m_shell; diff --git a/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp index 2999d3a..6f962bf 100644 --- a/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp +++ b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp @@ -38,6 +38,8 @@ #include "public/WebAnimationController.h" #include "public/WebBindings.h" #include "public/WebConsoleMessage.h" +#include "public/WebDeviceOrientation.h" +#include "public/WebDeviceOrientationClientMock.h" #include "public/WebDocument.h" #include "public/WebElement.h" #include "public/WebFrame.h" @@ -67,8 +69,7 @@ using namespace WebKit; using namespace std; LayoutTestController::LayoutTestController(TestShell* shell) - : m_timeoutFactory(this) - , m_shell(shell) + : m_shell(shell) , m_workQueue(this) { @@ -195,6 +196,10 @@ LayoutTestController::LayoutTestController(TestShell* shell) bindProperty("webHistoryItemCount", &m_webHistoryItemCount); } +LayoutTestController::~LayoutTestController() +{ +} + LayoutTestController::WorkQueue::~WorkQueue() { reset(); @@ -207,10 +212,9 @@ void LayoutTestController::WorkQueue::processWorkSoon() if (!m_queue.isEmpty()) { // We delay processing queued work to avoid recursion problems. - m_timer.Start(base::TimeDelta(), this, &WorkQueue::processWork); - } else if (!m_controller->m_waitUntilDone) { + postTask(new WorkQueueTask(this)); + } else if (!m_controller->m_waitUntilDone) m_controller->m_shell->testFinished(); - } } void LayoutTestController::WorkQueue::processWork() @@ -320,11 +324,8 @@ void LayoutTestController::setAcceptsEditing(const CppArgumentList& arguments, C void LayoutTestController::waitUntilDone(const CppArgumentList&, CppVariant* result) { - if (!webkit_support::BeingDebugged()) { - webkit_support::PostDelayedTaskFromHere( - m_timeoutFactory.NewRunnableMethod(&LayoutTestController::notifyDoneTimedOut), - m_shell->layoutTestTimeout()); - } + if (!webkit_support::BeingDebugged()) + postDelayedTask(new NotifyDoneTimedOutTask(this), m_shell->layoutTestTimeout()); m_waitUntilDone = true; result->setNull(); } @@ -332,17 +333,12 @@ void LayoutTestController::waitUntilDone(const CppArgumentList&, CppVariant* res void LayoutTestController::notifyDone(const CppArgumentList&, CppVariant* result) { // Test didn't timeout. Kill the timeout timer. - m_timeoutFactory.RevokeAll(); + m_taskList.revokeAll(); completeNotifyDone(false); result->setNull(); } -void LayoutTestController::notifyDoneTimedOut() -{ - completeNotifyDone(true); -} - void LayoutTestController::completeNotifyDone(bool isTimeout) { if (m_waitUntilDone && !m_shell->webViewHost()->topLoadingFrame() && m_workQueue.isEmpty()) { @@ -521,7 +517,7 @@ void LayoutTestController::reset() else m_closeRemainingWindows = true; m_workQueue.reset(); - m_timeoutFactory.RevokeAll(); + m_taskList.revokeAll(); } void LayoutTestController::locationChangeDone() @@ -1397,8 +1393,14 @@ void LayoutTestController::setEditingBehavior(const CppArgumentList& arguments, void LayoutTestController::setMockDeviceOrientation(const CppArgumentList& arguments, CppVariant* result) { - // FIXME: Implement for DeviceOrientation layout tests. - // See https://bugs.webkit.org/show_bug.cgi?id=30335. + 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; + + WebKit::WebDeviceOrientation orientation(arguments[0].toBoolean(), arguments[1].toDouble(), arguments[2].toBoolean(), arguments[3].toDouble(), arguments[4].toBoolean(), arguments[5].toDouble()); + + ASSERT(m_deviceOrientationClientMock); + m_deviceOrientationClientMock->setOrientation(orientation); } void LayoutTestController::setGeolocationPermission(const CppArgumentList& arguments, CppVariant* result) @@ -1454,3 +1456,10 @@ void LayoutTestController::markerTextForListItem(const CppArgumentList& args, Cp else result->set(element.document().frame()->markerTextForListItem(element).utf8()); } + +WebKit::WebDeviceOrientationClient* LayoutTestController::deviceOrientationClient() +{ + if (!m_deviceOrientationClientMock.get()) + m_deviceOrientationClientMock.set(new WebKit::WebDeviceOrientationClientMock()); + return m_deviceOrientationClientMock.get(); +} diff --git a/WebKitTools/DumpRenderTree/chromium/LayoutTestController.h b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.h index 6706157..7bb22ca 100644 --- a/WebKitTools/DumpRenderTree/chromium/LayoutTestController.h +++ b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.h @@ -42,13 +42,15 @@ #define LayoutTestController_h #include "CppBoundClass.h" -#include "base/timer.h" // FIXME: Remove this. +#include "Task.h" #include "public/WebString.h" #include "public/WebURL.h" #include <wtf/Deque.h> #include <wtf/OwnPtr.h> namespace WebKit { +class WebDeviceOrientationClient; +class WebDeviceOrientationClientMock; class WebSpeechInputController; class WebSpeechInputControllerMock; class WebSpeechInputListener; @@ -62,6 +64,8 @@ public: // 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. @@ -116,7 +120,6 @@ public: // to delay the completion of the test until notifyDone is called. void waitUntilDone(const CppArgumentList&, CppVariant*); void notifyDone(const CppArgumentList&, CppVariant*); - void notifyDoneTimedOut(); // Methods for adding actions to the work queue. Used in conjunction with // waitUntilDone/notifyDone above. @@ -319,6 +322,7 @@ public: void setWorkQueueFrozen(bool frozen) { m_workQueue.setFrozen(frozen); } WebKit::WebSpeechInputController* speechInputController(WebKit::WebSpeechInputListener*); + WebKit::WebDeviceOrientationClient* deviceOrientationClient(); bool shouldDumpAsText() { return m_dumpAsText; } bool shouldDumpEditingCallbacks() { return m_dumpEditingCallbacks; } bool shouldDumpFrameLoadCallbacks() { return m_dumpFrameLoadCallbacks; } @@ -360,6 +364,8 @@ public: virtual bool run(TestShell* shell) = 0; }; + TaskList* taskList() { return &m_taskList; } + private: friend class WorkItem; friend class WorkQueue; @@ -379,11 +385,17 @@ private: 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(); } + }; - base::OneShotTimer<WorkQueue> m_timer; + TaskList m_taskList; Deque<WorkItem*> m_queue; bool m_frozen; LayoutTestController* m_controller; @@ -396,6 +408,12 @@ private: 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); @@ -405,7 +423,7 @@ private: void resumeAnimations(); // Used for test timeouts. - ScopedRunnableMethodFactory<LayoutTestController> m_timeoutFactory; + TaskList m_taskList; // Non-owning pointer. The LayoutTestController is owned by the host. TestShell* m_shell; @@ -493,6 +511,8 @@ private: WebKit::WebURL m_userStyleSheetLocation; OwnPtr<WebKit::WebSpeechInputControllerMock> m_speechInputControllerMock; + + OwnPtr<WebKit::WebDeviceOrientationClientMock> m_deviceOrientationClientMock; }; #endif // LayoutTestController_h diff --git a/WebKitTools/DumpRenderTree/chromium/NotificationPresenter.cpp b/WebKitTools/DumpRenderTree/chromium/NotificationPresenter.cpp index 1098e38..7d4cbe3 100644 --- a/WebKitTools/DumpRenderTree/chromium/NotificationPresenter.cpp +++ b/WebKitTools/DumpRenderTree/chromium/NotificationPresenter.cpp @@ -31,14 +31,14 @@ #include "config.h" #include "NotificationPresenter.h" -#include "base/task.h" // FIXME: Remove this #include "googleurl/src/gurl.h" +#include "public/WebKit.h" +#include "public/WebKitClient.h" #include "public/WebNotification.h" #include "public/WebNotificationPermissionCallback.h" #include "public/WebSecurityOrigin.h" #include "public/WebString.h" #include "public/WebURL.h" -#include "webkit/support/webkit_support.h" #include <wtf/text/CString.h> #include <wtf/text/WTFString.h> @@ -51,9 +51,11 @@ static WebString identifierForNotification(const WebNotification& notification) return notification.title(); } -static void deferredDisplayDispatch(WebNotification notification) +static void deferredDisplayDispatch(void* context) { - notification.dispatchDisplayEvent(); + WebNotification* notification = static_cast<WebNotification*>(context); + notification->dispatchDisplayEvent(); + delete notification; } void NotificationPresenter::grantPermission(const WebString& origin) @@ -105,8 +107,7 @@ bool NotificationPresenter::show(const WebNotification& notification) WTF::String id(identifier.data(), identifier.length()); m_activeNotifications.set(id, notification); - WebNotification eventTarget(notification); - webkit_support::PostTaskFromHere(NewRunnableFunction(&deferredDisplayDispatch, eventTarget)); + webKitClient()->callOnMainThread(deferredDisplayDispatch, new WebNotification(notification)); return true; } diff --git a/WebKitTools/DumpRenderTree/chromium/Task.cpp b/WebKitTools/DumpRenderTree/chromium/Task.cpp new file mode 100644 index 0000000..3f90d8c --- /dev/null +++ b/WebKitTools/DumpRenderTree/chromium/Task.cpp @@ -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. + */ + +#include "config.h" +#include "Task.h" + +#include "public/WebKit.h" +#include "public/WebKitClient.h" +#include "webkit/support/webkit_support.h" + +WebTask::WebTask(TaskList* list): m_taskList(list) { m_taskList->registerTask(this); } +WebTask::~WebTask() { 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() +{ + for (unsigned i = 0; i < m_tasks.size(); ++i) + m_tasks[i]->cancel(); + m_tasks.clear(); +} + +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/WebKitTools/DumpRenderTree/chromium/Task.h b/WebKitTools/DumpRenderTree/chromium/Task.h new file mode 100644 index 0000000..39fb8f2 --- /dev/null +++ b/WebKitTools/DumpRenderTree/chromium/Task.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 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(); +private: + 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; } + 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/WebKitTools/DumpRenderTree/chromium/TestShell.cpp b/WebKitTools/DumpRenderTree/chromium/TestShell.cpp index 21a153d..4557803 100644 --- a/WebKitTools/DumpRenderTree/chromium/TestShell.cpp +++ b/WebKitTools/DumpRenderTree/chromium/TestShell.cpp @@ -42,6 +42,7 @@ #include "public/WebElement.h" #include "public/WebFrame.h" #include "public/WebHistoryItem.h" +#include "public/WebKit.h" #include "public/WebRuntimeFeatures.h" #include "public/WebScriptController.h" #include "public/WebSettings.h" @@ -204,6 +205,7 @@ void TestShell::resetWebSettings(WebView& webView) settings->setLocalStorageEnabled(true); settings->setOfflineWebApplicationCacheEnabled(true); settings->setAllowFileAccessFromFileURLs(true); + settings->setUserStyleSheetLocation(WebURL()); // LayoutTests were written with Safari Mac in mind which does not allow // tabbing to links by default. @@ -493,6 +495,7 @@ void TestShell::dump() if (!frame) return; bool shouldDumpAsText = m_layoutTestController->shouldDumpAsText(); + bool shouldGeneratePixelResults = m_layoutTestController->shouldGeneratePixelResults(); bool dumpedAnything = false; if (m_params.dumpTree) { dumpedAnything = true; @@ -502,7 +505,10 @@ void TestShell::dump() if (!shouldDumpAsText) { // Plain text pages should be dumped as text string mimeType = frame->dataSource()->response().mimeType().utf8(); - shouldDumpAsText = mimeType == "text/plain"; + if (mimeType == "text/plain") { + shouldDumpAsText = true; + shouldGeneratePixelResults = false; + } } if (shouldDumpAsText) { bool recursive = m_layoutTestController->shouldDumpChildFramesAsText(); @@ -520,7 +526,7 @@ void TestShell::dump() if (dumpedAnything && m_params.printSeparators) m_printer->handleTextFooter(); - if (m_params.dumpPixels && m_layoutTestController->shouldGeneratePixelResults()) { + 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. @@ -587,6 +593,8 @@ void TestShell::dumpImage(skia::PlatformCanvas* canvas) const bool discardTransparency = false; #elif OS(UNIX) bool discardTransparency = true; + if (areLayoutTestImagesOpaque()) + device.makeOpaque(0, 0, sourceBitmap.width(), sourceBitmap.height()); #endif // Compute MD5 sum. We should have done this before calling diff --git a/WebKitTools/DumpRenderTree/chromium/TestShell.h b/WebKitTools/DumpRenderTree/chromium/TestShell.h index 47261a3..cb5f862 100644 --- a/WebKitTools/DumpRenderTree/chromium/TestShell.h +++ b/WebKitTools/DumpRenderTree/chromium/TestShell.h @@ -186,5 +186,6 @@ private: void platformInit(int*, char***); void openStartupDialog(); +bool checkLayoutTestSystemDependencies(); #endif // TestShell_h diff --git a/WebKitTools/DumpRenderTree/chromium/TestShellGtk.cpp b/WebKitTools/DumpRenderTree/chromium/TestShellGtk.cpp index 56ee618..60408b9 100644 --- a/WebKitTools/DumpRenderTree/chromium/TestShellGtk.cpp +++ b/WebKitTools/DumpRenderTree/chromium/TestShellGtk.cpp @@ -203,3 +203,8 @@ void openStartupDialog() gtk_dialog_run(GTK_DIALOG(dialog)); // Runs a nested message loop. gtk_widget_destroy(dialog); } + +bool checkLayoutTestSystemDependencies() +{ + return true; +} diff --git a/WebKitTools/DumpRenderTree/chromium/TestShellMac.mm b/WebKitTools/DumpRenderTree/chromium/TestShellMac.mm index 71d990e..53ede56 100644 --- a/WebKitTools/DumpRenderTree/chromium/TestShellMac.mm +++ b/WebKitTools/DumpRenderTree/chromium/TestShellMac.mm @@ -137,3 +137,9 @@ void openStartupDialog() [alert addButtonWithTitle:@"OK"]; [alert runModal]; } + +bool checkLayoutTestSystemDependencies() +{ + return true; +} + diff --git a/WebKitTools/DumpRenderTree/chromium/TestShellWin.cpp b/WebKitTools/DumpRenderTree/chromium/TestShellWin.cpp index 0d818c4..9efcf5a 100644 --- a/WebKitTools/DumpRenderTree/chromium/TestShellWin.cpp +++ b/WebKitTools/DumpRenderTree/chromium/TestShellWin.cpp @@ -35,9 +35,18 @@ #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 WebThemeEngineDRT themeEngine; @@ -154,3 +163,82 @@ 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/WebKitTools/DumpRenderTree/chromium/WebViewHost.cpp b/WebKitTools/DumpRenderTree/chromium/WebViewHost.cpp index fae3f56..1e3a4d6 100644 --- a/WebKitTools/DumpRenderTree/chromium/WebViewHost.cpp +++ b/WebKitTools/DumpRenderTree/chromium/WebViewHost.cpp @@ -512,6 +512,11 @@ WebSpeechInputController* WebViewHost::speechInputController(WebKit::WebSpeechIn return m_shell->layoutTestController()->speechInputController(listener); } +WebKit::WebDeviceOrientationClient* WebViewHost::deviceOrientationClient() +{ + return m_shell->layoutTestController()->deviceOrientationClient(); +} + // WebWidgetClient ----------------------------------------------------------- void WebViewHost::didInvalidateRect(const WebRect& rect) diff --git a/WebKitTools/DumpRenderTree/chromium/WebViewHost.h b/WebKitTools/DumpRenderTree/chromium/WebViewHost.h index 5067342..3a84ebd 100644 --- a/WebKitTools/DumpRenderTree/chromium/WebViewHost.h +++ b/WebKitTools/DumpRenderTree/chromium/WebViewHost.h @@ -45,6 +45,7 @@ class LayoutTestController; class TestShell; namespace WebKit { class WebFrame; +class WebDeviceOrientationClient; class WebGeolocationServiceMock; class WebSpeechInputController; class WebSpeechInputListener; @@ -130,6 +131,7 @@ class WebViewHost : public WebKit::WebViewClient, public WebKit::WebFrameClient, virtual WebKit::WebNotificationPresenter* notificationPresenter(); virtual WebKit::WebGeolocationService* geolocationService(); virtual WebKit::WebSpeechInputController* speechInputController(WebKit::WebSpeechInputListener*); + virtual WebKit::WebDeviceOrientationClient* deviceOrientationClient(); // WebKit::WebWidgetClient virtual void didInvalidateRect(const WebKit::WebRect&); diff --git a/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp b/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp index bd9c0c9..af2e403 100644 --- a/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp +++ b/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp @@ -96,6 +96,8 @@ 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; @@ -128,11 +130,13 @@ static void appendString(gchar*& target, gchar* string) g_free(oldString); } -#if PLATFORM(X11) static void initializeFonts() { +#if PLATFORM(X11) static int numFonts = -1; + FcInit(); + // Some tests may add or remove fonts via the @font-face rule. // If that happens, font config should be re-created to suppress any unwanted change. FcFontSet* appFontSet = FcConfigGetFonts(0, FcSetApplication); @@ -160,8 +164,8 @@ static void initializeFonts() appFontSet = FcConfigGetFonts(config, FcSetApplication); numFonts = appFontSet->nfont; -} #endif +} static gchar* dumpFramesAsText(WebKitWebFrame* frame) { @@ -357,6 +361,50 @@ static void resetDefaultsToConsistentValues() setlocale(LC_ALL, ""); } +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(); @@ -516,9 +564,7 @@ static void runTest(const string& testPathOrURL) if (prevTestBFItem) g_object_ref(prevTestBFItem); -#if PLATFORM(X11) initializeFonts(); -#endif // Focus the web view before loading the test to avoid focusing problems gtk_widget_grab_focus(GTK_WIDGET(webView)); @@ -941,26 +987,8 @@ int main(int argc, char* argv[]) // We squelch all debug messages sent to the logger. g_log_set_default_handler(logHandler, 0); -#if PLATFORM(X11) - FcInit(); + initializeGlobalsFromCommandLineOptions(argc, argv); initializeFonts(); -#endif - - 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; - } window = gtk_window_new(GTK_WINDOW_POPUP); container = GTK_WIDGET(gtk_scrolled_window_new(NULL, NULL)); @@ -980,19 +1008,9 @@ int main(int argc, char* argv[]) gcController = new GCController(); axController = new AccessibilityController(); - if (argc == optind+1 && strcmp(argv[optind], "-") == 0) { - char filenameBuffer[2048]; + if (useLongRunningServerMode(argc, argv)) { printSeparators = true; - while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) { - char* newLineCharacter = strchr(filenameBuffer, '\n'); - if (newLineCharacter) - *newLineCharacter = '\0'; - - if (strlen(filenameBuffer) == 0) - continue; - - runTest(filenameBuffer); - } + runTestingServerLoop(); } else { printSeparators = (optind < argc-1 || (dumpPixels && dumpTree)); for (int i = optind; i != argc; ++i) diff --git a/WebKitTools/DumpRenderTree/gtk/EventSender.cpp b/WebKitTools/DumpRenderTree/gtk/EventSender.cpp index 63a4b81..fc118bc 100644 --- a/WebKitTools/DumpRenderTree/gtk/EventSender.cpp +++ b/WebKitTools/DumpRenderTree/gtk/EventSender.cpp @@ -110,7 +110,7 @@ static JSValueRef leapForwardCallback(JSContextRef context, JSObjectRef function return JSValueMakeUndefined(context); } -bool prepareMouseButtonEvent(GdkEvent* event, int eventSenderButtonNumber) +bool prepareMouseButtonEvent(GdkEvent* event, int eventSenderButtonNumber, guint modifiers) { WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); if (!view) @@ -133,7 +133,7 @@ bool prepareMouseButtonEvent(GdkEvent* event, int eventSenderButtonNumber) 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 = getStateFlags(); + event->button.state = modifiers | getStateFlags(); event->button.time = GDK_CURRENT_TIME; event->button.axes = 0; @@ -148,7 +148,7 @@ bool prepareMouseButtonEvent(GdkEvent* event, int eventSenderButtonNumber) 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)) + if (!prepareMouseButtonEvent(pressEvent, 2, 0)) return JSValueMakeUndefined(context); GdkEvent* releaseEvent = gdk_event_copy(pressEvent); @@ -170,6 +170,36 @@ static void updateClickCount(int button) 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; @@ -177,9 +207,10 @@ static JSValueRef mouseDownCallback(JSContextRef context, JSObjectRef function, 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)) + if (!prepareMouseButtonEvent(event, button, modifiers)) return JSValueMakeUndefined(context); buttonCurrentlyDown = event->button.button; @@ -220,9 +251,10 @@ static JSValueRef mouseUpCallback(JSContextRef context, JSObjectRef function, JS 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)) + if (!prepareMouseButtonEvent(event, button, modifiers)) return JSValueMakeUndefined(context); lastClickPositionX = lastMousePositionX; diff --git a/WebKitTools/DumpRenderTree/gtk/ImageDiff.cpp b/WebKitTools/DumpRenderTree/gtk/ImageDiff.cpp index c40b232..7e2744a 100644 --- a/WebKitTools/DumpRenderTree/gtk/ImageDiff.cpp +++ b/WebKitTools/DumpRenderTree/gtk/ImageDiff.cpp @@ -199,10 +199,15 @@ int main(int argc, char* argv[]) *newLineCharacter = '\0'; if (!strncmp("Content-Length: ", buffer, 16)) { - char* context; - strtok_r(buffer, " ", &context); - long imageSize = strtol(strtok_r(0, " ", &context), 0, 10); + 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"); diff --git a/WebKitTools/DumpRenderTree/mac/AccessibilityTextMarkerMac.mm b/WebKitTools/DumpRenderTree/mac/AccessibilityTextMarkerMac.mm new file mode 100644 index 0000000..9170ab6 --- /dev/null +++ b/WebKitTools/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/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm b/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm index d1592b2..fa4acf5 100644 --- a/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm +++ b/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm @@ -1190,3 +1190,70 @@ 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; +} + +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/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm b/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm index e756ebf..ffcb18a 100644 --- a/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm +++ b/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm @@ -62,6 +62,7 @@ #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/WebHTMLRepresentationInternal.h> @@ -292,6 +293,7 @@ WebView *createWebViewAndOffscreenWindow() [webView setEditingDelegate:editingDelegate]; [webView setResourceLoadDelegate:resourceLoadDelegate]; [webView _setGeolocationProvider:[MockGeolocationProvider shared]]; + [webView _setDeviceOrientationProvider:[[WebDeviceOrientationProviderMock alloc] init]]; // Register the same schemes that Safari does [WebView registerURLSchemeAsLocal:@"feed"]; diff --git a/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm b/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm index 97c177d..f55093e 100644 --- a/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm +++ b/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm @@ -45,9 +45,11 @@ #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/WebDOMOperationsPrivate.h> +#import <WebKit/WebDeviceOrientation.h> +#import <WebKit/WebDeviceOrientationProviderMock.h> #import <WebKit/WebFrame.h> #import <WebKit/WebFrameViewPrivate.h> #import <WebKit/WebGeolocationPosition.h> @@ -336,9 +338,11 @@ void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool forbidd 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. - + // 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]; } void LayoutTestController::setMockGeolocationPosition(double latitude, double longitude, double accuracy) diff --git a/WebKitTools/DumpRenderTree/mac/ObjCController.m b/WebKitTools/DumpRenderTree/mac/ObjCController.m index 641d2cc..f1d1c10 100644 --- a/WebKitTools/DumpRenderTree/mac/ObjCController.m +++ b/WebKitTools/DumpRenderTree/mac/ObjCController.m @@ -29,8 +29,12 @@ #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> @@ -73,6 +77,7 @@ static void* runJavaScriptThread(void* arg) || aSelector == @selector(testValueForKey) || aSelector == @selector(testHasWebScriptKey:) || aSelector == @selector(testArray) + || aSelector == @selector(setSelectElement:selectedIndex:allowingMultiple:) ) return NO; return YES; @@ -102,6 +107,8 @@ static void* runJavaScriptThread(void* arg) return @"testHasWebScriptKey"; if (aSelector == @selector(testArray)) return @"testArray"; + if (aSelector == @selector(setSelectElement:selectedIndex:allowingMultiple:)) + return @"setSelectElementSelectedIndexAllowingMultiple"; return nil; } @@ -263,4 +270,16 @@ static void* runJavaScriptThread(void* arg) 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/WebKitTools/DumpRenderTree/mac/TextInputController.m b/WebKitTools/DumpRenderTree/mac/TextInputController.m index 3ea9c22..a049ac5 100644 --- a/WebKitTools/DumpRenderTree/mac/TextInputController.m +++ b/WebKitTools/DumpRenderTree/mac/TextInputController.m @@ -33,6 +33,7 @@ #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> @@ -169,7 +170,8 @@ || aSelector == @selector(characterIndexForPointX:Y:) || aSelector == @selector(validAttributesForMarkedText) || aSelector == @selector(attributedStringWithString:) - || aSelector == @selector(setInputMethodHandler:)) + || aSelector == @selector(setInputMethodHandler:) + || aSelector == @selector(hasSpellingMarker:length:)) return NO; return YES; } @@ -194,6 +196,8 @@ return @"makeAttributedString"; // just a factory method, doesn't call into NSTextInput else if (aSelector == @selector(setInputMethodHandler:)) return @"setInputMethodHandler"; + else if (aSelector == @selector(hasSpellingMarker:length:)) + return @"hasSpellingMarker"; return nil; } @@ -427,4 +431,9 @@ return YES; } +- (BOOL)hasSpellingMarker:(int)from length:(int)length +{ + return [[webView mainFrame] hasSpellingMarker:from length:length]; +} + @end diff --git a/WebKitTools/DumpRenderTree/qt/ImageDiff.cpp b/WebKitTools/DumpRenderTree/qt/ImageDiff.cpp index 8ee68db..9282e2f 100644 --- a/WebKitTools/DumpRenderTree/qt/ImageDiff.cpp +++ b/WebKitTools/DumpRenderTree/qt/ImageDiff.cpp @@ -132,7 +132,10 @@ int main(int argc, char* argv[]) buffer.close(); const QByteArray &data = buffer.data(); printf("Content-Length: %lu\n", static_cast<unsigned long>(data.length())); - fwrite(data.constData(), 1, data.length(), stdout); + + // 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); } diff --git a/WebKitTools/DumpRenderTree/win/DumpRenderTree.vcproj b/WebKitTools/DumpRenderTree/win/DumpRenderTree.vcproj index 125c6c6..1e765c6 100644 --- a/WebKitTools/DumpRenderTree/win/DumpRenderTree.vcproj +++ b/WebKitTools/DumpRenderTree/win/DumpRenderTree.vcproj @@ -578,6 +578,14 @@ >
</File>
<File
+ RelativePath="..\AccessibilityTextMarker.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\AccessibilityTextMarker.h"
+ >
+ </File>
+ <File
RelativePath=".\DraggingInfo.h"
>
</File>
diff --git a/WebKitTools/EWebLauncher/main.c b/WebKitTools/EWebLauncher/main.c new file mode 100644 index 0000000..c1956a2 --- /dev/null +++ b/WebKitTools/EWebLauncher/main.c @@ -0,0 +1,850 @@ +/* + * 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; + +// 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; + +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_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; + Eina_Bool userScalable; +} Viewport; + +typedef struct _ELauncher { + Ecore_Evas *ee; + Evas *evas; + Evas_Object *bg; + Evas_Object *browser; + const char *theme; + const char *userAgent; + 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, unsigned char isFullscreen); + +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 void +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; + 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); +} + +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, userScalable; + + ewk_view_viewport_get(webview, &w, &h, &initScale, &maxScale, &minScale, &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)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.userScalable = (Eina_Bool)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); + } else if (!strcmp(ev->key, "F8")) { + info("Zoom in (F8) was pressed.\n"); + if (currentZoomLevel < MAX_ZOOM_LEVEL) + zoom_level_set(obj, ++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, NULL, 0); + } 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); + } +} + +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); + + free(themePath); + + 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, unsigned char isFullscreen) +{ + 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"); + + if (!theme) + theme = themePath; + + app->theme = theme; + app->userAgent = userAgent; + + 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); + app->browser = ewk_view_single_add(app->evas); + + ewk_view_theme_set(app->browser, theme); + if (userAgent) + ewk_view_setting_user_agent_set(app->browser, userAgent); + 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(void) +{ + const char **itr, *locations[] = { + "./default.edj", + "./WebKit/efl/DefaultTheme/default.edj", + "../WebKit/efl/DefaultTheme/default.edj", + DATA_DIR"/themes/default.edj", + NULL + }; + + for (itr = locations; *itr; itr++) { + struct stat st; + if (!stat(*itr, &st)) { + char path[PATH_MAX]; + if (realpath(*itr, path)) + return strdup(path); + } + } + + return NULL; +} + +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; + + 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_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(); + + 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, theme, userAgent, geometry, engine, isFullscreen); + 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/WebKitTools/GNUmakefile.am b/WebKitTools/GNUmakefile.am index 39df421..292ca7e 100644 --- a/WebKitTools/GNUmakefile.am +++ b/WebKitTools/GNUmakefile.am @@ -49,6 +49,8 @@ Programs_DumpRenderTree_SOURCES = \ WebKitTools/DumpRenderTree/DumpRenderTreePrefix.h \ WebKitTools/DumpRenderTree/AccessibilityController.cpp \ WebKitTools/DumpRenderTree/AccessibilityController.h \ + WebKitTools/DumpRenderTree/AccessibilityTextMarker.cpp \ + WebKitTools/DumpRenderTree/AccessibilityTextMarker.h \ WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp \ WebKitTools/DumpRenderTree/AccessibilityUIElement.h \ WebKitTools/DumpRenderTree/GCController.cpp \ diff --git a/WebKitTools/MiniBrowser/mac/WebBundle/WebBundleMain.m b/WebKitTools/MiniBrowser/mac/WebBundle/WebBundleMain.m index 17958c7..1fffce6 100644 --- a/WebKitTools/MiniBrowser/mac/WebBundle/WebBundleMain.m +++ b/WebKitTools/MiniBrowser/mac/WebBundle/WebBundleMain.m @@ -37,7 +37,7 @@ static WKBundleRef globalBundle; // WKBundlePageClient functions -void didClearWindowObjectForFrame(WKBundlePageRef page, WKBundleFrameRef frame, JSGlobalContextRef context, JSObjectRef window, const void *clientInfo) +void didClearWindowObjectForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleScriptWorldRef world, const void *clientInfo) { WKURLRef wkURL = WKBundleFrameCopyURL(WKBundlePageGetMainFrame(page)); CFURLRef cfURL = WKURLCopyCFURL(0, wkURL); diff --git a/WebKitTools/MiniBrowser/qt/BrowserView.cpp b/WebKitTools/MiniBrowser/qt/BrowserView.cpp new file mode 100644 index 0000000..a5e06ec --- /dev/null +++ b/WebKitTools/MiniBrowser/qt/BrowserView.cpp @@ -0,0 +1,75 @@ +/* + * 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> +#include "WKContext.h" + +static QWKPage* createNewPage(QWKPage* page) +{ + return page; +} + +BrowserView::BrowserView(QWidget* parent) + : QGraphicsView(parent) + , m_item(0) +{ + m_context.adopt(WKContextGetSharedProcessContext()); + + WKRetainPtr<WKPageNamespaceRef> pageNamespace(AdoptWK, WKPageNamespaceCreate(m_context.get())); + + m_item = new QGraphicsWKView(pageNamespace.get(), QGraphicsWKView::Simple, 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/WebKitTools/MiniBrowser/qt/BrowserView.h b/WebKitTools/MiniBrowser/qt/BrowserView.h new file mode 100644 index 0000000..42b7658 --- /dev/null +++ b/WebKitTools/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 "WKRetainPtr.h" + +class BrowserView : public QGraphicsView { + Q_OBJECT + +public: + BrowserView(QWidget* parent = 0); + virtual ~BrowserView() { delete m_item; } + + void load(const QString&); + QGraphicsWKView* view() const; + +protected: + virtual void resizeEvent(QResizeEvent*); + +private: + QGraphicsWKView* m_item; + WKRetainPtr<WKContextRef> m_context; +}; + +#endif diff --git a/WebKitTools/MiniBrowser/qt/BrowserWindow.cpp b/WebKitTools/MiniBrowser/qt/BrowserWindow.cpp index 2e0dccd..a703788 100644 --- a/WebKitTools/MiniBrowser/qt/BrowserWindow.cpp +++ b/WebKitTools/MiniBrowser/qt/BrowserWindow.cpp @@ -27,55 +27,8 @@ */ #include "BrowserWindow.h" -#include "WKPageNamespace.h" -#include "qwkpage.h" - -static QWKPage* createNewPage(QWKPage* page) -{ - return page; -} - -BrowserView::BrowserView(QWidget* parent) - : QGraphicsView(parent) - , m_item(0) -{ - m_context.adopt(WKContextGetSharedProcessContext()); - - WKRetainPtr<WKPageNamespaceRef> pageNamespace(AdoptWK, WKPageNamespaceCreate(m_context.get())); - - m_item = new QGraphicsWKView(pageNamespace.get(), QGraphicsWKView::Simple, 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 QUrl& url) -{ -#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) - return m_item->load(QUrl::fromUserInput(url.toString())); -#else - return m_item->load(url); -#endif -} - -QGraphicsWKView* BrowserView::view() const -{ - return m_item; -} +#include "WKPageNamespace.h" BrowserWindow::BrowserWindow() { @@ -106,19 +59,20 @@ BrowserWindow::BrowserWindow() this->setCentralWidget(m_browser); m_browser->setFocus(Qt::OtherFocusReason); + + resize(960, 640); + show(); } void BrowserWindow::load(const QString& url) { m_addressBar->setText(url); - m_browser->load(QUrl(url)); + m_browser->load(url); } BrowserWindow* BrowserWindow::newWindow(const QString& url) { BrowserWindow* window = new BrowserWindow(); - window->resize(960, 640); - window->show(); window->load(url); return window; } diff --git a/WebKitTools/MiniBrowser/qt/BrowserWindow.h b/WebKitTools/MiniBrowser/qt/BrowserWindow.h index 99d3e82..47e55b5 100644 --- a/WebKitTools/MiniBrowser/qt/BrowserWindow.h +++ b/WebKitTools/MiniBrowser/qt/BrowserWindow.h @@ -26,33 +26,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef BrowserWindow_h +#define BrowserWindow_h + #define PLATFORM(x) 0 -#include "WKContext.h" -#include "WKRetainPtr.h" -#include "qgraphicswkview.h" +#include "BrowserView.h" #include <QtGui> -#include <QGraphicsScene> -#include <QGraphicsView> -#include <stdint.h> - -class BrowserView : public QGraphicsView { - Q_OBJECT - -public: - BrowserView(QWidget* parent = 0); - virtual ~BrowserView() { delete m_item; } - - void load(const QUrl&); - QGraphicsWKView* view() const; - -protected: - virtual void resizeEvent(QResizeEvent*); - -private: - QGraphicsWKView* m_item; - WKRetainPtr<WKContextRef> m_context; -}; class BrowserWindow : public QMainWindow { Q_OBJECT @@ -76,3 +56,5 @@ private: QMenuBar* m_menu; QLineEdit* m_addressBar; }; + +#endif diff --git a/WebKitTools/MiniBrowser/qt/MiniBrowser.pro b/WebKitTools/MiniBrowser/qt/MiniBrowser.pro index 274b9e5..e42c49a 100644 --- a/WebKitTools/MiniBrowser/qt/MiniBrowser.pro +++ b/WebKitTools/MiniBrowser/qt/MiniBrowser.pro @@ -3,9 +3,11 @@ TARGET = MiniBrowser SOURCES += \ main.cpp \ + BrowserView.cpp \ BrowserWindow.cpp \ HEADERS += \ + BrowserView.h \ BrowserWindow.h \ CONFIG += uitools diff --git a/WebKitTools/MiniBrowser/qt/main.cpp b/WebKitTools/MiniBrowser/qt/main.cpp index 2bc346b..8ff3de8 100644 --- a/WebKitTools/MiniBrowser/qt/main.cpp +++ b/WebKitTools/MiniBrowser/qt/main.cpp @@ -26,8 +26,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <QtGui> #include "BrowserWindow.h" +#include <QtGui> int main(int argc, char** argv) { QApplication app(argc, argv); @@ -44,11 +44,11 @@ int main(int argc, char** argv) { urls.append("http://www.google.com"); } - BrowserWindow* window = 0; - foreach (QString url, urls) { - window = new BrowserWindow(); - window->newWindow(url); - } + BrowserWindow* window = new BrowserWindow(); + window->load(urls[0]); + + for (int i = 1; i < urls.size(); ++i) + window->newWindow(urls[i]); app.exec(); diff --git a/WebKitTools/MiniBrowser/win/BrowserWindow.cpp b/WebKitTools/MiniBrowser/win/BrowserWindow.cpp index e519b00..dc43a68 100644 --- a/WebKitTools/MiniBrowser/win/BrowserWindow.cpp +++ b/WebKitTools/MiniBrowser/win/BrowserWindow.cpp @@ -70,6 +70,10 @@ LRESULT BrowserWindow::wndProc(HWND window, UINT message, WPARAM wParam, LPARAM bool handled = true; switch (message) { + case WM_ERASEBKGND: + lResult = 1; + break; + case WM_COMMAND: lResult = onCommand(LOWORD(wParam), handled); break; diff --git a/WebKitTools/Scripts/VCSUtils.pm b/WebKitTools/Scripts/VCSUtils.pm index 05d7bd8..dd08baa 100644 --- a/WebKitTools/Scripts/VCSUtils.pm +++ b/WebKitTools/Scripts/VCSUtils.pm @@ -94,7 +94,7 @@ 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#^ (\+|-) ([^\r\n]+)#; # $2 is the start of the property's value (which may span multiple lines). +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. @@ -1037,9 +1037,9 @@ sub parseSvnProperty($$) } my $propertyChangeDelta; - if ($propertyValueType eq '+') { + if ($propertyValueType eq "+" || $propertyValueType eq "Merged") { $propertyChangeDelta = 1; - } elsif ($propertyValueType eq '-') { + } elsif ($propertyValueType eq "-" || $propertyValueType eq "Reverse-merged") { $propertyChangeDelta = -1; } else { die("Not reached."); @@ -1093,7 +1093,7 @@ sub parseSvnPropertyValue($$) $propertyValue = $2; # Does not include the end-of-line character(s). $eol = $POSTMATCH; } else { - die("Failed to find property value beginning with '+' or '-': \"$_\"."); + die("Failed to find property value beginning with '+', '-', 'Merged', or 'Reverse-merged': \"$_\"."); } while (<$fileHandle>) { diff --git a/WebKitTools/Scripts/do-webcore-rename b/WebKitTools/Scripts/do-webcore-rename index 54fb0af..a1674de 100755 --- a/WebKitTools/Scripts/do-webcore-rename +++ b/WebKitTools/Scripts/do-webcore-rename @@ -96,7 +96,7 @@ sub wanted my $isDOMTypeRename = 0; my %renames = ( # Renames go here in the form of: - # "HTMLDocumentParser" => "LegacyHTMLDocumentParser", + "DocLoader" => "CachedResourceLoader", ); my %renamesContemplatedForTheFuture = ( diff --git a/WebKitTools/Scripts/svn-apply b/WebKitTools/Scripts/svn-apply index 33b2279..1cf9c01 100755 --- a/WebKitTools/Scripts/svn-apply +++ b/WebKitTools/Scripts/svn-apply @@ -280,7 +280,7 @@ sub isDirectoryEmptyForRemoval($) 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)) { + if (-d File::Spec->catdir($dir, $item)) { $directoryIsEmpty = 0; } else { next if (scmWillDeleteFile(File::Spec->catdir($dir, $item))); diff --git a/WebKitTools/Scripts/validate-committer-lists b/WebKitTools/Scripts/validate-committer-lists index ad3d358..2519e01 100755 --- a/WebKitTools/Scripts/validate-committer-lists +++ b/WebKitTools/Scripts/validate-committer-lists @@ -38,7 +38,7 @@ 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.scm import Git +from webkitpy.common.checkout.scm import Git # WebKit includes a built copy of BeautifulSoup in Scripts/webkitpy # so this import should always succeed. diff --git a/WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffFooter.pl b/WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffFooter.pl index e305484..4f05431 100644 --- a/WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffFooter.pl +++ b/WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffFooter.pl @@ -60,6 +60,55 @@ 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 diff --git a/WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseSvnProperty.pl b/WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseSvnProperty.pl index bdca1ab..6914051 100644 --- a/WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseSvnProperty.pl +++ b/WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseSvnProperty.pl @@ -73,11 +73,77 @@ END 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 @@ -459,6 +525,40 @@ END "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. ## diff --git a/WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseSvnPropertyValue.pl b/WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseSvnPropertyValue.pl index 5fc2ff1..2de8ae3 100644 --- a/WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseSvnPropertyValue.pl +++ b/WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseSvnPropertyValue.pl @@ -58,6 +58,24 @@ END }, { # 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', - * @@ -152,6 +170,47 @@ 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; diff --git a/WebKitTools/Scripts/webkitpy/common/config/committers.py b/WebKitTools/Scripts/webkitpy/common/config/committers.py index 19ebc5f..6a45cab 100644 --- a/WebKitTools/Scripts/webkitpy/common/config/committers.py +++ b/WebKitTools/Scripts/webkitpy/common/config/committers.py @@ -74,7 +74,6 @@ committers_unable_to_review = [ Committer("Andrei Popescu", "andreip@google.com", "andreip"), Committer("Andrew Wellington", ["andrew@webkit.org", "proton@wiretapped.net"], "proton"), Committer("Andras Becsi", "abecsi@webkit.org", "bbandix"), - Committer("Andreas Kling", "andreas.kling@nokia.com", "kling"), Committer("Andy Estes", "aestes@apple.com", "estes"), Committer("Anthony Ricaud", "rik@webkit.org", "rik"), Committer("Anton Muhin", "antonm@chromium.org", "antonm"), @@ -90,6 +89,7 @@ committers_unable_to_review = [ 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("Csaba Osztrogonac", "ossy@webkit.org", "ossy"), @@ -110,12 +110,12 @@ committers_unable_to_review = [ 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("Hans Wennborg", "hans@chromium.org", "hwennborg"), 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("James Robinson", ["jamesr@chromium.org", "jamesr@google.com"], "jamesr"), Committer("Jay Civelli", "jcivelli@chromium.org", "jcivelli"), Committer("Jens Alfke", ["snej@chromium.org", "jens@apple.com"]), Committer("Jer Noble", "jer.noble@apple.com", "jernoble"), @@ -146,6 +146,7 @@ committers_unable_to_review = [ 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 Saboff", "msaboff@apple.com"), Committer("Michelangelo De Simone", "michelangelo@webkit.org", "michelangelo"), Committer("Mike Belshe", ["mbelshe@chromium.org", "mike@belshe.com"]), Committer("Mike Fenton", ["mifenton@rim.com", "mike.fenton@torchmobile.com"], "mfenton"), @@ -159,9 +160,10 @@ committers_unable_to_review = [ 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("Robert Hogan", ["robert@webkit.org", "robert@roberthogan.net"], "mwenge"), + Committer("Robert Hogan", ["robert@webkit.org", "robert@roberthogan.net", "lists@roberthogan.net"], "mwenge"), Committer("Roland Steiner", "rolandsteiner@chromium.org"), Committer("Ryosuke Niwa", "rniwa@webkit.org", "rniwa"), + Committer("Satish Sampath", "satish@chromium.org"), Committer("Scott Violet", "sky@chromium.org", "sky"), Committer("Stephen White", "senorblanco@chromium.org", "senorblanco"), Committer("Tony Gentilcore", "tonyg@chromium.org", "tonyg-cr"), @@ -192,14 +194,15 @@ 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"], "manyoso"), + 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("Antonio Gomes", "tonikitoo@webkit.org", "tonikitoo"), - Reviewer("Antti Koivisto", ["koivisto@iki.fi", "antti@apple.com"], "anttik"), + Reviewer("Andreas Kling", "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@sencha.com", "ariya.hidayat@gmail.com", "ariya@webkit.org"], "ariya"), Reviewer("Beth Dakin", "bdakin@apple.com", "dethbakin"), Reviewer("Brady Eidson", "beidson@apple.com", "bradee-oh"), @@ -228,21 +231,22 @@ reviewers_list = [ 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", "JoePeck"), + 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"], "kenne"), + 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"), + 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"), diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/failures/expected/hang.html b/WebKitTools/Scripts/webkitpy/layout_tests/data/failures/expected/hang.html new file mode 100644 index 0000000..4e0de08 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/failures/expected/hang.html @@ -0,0 +1 @@ +timeout-thread diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/http/tests/passes/text-expected.txt b/WebKitTools/Scripts/webkitpy/layout_tests/data/http/tests/passes/text-expected.txt new file mode 100644 index 0000000..2b38a06 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/http/tests/passes/text-expected.txt @@ -0,0 +1 @@ +text-txt diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/http/tests/passes/text.html b/WebKitTools/Scripts/webkitpy/layout_tests/data/http/tests/passes/text.html new file mode 100644 index 0000000..8e27be7 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/http/tests/passes/text.html @@ -0,0 +1 @@ +text diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/http/tests/ssl/text-expected.txt b/WebKitTools/Scripts/webkitpy/layout_tests/data/http/tests/ssl/text-expected.txt new file mode 100644 index 0000000..2b38a06 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/http/tests/ssl/text-expected.txt @@ -0,0 +1 @@ +text-txt diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/http/tests/ssl/text.html b/WebKitTools/Scripts/webkitpy/layout_tests/data/http/tests/ssl/text.html new file mode 100644 index 0000000..8e27be7 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/http/tests/ssl/text.html @@ -0,0 +1 @@ +text diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/platform/test/test_expectations.txt b/WebKitTools/Scripts/webkitpy/layout_tests/data/platform/test/test_expectations.txt index 16556e3..0619fde 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/data/platform/test/test_expectations.txt +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/platform/test/test_expectations.txt @@ -8,5 +8,6 @@ WONTFIX : failures/expected/missing_image.html = MISSING PASS WONTFIX : failures/expected/missing_text.html = MISSING PASS 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 diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/websocket/tests/passes/text-expected.txt b/WebKitTools/Scripts/webkitpy/layout_tests/data/websocket/tests/passes/text-expected.txt new file mode 100644 index 0000000..2b38a06 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/websocket/tests/passes/text-expected.txt @@ -0,0 +1 @@ +text-txt diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/websocket/tests/passes/text.html b/WebKitTools/Scripts/webkitpy/layout_tests/data/websocket/tests/passes/text.html new file mode 100644 index 0000000..8e27be7 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/websocket/tests/passes/text.html @@ -0,0 +1 @@ +text diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/deduplicate_tests.py b/WebKitTools/Scripts/webkitpy/layout_tests/deduplicate_tests.py index bb63f5e..c543d91 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/deduplicate_tests.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/deduplicate_tests.py @@ -130,6 +130,32 @@ def extract_platforms(paths): 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 find_dups(hashes, port_fallbacks): """Yields info about redundant test expectations. Args: @@ -151,7 +177,12 @@ def find_dups(hashes, port_fallbacks): for platform in platforms.keys(): for fallback in port_fallbacks[platform]: if fallback in platforms.keys(): - yield test, platform, fallback, platforms[platform] + # We have to verify that there isn't an intermediate result + # that causes this duplicate hash to exist. + if not has_intermediate_results(test, + port_fallbacks[platform], fallback): + path = os.path.join('LayoutTests', platforms[platform]) + yield test, platform, fallback, path def deduplicate(glob_pattern): diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py index 66dda32..be2e381 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py @@ -89,6 +89,47 @@ class ListDuplicatesTest(unittest.TestCase): 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' @@ -116,12 +157,12 @@ class ListDuplicatesTest(unittest.TestCase): self.assertEquals(('git', 'ls-tree', '-r', 'HEAD', 'LayoutTests'), MockExecutive.last_run_command[-1]) self.assertEquals(2, len(result)) self.assertEquals({'test': 'animage.png', - 'path': 'platform/chromium-linux/animage.png', + 'path': 'LayoutTests/platform/chromium-linux/animage.png', 'fallback': 'chromium-win', 'platform': 'chromium-linux'}, result[0]) self.assertEquals({'test': 'foo-expected.txt', - 'path': 'platform/chromium-linux/foo-expected.txt', + 'path': 'LayoutTests/platform/chromium-linux/foo-expected.txt', 'fallback': 'chromium-win', 'platform': 'chromium-linux'}, result[1]) @@ -131,7 +172,7 @@ class ListDuplicatesTest(unittest.TestCase): 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': 'platform/chromium-linux/foo-expected.txt', + 'path': 'LayoutTests/platform/chromium-linux/foo-expected.txt', 'fallback': 'chromium-win', 'platform': 'chromium-linux'}, result[0]) @@ -141,7 +182,7 @@ class ListDuplicatesTest(unittest.TestCase): self.assertEquals(('git', 'ls-tree', '-r', 'HEAD', 'LayoutTests'), MockExecutive.last_run_command[-1]) self.assertEquals(1, len(result)) self.assertEquals({'test': 'animage.png', - 'path': 'platform/chromium-linux/animage.png', + 'path': 'LayoutTests/platform/chromium-linux/animage.png', 'fallback': 'chromium-win', 'platform': 'chromium-linux'}, result[0]) diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py index ec33086..9b963ca 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py @@ -47,6 +47,7 @@ import sys import thread import threading import time +import traceback import test_failures @@ -54,6 +55,23 @@ _log = logging.getLogger("webkitpy.layout_tests.layout_package." "dump_render_tree_thread") +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()) + + def _process_output(port, test_info, test_types, test_args, configuration, output_dir, crash, timeout, test_run_time, actual_checksum, output, error): @@ -167,6 +185,7 @@ class SingleTestThread(threading.Thread): self._test_args = test_args self._configuration = configuration self._output_dir = output_dir + self._driver = None def run(self): self._covered_run() @@ -175,18 +194,19 @@ class SingleTestThread(threading.Thread): # FIXME: this is a separate routine to work around a bug # in coverage: see http://bitbucket.org/ned/coveragepy/issue/85. test_info = self._test_info - driver = self._port.create_driver(self._image_path, self._shell_args) - driver.start() + self._driver = self._port.create_driver(self._image_path, + self._shell_args) + self._driver.start() start = time.time() crash, timeout, actual_checksum, output, error = \ - driver.run_test(test_info.uri.strip(), test_info.timeout, - test_info.image_hash()) + self._driver.run_test(test_info.uri.strip(), test_info.timeout, + test_info.image_hash()) end = time.time() self._test_result = _process_output(self._port, test_info, self._test_types, self._test_args, self._configuration, self._output_dir, crash, timeout, end - start, actual_checksum, output, error) - driver.stop() + self._driver.stop() def get_test_result(self): return self._test_result @@ -312,9 +332,7 @@ class TestShellThread(WatchableThread): # Save the exception for our caller to see. self._exception_info = sys.exc_info() self._stop_time = time.time() - # Re-raise it and die. - _log.error('%s dying, exception raised: %s' % (self.getName(), - self._exception_info)) + _log.error('%s dying, exception raised' % self.getName()) self._stop_time = time.time() @@ -426,7 +444,7 @@ class TestShellThread(WatchableThread): worker.start() thread_timeout = _milliseconds_to_seconds( - _pad_timeout(test_info.timeout)) + _pad_timeout(int(test_info.timeout))) thread._next_timeout = time.time() + thread_timeout worker.join(thread_timeout) if worker.isAlive(): @@ -439,11 +457,13 @@ class TestShellThread(WatchableThread): # that tradeoff in order to avoid losing the rest of this # thread's results. _log.error('Test thread hung: killing all DumpRenderTrees') - worker._driver.stop() + 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_info.filename) @@ -476,7 +496,7 @@ class TestShellThread(WatchableThread): start = time.time() thread_timeout = _milliseconds_to_seconds( - _pad_timeout(test_info.timeout)) + _pad_timeout(int(test_info.timeout))) self._next_timeout = start + thread_timeout crash, timeout, actual_checksum, output, error = \ diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread_unittest.py new file mode 100644 index 0000000..63f86d9 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread_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. + +""""Tests code paths not covered by the regular unit tests.""" + +import sys +import unittest + +import dump_render_tree_thread + + +class Test(unittest.TestCase): + def test_find_thread_stack_found(self): + id, stack = sys._current_frames().items()[0] + found_stack = dump_render_tree_thread.find_thread_stack(id) + self.assertNotEqual(found_stack, None) + + def test_find_thread_stack_not_found(self): + found_stack = dump_render_tree_thread.find_thread_stack(0) + self.assertEqual(found_stack, None) + + +if __name__ == '__main__': + unittest.main() diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py index 15eceee..765b4d8 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py @@ -37,6 +37,8 @@ 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. @@ -85,13 +87,14 @@ class JSONResultsGeneratorBase(object): INCREMENTAL_RESULTS_FILENAME = "incremental_results.json" URL_FOR_TEST_LIST_JSON = \ - "http://%s/testfile?builder=%s&name=%s&testlistjson=1" + "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_results_server=None, + test_type=""): """Modifies the results.json file. Grabs it off the archive directory if it is not found locally. @@ -129,6 +132,7 @@ class JSONResultsGeneratorBase(object): self._svn_repositories = {} self._test_results_server = test_results_server + self._test_type = test_type self._json = None self._archived_results = None @@ -287,7 +291,8 @@ class JSONResultsGeneratorBase(object): results_file_url = (self.URL_FOR_TEST_LIST_JSON % (urllib2.quote(self._test_results_server), urllib2.quote(self._builder_name), - self.RESULTS_FILENAME)) + self.RESULTS_FILENAME, + urllib2.quote(self._test_type))) else: # Check if we have the archived JSON file on the buildbot # server. @@ -518,9 +523,33 @@ class JSONResultsGenerator(JSONResultsGeneratorBase): # The flag is for backward compatibility. output_json_in_init = True + def _upload_json_files(self): + if not self._test_results_server or not self._test_type: + return + + _log.info("Uploading JSON files for %s to the server: %s", + self._builder_name, self._test_results_server) + attrs = [("builder", self._builder_name), ("testtype", self._test_type)] + json_files = [self.INCREMENTAL_RESULTS_FILENAME] + + 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 __init__(self, port, builder_name, build_name, build_number, results_file_base_path, builder_base_url, - test_timings, failures, passed_tests, skipped_tests, all_tests): + test_timings, failures, passed_tests, skipped_tests, all_tests, + test_results_server=None, test_type=None): """Generates a JSON results file. Args @@ -536,8 +565,13 @@ class JSONResultsGenerator(JSONResultsGeneratorBase): skipped_tests: A set containing all the skipped tests. all_tests: List of all the tests that were run. This should not include skipped tests. + test_results_server: server that hosts test results json. + test_type: the test type. """ + self._test_type = test_type + self._results_directory = results_file_base_path + # Create a map of (name, TestResult). test_results_map = dict() get = test_results_map.get @@ -557,10 +591,16 @@ class JSONResultsGenerator(JSONResultsGeneratorBase): if test not in test_results_map: test_results_map[test] = TestResult(test) + # Generate the JSON with incremental flag enabled. + # (This should also output the full result for now.) super(JSONResultsGenerator, self).__init__( builder_name, build_name, build_number, results_file_base_path, builder_base_url, test_results_map, - svn_repositories=port.test_repository_paths()) + svn_repositories=port.test_repository_paths(), + generate_incremental_results=True, + test_results_server=test_results_server, + test_type=test_type) if self.__class__.output_json_in_init: self.generate_json_output() + self._upload_json_files() diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py index 0dda774..9125f9e 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py @@ -120,7 +120,7 @@ class Port(object): def check_image_diff(self, override_step=None, logging=True): """This routine is used to check whether image_diff binary exists.""" - raise NotImplemented('Port.check_image_diff') + raise NotImplementedError('Port.check_image_diff') def compare_text(self, expected_text, actual_text): """Return whether or not the two strings are *not* equal. This @@ -141,26 +141,9 @@ class Port(object): |tolerance| should be a percentage value (0.0 - 100.0). If it is omitted, the port default tolerance value is used. - While this is a generic routine, we include it in the Port - interface so that it can be overriden for testing purposes.""" - executable = self._path_to_image_diff() - - if diff_filename: - cmd = [executable, '--diff', expected_filename, actual_filename, - diff_filename] - else: - cmd = [executable, expected_filename, actual_filename] + """ + raise NotImplementedError('Port.diff_image') - result = True - try: - if self._executive.run_command(cmd, return_exit_code=True) == 0: - return False - except OSError, e: - if e.errno == errno.ENOENT or e.errno == errno.EACCES: - _compare_available = False - else: - raise e - return result def diff_text(self, expected_text, actual_text, expected_filename, actual_filename): @@ -305,6 +288,18 @@ class Port(object): """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 = os.path.join(self.layout_tests_dir(), test_or_category) + if os.path.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.""" try: @@ -341,84 +336,16 @@ class Port(object): if the port does not use expectations files.""" raise NotImplementedError('Port.path_to_test_expectations_file') - def remove_directory(self, *path): - """Recursively removes a directory, even if it's marked read-only. - - Remove the directory located at *path, if it exists. - - shutil.rmtree() doesn't work on Windows if any of the files - or directories are read-only, which svn repositories and - some .svn files are. We need to be able to force the files - to be writable (i.e., deletable) as we traverse the tree. - - Even with all this, Windows still sometimes fails to delete a file, - citing a permission error (maybe something to do with antivirus - scans or disk indexing). The best suggestion any of the user - forums had was to wait a bit and try again, so we do that too. - It's hand-waving, but sometimes it works. :/ - """ - file_path = os.path.join(*path) - if not os.path.exists(file_path): - return - - win32 = False - if sys.platform == 'win32': - win32 = True - # Some people don't have the APIs installed. In that case we'll do - # without. - try: - win32api = __import__('win32api') - win32con = __import__('win32con') - except ImportError: - win32 = False - - def remove_with_retry(rmfunc, path): - os.chmod(path, os.stat.S_IWRITE) - if win32: - win32api.SetFileAttributes(path, - win32con.FILE_ATTRIBUTE_NORMAL) - try: - return rmfunc(path) - except EnvironmentError, e: - if e.errno != errno.EACCES: - raise - print 'Failed to delete %s: trying again' % repr(path) - time.sleep(0.1) - return rmfunc(path) - else: - - def remove_with_retry(rmfunc, path): - if os.path.islink(path): - return os.remove(path) - else: - return rmfunc(path) - - for root, dirs, files in os.walk(file_path, topdown=False): - # For POSIX: making the directory writable guarantees - # removability. Windows will ignore the non-read-only - # bits in the chmod value. - os.chmod(root, 0770) - for name in files: - remove_with_retry(os.remove, os.path.join(root, name)) - for name in dirs: - remove_with_retry(os.rmdir, os.path.join(root, name)) - - remove_with_retry(os.rmdir, file_path) - - def test_platform_name(self): - return self._name - 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.""" - # FIXME This should assert() here but cannot due to printing_unittest.Testprinter - # assert(filename.startswith(self.layout_tests_dir())) + assert(filename.startswith(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 NotImplemented('Port.results_directory') + raise NotImplementedError('Port.results_directory') def setup_test_run(self): """Perform port-specific work at the beginning of a test run.""" @@ -608,7 +535,6 @@ class Port(object): _wdiff_available = False return "" raise - assert(False) # Should never be reached. _pretty_patch_error_html = "Failed to run PrettyPatch, see error console." @@ -636,7 +562,7 @@ class Port(object): return self._pretty_patch_error_html def _webkit_build_directory(self, args): - args = [self.script_path("webkit-build-directory")] + args + args = ["perl", self.script_path("webkit-build-directory")] + args return self._executive.run_command(args).rstrip() def _configuration_file_path(self): @@ -691,6 +617,10 @@ class Port(object): """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 @@ -808,10 +738,5 @@ class Driver: if it has exited.""" raise NotImplementedError('Driver.poll') - def returncode(self): - """Returns the system-specific returncode if the Driver has stopped or - exited.""" - raise NotImplementedError('Driver.returncode') - def stop(self): raise NotImplementedError('Driver.stop') diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/base_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/base_unittest.py index f821353..1cc426f 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/base_unittest.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/base_unittest.py @@ -27,15 +27,49 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import base -import unittest +import os +import StringIO +import sys import tempfile +import unittest from webkitpy.common.system.executive import Executive, ScriptError from webkitpy.thirdparty.mock import Mock -class PortTest(unittest.TestCase): +# FIXME: This makes StringIO objects work with "with". Remove +# when we upgrade to 2.6. +class NewStringIO(StringIO.StringIO): + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + pass + + +class MockExecutive(): + def __init__(self, exception): + self._exception = exception + + def run_command(self, *args, **kwargs): + raise self._exception + +class UnitTestPort(base.Port): + """Subclass of base.Port used for unit testing.""" + def __init__(self, configuration_contents=None, executive_exception=None): + base.Port.__init__(self) + self._configuration_contents = configuration_contents + if executive_exception: + self._executive = MockExecutive(executive_exception) + + def _open_configuration_file(self): + if self._configuration_contents: + return NewStringIO(self._configuration_contents) + return base.Port._open_configuration_file(self) + + +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) @@ -63,6 +97,26 @@ class PortTest(unittest.TestCase): new_file.flush() return new_file + def test_pretty_patch_os_error(self): + port = UnitTestPort(executive_exception=OSError) + 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_pretty_patch_script_error(self): + # FIXME: This is some ugly white-box test hacking ... + base._pretty_patch_available = True + port = UnitTestPort(executive_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 @@ -109,6 +163,79 @@ class PortTest(unittest.TestCase): self.assertFalse(base._wdiff_available) base._wdiff_available = True + def test_default_configuration_notfound(self): + port = UnitTestPort() + self.assertEqual(port.default_configuration(), "Release") + + 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_default_configuration_found(self): + port = UnitTestPort(configuration_contents="Debug") + self.assertEqual(port.default_configuration(), "Debug") + + def test_default_configuration_unknown(self): + port = UnitTestPort(configuration_contents="weird_value") + self.assertEqual(port.default_configuration(), "weird_value") + + 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() + + +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, None, None) + 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.show_html_results_file, None) + 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, "", None) + self.assertVirtual(base.Driver, base.Port, "", None) + + def test_virtual_driver_methods(self): + class VirtualDriver(base.Driver): + def __init__(self): + pass + + driver = VirtualDriver() + self.assertVirtual(driver.run_test, None, None, None) + self.assertVirtual(driver.poll) + self.assertVirtual(driver.stop) + class DriverTest(unittest.TestCase): @@ -124,3 +251,7 @@ class DriverTest(unittest.TestCase): 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/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium.py index 6cfc0b8..896eab1 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium.py @@ -46,6 +46,8 @@ import base import http_server from webkitpy.common.system.executive import Executive +from webkitpy.layout_tests.layout_package import test_files +from webkitpy.layout_tests.layout_package import test_expectations # Chromium DRT on OSX uses WebKitDriver. if sys.platform == 'darwin': @@ -124,6 +126,26 @@ class ChromiumPort(base.Port): return check_file_exists(image_diff_path, 'image diff exe', override_step, logging) + def diff_image(self, expected_filename, actual_filename, + diff_filename=None, tolerance=0): + executable = self._path_to_image_diff() + if diff_filename: + cmd = [executable, '--diff', expected_filename, actual_filename, + diff_filename] + else: + cmd = [executable, expected_filename, actual_filename] + + result = True + try: + if self._executive.run_command(cmd, return_exit_code=True) == 0: + return False + except OSError, e: + if e.errno == errno.ENOENT or e.errno == errno.EACCES: + _compare_available = False + else: + raise e + return result + def driver_name(self): return "test_shell" @@ -162,7 +184,7 @@ class ChromiumPort(base.Port): shutil.rmtree(cachedir) def show_results_html_file(self, results_filename): - uri = self.filename_to_uri(results_filename) + uri = self.get_absolute_path(results_filename) if self._options.use_drt: # FIXME: This should use User.open_url webbrowser.open(uri, new=1) @@ -233,6 +255,24 @@ class ChromiumPort(base.Port): with codecs.open(overrides_path, "r", "utf-8") as file: return file.read() + drt_overrides + 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 = test_files.gather_test_files(self, '*') + 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=True, + tests_are_present=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') @@ -330,9 +370,6 @@ class ChromiumDriver(base.Driver): # http://bugs.python.org/issue1731717 return self._proc.poll() - def returncode(self): - return self._proc.returncode - def _write_command_and_read_line(self, input=None): """Returns a tuple: (line, did_crash)""" try: diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py index a32eafd..7a005b1 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py @@ -32,6 +32,7 @@ import chromium_mac import chromium_win import unittest import StringIO +import os from webkitpy.thirdparty.mock import Mock @@ -95,3 +96,22 @@ class ChromiumDriverTest(unittest.TestCase): '/xcodebuild/Release/ImageDiff')) # 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): + class MockOptions: + def __init__(self): + self.use_drt = True + + port = chromium_linux.ChromiumLinuxPort('test-port', options=MockOptions()) + + 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 +DEFER LINUX WIN : fast/js/very-good.js = TIMEOUT PASS""" + port.test_expectations_overrides = lambda: '' + + skipped_tests = port.skipped_layout_tests(extra_test_files=[fake_test, ]) + self.assertTrue("fast/js/not-good.js" in skipped_tests) + +if __name__ == '__main__': + unittest.main() diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/dryrun.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/dryrun.py index e01bd2f..1af01ad 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/dryrun.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/dryrun.py @@ -70,14 +70,11 @@ def _read_file(path, mode='r'): def _write_file(path, contents, mode='w'): """Write the string to the specified path. - Returns nothing if the write fails, instead of raising an IOError. + Writes should never fail, so we may raise IOError. """ - try: - with open(path, mode) as f: + with open(path, mode) as f: f.write(contents) - except IOError: - pass class DryRunPort(object): @@ -134,9 +131,6 @@ class DryrunDriver(base.Driver): def poll(self): return None - def returncode(self): - return 0 - def run_test(self, uri, timeoutms, image_hash): test_name = self._uri_to_test(uri) diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/factory.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/factory.py index 258bf33..5704f65 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/factory.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/factory.py @@ -32,6 +32,10 @@ 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): """Returns an object implementing the Port interface. If @@ -88,3 +92,9 @@ def get(port_name=None, options=None): return google_chrome.GetGoogleChromePort(port_name, options) raise NotImplementedError('unsupported port: %s' % port_to_use) + + +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/WebKitTools/Scripts/webkitpy/layout_tests/port/factory_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/factory_unittest.py index d8dffdf..c0a4c5e 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/factory_unittest.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/factory_unittest.py @@ -34,6 +34,7 @@ import chromium_mac import chromium_win import dryrun import factory +import google_chrome import gtk import mac import qt @@ -69,16 +70,16 @@ class FactoryTest(unittest.TestCase): def tearDown(self): sys.platform = self.real_sys_platform - def assert_port(self, port_name, expected_port): + 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 """ - self.assertTrue(isinstance(factory.get(port_name=port_name), - expected_port)) + 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. @@ -114,6 +115,18 @@ class FactoryTest(unittest.TestCase): 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) @@ -136,3 +149,38 @@ class FactoryTest(unittest.TestCase): 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/WebKitTools/Scripts/webkitpy/layout_tests/port/lighttpd.conf b/WebKitTools/Scripts/webkitpy/layout_tests/port/lighttpd.conf index 2e9c82e..26ca22f 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/lighttpd.conf +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/lighttpd.conf @@ -22,7 +22,7 @@ mimetype.assign = ( ".htm" => "text/html", ".xhtml" => "application/xhtml+xml", ".xhtmlmp" => "application/vnd.wap.xhtml+xml", - ".js" => "text/javascript", + ".js" => "application/x-javascript", ".log" => "text/plain", ".conf" => "text/plain", ".text" => "text/plain", diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/mac_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/mac_unittest.py index ae7d40c..327b19e 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/mac_unittest.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/mac_unittest.py @@ -26,14 +26,27 @@ # (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 StringIO +import port_testcase + -class MacTest(unittest.TestCase): +class MacTest(port_testcase.PortTestCase): + def make_port(self, options=port_testcase.MockOptions()): + 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 = mac.MacPort() + 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. @@ -57,7 +70,9 @@ svg/batik/text/smallFonts.svg ] def test_skipped_file_paths(self): - port = mac.MacPort() + 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) diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/port_testcase.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/port_testcase.py new file mode 100644 index 0000000..2d650f5 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/port_testcase.py @@ -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. + +"""Unit testing base class for Port implementations.""" + +import os +import tempfile +import unittest + + +class MockOptions(object): + def __init__(self, + results_directory='layout-test-results', + use_apache=True, + configuration='Release'): + self.results_directory = results_directory + self.use_apache = use_apache + self.configuration = configuration + + +class PortTestCase(unittest.TestCase): + """Tests the WebKit port implementation.""" + def make_port(self, options=MockOptions()): + """Override in subclass.""" + raise NotImplementedError() + + 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') + file2 = os.path.join(dir, 'fast', 'css', + 'remove-shorthand-expected.png') + tmpfile = tempfile.mktemp() + + self.assertFalse(port.diff_image(file1, file1)) + self.assertTrue(port.diff_image(file1, file2)) + + self.assertTrue(port.diff_image(file1, file2, tmpfile)) + # 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/WebKitTools/Scripts/webkitpy/layout_tests/port/qt.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/qt.py index 41b2ba0..158c633 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/qt.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/qt.py @@ -93,6 +93,12 @@ class QtPort(WebKitPort): def _path_to_driver(self): return self._build_path('bin/DumpRenderTree') + 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') diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/server_process.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/server_process.py index 62ca693..8e0bc11 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/server_process.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/server_process.py @@ -29,7 +29,6 @@ """Package that implements the ServerProcess wrapper class""" -import fcntl import logging import os import select @@ -37,6 +36,8 @@ import signal import subprocess import sys import time +if sys.platform != 'win32': + import fcntl from webkitpy.common.system.executive import Executive @@ -109,14 +110,6 @@ class ServerProcess: return self._proc.poll() return None - def returncode(self): - """Returns the exit code from the subprcoess; returns None if the - process hasn't exited (this is a wrapper around subprocess.returncode). - """ - if self._proc: - return self._proc.returncode - return None - def write(self, input): """Write a request to the subprocess. The subprocess is (re-)start()'ed if is not already running.""" diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py index e309334..a3a16c3 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py @@ -76,6 +76,9 @@ class TestPort(base.Port): def options(self): return self._options + def skipped_layout_tests(self): + return [] + def path_to_test_expectations_file(self): return self.path_from_webkit_base('WebKitTools', 'Scripts', 'webkitpy', 'layout_tests', 'data', 'platform', 'test', @@ -145,9 +148,6 @@ class TestDriver(base.Driver): def poll(self): return True - def returncode(self): - return 0 - def run_test(self, uri, timeoutms, image_hash): basename = uri[(uri.rfind("/") + 1):uri.rfind(".html")] @@ -179,6 +179,7 @@ class TestDriver(base.Driver): raise ValueError('exception from ' + basename) crash = 'crash' in basename + timeout = 'timeout' in basename or 'hang' in basename timeout = 'timeout' in basename if 'text' in basename: output = basename + '_failed-txt\n' @@ -196,6 +197,9 @@ class TestDriver(base.Driver): f.write(basename + "-png\n") if 'checksum' in basename: checksum = basename + "_failed-checksum\n" + + if 'hang' in basename: + time.sleep((float(timeoutms) * 4) / 1000.0) else: crash = False timeout = False diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/webkit.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/webkit.py index cedc028..b085ceb 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/webkit.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/webkit.py @@ -1,5 +1,6 @@ #!/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 @@ -41,6 +42,9 @@ import signal import sys import time import webbrowser +import operator +import tempfile +import shutil from webkitpy.common.system.executive import Executive @@ -217,6 +221,66 @@ class WebKitPort(base.Port): "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"], + "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. @@ -238,7 +302,8 @@ class WebKitPort(base.Port): "http/tests/webarchive", "svg/custom/image-with-prefix-in-webarchive.svg", ] - return disabled_feature_tests + webarchive_tests + 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 = [] @@ -279,14 +344,17 @@ class WebKitPort(base.Port): # 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()) - skip_lines = map(lambda test_path: "BUG_SKIPPED SKIP : %s = FAIL" % - test_path, tests_to_skip) - return "\n".join(skip_lines) + return tests_to_skip def test_platform_name(self): return self._name + self.version() @@ -306,6 +374,9 @@ class WebKitPort(base.Port): 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 @@ -338,6 +409,10 @@ class WebKitDriver(base.Driver): self._port = port # FIXME: driver_options is never used. self._image_path = image_path + self._driver_tempdir = tempfile.mkdtemp(prefix='DumpRenderTree-') + + def __del__(self): + shutil.rmtree(self._driver_tempdir) def start(self): command = [] @@ -348,6 +423,7 @@ class WebKitDriver(base.Driver): command.append('--pixel-tests') 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", command, environment) @@ -359,9 +435,6 @@ class WebKitDriver(base.Driver): self._server_process.start() return - def returncode(self): - return self._server_process.returncode() - # FIXME: This function is huge. def run_test(self, uri, timeoutms, image_hash): if uri.startswith("file:///"): diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py new file mode 100644 index 0000000..fbfadc3 --- /dev/null +++ b/WebKitTools/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", "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/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py index 4132260..2e2da6d 100755 --- a/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py @@ -53,7 +53,6 @@ import logging import math import optparse import os -import pdb import platform import Queue import random @@ -371,7 +370,7 @@ class TestRunner: assert(test_size > 0) except: _log.critical("invalid chunk '%s'" % chunk_value) - sys.exit(1) + return None # Get the number of tests num_tests = len(test_files) @@ -675,8 +674,7 @@ class TestRunner: # 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]) + raise exception_info[0], exception_info[1], exception_info[2] if thread.isAlive(): some_thread_is_alive = True @@ -1350,11 +1348,18 @@ class TestRunner: def read_test_files(files): tests = [] for file in files: - # FIXME: This could be cleaner using a list comprehension. - for line in codecs.open(file, "r", "utf-8"): - line = test_expectations.strip_comments(line) - if line: - tests.append(line) + 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 @@ -1398,7 +1403,12 @@ def run(port, options, args, regular_output=sys.stderr, test_runner._print_config() printer.print_update("Collecting tests ...") - test_runner.collect_tests(args, last_unexpected_results) + try: + test_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: @@ -1695,31 +1705,14 @@ def parse_args(args=None): return options, args -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()) - - def _log_wedged_thread(thread): """Log information about the given thread state.""" id = thread.id() - stack = _find_thread_stack(id) + stack = dump_render_tree_thread.find_thread_stack(id) assert(stack is not None) _log.error("") _log.error("thread %s (%d) is wedged" % (thread.getName(), id)) - _log_stack(stack) + dump_render_tree_thread.log_stack(stack) _log.error("") diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py index 4cbfdfc..aa96962 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py @@ -32,9 +32,9 @@ import codecs import logging import os -import pdb import Queue import sys +import tempfile import thread import time import threading @@ -59,7 +59,10 @@ def passing_run(args=[], port_obj=None, record_results=False, new_args.extend(args) if not tests_included: # We use the glob to test that globbing works. - new_args.extend(['passes', 'failures/expected/*']) + new_args.extend(['passes', + 'http/tests', + 'websocket/tests', + 'failures/expected/*']) options, parsed_args = run_webkit_tests.parse_args(new_args) if port_obj is None: port_obj = port.get(options.platform, options) @@ -71,10 +74,12 @@ def logging_run(args=[], tests_included=False): new_args = ['--no-record-results'] if not '--platform' in args: new_args.extend(['--platform', 'test']) - if args: - new_args.extend(args) + new_args.extend(args) if not tests_included: - new_args.extend(['passes', 'failures/expected/*']) + new_args.extend(['passes', + 'http/tests' + 'websocket/tests', + 'failures/expected/*']) options, parsed_args = run_webkit_tests.parse_args(new_args) port_obj = port.get(options.platform, options) buildbot_output = array_stream.ArrayStream() @@ -119,6 +124,14 @@ class MainTest(unittest.TestCase): self.assertTrue(out.empty()) self.assertFalse(err.empty()) + def test_hung_thread(self): + res, out, err = 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. @@ -175,6 +188,19 @@ class MainTest(unittest.TestCase): # FIXME: verify # of tests run self.assertTrue(passing_run(['passes/text.html'], tests_included=True)) + def test_test_list(self): + filename = tempfile.mktemp() + tmpfile = file(filename, mode='w+') + tmpfile.write('passes/text.html') + tmpfile.close() + self.assertTrue(passing_run(['--test-list=%s' % filename], + tests_included=True)) + os.remove(filename) + res, out, err = 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. res, out, err = logging_run(tests_included=True) @@ -279,6 +305,13 @@ class DryrunTest(unittest.TestCase): self.assertTrue(passing_run(['--platform', 'dryrun-mac', 'fast/html'])) + def test_test(self): + res, out, err = logging_run(['--platform', 'dryrun-test', + '--pixel-tests']) + self.assertEqual(res, 2) + self.assertFalse(out.empty()) + self.assertFalse(err.empty()) + class TestThread(dump_render_tree_thread.WatchableThread): def __init__(self, started_queue, stopping_queue): @@ -388,13 +421,6 @@ class StandaloneFunctionsTest(unittest.TestCase): self.assertFalse(child_thread.isAlive()) oc.restore_output() - def test_find_thread_stack(self): - id, stack = sys._current_frames().items()[0] - found_stack = run_webkit_tests._find_thread_stack(id) - self.assertNotEqual(found_stack, None) - - found_stack = run_webkit_tests._find_thread_stack(0) - self.assertEqual(found_stack, None) if __name__ == '__main__': unittest.main() diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/queries.py b/WebKitTools/Scripts/webkitpy/tool/commands/queries.py index 91ce5e9..9b8d162 100644 --- a/WebKitTools/Scripts/webkitpy/tool/commands/queries.py +++ b/WebKitTools/Scripts/webkitpy/tool/commands/queries.py @@ -37,6 +37,7 @@ 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 BugsToCommit(AbstractDeclarativeCommand): @@ -284,3 +285,28 @@ and displayes the status of each builder.""" 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): + class Options: + # Required for chromium port. + use_drt = True + + results = dict([(test_name, []) for test_name in args]) + for port_name, port_object in tool.port_factory.get_all(options=Options).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/WebKitTools/Scripts/webkitpy/tool/commands/queries_unittest.py b/WebKitTools/Scripts/webkitpy/tool/commands/queries_unittest.py index 98ed545..7dddfe7 100644 --- a/WebKitTools/Scripts/webkitpy/tool/commands/queries_unittest.py +++ b/WebKitTools/Scripts/webkitpy/tool/commands/queries_unittest.py @@ -61,3 +61,13 @@ class QueryCommandsTest(CommandsTest): 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) diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/queues_unittest.py b/WebKitTools/Scripts/webkitpy/tool/commands/queues_unittest.py index f86e9a2..fd6543c 100644 --- a/WebKitTools/Scripts/webkitpy/tool/commands/queues_unittest.py +++ b/WebKitTools/Scripts/webkitpy/tool/commands/queues_unittest.py @@ -28,12 +28,14 @@ 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 @@ -133,6 +135,16 @@ class AbstractReviewQueueTest(CommandsTest): self.assertFalse(queue.is_terminal_status("Foo")) +class NeedsUpdateSequence(StepSequence): + def _run(self, tool, options, state): + raise CheckoutNeedsUpdate([], 1, "", None) + + +class AlwaysCommitQueueTool(object): + def command_by_name(self, name): + return CommitQueue + + class CommitQueueTest(QueuesTest): def test_commit_queue(self): expected_stderr = { @@ -226,6 +238,20 @@ MOCK: update_work_items: commit-queue [106, 197] attachments.sort(queue._patch_cmp) self.assertEqual(attachments, expected_sort) + 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.\n" + OutputCapture().assert_outputs(self, sequence.run_and_handle_errors, [tool, options], expected_exception=TryAgain, expected_stderr=expected_stderr) + + self.assertEquals(options.update, True) + self.assertEquals(options.build, False) + self.assertEquals(options.test, False) + class RietveldUploadQueueTest(QueuesTest): def test_rietveld_upload_queue(self): diff --git a/WebKitTools/Scripts/webkitpy/tool/main.py b/WebKitTools/Scripts/webkitpy/tool/main.py index 0dd5017..9531b63 100755 --- a/WebKitTools/Scripts/webkitpy/tool/main.py +++ b/WebKitTools/Scripts/webkitpy/tool/main.py @@ -40,6 +40,7 @@ from webkitpy.common.net.rietveld import Rietveld from webkitpy.common.net.irc.ircproxy import IRCProxy from webkitpy.common.system.executive import Executive from webkitpy.common.system.user import User +from webkitpy.layout_tests import port import webkitpy.tool.commands as commands # FIXME: Remove these imports once all the commands are in the root of the # command package. @@ -76,6 +77,7 @@ class WebKitPatch(MultiCommandTool): self._checkout = None self.status_server = StatusServer() self.codereview = Rietveld(self.executive) + self.port_factory = port.factory def scm(self): # Lazily initialize SCM to not error-out before command line parsing (or when running non-scm commands). diff --git a/WebKitTools/Scripts/webkitpy/tool/mocktool.py b/WebKitTools/Scripts/webkitpy/tool/mocktool.py index 7eb8f4c..e3d36ce 100644 --- a/WebKitTools/Scripts/webkitpy/tool/mocktool.py +++ b/WebKitTools/Scripts/webkitpy/tool/mocktool.py @@ -556,6 +556,24 @@ class MockRietveld(): log("MOCK: Uploading patch to rietveld") +class MockTestPort1(): + + def skips_layout_test(self, test_name): + return test_name in ["media/foo/bar.html", "foo"] + + +class MockTestPort2(): + + def skips_layout_test(self, test_name): + return test_name == "media/foo/bar.html" + + +class MockPortFactory(): + + def get_all(self, options=None): + return {"test_port1": MockTestPort1(), "test_port2": MockTestPort2()} + + class MockTool(): def __init__(self, log_executive=False): @@ -570,6 +588,7 @@ class MockTool(): self.status_server = MockStatusServer() self.irc_password = "MOCK irc password" self.codereview = MockRietveld(self.executive) + self.port_factory = MockPortFactory() def scm(self): return self._scm diff --git a/WebKitTools/TestResultServer/model/datastorefile.py b/WebKitTools/TestResultServer/model/datastorefile.py index dd4c366..ac28d64 100755 --- a/WebKitTools/TestResultServer/model/datastorefile.py +++ b/WebKitTools/TestResultServer/model/datastorefile.py @@ -58,6 +58,9 @@ class DataStoreFile(db.Model): 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 @@ -82,11 +85,18 @@ class DataStoreFile(db.Model): return False start = 0 - keys = self.data_keys - self.data_keys = [] + # 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.pop(0) + key = keys[0] data_entry = DataEntry.get(key) if not data_entry: logging.warning("Found key, but no data entry: %s", key) @@ -95,16 +105,27 @@ class DataStoreFile(db.Model): data_entry = DataEntry() data_entry.data = db.Blob(data[start: start + MAX_ENTRY_LEN]) - data_entry.put() + 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.data_keys.append(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 diff --git a/WebKitTools/TestResultServer/model/jsonresults.py b/WebKitTools/TestResultServer/model/jsonresults.py index e5eb7f7..4520e96 100755 --- a/WebKitTools/TestResultServer/model/jsonresults.py +++ b/WebKitTools/TestResultServer/model/jsonresults.py @@ -413,6 +413,7 @@ class JsonResults(object): # Use the incremental data if there is no aggregated file to merge. file = TestFile() file.builder = builder + file.test_type = test_type file.name = JSON_RESULTS_FILE new_results = incremental logging.info("No existing json results, incremental json is saved.") diff --git a/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp b/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp index c7f9a84..bf7a029 100644 --- a/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp +++ b/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp @@ -35,6 +35,7 @@ #include <WebKit2/WKBundlePagePrivate.h> #include <WebKit2/WKRetainPtr.h> #include <WebKit2/WKBundleRange.h> +#include <WebKit2/WKBundleScriptWorld.h> using namespace std; @@ -198,9 +199,9 @@ void InjectedBundlePage::didReceiveTitleForFrame(WKBundlePageRef page, WKStringR static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didReceiveTitleForFrame(title, frame); } -void InjectedBundlePage::didClearWindowForFrame(WKBundlePageRef page, WKBundleFrameRef frame, JSGlobalContextRef context, JSObjectRef window, const void *clientInfo) +void InjectedBundlePage::didClearWindowForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleScriptWorldRef world, const void *clientInfo) { - static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didClearWindowForFrame(frame, context, window); + static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didClearWindowForFrame(frame, world); } void InjectedBundlePage::didCancelClientRedirectForFrame(WKBundlePageRef page, WKBundleFrameRef frame, const void* clientInfo) @@ -412,11 +413,17 @@ void InjectedBundlePage::didReceiveTitleForFrame(WKStringRef title, WKBundleFram InjectedBundle::shared().os() << "TITLE CHANGED: " << title << "\n"; } -void InjectedBundlePage::didClearWindowForFrame(WKBundleFrameRef frame, JSGlobalContextRef context, JSObjectRef window) +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); diff --git a/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h b/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h index 3f63bf3..cde1655 100644 --- a/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h +++ b/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h @@ -52,7 +52,7 @@ private: static void didFinishLoadForFrame(WKBundlePageRef, WKBundleFrameRef, const void*); static void didFailLoadWithErrorForFrame(WKBundlePageRef, WKBundleFrameRef, const void*); static void didReceiveTitleForFrame(WKBundlePageRef, WKStringRef title, WKBundleFrameRef, const void*); - static void didClearWindowForFrame(WKBundlePageRef, WKBundleFrameRef, JSGlobalContextRef, JSObjectRef window, 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 didChangeLocationWithinPageForFrame(WKBundlePageRef, WKBundleFrameRef, const void*); @@ -67,7 +67,7 @@ private: void didFinishLoadForFrame(WKBundleFrameRef); void didFailLoadWithErrorForFrame(WKBundleFrameRef); void didReceiveTitleForFrame(WKStringRef title, WKBundleFrameRef); - void didClearWindowForFrame(WKBundleFrameRef, JSGlobalContextRef, JSObjectRef window); + void didClearWindowForFrame(WKBundleFrameRef, WKBundleScriptWorldRef); void didCancelClientRedirectForFrame(WKBundleFrameRef); void willPerformClientRedirectForFrame(WKBundleFrameRef, WKURLRef url, double delay, double date); void didChangeLocationWithinPageForFrame(WKBundleFrameRef); |