diff options
Diffstat (limited to 'WebKitTools/DumpRenderTree')
31 files changed, 2106 insertions, 275 deletions
diff --git a/WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp b/WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp index 9cf34de..c4d5e6f 100644 --- a/WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp +++ b/WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp @@ -171,6 +171,15 @@ static JSValueRef childAtIndexCallback(JSContextRef context, JSObjectRef functio return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->getChildAtIndex(indexNumber)); } +static JSValueRef linkedUIElementAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int indexNumber = -1; + if (argumentCount == 1) + indexNumber = JSValueToNumber(context, arguments[0], exception); + + return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->linkedUIElementAtIndex(indexNumber)); +} + static JSValueRef disclosedRowAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { int indexNumber = 0; @@ -703,6 +712,7 @@ JSClassRef AccessibilityUIElement::getJSClass() { "boundsForRange", boundsForRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "stringForRange", stringForRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "childAtIndex", childAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "linkedUIElementAtIndex", linkedUIElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "indexOfChild", indexOfChildCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "elementAtPoint", elementAtPointCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "attributesOfColumnHeaders", attributesOfColumnHeadersCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, diff --git a/WebKitTools/DumpRenderTree/AccessibilityUIElement.h b/WebKitTools/DumpRenderTree/AccessibilityUIElement.h index f62ec1a..2a06962 100644 --- a/WebKitTools/DumpRenderTree/AccessibilityUIElement.h +++ b/WebKitTools/DumpRenderTree/AccessibilityUIElement.h @@ -91,6 +91,8 @@ public: // Methods - platform-independent implementations JSStringRef allAttributes(); JSStringRef attributesOfLinkedUIElements(); + AccessibilityUIElement linkedUIElementAtIndex(unsigned); + JSStringRef attributesOfDocumentLinks(); JSStringRef attributesOfChildren(); JSStringRef parameterizedAttributeNames(); diff --git a/WebKitTools/DumpRenderTree/DumpRenderTree.gypi b/WebKitTools/DumpRenderTree/DumpRenderTree.gypi index 280c8dd..5fc8dab 100644 --- a/WebKitTools/DumpRenderTree/DumpRenderTree.gypi +++ b/WebKitTools/DumpRenderTree/DumpRenderTree.gypi @@ -34,5 +34,15 @@ 'chromium/WebViewHost.cpp', 'chromium/WebViewHost.h', ], + 'conditions': [ + ['OS=="win"', { + 'drt_files': [ + 'chromium/WebThemeControlDRT.cpp', + 'chromium/WebThemeControlDRT.h', + 'chromium/WebThemeEngineDRT.cpp', + 'chromium/WebThemeEngineDRT.h', + ], + }], + ], } } diff --git a/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj b/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj index 3adfaf2..6a49b44 100644 --- a/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj +++ b/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj @@ -117,6 +117,8 @@ BCD08B3A0E1057EF00A7D0C1 /* AccessibilityController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCD08B390E1057EF00A7D0C1 /* AccessibilityController.cpp */; }; BCD08B710E1059D200A7D0C1 /* AccessibilityControllerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCD08B700E1059D200A7D0C1 /* AccessibilityControllerMac.mm */; }; BCF6C6500C98E9C000AC063E /* GCController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCF6C64F0C98E9C000AC063E /* GCController.cpp */; }; + E1B7816511AF31B7007E1BC2 /* MockGeolocationProvider.mm in Sources */ = {isa = PBXBuildFile; fileRef = E1B7808711AF1669007E1BC2 /* MockGeolocationProvider.mm */; }; + E1B7816711AF31C3007E1BC2 /* MockGeolocationProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = E1B7808511AF1643007E1BC2 /* MockGeolocationProvider.h */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -275,6 +277,8 @@ BCD08B390E1057EF00A7D0C1 /* AccessibilityController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AccessibilityController.cpp; sourceTree = "<group>"; }; BCD08B700E1059D200A7D0C1 /* AccessibilityControllerMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AccessibilityControllerMac.mm; path = mac/AccessibilityControllerMac.mm; sourceTree = "<group>"; }; BCF6C64F0C98E9C000AC063E /* GCController.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 30; path = GCController.cpp; sourceTree = "<group>"; }; + E1B7808511AF1643007E1BC2 /* MockGeolocationProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MockGeolocationProvider.h; path = mac/MockGeolocationProvider.h; sourceTree = "<group>"; }; + E1B7808711AF1669007E1BC2 /* MockGeolocationProvider.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MockGeolocationProvider.mm; path = mac/MockGeolocationProvider.mm; sourceTree = "<group>"; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -378,6 +382,8 @@ BC0131D80C9772010087317D /* LayoutTestController.cpp */, BC0131D90C9772010087317D /* LayoutTestController.h */, BCA18B220C9B014B00114369 /* LayoutTestControllerMac.mm */, + E1B7808511AF1643007E1BC2 /* MockGeolocationProvider.h */, + E1B7808711AF1669007E1BC2 /* MockGeolocationProvider.mm */, BCA18B6D0C9B08DB00114369 /* NavigationController.h */, BCA18B6E0C9B08DB00114369 /* NavigationController.m */, BCA18B2F0C9B01B400114369 /* ObjCController.h */, @@ -546,6 +552,7 @@ BC9D90250C97472E0099A4A3 /* WorkQueue.h in Headers */, BC9D90260C97472E0099A4A3 /* WorkQueueItem.h in Headers */, 5185F6B310714E12007AA393 /* HistoryDelegate.h in Headers */, + E1B7816711AF31C3007E1BC2 /* MockGeolocationProvider.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -712,6 +719,7 @@ BC9D90240C97472E0099A4A3 /* WorkQueue.cpp in Sources */, BCA18B260C9B015C00114369 /* WorkQueueItemMac.mm in Sources */, 5185F6B210714E07007AA393 /* HistoryDelegate.mm in Sources */, + E1B7816511AF31B7007E1BC2 /* MockGeolocationProvider.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/WebKitTools/DumpRenderTree/chromium/EventSender.cpp b/WebKitTools/DumpRenderTree/chromium/EventSender.cpp index 381112e..7695095 100644 --- a/WebKitTools/DumpRenderTree/chromium/EventSender.cpp +++ b/WebKitTools/DumpRenderTree/chromium/EventSender.cpp @@ -716,8 +716,7 @@ void EventSender::replaySavedEvents() { replayingSavedEvents = true; while (!mouseEventQueue.isEmpty()) { - SavedEvent e = mouseEventQueue.first(); - mouseEventQueue.removeFirst(); + SavedEvent e = mouseEventQueue.takeFirst(); switch (e.type) { case SavedEvent::MouseMove: { diff --git a/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp index b4e3764..89e16e0 100644 --- a/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp +++ b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp @@ -201,8 +201,7 @@ void LayoutTestController::WorkQueue::processWork() // Quit doing work once a load is in progress. while (!m_queue.isEmpty()) { bool startedLoad = m_queue.first()->run(shell); - delete m_queue.first(); - m_queue.removeFirst(); + delete m_queue.takeFirst(); if (startedLoad) return; } @@ -215,8 +214,7 @@ void LayoutTestController::WorkQueue::reset() { m_frozen = false; while (!m_queue.isEmpty()) { - delete m_queue.first(); - m_queue.removeFirst(); + delete m_queue.takeFirst(); } } diff --git a/WebKitTools/DumpRenderTree/chromium/TestShellWin.cpp b/WebKitTools/DumpRenderTree/chromium/TestShellWin.cpp index 3884e94..a9ca6a9 100644 --- a/WebKitTools/DumpRenderTree/chromium/TestShellWin.cpp +++ b/WebKitTools/DumpRenderTree/chromium/TestShellWin.cpp @@ -31,6 +31,7 @@ #include "config.h" #include "TestShell.h" +#include "WebThemeEngineDRT.h" #include "webkit/support/webkit_support.h" #include <fcntl.h> #include <io.h> @@ -38,6 +39,9 @@ #include <shlwapi.h> #include <sys/stat.h> +// Theme engine +static WebThemeEngineDRT themeEngine; + // Thread main to run for the thread which just tests for timeout. unsigned int __stdcall watchDogThread(void* arg) { @@ -105,6 +109,9 @@ void platformInit() _setmode(_fileno(stdout), _O_BINARY); _setmode(_fileno(stderr), _O_BINARY); + // Set theme engine. + webkit_support::SetThemeEngine(&themeEngine); + // Load Ahem font. // AHEM____.TTF is copied to the directory of DumpRenderTree.exe by WebKit.gyp. WCHAR path[_MAX_PATH]; diff --git a/WebKitTools/DumpRenderTree/chromium/WebThemeControlDRT.cpp b/WebKitTools/DumpRenderTree/chromium/WebThemeControlDRT.cpp new file mode 100755 index 0000000..df12476 --- /dev/null +++ b/WebKitTools/DumpRenderTree/chromium/WebThemeControlDRT.cpp @@ -0,0 +1,518 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This file implements a simple generic version of the WebThemeEngine, +// which is used to draw all the native controls on a web page. We use this +// file when running in layout test mode in order to remove any +// platform-specific rendering differences due to themes, colors, etc. +// + +#include "config.h" +#include "WebThemeControlDRT.h" + +#include "skia/ext/platform_canvas.h" +#include "skia/ext/skia_utils_win.h" +#include "third_party/skia/include/core/SkPaint.h" +#include "third_party/skia/include/core/SkPath.h" +#include "third_party/skia/include/core/SkRect.h" + +#include <wtf/Assertions.h> + +using namespace std; +using namespace skia; + +static const SkColor edgeColor = SK_ColorBLACK; +static const SkColor readOnlyColor = SkColorSetRGB(0xe9, 0xc2, 0xa6); +static const SkColor fgColor = SK_ColorBLACK; +static const SkColor bgColors[] = { + SK_ColorBLACK, // Unknown + SkColorSetRGB(0xc9, 0xc9, 0xc9), // Disabled + SkColorSetRGB(0xf3, 0xe0, 0xd0), // Readonly + SkColorSetRGB(0x89, 0xc4, 0xff), // Normal + SkColorSetRGB(0x43, 0xf9, 0xff), // Hot + SkColorSetRGB(0x20, 0xf6, 0xcc), // Focused + SkColorSetRGB(0x00, 0xf3, 0xac), // Hover + SkColorSetRGB(0xa9, 0xff, 0x12), // Pressed + SkColorSetRGB(0xcc, 0xcc, 0xcc) // Indeterminate +}; + +static SkIRect validate(const SkIRect& rect, WebThemeControlDRT::Type ctype) +{ + switch (ctype) { + case WebThemeControlDRT::UncheckedBoxType: + case WebThemeControlDRT::CheckedBoxType: + case WebThemeControlDRT::UncheckedRadioType: + case WebThemeControlDRT::CheckedRadioType: { + SkIRect retval = rect; + + // The maximum width and height is 13. + // Center the square in the passed rectangle. + const int maxControlSize = 13; + int controlSize = min(rect.width(), rect.height()); + controlSize = min(controlSize, maxControlSize); + + retval.fLeft = rect.fLeft + (rect.width() / 2) - (controlSize / 2); + retval.fRight = retval.fLeft + controlSize - 1; + retval.fTop = rect.fTop + (rect.height() / 2) - (controlSize / 2); + retval.fBottom = retval.fTop + controlSize - 1; + + return retval; + } + + default: + return rect; + } +} + +// WebThemeControlDRT + +WebThemeControlDRT::WebThemeControlDRT(PlatformCanvas* canvas, + const SkIRect& irect, + Type ctype, + State cstate) + : m_canvas(canvas) + , m_irect(validate(irect, ctype)) + , m_type(ctype) + , m_state(cstate) + , m_left(m_irect.fLeft) + , m_right(m_irect.fRight) + , m_top(m_irect.fTop) + , m_bottom(m_irect.fBottom) + , m_height(m_irect.height()) + , m_width(m_irect.width()) + , m_edgeColor(edgeColor) + , m_bgColor(bgColors[cstate]) + , m_fgColor(fgColor) +{ +} + +WebThemeControlDRT::~WebThemeControlDRT() +{ +} + +void WebThemeControlDRT::box(const SkIRect& rect, SkColor fillColor) +{ + SkPaint paint; + + paint.setStyle(SkPaint::kFill_Style); + paint.setColor(fillColor); + m_canvas->drawIRect(rect, paint); + + paint.setColor(m_edgeColor); + paint.setStyle(SkPaint::kStroke_Style); + m_canvas->drawIRect(rect, paint); +} + +void WebThemeControlDRT::line(int x0, int y0, int x1, int y1, SkColor color) +{ + SkPaint paint; + paint.setColor(color); + m_canvas->drawLine(SkIntToScalar(x0), SkIntToScalar(y0), + SkIntToScalar(x1), SkIntToScalar(y1), + paint); +} + +void WebThemeControlDRT::triangle(int x0, int y0, + int x1, int y1, + int x2, int y2, + SkColor color) +{ + SkPath path; + SkPaint paint; + + paint.setColor(color); + paint.setStyle(SkPaint::kFill_Style); + path.incReserve(4); + path.moveTo(SkIntToScalar(x0), SkIntToScalar(y0)); + path.lineTo(SkIntToScalar(x1), SkIntToScalar(y1)); + path.lineTo(SkIntToScalar(x2), SkIntToScalar(y2)); + path.close(); + m_canvas->drawPath(path, paint); + + paint.setColor(m_edgeColor); + paint.setStyle(SkPaint::kStroke_Style); + m_canvas->drawPath(path, paint); +} + +void WebThemeControlDRT::roundRect(SkColor color) +{ + SkRect rect; + SkScalar radius = SkIntToScalar(5); + SkPaint paint; + + rect.set(m_irect); + paint.setColor(color); + paint.setStyle(SkPaint::kFill_Style); + m_canvas->drawRoundRect(rect, radius, radius, paint); + + paint.setColor(m_edgeColor); + paint.setStyle(SkPaint::kStroke_Style); + m_canvas->drawRoundRect(rect, radius, radius, paint); +} + +void WebThemeControlDRT::oval(SkColor color) +{ + SkRect rect; + SkPaint paint; + + rect.set(m_irect); + paint.setColor(color); + paint.setStyle(SkPaint::kFill_Style); + m_canvas->drawOval(rect, paint); + + paint.setColor(m_edgeColor); + paint.setStyle(SkPaint::kStroke_Style); + m_canvas->drawOval(rect, paint); +} + +void WebThemeControlDRT::circle(SkScalar radius, SkColor color) +{ + SkScalar cy = SkIntToScalar(m_top + m_height / 2); + SkScalar cx = SkIntToScalar(m_left + m_width / 2); + SkPaint paint; + + paint.setColor(color); + paint.setStyle(SkPaint::kFill_Style); + m_canvas->drawCircle(cx, cy, radius, paint); + + paint.setColor(m_edgeColor); + paint.setStyle(SkPaint::kStroke_Style); + m_canvas->drawCircle(cx, cy, radius, paint); +} + +void WebThemeControlDRT::nestedBoxes(int indentLeft, + int indentTop, + int indentRight, + int indentBottom, + SkColor outerColor, + SkColor innerColor) +{ + SkIRect lirect; + box(m_irect, outerColor); + lirect.set(m_irect.fLeft + indentLeft, + m_irect.fTop + indentTop, + m_irect.fRight - indentRight, + m_irect.fBottom - indentBottom); + box(lirect, innerColor); +} + +void WebThemeControlDRT::markState() +{ + // The horizontal lines in a read only control are spaced by this amount. + const int readOnlyLineOffset = 5; + + // The length of a triangle side for the corner marks. + const int triangleSize = 5; + + switch (m_state) { + case UnknownState: + case DisabledState: + case NormalState: + // Don't visually mark these states (color is enough). + break; + case ReadOnlyState: + // Drawing lines across the control. + for (int i = m_top + readOnlyLineOffset; i < m_bottom; i += readOnlyLineOffset) + line(m_left + 1, i, m_right - 1, i, readOnlyColor); + break; + + case HotState: + // Draw a triangle in the upper left corner of the control. + triangle(m_left, m_top, + m_left + triangleSize, m_top, + m_left, m_top + triangleSize, m_edgeColor); + break; + + case HoverState: + // Draw a triangle in the upper right corner of the control. + triangle(m_right, m_top, + m_right, m_top + triangleSize, + m_right - triangleSize, m_top, m_edgeColor); + break; + + case FocusedState: + // Draw a triangle in the bottom right corner of the control. + triangle(m_right, m_bottom, + m_right - triangleSize, m_bottom, + m_right, m_bottom - triangleSize, m_edgeColor); + break; + + case PressedState: + // Draw a triangle in the bottom left corner of the control. + triangle(m_left, m_bottom, + m_left, m_bottom - triangleSize, + m_left + triangleSize, m_bottom, m_edgeColor); + break; + + default: + ASSERT_NOT_REACHED(); + CRASH(); + break; + } +} + +void WebThemeControlDRT::draw() +{ + int halfWidth = m_width / 2; + int halfHeight = m_height / 2; + int quarterWidth = m_width / 4; + int quarterHeight = m_height / 4; + + // Indent amounts for the check in a checkbox or radio button. + const int checkIndent = 3; + + // Indent amounts for short and long sides of the scrollbar notches. + const int notchLongOffset = 1; + const int notchShortOffset = 4; + const int noOffset = 0; + + // Indent amounts for the short and long sides of a scroll thumb box. + const int thumbLongIndent = 0; + const int thumbShortIndent = 2; + + // Indents for the crosshatch on a scroll grip. + const int gripLongIndent = 3; + const int gripShortIndent = 5; + + // Indents for the the slider track. + const int sliderIndent = 2; + + m_canvas->beginPlatformPaint(); + + switch (m_type) { + case UnknownType: + ASSERT_NOT_REACHED(); + CRASH(); + break; + + case TextFieldType: + // We render this by hand outside of this function. + ASSERT_NOT_REACHED(); + CRASH(); + break; + + case PushButtonType: + // push buttons render as a rounded rectangle + roundRect(m_bgColor); + break; + + case UncheckedBoxType: + // Unchecked boxes are simply plain boxes. + box(m_irect, m_bgColor); + break; + + case CheckedBoxType: + nestedBoxes(checkIndent, checkIndent, checkIndent, checkIndent, m_bgColor, m_fgColor); + break; + + case UncheckedRadioType: + circle(SkIntToScalar(halfHeight), m_bgColor); + break; + + case CheckedRadioType: + circle(SkIntToScalar(halfHeight), m_bgColor); + circle(SkIntToScalar(halfHeight - checkIndent), m_fgColor); + break; + + case HorizontalScrollTrackBackType: { + // Draw a box with a notch at the left. + int longOffset = halfHeight - notchLongOffset; + int shortOffset = m_width - notchShortOffset; + nestedBoxes(noOffset, longOffset, shortOffset, longOffset, m_bgColor, m_edgeColor); + break; + } + + case HorizontalScrollTrackForwardType: { + // Draw a box with a notch at the right. + int longOffset = halfHeight - notchLongOffset; + int shortOffset = m_width - notchShortOffset; + nestedBoxes(shortOffset, longOffset, noOffset, longOffset, m_bgColor, m_fgColor); + break; + } + + case VerticalScrollTrackBackType: { + // Draw a box with a notch at the top. + int longOffset = halfWidth - notchLongOffset; + int shortOffset = m_height - notchShortOffset; + nestedBoxes(longOffset, noOffset, longOffset, shortOffset, m_bgColor, m_fgColor); + break; + } + + case VerticalScrollTrackForwardType: { + // Draw a box with a notch at the bottom. + int longOffset = halfWidth - notchLongOffset; + int shortOffset = m_height - notchShortOffset; + nestedBoxes(longOffset, shortOffset, longOffset, noOffset, m_bgColor, m_fgColor); + break; + } + + case HorizontalScrollThumbType: + // Draw a narrower box on top of the outside box. + nestedBoxes(thumbLongIndent, thumbShortIndent, thumbLongIndent, thumbShortIndent, m_bgColor, m_bgColor); + break; + + case VerticalScrollThumbType: + // Draw a shorter box on top of the outside box. + nestedBoxes(thumbShortIndent, thumbLongIndent, thumbShortIndent, thumbLongIndent, m_bgColor, m_bgColor); + break; + + case HorizontalSliderThumbType: + // Slider thumbs are ovals. + oval(m_bgColor); + break; + + case HorizontalScrollGripType: { + // Draw a horizontal crosshatch for the grip. + int longOffset = halfWidth - gripLongIndent; + line(m_left + gripLongIndent, m_top + halfHeight, + m_right - gripLongIndent, m_top + halfHeight, m_fgColor); + line(m_left + longOffset, m_top + gripShortIndent, + m_left + longOffset, m_bottom - gripShortIndent, m_fgColor); + line(m_right - longOffset, m_top + gripShortIndent, + m_right - longOffset, m_bottom - gripShortIndent, m_fgColor); + break; + } + + case VerticalScrollGripType: { + // Draw a vertical crosshatch for the grip. + int longOffset = halfHeight - gripLongIndent; + line(m_left + halfWidth, m_top + gripLongIndent, + m_left + halfWidth, m_bottom - gripLongIndent, m_fgColor); + line(m_left + gripShortIndent, m_top + longOffset, + m_right - gripShortIndent, m_top + longOffset, m_fgColor); + line(m_left + gripShortIndent, m_bottom - longOffset, + m_right - gripShortIndent, m_bottom - longOffset, m_fgColor); + break; + } + + case LeftArrowType: + // Draw a left arrow inside a box. + box(m_irect, m_bgColor); + triangle(m_right - quarterWidth, m_top + quarterHeight, + m_right - quarterWidth, m_bottom - quarterHeight, + m_left + quarterWidth, m_top + halfHeight, m_fgColor); + break; + + case RightArrowType: + // Draw a left arrow inside a box. + box(m_irect, m_bgColor); + triangle(m_left + quarterWidth, m_top + quarterHeight, + m_right - quarterWidth, m_top + halfHeight, + m_left + quarterWidth, m_bottom - quarterHeight, m_fgColor); + break; + + case UpArrowType: + // Draw an up arrow inside a box. + box(m_irect, m_bgColor); + triangle(m_left + quarterWidth, m_bottom - quarterHeight, + m_left + halfWidth, m_top + quarterHeight, + m_right - quarterWidth, m_bottom - quarterHeight, m_fgColor); + break; + + case DownArrowType: + // Draw a down arrow inside a box. + box(m_irect, m_bgColor); + triangle(m_left + quarterWidth, m_top + quarterHeight, + m_right - quarterWidth, m_top + quarterHeight, + m_left + halfWidth, m_bottom - quarterHeight, m_fgColor); + break; + + case HorizontalSliderTrackType: { + // Draw a narrow rect for the track plus box hatches on the ends. + SkIRect lirect; + lirect = m_irect; + lirect.inset(noOffset, halfHeight - sliderIndent); + box(lirect, m_bgColor); + line(m_left, m_top, m_left, m_bottom, m_edgeColor); + line(m_right, m_top, m_right, m_bottom, m_edgeColor); + break; + } + + case DropDownButtonType: + // Draw a box with a big down arrow on top. + box(m_irect, m_bgColor); + triangle(m_left + quarterWidth, m_top, + m_right - quarterWidth, m_top, + m_left + halfWidth, m_bottom, m_fgColor); + break; + + default: + ASSERT_NOT_REACHED(); + CRASH(); + break; + } + + markState(); + m_canvas->endPlatformPaint(); +} + +// Because rendering a text field is dependent on input +// parameters the other controls don't have, we render it directly +// rather than trying to overcomplicate draw() further. +void WebThemeControlDRT::drawTextField(bool drawEdges, bool fillContentArea, SkColor color) +{ + SkPaint paint; + + m_canvas->beginPlatformPaint(); + if (fillContentArea) { + paint.setColor(color); + paint.setStyle(SkPaint::kFill_Style); + m_canvas->drawIRect(m_irect, paint); + } + if (drawEdges) { + paint.setColor(m_edgeColor); + paint.setStyle(SkPaint::kStroke_Style); + m_canvas->drawIRect(m_irect, paint); + } + + markState(); + m_canvas->endPlatformPaint(); +} + +void WebThemeControlDRT::drawProgressBar(const SkIRect& fillRect) +{ + SkPaint paint; + + m_canvas->beginPlatformPaint(); + paint.setColor(m_bgColor); + paint.setStyle(SkPaint::kFill_Style); + m_canvas->drawIRect(m_irect, paint); + + // Emulate clipping + SkIRect tofill; + tofill.intersect(m_irect, fillRect); + paint.setColor(m_fgColor); + paint.setStyle(SkPaint::kFill_Style); + m_canvas->drawIRect(tofill, paint); + + markState(); + m_canvas->endPlatformPaint(); +} + diff --git a/WebKitTools/DumpRenderTree/chromium/WebThemeControlDRT.h b/WebKitTools/DumpRenderTree/chromium/WebThemeControlDRT.h new file mode 100755 index 0000000..1f73610 --- /dev/null +++ b/WebKitTools/DumpRenderTree/chromium/WebThemeControlDRT.h @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// WebThemeControlDRT implements the generic rendering of controls +// needed by WebThemeEngineDRT. See the comments in that class +// header file for why this class is needed and used. +// +// This class implements a generic set of widgets using Skia. The widgets +// are optimized for testability, not a pleasing appearance. +// + +#ifndef WebThemeControlDRT_h +#define WebThemeControlDRT_h + +#include "skia/ext/platform_canvas.h" +#include "third_party/skia/include/core/SkColor.h" +#include <wtf/Noncopyable.h> + +// Skia forward declarations +struct SkIRect; + +class WebThemeControlDRT : public Noncopyable { +public: + // This list of states mostly mirrors the list in WebCore/platform/ThemeTypes.h + // but is maintained separately since that isn't public and also to minimize + // dependencies. + // Note that the WebKit ThemeTypes seem to imply that a control can be + // in multiple states simultaneously but WebThemeEngine only allows for + // a single state at a time. + // + // Some definitions for the various states: + // Disabled - indicates that a control can't be modified or selected + // (corresponds to HTML 'disabled' attribute) + // ReadOnly - indicates that a control can't be modified but can be + // selected + // Normal - the normal state of control on the page when it isn't + // focused or otherwise active + // Hot - when the mouse is hovering over a part of the control, + // all the other parts are considered "hot" + // Hover - when the mouse is directly over a control (the CSS + // :hover pseudo-class) + // Focused - when the control has the keyboard focus + // Pressed - when the control is being triggered (by a mousedown or + // a key event). + // Indeterminate - when set to indeterminate (only for progress bar) + enum State { + UnknownState = 0, + DisabledState, + ReadOnlyState, + NormalState, + HotState, + HoverState, + FocusedState, + PressedState, + IndeterminateState + }; + + // This list of types mostly mirrors the list in + // WebCore/platform/ThemeTypes.h but is maintained + // separately since that isn't public and also to minimize dependencies. + // + // Note that what the user might think of as a single control can be + // made up of multiple parts. For example, a single scroll bar contains + // six clickable parts - two arrows, the "thumb" indicating the current + // position on the bar, the other two parts of the bar (before and after + // the thumb) and the "gripper" on the thumb itself. + // + enum Type { + UnknownType = 0, + TextFieldType, + PushButtonType, + UncheckedBoxType, + CheckedBoxType, + UncheckedRadioType, + CheckedRadioType, + HorizontalScrollTrackBackType, + HorizontalScrollTrackForwardType, + HorizontalScrollThumbType, + HorizontalScrollGripType, + VerticalScrollTrackBackType, + VerticalScrollTrackForwardType, + VerticalScrollThumbType, + VerticalScrollGripType, + LeftArrowType, + RightArrowType, + UpArrowType, + DownArrowType, + HorizontalSliderTrackType, + HorizontalSliderThumbType, + DropDownButtonType, + ProgressBarType + }; + + // canvas is the canvas to draw onto, and rect gives the size of the + // control. ctype and cstate specify the type and state of the control. + WebThemeControlDRT(skia::PlatformCanvas* canvas, + const SkIRect& rect, + Type ctype, + State cstate); + ~WebThemeControlDRT(); + + // Draws the control. + void draw(); + + // Use this for TextField controls instead, because the logic + // for drawing them is dependent on what WebKit tells us to do. + // If drawEdges is true, draw an edge around the control. If + // fillContentArea is true, fill the content area with the given color. + void drawTextField(bool drawEdges, bool fillContentArea, SkColor color); + + // Use this for drawing ProgressBar controls instead, since we + // need to know the rect to fill inside the bar. + void drawProgressBar(const SkIRect& fillRect); + +private: + // Draws a box of size specified by irect, filled with the given color. + // The box will have a border drawn in the default edge color. + void box(const SkIRect& irect, SkColor color); + + + // Draws a triangle of size specified by the three pairs of coordinates, + // filled with the given color. The box will have an edge drawn in the + // default edge color. + void triangle(int x0, int y0, int x1, int y1, int x2, int y2, SkColor color); + + // Draws a rectangle the size of the control with rounded corners, filled + // with the specified color (and with a border in the default edge color). + void roundRect(SkColor color); + + // Draws an oval the size of the control, filled with the specified color + // and with a border in the default edge color. + void oval(SkColor color); + + // Draws a circle centered in the control with the specified radius, + // filled with the specified color, and with a border draw in the + // default edge color. + void circle(SkScalar radius, SkColor color); + + // Draws a box the size of the control, filled with the outerColor and + // with a border in the default edge color, and then draws another box + // indented on all four sides by the specified amounts, filled with the + // inner color and with a border in the default edge color. + void nestedBoxes(int indentLeft, + int indentTop, + int indentRight, + int indentBottom, + SkColor outerColor, + SkColor innerColor); + + // Draws a line between the two points in the given color. + void line(int x0, int y0, int x1, int y1, SkColor color); + + // Draws a distinctive mark on the control for each state, so that the + // state of the control can be determined without needing to know which + // color is which. + void markState(); + + skia::PlatformCanvas* m_canvas; + const SkIRect m_irect; + const Type m_type; + const State m_state; + const SkColor m_edgeColor; + const SkColor m_bgColor; + const SkColor m_fgColor; + + // The following are convenience accessors for m_irect. + const int m_left; + const int m_right; + const int m_top; + const int m_bottom; + const int m_width; + const int m_height; +}; + +#endif // WebThemeControlDRT_h diff --git a/WebKitTools/DumpRenderTree/chromium/WebThemeEngineDRT.cpp b/WebKitTools/DumpRenderTree/chromium/WebThemeEngineDRT.cpp new file mode 100755 index 0000000..b3092cc --- /dev/null +++ b/WebKitTools/DumpRenderTree/chromium/WebThemeEngineDRT.cpp @@ -0,0 +1,674 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING 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 "WebThemeEngineDRT.h" + +#include "WebThemeControlDRT.h" +#include "public/WebRect.h" +#include "third_party/skia/include/core/SkRect.h" + +// Although all this code is generic, we include these headers +// to pull in the Windows #defines for the parts and states of +// the controls. +#include <vsstyle.h> +#include <windows.h> + +#include <wtf/Assertions.h> + +using namespace WebKit; + +// We define this for clarity, although there really should be a DFCS_NORMAL in winuser.h. +static const int dfcsNormal = 0x0000; + +static SkIRect webRectToSkIRect(const WebRect& webRect) +{ + SkIRect irect; + irect.set(webRect.x, webRect.y, webRect.x + webRect.width, webRect.y + webRect.height); + return irect; +} + +static void drawControl(WebCanvas* canvas, + const WebRect& rect, + WebThemeControlDRT::Type ctype, + WebThemeControlDRT::State cstate) +{ + WebThemeControlDRT control(canvas, webRectToSkIRect(rect), ctype, cstate); + control.draw(); +} + +static void drawTextField(WebCanvas* canvas, + const WebRect& rect, + WebThemeControlDRT::Type ctype, + WebThemeControlDRT::State cstate, + bool drawEdges, + bool fillContentArea, + WebColor color) +{ + WebThemeControlDRT control(canvas, webRectToSkIRect(rect), ctype, cstate); + control.drawTextField(drawEdges, fillContentArea, color); +} + +static void drawProgressBar(WebCanvas* canvas, + WebThemeControlDRT::Type ctype, + WebThemeControlDRT::State cstate, + const WebRect& barRect, + const WebRect& fillRect) +{ + WebThemeControlDRT control(canvas, webRectToSkIRect(barRect), ctype, cstate); + control.drawProgressBar(webRectToSkIRect(fillRect)); +} + +// WebThemeEngineDRT + +void WebThemeEngineDRT::paintButton(WebCanvas* canvas, + int part, + int state, + int classicState, + const WebRect& rect) +{ + WebThemeControlDRT::Type ctype = WebThemeControlDRT::UnknownType; + WebThemeControlDRT::State cstate = WebThemeControlDRT::UnknownState; + + if (part == BP_CHECKBOX) { + switch (state) { + case CBS_UNCHECKEDNORMAL: + ASSERT(classicState == dfcsNormal); + ctype = WebThemeControlDRT::UncheckedBoxType; + cstate = WebThemeControlDRT::NormalState; + break; + + case CBS_UNCHECKEDHOT: + ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_HOT)); + ctype = WebThemeControlDRT::UncheckedBoxType; + cstate = WebThemeControlDRT::HotState; + break; + + case CBS_UNCHECKEDPRESSED: + ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_PUSHED)); + ctype = WebThemeControlDRT::UncheckedBoxType; + cstate = WebThemeControlDRT::PressedState; + break; + + case CBS_UNCHECKEDDISABLED: + ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_INACTIVE)); + ctype = WebThemeControlDRT::UncheckedBoxType; + cstate = WebThemeControlDRT::DisabledState; + break; + + case CBS_CHECKEDNORMAL: + ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED)); + ctype = WebThemeControlDRT::CheckedBoxType; + cstate = WebThemeControlDRT::NormalState; + break; + + case CBS_CHECKEDHOT: + ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_HOT)); + ctype = WebThemeControlDRT::CheckedBoxType; + cstate = WebThemeControlDRT::HotState; + break; + + case CBS_CHECKEDPRESSED: + ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_PUSHED)); + ctype = WebThemeControlDRT::CheckedBoxType; + cstate = WebThemeControlDRT::PressedState; + break; + + case CBS_CHECKEDDISABLED: + ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_INACTIVE)); + ctype = WebThemeControlDRT::CheckedBoxType; + cstate = WebThemeControlDRT::DisabledState; + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + } else if (BP_RADIOBUTTON == part) { + switch (state) { + case RBS_UNCHECKEDNORMAL: + ASSERT(classicState == DFCS_BUTTONRADIO); + ctype = WebThemeControlDRT::UncheckedRadioType; + cstate = WebThemeControlDRT::NormalState; + break; + + case RBS_UNCHECKEDHOT: + ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_HOT)); + ctype = WebThemeControlDRT::UncheckedRadioType; + cstate = WebThemeControlDRT::HotState; + break; + + case RBS_UNCHECKEDPRESSED: + ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_PUSHED)); + ctype = WebThemeControlDRT::UncheckedRadioType; + cstate = WebThemeControlDRT::PressedState; + break; + + case RBS_UNCHECKEDDISABLED: + ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_INACTIVE)); + ctype = WebThemeControlDRT::UncheckedRadioType; + cstate = WebThemeControlDRT::DisabledState; + break; + + case RBS_CHECKEDNORMAL: + ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED)); + ctype = WebThemeControlDRT::CheckedRadioType; + cstate = WebThemeControlDRT::NormalState; + break; + + case RBS_CHECKEDHOT: + ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED | DFCS_HOT)); + ctype = WebThemeControlDRT::CheckedRadioType; + cstate = WebThemeControlDRT::HotState; + break; + + case RBS_CHECKEDPRESSED: + ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED | DFCS_PUSHED)); + ctype = WebThemeControlDRT::CheckedRadioType; + cstate = WebThemeControlDRT::PressedState; + break; + + case RBS_CHECKEDDISABLED: + ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED | DFCS_INACTIVE)); + ctype = WebThemeControlDRT::CheckedRadioType; + cstate = WebThemeControlDRT::DisabledState; + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + } else if (BP_PUSHBUTTON == part) { + switch (state) { + case PBS_NORMAL: + ASSERT(classicState == DFCS_BUTTONPUSH); + ctype = WebThemeControlDRT::PushButtonType; + cstate = WebThemeControlDRT::NormalState; + break; + + case PBS_HOT: + ASSERT(classicState == (DFCS_BUTTONPUSH | DFCS_HOT)); + ctype = WebThemeControlDRT::PushButtonType; + cstate = WebThemeControlDRT::HotState; + break; + + case PBS_PRESSED: + ASSERT(classicState == (DFCS_BUTTONPUSH | DFCS_PUSHED)); + ctype = WebThemeControlDRT::PushButtonType; + cstate = WebThemeControlDRT::PressedState; + break; + + case PBS_DISABLED: + ASSERT(classicState == (DFCS_BUTTONPUSH | DFCS_INACTIVE)); + ctype = WebThemeControlDRT::PushButtonType; + cstate = WebThemeControlDRT::DisabledState; + break; + + case PBS_DEFAULTED: + ASSERT(classicState == DFCS_BUTTONPUSH); + ctype = WebThemeControlDRT::PushButtonType; + cstate = WebThemeControlDRT::FocusedState; + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + } else { + ASSERT_NOT_REACHED(); + } + + drawControl(canvas, rect, ctype, cstate); +} + + +void WebThemeEngineDRT::paintMenuList(WebCanvas* canvas, + int part, + int state, + int classicState, + const WebRect& rect) +{ + WebThemeControlDRT::Type ctype = WebThemeControlDRT::UnknownType; + WebThemeControlDRT::State cstate = WebThemeControlDRT::UnknownState; + + if (CP_DROPDOWNBUTTON == part) { + ctype = WebThemeControlDRT::DropDownButtonType; + switch (state) { + case CBXS_NORMAL: + ASSERT(classicState == DFCS_MENUARROW); + cstate = WebThemeControlDRT::NormalState; + break; + + case CBXS_HOT: + ASSERT(classicState == (DFCS_MENUARROW | DFCS_HOT)); + cstate = WebThemeControlDRT::HoverState; + break; + + case CBXS_PRESSED: + ASSERT(classicState == (DFCS_MENUARROW | DFCS_PUSHED)); + cstate = WebThemeControlDRT::PressedState; + break; + + case CBXS_DISABLED: + ASSERT(classicState == (DFCS_MENUARROW | DFCS_INACTIVE)); + cstate = WebThemeControlDRT::DisabledState; + break; + + default: + CRASH(); + break; + } + } else { + CRASH(); + } + + drawControl(canvas, rect, ctype, cstate); +} + +void WebThemeEngineDRT::paintScrollbarArrow(WebCanvas* canvas, + int state, + int classicState, + const WebRect& rect) +{ + WebThemeControlDRT::Type ctype = WebThemeControlDRT::UnknownType; + WebThemeControlDRT::State cstate = WebThemeControlDRT::UnknownState; + + switch (state) { + case ABS_UPNORMAL: + ASSERT(classicState == DFCS_SCROLLUP); + ctype = WebThemeControlDRT::UpArrowType; + cstate = WebThemeControlDRT::NormalState; + break; + + case ABS_DOWNNORMAL: + ASSERT(classicState == DFCS_SCROLLDOWN); + ctype = WebThemeControlDRT::DownArrowType; + cstate = WebThemeControlDRT::NormalState; + break; + + case ABS_LEFTNORMAL: + ASSERT(classicState == DFCS_SCROLLLEFT); + ctype = WebThemeControlDRT::LeftArrowType; + cstate = WebThemeControlDRT::NormalState; + break; + + case ABS_RIGHTNORMAL: + ASSERT(classicState == DFCS_SCROLLRIGHT); + ctype = WebThemeControlDRT::RightArrowType; + cstate = WebThemeControlDRT::NormalState; + break; + + case ABS_UPHOT: + ASSERT(classicState == (DFCS_SCROLLUP | DFCS_HOT)); + ctype = WebThemeControlDRT::UpArrowType; + cstate = WebThemeControlDRT::HotState; + break; + + case ABS_DOWNHOT: + ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_HOT)); + ctype = WebThemeControlDRT::DownArrowType; + cstate = WebThemeControlDRT::HotState; + break; + + case ABS_LEFTHOT: + ASSERT(classicState == (DFCS_SCROLLLEFT | DFCS_HOT)); + ctype = WebThemeControlDRT::LeftArrowType; + cstate = WebThemeControlDRT::HotState; + break; + + case ABS_RIGHTHOT: + ASSERT(classicState == (DFCS_SCROLLRIGHT | DFCS_HOT)); + ctype = WebThemeControlDRT::RightArrowType; + cstate = WebThemeControlDRT::HotState; + break; + + case ABS_UPHOVER: + ASSERT(classicState == DFCS_SCROLLUP); + ctype = WebThemeControlDRT::UpArrowType; + cstate = WebThemeControlDRT::HoverState; + break; + + case ABS_DOWNHOVER: + ASSERT(classicState == DFCS_SCROLLDOWN); + ctype = WebThemeControlDRT::DownArrowType; + cstate = WebThemeControlDRT::HoverState; + break; + + case ABS_LEFTHOVER: + ASSERT(classicState == DFCS_SCROLLLEFT); + ctype = WebThemeControlDRT::LeftArrowType; + cstate = WebThemeControlDRT::HoverState; + break; + + case ABS_RIGHTHOVER: + ASSERT(classicState == DFCS_SCROLLRIGHT); + ctype = WebThemeControlDRT::RightArrowType; + cstate = WebThemeControlDRT::HoverState; + break; + + case ABS_UPPRESSED: + ASSERT(classicState == (DFCS_SCROLLUP | DFCS_PUSHED | DFCS_FLAT)); + ctype = WebThemeControlDRT::UpArrowType; + cstate = WebThemeControlDRT::PressedState; + break; + + case ABS_DOWNPRESSED: + ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_PUSHED | DFCS_FLAT)); + ctype = WebThemeControlDRT::DownArrowType; + cstate = WebThemeControlDRT::PressedState; + break; + + case ABS_LEFTPRESSED: + ASSERT(classicState == (DFCS_SCROLLLEFT | DFCS_PUSHED | DFCS_FLAT)); + ctype = WebThemeControlDRT::LeftArrowType; + cstate = WebThemeControlDRT::PressedState; + break; + + case ABS_RIGHTPRESSED: + ASSERT(classicState == (DFCS_SCROLLRIGHT | DFCS_PUSHED | DFCS_FLAT)); + ctype = WebThemeControlDRT::RightArrowType; + cstate = WebThemeControlDRT::PressedState; + break; + + case ABS_UPDISABLED: + ASSERT(classicState == (DFCS_SCROLLUP | DFCS_INACTIVE)); + ctype = WebThemeControlDRT::UpArrowType; + cstate = WebThemeControlDRT::DisabledState; + break; + + case ABS_DOWNDISABLED: + ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_INACTIVE)); + ctype = WebThemeControlDRT::DownArrowType; + cstate = WebThemeControlDRT::DisabledState; + break; + + case ABS_LEFTDISABLED: + ASSERT(classicState == (DFCS_SCROLLLEFT | DFCS_INACTIVE)); + ctype = WebThemeControlDRT::LeftArrowType; + cstate = WebThemeControlDRT::DisabledState; + break; + + case ABS_RIGHTDISABLED: + ASSERT(classicState == (DFCS_SCROLLRIGHT | DFCS_INACTIVE)); + ctype = WebThemeControlDRT::RightArrowType; + cstate = WebThemeControlDRT::DisabledState; + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + + drawControl(canvas, rect, ctype, cstate); +} + +void WebThemeEngineDRT::paintScrollbarThumb(WebCanvas* canvas, + int part, + int state, + int classicState, + const WebRect& rect) +{ + WebThemeControlDRT::Type ctype = WebThemeControlDRT::UnknownType; + WebThemeControlDRT::State cstate = WebThemeControlDRT::UnknownState; + + switch (part) { + case SBP_THUMBBTNHORZ: + ctype = WebThemeControlDRT::HorizontalScrollThumbType; + break; + + case SBP_THUMBBTNVERT: + ctype = WebThemeControlDRT::VerticalScrollThumbType; + break; + + case SBP_GRIPPERHORZ: + ctype = WebThemeControlDRT::HorizontalScrollGripType; + break; + + case SBP_GRIPPERVERT: + ctype = WebThemeControlDRT::VerticalScrollGripType; + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + + switch (state) { + case SCRBS_NORMAL: + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRT::NormalState; + break; + + case SCRBS_HOT: + ASSERT(classicState == DFCS_HOT); + cstate = WebThemeControlDRT::HotState; + break; + + case SCRBS_HOVER: + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRT::HoverState; + break; + + case SCRBS_PRESSED: + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRT::PressedState; + break; + + case SCRBS_DISABLED: + ASSERT_NOT_REACHED(); // This should never happen in practice. + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + + drawControl(canvas, rect, ctype, cstate); +} + +void WebThemeEngineDRT::paintScrollbarTrack(WebCanvas* canvas, + int part, + int state, + int classicState, + const WebRect& rect, + const WebRect& alignRect) +{ + WebThemeControlDRT::Type ctype = WebThemeControlDRT::UnknownType; + WebThemeControlDRT::State cstate = WebThemeControlDRT::UnknownState; + + switch (part) { + case SBP_UPPERTRACKHORZ: + ctype = WebThemeControlDRT::HorizontalScrollTrackBackType; + break; + + case SBP_LOWERTRACKHORZ: + ctype = WebThemeControlDRT::HorizontalScrollTrackForwardType; + break; + + case SBP_UPPERTRACKVERT: + ctype = WebThemeControlDRT::VerticalScrollTrackBackType; + break; + + case SBP_LOWERTRACKVERT: + ctype = WebThemeControlDRT::VerticalScrollTrackForwardType; + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + + switch (state) { + case SCRBS_NORMAL: + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRT::NormalState; + break; + + case SCRBS_HOT: + ASSERT_NOT_REACHED(); // This should never happen in practice. + break; + + case SCRBS_HOVER: + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRT::HoverState; + break; + + case SCRBS_PRESSED: + ASSERT_NOT_REACHED(); // This should never happen in practice. + break; + + case SCRBS_DISABLED: + ASSERT(classicState == DFCS_INACTIVE); + cstate = WebThemeControlDRT::DisabledState; + break; + + default: + CRASH(); + break; + } + + drawControl(canvas, rect, ctype, cstate); +} + +void WebThemeEngineDRT::paintTextField(WebCanvas* canvas, + int part, + int state, + int classicState, + const WebRect& rect, + WebColor color, + bool fillContentArea, + bool drawEdges) +{ + WebThemeControlDRT::Type ctype = WebThemeControlDRT::UnknownType; + WebThemeControlDRT::State cstate = WebThemeControlDRT::UnknownState; + + ASSERT(EP_EDITTEXT == part); + ctype = WebThemeControlDRT::TextFieldType; + + switch (state) { + case ETS_NORMAL: + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRT::NormalState; + break; + + case ETS_HOT: + ASSERT(classicState == DFCS_HOT); + cstate = WebThemeControlDRT::HotState; + break; + + case ETS_DISABLED: + ASSERT(classicState == DFCS_INACTIVE); + cstate = WebThemeControlDRT::DisabledState; + break; + + case ETS_SELECTED: + ASSERT(classicState == DFCS_PUSHED); + cstate = WebThemeControlDRT::PressedState; + break; + + case ETS_FOCUSED: + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRT::FocusedState; + break; + + case ETS_READONLY: + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRT::ReadOnlyState; + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + + drawTextField(canvas, rect, ctype, cstate, drawEdges, fillContentArea, color); +} + +void WebThemeEngineDRT::paintTrackbar(WebCanvas* canvas, + int part, + int state, + int classicState, + const WebRect& rect) +{ + WebThemeControlDRT::Type ctype = WebThemeControlDRT::UnknownType; + WebThemeControlDRT::State cstate = WebThemeControlDRT::UnknownState; + + if (TKP_THUMBBOTTOM == part) { + ctype = WebThemeControlDRT::HorizontalSliderThumbType; + switch (state) { + case TUS_NORMAL: + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRT::NormalState; + break; + + case TUS_HOT: + ASSERT(classicState == DFCS_HOT); + cstate = WebThemeControlDRT::HotState; + break; + + case TUS_DISABLED: + ASSERT(classicState == DFCS_INACTIVE); + cstate = WebThemeControlDRT::DisabledState; + break; + + case TUS_PRESSED: + ASSERT(classicState == DFCS_PUSHED); + cstate = WebThemeControlDRT::PressedState; + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + } else if (TKP_TRACK == part) { + ctype = WebThemeControlDRT::HorizontalSliderTrackType; + ASSERT(part == TUS_NORMAL); + ASSERT(classicState == dfcsNormal); + cstate = WebThemeControlDRT::NormalState; + } else { + ASSERT_NOT_REACHED(); + } + + drawControl(canvas, rect, ctype, cstate); +} + + +void WebThemeEngineDRT::paintProgressBar(WebKit::WebCanvas* canvas, + const WebKit::WebRect& barRect, + const WebKit::WebRect& valueRect, + bool determinate, + double) +{ + WebThemeControlDRT::Type ctype = WebThemeControlDRT::ProgressBarType; + WebThemeControlDRT::State cstate = determinate ? WebThemeControlDRT::NormalState + : WebThemeControlDRT::IndeterminateState; + drawProgressBar(canvas, ctype, cstate, barRect, valueRect); +} + diff --git a/WebKitTools/DumpRenderTree/chromium/WebThemeEngineDRT.h b/WebKitTools/DumpRenderTree/chromium/WebThemeEngineDRT.h new file mode 100755 index 0000000..89805b1 --- /dev/null +++ b/WebKitTools/DumpRenderTree/chromium/WebThemeEngineDRT.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This implements the WebThemeEngine API used by the Windows version of +// Chromium to render native form controls like checkboxes, radio buttons, +// and scroll bars. +// The normal implementation (native_theme) renders the controls using either +// the UXTheme theming engine present in XP, Vista, and Win 7, or the "classic" +// theme used if that theme is selected in the Desktop settings. +// Unfortunately, both of these themes render controls differently on the +// different versions of Windows. +// +// In order to ensure maximum consistency of baselines across the different +// Windows versions, we provide a simple implementation for DRT here +// instead. These controls are actually platform-independent (they're rendered +// using Skia) and could be used on Linux and the Mac as well, should we +// choose to do so at some point. +// + +#ifndef WebThemeEngineDRT_h +#define WebThemeEngineDRT_h + +#include "public/WebThemeEngine.h" +#include <wtf/Noncopyable.h> + +class WebThemeEngineDRT : public WebKit::WebThemeEngine, public Noncopyable { +public: + WebThemeEngineDRT() {} + + // WebThemeEngine methods: + virtual void paintButton( + WebKit::WebCanvas*, int part, int state, int classicState, + const WebKit::WebRect&); + + virtual void paintMenuList( + WebKit::WebCanvas*, int part, int state, int classicState, + const WebKit::WebRect&); + + virtual void paintScrollbarArrow( + WebKit::WebCanvas*, int state, int classicState, + const WebKit::WebRect&); + + virtual void paintScrollbarThumb( + WebKit::WebCanvas*, int part, int state, int classicState, + const WebKit::WebRect&); + + virtual void paintScrollbarTrack( + WebKit::WebCanvas*, int part, int state, int classicState, + const WebKit::WebRect&, const WebKit::WebRect& alignRect); + + virtual void paintTextField( + WebKit::WebCanvas*, int part, int state, int classicState, + const WebKit::WebRect&, WebKit::WebColor, bool fillContentArea, + bool drawEdges); + + virtual void paintTrackbar( + WebKit::WebCanvas*, int part, int state, int classicState, + const WebKit::WebRect&); + + virtual void paintProgressBar( + WebKit::WebCanvas*, const WebKit::WebRect& barRect, + const WebKit::WebRect& valueRect, + bool determinate, double time); +}; + +#endif // WebThemeEngineDRT_h diff --git a/WebKitTools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp b/WebKitTools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp index 3735d0a..d186ffa 100644 --- a/WebKitTools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp +++ b/WebKitTools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp @@ -112,6 +112,12 @@ AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y) return 0; } +AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index) +{ + // FIXME: implement + return 0; +} + AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index) { Vector<AccessibilityUIElement> children; diff --git a/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp b/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp index 02c0abb..14577f1 100644 --- a/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp +++ b/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp @@ -388,8 +388,18 @@ void dump() if (gLayoutTestController->dumpAsText()) result = dumpFramesAsText(mainFrame); - else + else { + // Widget resizing is done asynchronously in GTK+. We pump the main + // loop here, to flush any pending resize requests. This prevents + // timing issues which affect the size of elements in the output. + // We only enable this workaround for tests that print the render tree + // because this seems to break some dumpAsText tests: see bug 39988 + // After fixing that test, we should apply this approach to all dumps. + while (gtk_events_pending()) + gtk_main_iteration(); + result = webkit_web_frame_dump_render_tree(mainFrame); + } if (!result) { const char* errorMessage; @@ -525,8 +535,10 @@ static void runTest(const string& testPathOrURL) gtk_main(); // If developer extras enabled Web Inspector may have been open by the test. - if (shouldEnableDeveloperExtras(pathOrURL.c_str())) + if (shouldEnableDeveloperExtras(pathOrURL.c_str())) { gLayoutTestController->closeWebInspector(); + gLayoutTestController->setDeveloperExtrasEnabled(false); + } // Also check if we still have opened webViews and free them. if (gLayoutTestController->closeRemainingWindowsWhenComplete() || webViewList) { @@ -663,7 +675,7 @@ static void webViewWindowObjectCleared(WebKitWebView* view, WebKitWebFrame* fram ASSERT(!exception); JSStringRef eventSenderStr = JSStringCreateWithUTF8CString("eventSender"); - JSValueRef eventSender = makeEventSender(context); + JSValueRef eventSender = makeEventSender(context, !webkit_web_frame_get_parent(frame)); JSObjectSetProperty(context, windowObject, eventSenderStr, eventSender, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0); JSStringRelease(eventSenderStr); } diff --git a/WebKitTools/DumpRenderTree/gtk/EventSender.cpp b/WebKitTools/DumpRenderTree/gtk/EventSender.cpp index 9c27d8c..0ef4a42 100644 --- a/WebKitTools/DumpRenderTree/gtk/EventSender.cpp +++ b/WebKitTools/DumpRenderTree/gtk/EventSender.cpp @@ -45,28 +45,27 @@ #include <gdk/gdkkeysyms.h> #include <string.h> -// TODO: Currently drag and drop related code is left out and -// should be merged once we have drag and drop support in WebCore. +// FIXME: Implement support for synthesizing drop events. extern "C" { extern void webkit_web_frame_layout(WebKitWebFrame* frame); } -static bool down = false; -static bool currentEventButton = 1; -static bool dragMode = true; -static bool replayingSavedEvents = false; +static bool dragMode; +static int timeOffset = 0; + static int lastMousePositionX; static int lastMousePositionY; - static int lastClickPositionX; static int lastClickPositionY; -static int clickCount = 0; +static int lastClickTimeOffset; +static int lastClickButton; +static int buttonCurrentlyDown; +static int clickCount; struct DelayedMessage { GdkEvent event; gulong delay; - gboolean isDragEvent; }; static DelayedMessage msgQueue[1024]; @@ -84,6 +83,10 @@ enum KeyLocationCode { DOM_KEY_LOCATION_NUMPAD = 0x03 }; +static void sendOrQueueEvent(GdkEvent, bool = true); +static void dispatchEvent(GdkEvent event); +static guint getStateFlags(); + static JSValueRef getDragModeCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) { return JSValueMakeBoolean(context, dragMode); @@ -97,46 +100,15 @@ static bool setDragModeCallback(JSContextRef context, JSObjectRef object, JSStri static JSValueRef leapForwardCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { - // FIXME: Add proper support for forward leaps - return JSValueMakeUndefined(context); -} - -static JSValueRef contextClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - webkit_web_frame_layout(mainFrame); - - WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); - if (!view) - return JSValueMakeUndefined(context); - - GdkEvent event; - memset(&event, 0, sizeof(event)); - event.button.button = 3; - event.button.x = lastMousePositionX; - event.button.y = lastMousePositionY; - event.button.window = GTK_WIDGET(view)->window; - - gboolean return_val; - down = true; - event.type = GDK_BUTTON_PRESS; - g_signal_emit_by_name(view, "button_press_event", &event, &return_val); - - down = false; - event.type = GDK_BUTTON_RELEASE; - g_signal_emit_by_name(view, "button_release_event", &event, &return_val); + if (argumentCount > 0) { + msgQueue[endOfQueue].delay = JSValueToNumber(context, arguments[0], exception); + timeOffset += msgQueue[endOfQueue].delay; + ASSERT(!exception || !*exception); + } return JSValueMakeUndefined(context); } -static void updateClickCount(int button) -{ - // FIXME: take the last clicked button number and the time of last click into account. - if (lastClickPositionX != lastMousePositionX || lastClickPositionY != lastMousePositionY || currentEventButton != button) - clickCount = 1; - else - clickCount++; -} - #if !GTK_CHECK_VERSION(2,17,3) static void getRootCoords(GtkWidget* view, int* rootX, int* rootY) { @@ -152,131 +124,139 @@ static void getRootCoords(GtkWidget* view, int* rootX, int* rootY) } #endif -static JSValueRef mouseDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +bool prepareMouseButtonEvent(GdkEvent* event, int eventSenderButtonNumber) { WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); if (!view) - return JSValueMakeUndefined(context); + return false; + + // The logic for mapping EventSender button numbers to GDK button + // numbers originates from the Windows EventSender. + int gdkButtonNumber = 3; + if (eventSenderButtonNumber >= 0 && eventSenderButtonNumber <= 2) + gdkButtonNumber = eventSenderButtonNumber + 1; + + // fast/events/mouse-click-events expects the 4th button + // to be event.button = 1, so send a middle-button event. + else if (eventSenderButtonNumber == 3) + gdkButtonNumber = 2; + + memset(event, 0, sizeof(event)); + event->button.button = gdkButtonNumber; + event->button.x = lastMousePositionX; + event->button.y = lastMousePositionY; + event->button.window = GTK_WIDGET(view)->window; + event->button.device = gdk_device_get_core_pointer(); + event->button.state = getStateFlags(); + + // Mouse up & down events dispatched via g_signal_emit_by_name must offset + // their time value, so that WebKit can detect where sequences of mouse + // clicks begin and end. This should not interfere with GDK or GTK+ event + // processing, because the event is only seen by the widget. + event->button.time = GDK_CURRENT_TIME + timeOffset; + + int xRoot, yRoot; +#if GTK_CHECK_VERSION(2, 17, 3) + gdk_window_get_root_coords(GTK_WIDGET(view)->window, lastMousePositionX, lastMousePositionY, &xRoot, &yRoot); +#else + getRootCoords(GTK_WIDGET(view), &xRoot, &yRoot); +#endif + event->button.x_root = xRoot; + event->button.y_root = yRoot; - down = true; + return true; +} +static JSValueRef contextClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ GdkEvent event; - memset(&event, 0, sizeof(event)); + if (!prepareMouseButtonEvent(&event, 2)) + return JSValueMakeUndefined(context); + event.type = GDK_BUTTON_PRESS; - event.button.button = 1; + sendOrQueueEvent(event); + event.type = GDK_BUTTON_RELEASE; + sendOrQueueEvent(event); + + return JSValueMakeUndefined(context); +} + +static void updateClickCount(int button) +{ + if (lastClickPositionX != lastMousePositionX + || lastClickPositionY != lastMousePositionY + || lastClickButton != button + || timeOffset - lastClickTimeOffset >= 1) + clickCount = 1; + else + clickCount++; +} +static JSValueRef mouseDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int button = 0; if (argumentCount == 1) { - event.button.button = (int)JSValueToNumber(context, arguments[0], exception) + 1; + button = static_cast<int>(JSValueToNumber(context, arguments[0], exception)); g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context)); } - currentEventButton = event.button.button; - - event.button.x = lastMousePositionX; - event.button.y = lastMousePositionY; - event.button.window = GTK_WIDGET(view)->window; - event.button.time = GDK_CURRENT_TIME; - event.button.device = gdk_device_get_core_pointer(); - - int x_root, y_root; -#if GTK_CHECK_VERSION(2,17,3) - gdk_window_get_root_coords(GTK_WIDGET(view)->window, lastMousePositionX, lastMousePositionY, &x_root, &y_root); -#else - getRootCoords(GTK_WIDGET(view), &x_root, &y_root); -#endif + GdkEvent event; + if (!prepareMouseButtonEvent(&event, button)) + return JSValueMakeUndefined(context); - event.button.x_root = x_root; - event.button.y_root = y_root; + buttonCurrentlyDown = event.button.button; + // Normally GDK will send both GDK_BUTTON_PRESS and GDK_2BUTTON_PRESS for + // the second button press during double-clicks. WebKit GTK+ selectively + // ignores the first GDK_BUTTON_PRESS of that pair using gdk_event_peek. + // Since our events aren't ever going onto the GDK event queue, WebKit won't + // be able to filter out the first GDK_BUTTON_PRESS, so we just don't send + // it here. Eventually this code should probably figure out a way to get all + // appropriate events onto the event queue and this work-around should be + // removed. updateClickCount(event.button.button); + if (clickCount == 2) + event.type = GDK_2BUTTON_PRESS; + else if (clickCount == 3) + event.type = GDK_3BUTTON_PRESS; + else + event.type = GDK_BUTTON_PRESS; - if (!msgQueue[endOfQueue].delay) { - webkit_web_frame_layout(mainFrame); - - gboolean return_val; - g_signal_emit_by_name(view, "button_press_event", &event, &return_val); - if (clickCount == 2) { - event.type = GDK_2BUTTON_PRESS; - g_signal_emit_by_name(view, "button_press_event", &event, &return_val); - } - } else { - // replaySavedEvents should have the required logic to make leapForward delays work - msgQueue[endOfQueue++].event = event; - replaySavedEvents(); - } - + sendOrQueueEvent(event); return JSValueMakeUndefined(context); } static guint getStateFlags() { - guint state = 0; - - if (down) { - if (currentEventButton == 1) - state = GDK_BUTTON1_MASK; - else if (currentEventButton == 2) - state = GDK_BUTTON2_MASK; - else if (currentEventButton == 3) - state = GDK_BUTTON3_MASK; - } else - state = 0; - - return state; + if (buttonCurrentlyDown == 1) + return GDK_BUTTON1_MASK; + if (buttonCurrentlyDown == 2) + return GDK_BUTTON2_MASK; + if (buttonCurrentlyDown == 3) + return GDK_BUTTON3_MASK; + return 0; } static JSValueRef mouseUpCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { - - WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); - if (!view) - return JSValueMakeUndefined(context); - - GdkEvent event; - memset(&event, 0, sizeof(event)); - event.type = GDK_BUTTON_RELEASE; - event.button.button = 1; - + int button = 0; if (argumentCount == 1) { - event.button.button = (int)JSValueToNumber(context, arguments[0], exception) + 1; + button = static_cast<int>(JSValueToNumber(context, arguments[0], exception)); g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context)); } - currentEventButton = event.button.button; - - event.button.x = lastMousePositionX; - event.button.y = lastMousePositionY; - event.button.window = GTK_WIDGET(view)->window; - event.button.time = GDK_CURRENT_TIME; - event.button.device = gdk_device_get_core_pointer(); - event.button.state = getStateFlags(); - - down = false; - - int x_root, y_root; -#if GTK_CHECK_VERSION(2,17,3) - gdk_window_get_root_coords(GTK_WIDGET(view)->window, lastMousePositionX, lastMousePositionY, &x_root, &y_root); -#else - getRootCoords(GTK_WIDGET(view), &x_root, &y_root); -#endif - - event.button.x_root = x_root; - event.button.y_root = y_root; - - if ((dragMode && !replayingSavedEvents) || msgQueue[endOfQueue].delay) { - msgQueue[endOfQueue].event = event; - msgQueue[endOfQueue++].isDragEvent = true; - replaySavedEvents(); - } else { - webkit_web_frame_layout(mainFrame); - - gboolean return_val; - g_signal_emit_by_name(view, "button_release_event", &event, &return_val); - } + GdkEvent event; + if (!prepareMouseButtonEvent(&event, button)) + return JSValueMakeUndefined(context); lastClickPositionX = lastMousePositionX; lastClickPositionY = lastMousePositionY; + lastClickButton = buttonCurrentlyDown; + lastClickTimeOffset = timeOffset; + buttonCurrentlyDown = 0; + event.type = GDK_BUTTON_RELEASE; + sendOrQueueEvent(event); return JSValueMakeUndefined(context); } @@ -299,32 +279,22 @@ static JSValueRef mouseMoveToCallback(JSContextRef context, JSObjectRef function event.type = GDK_MOTION_NOTIFY; event.motion.x = lastMousePositionX; event.motion.y = lastMousePositionY; + event.motion.time = GDK_CURRENT_TIME; event.motion.window = GTK_WIDGET(view)->window; event.motion.device = gdk_device_get_core_pointer(); + event.motion.state = getStateFlags(); - int x_root, y_root; + int xRoot, yRoot; #if GTK_CHECK_VERSION(2,17,3) - gdk_window_get_root_coords(GTK_WIDGET(view)->window, lastMousePositionX, lastMousePositionY, &x_root, &y_root); + gdk_window_get_root_coords(GTK_WIDGET(view)->window, lastMousePositionX, lastMousePositionY, &xRoot, &yRoot); #else - getRootCoords(GTK_WIDGET(view), &x_root, &y_root); + getRootCoords(GTK_WIDGET(view), &xRoot, &yRoot); #endif + event.motion.x_root = xRoot; + event.motion.y_root = yRoot; - event.motion.x_root = x_root; - event.motion.y_root = y_root; - - event.motion.state = getStateFlags(); - - if (dragMode && down && !replayingSavedEvents) { - msgQueue[endOfQueue].event = event; - msgQueue[endOfQueue++].isDragEvent = true; - } else { - webkit_web_frame_layout(mainFrame); - - gboolean return_val; - g_signal_emit_by_name(view, "motion_notify_event", &event, &return_val); - } - + sendOrQueueEvent(event, false); return JSValueMakeUndefined(context); } @@ -363,14 +333,7 @@ static JSValueRef mouseWheelToCallback(JSContextRef context, JSObjectRef functio else g_assert_not_reached(); - if (dragMode && down && !replayingSavedEvents) { - msgQueue[endOfQueue].event = event; - msgQueue[endOfQueue++].isDragEvent = true; - } else { - webkit_web_frame_layout(mainFrame); - gtk_main_do_event(&event); - } - + sendOrQueueEvent(event); return JSValueMakeUndefined(context); } @@ -383,49 +346,49 @@ static JSValueRef beginDragWithFilesCallback(JSContextRef context, JSObjectRef f return JSValueMakeUndefined(context); } -void replaySavedEvents() +static void sendOrQueueEvent(GdkEvent event, bool shouldReplaySavedEvents) { - // FIXME: This doesn't deal with forward leaps, but it should. + // Mouse move events are queued if the previous event was queued or if a + // delay was set up by leapForward(). + if (buttonCurrentlyDown || endOfQueue != startOfQueue || msgQueue[endOfQueue].delay) { + msgQueue[endOfQueue++].event = event; + + if (shouldReplaySavedEvents) + replaySavedEvents(); + + return; + } + + dispatchEvent(event); +} +static void dispatchEvent(GdkEvent event) +{ + webkit_web_frame_layout(mainFrame); WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); if (!view) return; - replayingSavedEvents = true; - - for (unsigned queuePos = 0; queuePos < endOfQueue; queuePos++) { - GdkEvent event = msgQueue[queuePos].event; - gboolean return_val; - - switch (event.type) { - case GDK_BUTTON_RELEASE: - g_signal_emit_by_name(view, "button_release_event", &event, &return_val); - break; - case GDK_BUTTON_PRESS: - g_signal_emit_by_name(view, "button_press_event", &event, &return_val); - break; - case GDK_MOTION_NOTIFY: - g_signal_emit_by_name(view, "motion_notify_event", &event, &return_val); - break; - default: - continue; - } + gtk_main_do_event(&event); +} - startOfQueue++; - } +void replaySavedEvents() +{ + // FIXME: Eventually we may need to have more sophisticated logic to + // track drag-and-drop operations. + + // First send all the events that are ready to be sent + while (startOfQueue < endOfQueue) { + if (msgQueue[startOfQueue].delay) { + g_usleep(msgQueue[startOfQueue].delay * 1000); + msgQueue[startOfQueue].delay = 0; + } - int numQueuedMessages = endOfQueue - startOfQueue; - if (!numQueuedMessages) { - startOfQueue = 0; - endOfQueue = 0; - replayingSavedEvents = false; - return; + dispatchEvent(msgQueue[startOfQueue++].event); } startOfQueue = 0; endOfQueue = 0; - - replayingSavedEvents = false; } static JSValueRef keyDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) @@ -566,13 +529,11 @@ static JSValueRef keyDownCallback(JSContextRef context, JSObjectRef function, JS g_free(keys); } - gboolean return_val; event.key.type = GDK_KEY_PRESS; - - g_signal_emit_by_name(view, "key-press-event", &event.key, &return_val); + dispatchEvent(event); event.key.type = GDK_KEY_RELEASE; - g_signal_emit_by_name(view, "key-release-event", &event.key, &return_val); + dispatchEvent(event); return JSValueMakeUndefined(context); } @@ -661,17 +622,24 @@ static JSClassRef getClass(JSContextRef context) return eventSenderClass; } -JSObjectRef makeEventSender(JSContextRef context) +JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame) { - down = false; - dragMode = true; - lastMousePositionX = lastMousePositionY = 0; - lastClickPositionX = lastClickPositionY = 0; - - if (!replayingSavedEvents) { - // This function can be called in the middle of a test, even - // while replaying saved events. Resetting these while doing that - // can break things. + if (isTopFrame) { + dragMode = true; + + // Fly forward in time one second when the main frame loads. This will + // ensure that when a test begins clicking in the same location as + // a previous test, those clicks won't be interpreted as continuations + // of the previous test's click sequences. + timeOffset += 1000; + + lastMousePositionX = lastMousePositionY = 0; + lastClickPositionX = lastClickPositionY = 0; + lastClickTimeOffset = 0; + lastClickButton = 0; + buttonCurrentlyDown = 0; + clickCount = 0; + endOfQueue = 0; startOfQueue = 0; } diff --git a/WebKitTools/DumpRenderTree/gtk/EventSender.h b/WebKitTools/DumpRenderTree/gtk/EventSender.h index 272e8a9..ce33ccc 100644 --- a/WebKitTools/DumpRenderTree/gtk/EventSender.h +++ b/WebKitTools/DumpRenderTree/gtk/EventSender.h @@ -33,7 +33,7 @@ typedef const struct OpaqueJSContext* JSContextRef; typedef struct OpaqueJSValue* JSObjectRef; -JSObjectRef makeEventSender(JSContextRef context); +JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame); void replaySavedEvents(); #endif diff --git a/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm b/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm index 3fa9c40..939398d 100644 --- a/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm +++ b/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm @@ -337,6 +337,17 @@ AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index) return 0; } +AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index) +{ + BEGIN_AX_OBJC_EXCEPTIONS + NSArray* objects = [m_element accessibilityAttributeValue:NSAccessibilityLinkedUIElementsAttribute]; + if (index < [objects count]) + return [objects objectAtIndex:index]; + END_AX_OBJC_EXCEPTIONS + + return 0; +} + AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index) { BEGIN_AX_OBJC_EXCEPTIONS diff --git a/WebKitTools/DumpRenderTree/mac/Configurations/Base.xcconfig b/WebKitTools/DumpRenderTree/mac/Configurations/Base.xcconfig index 5f989e0..28a0518 100644 --- a/WebKitTools/DumpRenderTree/mac/Configurations/Base.xcconfig +++ b/WebKitTools/DumpRenderTree/mac/Configurations/Base.xcconfig @@ -27,6 +27,7 @@ GCC_PREPROCESSOR_DEFINITIONS = ENABLE_DASHBOARD_SUPPORT WEBKIT_VERSION_MIN_REQUI DEBUG_INFORMATION_FORMAT = dwarf PREBINDING = NO GCC_C_LANGUAGE_STANDARD = gnu99 +GCC_OBJC_CALL_CXX_CDTORS = YES GCC_PRECOMPILE_PREFIX_HEADER = YES GCC_TREAT_WARNINGS_AS_ERRORS = YES GCC_WARN_UNUSED_FUNCTION = YES diff --git a/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm b/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm index 8fd5298..9e4b203 100644 --- a/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm +++ b/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm @@ -41,6 +41,7 @@ #import "HistoryDelegate.h" #import "JavaScriptThreading.h" #import "LayoutTestController.h" +#import "MockGeolocationProvider.h" #import "NavigationController.h" #import "ObjCPlugin.h" #import "ObjCPluginFunction.h" @@ -291,6 +292,7 @@ WebView *createWebViewAndOffscreenWindow() [webView setFrameLoadDelegate:frameLoadDelegate]; [webView setEditingDelegate:editingDelegate]; [webView setResourceLoadDelegate:resourceLoadDelegate]; + [webView _setGeolocationProvider:[MockGeolocationProvider shared]]; // Register the same schemes that Safari does [WebView registerURLSchemeAsLocal:@"feed"]; @@ -1181,6 +1183,8 @@ static void resetWebViewToConsistentStateBeforeTesting() [WebView _setUsesTestModeFocusRingColor:YES]; [WebView _resetOriginAccessWhitelists]; + + [[MockGeolocationProvider shared] stopTimer]; } static void runTest(const string& testPathOrURL) @@ -1291,8 +1295,10 @@ static void runTest(const string& testPathOrURL) } // If developer extras enabled Web Inspector may have been open by the test. - if (shouldEnableDeveloperExtras(pathOrURL.c_str())) + if (shouldEnableDeveloperExtras(pathOrURL.c_str())) { gLayoutTestController->closeWebInspector(); + gLayoutTestController->setDeveloperExtrasEnabled(false); + } resetWebViewToConsistentStateBeforeTesting(); diff --git a/WebKitTools/DumpRenderTree/mac/EventSendingController.mm b/WebKitTools/DumpRenderTree/mac/EventSendingController.mm index b5b6f82..73831ff 100644 --- a/WebKitTools/DumpRenderTree/mac/EventSendingController.mm +++ b/WebKitTools/DumpRenderTree/mac/EventSendingController.mm @@ -122,7 +122,7 @@ BOOL replayingSavedEvents; { if (aSelector == @selector(beginDragWithFiles:) || aSelector == @selector(clearKillRing) - || aSelector == @selector(contextClick:) + || aSelector == @selector(contextClick) || aSelector == @selector(enableDOMUIEventLogging:) || aSelector == @selector(fireKeyboardEventsToElement:) || aSelector == @selector(keyDown:withModifiers:withLocation:) @@ -152,7 +152,7 @@ BOOL replayingSavedEvents; { if (aSelector == @selector(beginDragWithFiles:)) return @"beginDragWithFiles"; - if (aSelector == @selector(contextClick:)) + if (aSelector == @selector(contextClick)) return @"contextClick"; if (aSelector == @selector(enableDOMUIEventLogging:)) return @"enableDOMUIEventLogging"; @@ -494,7 +494,7 @@ static int buildModifierFlags(const WebScriptObject* modifiers) [self mouseScrollByX:x andY:y continuously:NO]; } -- (void)contextClick:(BOOL)shouldPrintMenuItems +- (NSArray *)contextClick { [[[mainFrame frameView] documentView] layout]; [self updateClickCountForButton:RightMouseButton]; @@ -510,21 +510,24 @@ static int buildModifierFlags(const WebScriptObject* modifiers) pressure:0.0]; NSView *subView = [[mainFrame webView] hitTest:[event locationInWindow]]; + NSMutableArray *menuItemStrings = [NSMutableArray array]; + if (subView) { NSMenu* menu = [subView menuForEvent:event]; - if (shouldPrintMenuItems) { - printf("ContextMenuItems: "); - for (int i = 0; i < [menu numberOfItems]; ++i) { - NSMenuItem* menuItem = [menu itemAtIndex:i]; - if (!strcmp("Inspect Element", [[menuItem title] UTF8String])) - continue; - if (i > 0) - printf(", "); - fputs([menuItem isSeparatorItem] ? "<separator>" : [[menuItem title] UTF8String], stdout); - } - printf("\n"); + + for (int i = 0; i < [menu numberOfItems]; ++i) { + NSMenuItem* menuItem = [menu itemAtIndex:i]; + if (!strcmp("Inspect Element", [[menuItem title] UTF8String])) + continue; + + if ([menuItem isSeparatorItem]) + [menuItemStrings addObject:@"<separator>"]; + else + [menuItemStrings addObject:[menuItem title]]; } } + + return menuItemStrings; } - (void)scheduleAsynchronousClick diff --git a/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm b/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm index 898235b..eb01090 100644 --- a/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm +++ b/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm @@ -31,6 +31,7 @@ #import "LayoutTestController.h" #import "EditingDelegate.h" +#import "MockGeolocationProvider.h" #import "PolicyDelegate.h" #import "WorkQueue.h" #import "WorkQueueItem.h" @@ -47,7 +48,7 @@ #import <WebKit/WebDatabaseManagerPrivate.h> #import <WebKit/WebFrame.h> #import <WebKit/WebFrameViewPrivate.h> -#import <WebKit/WebGeolocationMockPrivate.h> +#import <WebKit/WebGeolocationPosition.h> #import <WebKit/WebHTMLRepresentation.h> #import <WebKit/WebHTMLViewPrivate.h> #import <WebKit/WebHistory.h> @@ -55,6 +56,7 @@ #import <WebKit/WebIconDatabasePrivate.h> #import <WebKit/WebInspectorPrivate.h> #import <WebKit/WebNSURLExtras.h> +#import <WebKit/WebKitErrors.h> #import <WebKit/WebPreferences.h> #import <WebKit/WebPreferencesPrivate.h> #import <WebKit/WebScriptWorld.h> @@ -298,14 +300,17 @@ void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool forbidd void LayoutTestController::setMockGeolocationPosition(double latitude, double longitude, double accuracy) { - [WebGeolocationMock setPosition:latitude:longitude:accuracy]; + WebGeolocationPosition *position = [[WebGeolocationPosition alloc] initWithTimestamp:0 latitude:latitude longitude:longitude accuracy:accuracy]; + [[MockGeolocationProvider shared] setPosition:position]; + [position release]; } void LayoutTestController::setMockGeolocationError(int code, JSStringRef message) { RetainPtr<CFStringRef> messageCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, message)); NSString *messageNS = (NSString *)messageCF.get(); - [WebGeolocationMock setError:code:messageNS]; + NSError *error = [NSError errorWithDomain:WebKitErrorDomain code:code userInfo:[NSDictionary dictionaryWithObject:messageNS forKey:NSLocalizedDescriptionKey]]; + [[MockGeolocationProvider shared] setError:error]; } void LayoutTestController::setIconDatabaseEnabled(bool iconDatabaseEnabled) diff --git a/WebKitTools/DumpRenderTree/mac/MockGeolocationProvider.h b/WebKitTools/DumpRenderTree/mac/MockGeolocationProvider.h new file mode 100644 index 0000000..311d1e9 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/MockGeolocationProvider.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MockGeolocationProvider_h +#define MockGeolocationProvider_h + +#import <WebKit/WebViewPrivate.h> +#import <wtf/HashSet.h> + +@interface MockGeolocationProvider : NSObject<WebGeolocationProvider> { + WebGeolocationPosition *_lastPosition; + NSError *_error; + NSTimer *_timer; + HashSet<WebView *> _registeredViews; +} + ++ (MockGeolocationProvider *)shared; + +- (void)setPosition:(WebGeolocationPosition *)position; +- (void)setError:(NSError *)error; + +- (void)stopTimer; + +@end +#endif diff --git a/WebKitTools/DumpRenderTree/mac/MockGeolocationProvider.mm b/WebKitTools/DumpRenderTree/mac/MockGeolocationProvider.mm new file mode 100644 index 0000000..55d7257 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/MockGeolocationProvider.mm @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "MockGeolocationProvider.h" + + +@implementation MockGeolocationProvider + ++ (MockGeolocationProvider *)shared +{ + static MockGeolocationProvider *provider = [[MockGeolocationProvider alloc] init]; + return provider; +} + +- (void)dealloc +{ + ASSERT(_registeredViews.isEmpty()); + + [_lastPosition release]; + [_error release]; + [super dealloc]; +} + +- (void)setPosition:(WebGeolocationPosition *)position +{ + if (_lastPosition != position) { + [_lastPosition release]; + _lastPosition = [position retain]; + } + + [_error release]; + _error = 0; + + if (!_timer) + _timer = [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(timerFired) userInfo:0 repeats:NO]; +} + +- (void)setError:(NSError *)error +{ + if (_error != error) { + [_error release]; + _error = [error retain]; + } + + [_lastPosition release]; + _lastPosition = 0; + + if (!_timer) + _timer = [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(timerFired) userInfo:0 repeats:NO]; +} + +- (void)registerWebView:(WebView *)webView +{ + _registeredViews.add(webView); +} + +- (void)unregisterWebView:(WebView *)webView +{ + _registeredViews.remove(webView); +} + +- (WebGeolocationPosition *)lastPosition +{ + return _lastPosition; +} + +- (void)stopTimer +{ + [_timer invalidate]; + _timer = 0; +} + +- (void)timerFired +{ + _timer = 0; + + // Expect that views won't be (un)registered while iterating. + HashSet<WebView*> views = _registeredViews; + for (HashSet<WebView*>::iterator iter = views.begin(); iter != views.end(); ++iter) { + if (_error) + [*iter _geolocationDidFailWithError:_error]; + else + [*iter _geolocationDidChangePosition:_lastPosition]; + } +} + +@end diff --git a/WebKitTools/DumpRenderTree/mac/UIDelegate.mm b/WebKitTools/DumpRenderTree/mac/UIDelegate.mm index 19ceb95..e6754c1 100644 --- a/WebKitTools/DumpRenderTree/mac/UIDelegate.mm +++ b/WebKitTools/DumpRenderTree/mac/UIDelegate.mm @@ -157,12 +157,11 @@ DumpRenderTreeDraggingInfo *draggingInfo = nil; - (void)webView:(WebView *)webView decidePolicyForGeolocationRequestFromOrigin:(WebSecurityOrigin *)origin frame:(WebFrame *)frame listener:(id<WebGeolocationPolicyListener>)listener { - if (gLayoutTestController->isGeolocationPermissionSet()) { - if (gLayoutTestController->geolocationPermission()) - [listener allow]; - else - [listener deny]; - } + // FIXME: If mock permission isn't set yet, we should send the response asynchronously. + if (gLayoutTestController->isGeolocationPermissionSet() && gLayoutTestController->geolocationPermission()) + [listener allow]; + else + [listener deny]; } - (BOOL)webView:(WebView *)sender shouldHaltPlugin:(DOMNode *)pluginNode diff --git a/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.cpp b/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.cpp index ba9780b..f5fbb5c 100644 --- a/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.cpp +++ b/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.cpp @@ -135,9 +135,9 @@ void checkPermissionCallback(QObject* receiver, const QUrl& url, NotificationPer qobject_cast<DumpRenderTree*>(receiver)->checkPermission(url, permission); } -void requestPermissionCallback(QObject* receiver, QWebPage* page, const QString& origin) +void requestPermissionCallback(QObject* receiver, const QString& origin) { - qobject_cast<DumpRenderTree*>(receiver)->requestPermission(page, origin); + qobject_cast<DumpRenderTree*>(receiver)->requestPermission(origin); } WebPage::WebPage(QObject* parent, DumpRenderTree* drt) @@ -153,14 +153,13 @@ WebPage::WebPage(QObject* parent, DumpRenderTree* drt) globalSettings->setFontSize(QWebSettings::DefaultFixedFontSize, 13); globalSettings->setAttribute(QWebSettings::JavascriptCanOpenWindows, true); - globalSettings->setAttribute(QWebSettings::DOMPasteAllowed, true); + globalSettings->setAttribute(QWebSettings::JavascriptCanAccessClipboard, true); globalSettings->setAttribute(QWebSettings::LinksIncludedInFocusChain, false); globalSettings->setAttribute(QWebSettings::PluginsEnabled, true); globalSettings->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls, true); globalSettings->setAttribute(QWebSettings::JavascriptEnabled, true); globalSettings->setAttribute(QWebSettings::PrivateBrowsingEnabled, false); globalSettings->setAttribute(QWebSettings::SpatialNavigationEnabled, false); - globalSettings->setAttribute(QWebSettings::JavaScriptCanAccessClipboard, true); connect(this, SIGNAL(geometryChangeRequested(const QRect &)), this, SLOT(setViewGeometry(const QRect & ))); @@ -168,7 +167,7 @@ WebPage::WebPage(QObject* parent, DumpRenderTree* drt) setNetworkAccessManager(m_drt->networkAccessManager()); setPluginFactory(new TestPlugin(this)); - DumpRenderTreeSupportQt::setNotificationsReceiver(this, m_drt); + DumpRenderTreeSupportQt::setNotificationsReceiver(m_drt); DumpRenderTreeSupportQt::setCheckPermissionFunction(checkPermissionCallback); DumpRenderTreeSupportQt::setRequestPermissionFunction(requestPermissionCallback); @@ -201,7 +200,7 @@ void WebPage::resetSettings() settings()->resetAttribute(QWebSettings::OfflineWebApplicationCacheEnabled); settings()->resetAttribute(QWebSettings::LocalContentCanAccessRemoteUrls); settings()->resetAttribute(QWebSettings::PluginsEnabled); - settings()->resetAttribute(QWebSettings::JavaScriptCanAccessClipboard); + settings()->resetAttribute(QWebSettings::JavascriptCanAccessClipboard); settings()->resetAttribute(QWebSettings::AutoLoadImages); m_drt->layoutTestController()->setCaretBrowsingEnabled(false); @@ -349,24 +348,51 @@ QObject* WebPage::createPlugin(const QString& classId, const QUrl& url, const QS #endif } +bool WebPage::allowGeolocationRequest(QWebFrame *) +{ + return m_drt->layoutTestController()->geolocationPermission(); +} + +WebViewGraphicsBased::WebViewGraphicsBased(QWidget* parent) + : m_item(new QGraphicsWebView) +{ + setScene(new QGraphicsScene(this)); + scene()->addItem(m_item); +} + DumpRenderTree::DumpRenderTree() : m_dumpPixels(false) , m_stdin(0) , m_enableTextOutput(false) , m_singleFileMode(false) + , m_graphicsBased(false) , m_persistentStoragePath(QString(getenv("DUMPRENDERTREE_TEMP"))) { + + QByteArray viewMode = getenv("QT_DRT_WEBVIEW_MODE"); + if (viewMode == "graphics") + setGraphicsBased(true); + DumpRenderTreeSupportQt::overwritePluginDirectories(); QWebSettings::enablePersistentStorage(m_persistentStoragePath); m_networkAccessManager = new NetworkAccessManager(this); // create our primary testing page/view. - m_mainView = new QWebView(0); - m_mainView->resize(QSize(LayoutTestController::maxViewWidth, LayoutTestController::maxViewHeight)); - m_page = new WebPage(m_mainView, this); - m_mainView->setPage(m_page); + if (isGraphicsBased()) { + WebViewGraphicsBased* view = new WebViewGraphicsBased(0); + m_page = new WebPage(view, this); + view->setPage(m_page); + m_mainView = view; + } else { + QWebView* view = new QWebView(0); + m_page = new WebPage(view, this); + view->setPage(m_page); + m_mainView = view; + } + m_mainView->setContextMenuPolicy(Qt::NoContextMenu); + m_mainView->resize(QSize(LayoutTestController::maxViewWidth, LayoutTestController::maxViewHeight)); // clean up cache by resetting quota. qint64 quota = webPage()->settings()->offlineWebApplicationCacheQuota(); @@ -687,10 +713,18 @@ static QString dumpHistoryItem(const QWebHistoryItem& item, int indent, bool cur result.append(url); } - // FIXME: Wrong, need (private?) API for determining this. - result.append(QLatin1String(" **nav target**")); + QString target = DumpRenderTreeSupportQt::historyItemTarget(item); + if (!target.isEmpty()) + result.append(QString(QLatin1String(" (in frame \"%1\")")).arg(target)); + + if (DumpRenderTreeSupportQt::isTargetItem(item)) + result.append(QLatin1String(" **nav target**")); result.append(QLatin1String("\n")); + QList<QWebHistoryItem> children = DumpRenderTreeSupportQt::getChildHistoryItems(item); + for (int i = 0; i < children.size(); ++i) + result += dumpHistoryItem(children.at(i), 12, false); + return result; } @@ -920,9 +954,9 @@ void DumpRenderTree::checkPermission(const QUrl& url, NotificationPermission& pe permission = m_controller->checkDesktopNotificationPermission(url.scheme() + "://" + url.host()) ? NotificationAllowed : NotificationDenied; } -void DumpRenderTree::requestPermission(QWebPage* page, const QString& origin) +void DumpRenderTree::requestPermission(const QString& origin) { - DumpRenderTreeSupportQt::allowNotificationForOrigin(page, origin); + DumpRenderTreeSupportQt::allowNotificationForOrigin(origin); } #if defined(Q_WS_X11) diff --git a/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.h b/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.h index 3fa4485..2ec972a 100644 --- a/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.h +++ b/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.h @@ -41,6 +41,8 @@ #endif #include "../../../WebKit/qt/WebCoreSupport/DumpRenderTreeSupportQt.h" +#include <qgraphicsview.h> +#include <qgraphicswebview.h> #include <qwebframe.h> #include <qwebinspector.h> #include <qwebpage.h> @@ -80,6 +82,9 @@ public: void setSingleFileMode(bool flag) { m_singleFileMode = flag; } bool isSingleFileMode() { return m_singleFileMode; } + void setGraphicsBased(bool flag) { m_graphicsBased = flag; } + bool isGraphicsBased() { return m_graphicsBased; } + void setDumpPixels(bool); void closeRemainingWindows(); @@ -115,7 +120,7 @@ public Q_SLOTS: void statusBarMessage(const QString& message); void windowCloseRequested(); void checkPermission(const QUrl&, NotificationPermission&); - void requestPermission(QWebPage* page, const QString&); + void requestPermission(const QString&); Q_SIGNALS: void quit(); @@ -135,7 +140,7 @@ private: QString m_expectedHash; WebPage *m_page; - QWebView* m_mainView; + QWidget* m_mainView; EventSender *m_eventSender; TextInputController *m_textInputController; @@ -147,6 +152,7 @@ private: QList<QObject*> windows; bool m_enableTextOutput; bool m_singleFileMode; + bool m_graphicsBased; QString m_persistentStoragePath; }; @@ -185,6 +191,7 @@ public: public slots: bool shouldInterruptJavaScript() { return false; } + bool allowGeolocationRequest(QWebFrame *frame); protected: bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type); @@ -202,6 +209,18 @@ private: DumpRenderTree *m_drt; }; +class WebViewGraphicsBased : public QGraphicsView { + Q_OBJECT + +public: + WebViewGraphicsBased(QWidget* parent); + QGraphicsWebView* graphicsView() const { return m_item; } + void setPage(QWebPage* page) { m_item->setPage(page); } + +private: + QGraphicsWebView* m_item; +}; + } #endif diff --git a/WebKitTools/DumpRenderTree/qt/EventSenderQt.cpp b/WebKitTools/DumpRenderTree/qt/EventSenderQt.cpp index a548a63..7ec505f 100644 --- a/WebKitTools/DumpRenderTree/qt/EventSenderQt.cpp +++ b/WebKitTools/DumpRenderTree/qt/EventSenderQt.cpp @@ -29,8 +29,7 @@ #include "config.h" #include "EventSenderQt.h" -//#include <QtDebug> - +#include <QGraphicsSceneMouseEvent> #include <QtTest/QtTest> #define KEYCODE_DEL 127 @@ -111,10 +110,16 @@ void EventSender::mouseDown(int button) m_mouseButtons |= mouseButton; // qDebug() << "EventSender::mouseDown" << frame; - QMouseEvent* event; - event = new QMouseEvent((m_clickCount == 2) ? QEvent::MouseButtonDblClick : + QEvent* event; + if (isGraphicsBased()) { + event = createGraphicsSceneMouseEvent((m_clickCount == 2) ? + QEvent::GraphicsSceneMouseDoubleClick : QEvent::GraphicsSceneMousePress, + m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier); + } else { + event = new QMouseEvent((m_clickCount == 2) ? QEvent::MouseButtonDblClick : QEvent::MouseButtonPress, m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier); + } sendOrQueueEvent(event); @@ -146,7 +151,15 @@ void EventSender::mouseUp(int button) m_mouseButtons &= ~mouseButton; // qDebug() << "EventSender::mouseUp" << frame; - QMouseEvent* event = new QMouseEvent(QEvent::MouseButtonRelease, m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier); + QEvent* event; + if (isGraphicsBased()) { + event = createGraphicsSceneMouseEvent(QEvent::GraphicsSceneMouseRelease, + m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier); + } else { + event = new QMouseEvent(QEvent::MouseButtonRelease, + m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier); + } + sendOrQueueEvent(event); } @@ -154,7 +167,16 @@ void EventSender::mouseMoveTo(int x, int y) { // qDebug() << "EventSender::mouseMoveTo" << x << y; m_mousePos = QPoint(x, y); - QMouseEvent* event = new QMouseEvent(QEvent::MouseMove, m_mousePos, m_mousePos, Qt::NoButton, m_mouseButtons, Qt::NoModifier); + + QEvent* event; + if (isGraphicsBased()) { + event = createGraphicsSceneMouseEvent(QEvent::GraphicsSceneMouseMove, + m_mousePos, m_mousePos, Qt::NoButton, m_mouseButtons, Qt::NoModifier); + } else { + event = new QMouseEvent(QEvent::MouseMove, + m_mousePos, m_mousePos, Qt::NoButton, m_mouseButtons, Qt::NoModifier); + } + sendOrQueueEvent(event); } @@ -306,19 +328,19 @@ void EventSender::keyDown(const QString& string, const QStringList& modifiers, u } } QKeyEvent event(QEvent::KeyPress, code, modifs, s); - QApplication::sendEvent(m_page, &event); + sendEvent(m_page, &event); QKeyEvent event2(QEvent::KeyRelease, code, modifs, s); - QApplication::sendEvent(m_page, &event2); + sendEvent(m_page, &event2); } void EventSender::contextClick() { QMouseEvent event(QEvent::MouseButtonPress, m_mousePos, Qt::RightButton, Qt::RightButton, Qt::NoModifier); - QApplication::sendEvent(m_page, &event); + sendEvent(m_page, &event); QMouseEvent event2(QEvent::MouseButtonRelease, m_mousePos, Qt::RightButton, Qt::RightButton, Qt::NoModifier); - QApplication::sendEvent(m_page, &event2); + sendEvent(m_page, &event2); QContextMenuEvent event3(QContextMenuEvent::Mouse, m_mousePos); - QApplication::sendEvent(m_page->view(), &event3); + sendEvent(m_page->view(), &event3); } void EventSender::scheduleAsynchronousClick() @@ -431,7 +453,7 @@ void EventSender::sendTouchEvent(QEvent::Type type) #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) QTouchEvent event(type, QTouchEvent::TouchScreen, m_touchModifiers); event.setTouchPoints(m_touchPoints); - QApplication::sendEvent(m_page, &event); + sendEvent(m_page, &event); QList<QTouchEvent::TouchPoint>::Iterator it = m_touchPoints.begin(); while (it != m_touchPoints.end()) { if (it->state() == Qt::TouchPointReleased) @@ -493,7 +515,7 @@ void EventSender::sendOrQueueEvent(QEvent* event) // 3. A call to mouseMoveTo while the mouse button is pressed could initiate a drag operation, and that does not return until mouseUp is processed. // To be safe and avoid a deadlock, this event is queued. if (endOfQueue == startOfQueue && !eventQueue[endOfQueue].m_delay && (!(m_mouseButtonPressed && (m_eventLoop && event->type() == QEvent::MouseButtonRelease)))) { - QApplication::sendEvent(m_page->view(), event); + sendEvent(m_page->view(), event); delete event; return; } @@ -541,13 +563,16 @@ bool EventSender::eventFilter(QObject* watched, QEvent* event) case QEvent::Leave: return true; case QEvent::MouseButtonPress: + case QEvent::GraphicsSceneMousePress: m_mouseButtonPressed = true; break; case QEvent::MouseMove: + case QEvent::GraphicsSceneMouseMove: if (m_mouseButtonPressed) m_drag = true; break; case QEvent::MouseButtonRelease: + case QEvent::GraphicsSceneMouseRelease: m_mouseButtonPressed = false; m_drag = false; break; @@ -562,3 +587,24 @@ void EventSender::timerEvent(QTimerEvent* ev) { m_clickTimer.stop(); } + +QGraphicsSceneMouseEvent* EventSender::createGraphicsSceneMouseEvent(QEvent::Type type, const QPoint& pos, const QPoint& screenPos, Qt::MouseButton button, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers) +{ + QGraphicsSceneMouseEvent* event; + event = new QGraphicsSceneMouseEvent(type); + event->setPos(pos); + event->setScreenPos(screenPos); + event->setButton(button); + event->setButtons(buttons); + event->setModifiers(modifiers); + + return event; +} + +void EventSender::sendEvent(QObject* receiver, QEvent* event) +{ + if (WebCore::WebViewGraphicsBased* view = qobject_cast<WebCore::WebViewGraphicsBased*>(receiver)) + view->scene()->sendEvent(view->graphicsView(), event); + else + QApplication::sendEvent(receiver, event); +} diff --git a/WebKitTools/DumpRenderTree/qt/EventSenderQt.h b/WebKitTools/DumpRenderTree/qt/EventSenderQt.h index d5b45ac..51c8325 100644 --- a/WebKitTools/DumpRenderTree/qt/EventSenderQt.h +++ b/WebKitTools/DumpRenderTree/qt/EventSenderQt.h @@ -29,6 +29,9 @@ #ifndef EventSenderQt_h #define EventSenderQt_h + +#include "DumpRenderTreeQt.h" + #include <QApplication> #include <QBasicTimer> #include <QEvent> @@ -83,6 +86,11 @@ protected: void timerEvent(QTimerEvent*); private: + bool isGraphicsBased() const { return qobject_cast<WebCore::WebViewGraphicsBased*>(m_page->view()); } + QGraphicsSceneMouseEvent* createGraphicsSceneMouseEvent(QEvent::Type, const QPoint& pos, const QPoint& screenPos, Qt::MouseButton, Qt::MouseButtons, Qt::KeyboardModifiers); + void sendEvent(QObject* receiver, QEvent* event); + +private: void sendTouchEvent(QEvent::Type); void sendOrQueueEvent(QEvent*); void replaySavedEvents(bool flush); diff --git a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp index 9079be2..8450376 100644 --- a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp +++ b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp @@ -410,7 +410,7 @@ void LayoutTestController::setMainFrameIsFirstResponder(bool isFirst) void LayoutTestController::setJavaScriptCanAccessClipboard(bool enable) { - m_drt->webPage()->settings()->setAttribute(QWebSettings::JavaScriptCanAccessClipboard, enable); + m_drt->webPage()->settings()->setAttribute(QWebSettings::JavascriptCanAccessClipboard, enable); } void LayoutTestController::setXSSAuditorEnabled(bool enable) @@ -513,6 +513,8 @@ void LayoutTestController::overridePreference(const QString& name, const QVarian setCaretBrowsingEnabled(value.toBool()); else if (name == "WebKitPluginsEnabled") settings->setAttribute(QWebSettings::PluginsEnabled, value.toBool()); + else if (name == "WebKitWebGLEnabled") + settings->setAttribute(QWebSettings::WebGLEnabled, value.toBool()); else printf("ERROR: LayoutTestController::overridePreference() does not support the '%s' preference\n", name.toLatin1().data()); @@ -564,8 +566,7 @@ int LayoutTestController::numberOfPages(float width, float height) bool LayoutTestController::callShouldCloseOnWebView() { - // FIXME: Implement for testing fix for https://bugs.webkit.org/show_bug.cgi?id=27481 - return false; + return DumpRenderTreeSupportQt::shouldClose(m_drt->webPage()->mainFrame()); } void LayoutTestController::setScrollbarPolicy(const QString& orientation, const QString& policy) @@ -645,5 +646,21 @@ void LayoutTestController::setEditingBehavior(const QString& editingBehavior) DumpRenderTreeSupportQt::setEditingBehavior(m_drt->webPage(), editingBehavior); } +void LayoutTestController::setGeolocationPermission(bool allow) +{ + m_isGeolocationPermissionSet = true; + m_geolocationPermission = allow; +} + +void LayoutTestController::setMockGeolocationError(int code, const QString& message) +{ + DumpRenderTreeSupportQt::setMockGeolocationError(code, message); +} + +void LayoutTestController::setMockGeolocationPosition(double latitude, double longitude, double accuracy) +{ + DumpRenderTreeSupportQt::setMockGeolocationPosition(latitude, longitude, accuracy); +} + const unsigned LayoutTestController::maxViewWidth = 800; const unsigned LayoutTestController::maxViewHeight = 600; diff --git a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h index d7bb839..a041ad0 100644 --- a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h +++ b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h @@ -180,6 +180,15 @@ public slots: int pageNumberForElementById(const QString& id, float width = 0, float height = 0); int numberOfPages(float width = maxViewWidth, float height = maxViewHeight); bool callShouldCloseOnWebView(); + // For now, this is a no-op. This may change depending on outcome of + // https://bugs.webkit.org/show_bug.cgi?id=33333 + void setCallCloseOnWebViews() {} + + void setMockGeolocationError(int code, const QString& message); + void setMockGeolocationPosition(double latitude, double longitude, double accuracy); + void setGeolocationPermission(bool allow); + bool isGeolocationPermissionSet() const { return m_isGeolocationPermissionSet; } + bool geolocationPermission() const { return m_geolocationPermission; } /* Policy values: 'on', 'auto' or 'off'. @@ -212,6 +221,8 @@ private: bool m_handleErrorPages; bool m_loadFinished; bool m_globalFlag; + bool m_isGeolocationPermissionSet; + bool m_geolocationPermission; QUrl m_userStyleSheetLocation; QBasicTimer m_timeoutTimer; diff --git a/WebKitTools/DumpRenderTree/win/AccessibilityUIElementWin.cpp b/WebKitTools/DumpRenderTree/win/AccessibilityUIElementWin.cpp index 9f00ae4..6aef32e 100644 --- a/WebKitTools/DumpRenderTree/win/AccessibilityUIElementWin.cpp +++ b/WebKitTools/DumpRenderTree/win/AccessibilityUIElementWin.cpp @@ -100,6 +100,12 @@ AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y) return 0; } +AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index) +{ + // FIXME: implement + return 0; +} + AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index) { COMPtr<IDispatch> child; diff --git a/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp b/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp index b22f342..1ed54d5 100644 --- a/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp +++ b/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp @@ -969,8 +969,10 @@ static void runTest(const string& testPathOrURL) DispatchMessage(&msg); } - if (shouldEnableDeveloperExtras(pathOrURL.c_str())) + if (shouldEnableDeveloperExtras(pathOrURL.c_str())) { gLayoutTestController->closeWebInspector(); + gLayoutTestController->setDeveloperExtrasEnabled(false); + } resetWebViewToConsistentStateBeforeTesting(); |