36e2d668a0233e5500022c9859bb703f2977d5ee
[WebKit.git] / WebKitTools / WebKitTestRunner / InjectedBundle / LayoutTestController.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "LayoutTestController.h"
27 #include "InjectedBundle.h"
28 #include "InjectedBundlePage.h"
29
30 #include <JavaScriptCore/JSRetainPtr.h>
31 #include <WebKit2/WKBundleFrame.h>
32 #include <WebKit2/WKRetainPtr.h>
33 #include <WebKit2/WKStringCF.h>
34 #include <WebKit2/WebKit2.h>
35
36 namespace WTR {
37
38 PassRefPtr<LayoutTestController> LayoutTestController::create(const std::string& testPathOrURL)
39 {
40     return adoptRef(new LayoutTestController(testPathOrURL));
41 }
42
43 LayoutTestController::LayoutTestController(const std::string& testPathOrURL)
44     : m_dumpAsText(false)
45     , m_waitToDump(false)
46     , m_testRepaint(false)
47     , m_testRepaintSweepHorizontally(false)
48     , m_testPathOrURL(testPathOrURL)
49 {
50 }
51
52 LayoutTestController::~LayoutTestController()
53 {
54 }
55
56 static const CFTimeInterval waitToDumpWatchdogInterval = 30.0;
57
58 void LayoutTestController::display()
59 {
60     // FIXME: actually implement, once we want pixel tests
61 }
62
63 void LayoutTestController::invalidateWaitToDumpWatchdog()
64 {
65     if (m_waitToDumpWatchdog) {
66         CFRunLoopTimerInvalidate(m_waitToDumpWatchdog.get());
67         m_waitToDumpWatchdog = 0;
68     }
69 }
70
71 static void waitUntilDoneWatchdogFired(CFRunLoopTimerRef timer, void* info)
72 {
73     InjectedBundle::shared().layoutTestController()->waitToDumpWatchdogTimerFired();
74 }
75
76 void LayoutTestController::setWaitToDump()
77 {
78     m_waitToDump = true;
79     if (!m_waitToDumpWatchdog) {
80         m_waitToDumpWatchdog.adoptCF(CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + waitToDumpWatchdogInterval, 
81                                                       0, 0, 0, waitUntilDoneWatchdogFired, NULL));
82         CFRunLoopAddTimer(CFRunLoopGetCurrent(), m_waitToDumpWatchdog.get(), kCFRunLoopCommonModes);
83     }
84 }
85
86 void LayoutTestController::waitToDumpWatchdogTimerFired()
87 {
88     invalidateWaitToDumpWatchdog();
89     const char* message = "FAIL: Timed out waiting for notifyDone to be called\n";
90     InjectedBundle::shared().os() << message << "\n";
91     InjectedBundle::shared().done();
92 }
93
94 void LayoutTestController::notifyDone()
95 {
96     if (m_waitToDump && !InjectedBundle::shared().page()->isLoading())
97         InjectedBundle::shared().page()->dump();
98     m_waitToDump = false;
99 }
100
101 unsigned LayoutTestController::numberOfActiveAnimations() const
102 {
103     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
104     return WKBundleFrameGetNumberOfActiveAnimations(mainFrame);
105 }
106
107 bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId)
108 {
109     RetainPtr<CFStringRef> idCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, elementId));
110     WKRetainPtr<WKStringRef> idWK(AdoptWK, WKStringCreateWithCFString(idCF.get()));
111     RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, animationName));
112     WKRetainPtr<WKStringRef> nameWK(AdoptWK, WKStringCreateWithCFString(nameCF.get()));
113
114     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
115     return WKBundleFramePauseAnimationOnElementWithId(mainFrame, nameWK.get(), idWK.get(), time);
116 }
117
118 static JSValueRef displayCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
119 {
120     // Has mac & windows implementation
121     LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
122     controller->display();
123
124     return JSValueMakeUndefined(context);
125 }
126
127 static JSValueRef dumpAsTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
128 {
129     LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
130     controller->setDumpAsText(true);
131     return JSValueMakeUndefined(context);
132 }
133
134 static JSValueRef waitUntilDoneCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
135 {
136     LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
137     controller->setWaitToDump();
138     return JSValueMakeUndefined(context);
139 }
140
141 static JSValueRef notifyDoneCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
142 {
143     LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
144     controller->notifyDone();
145     return JSValueMakeUndefined(context);
146 }
147
148 static JSValueRef numberOfActiveAnimationsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
149 {
150     if (argumentCount)
151         return JSValueMakeUndefined(context);
152
153     LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
154     return JSValueMakeNumber(context, controller->numberOfActiveAnimations());
155 }
156
157 static JSValueRef pauseAnimationAtTimeOnElementWithIdCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
158 {
159     if (argumentCount != 3)
160         return JSValueMakeUndefined(context);
161
162     JSRetainPtr<JSStringRef> animationName(Adopt, JSValueToStringCopy(context, arguments[0], exception));
163     ASSERT(!*exception);
164     double time = JSValueToNumber(context, arguments[1], exception);
165     ASSERT(!*exception);
166     JSRetainPtr<JSStringRef> elementId(Adopt, JSValueToStringCopy(context, arguments[2], exception));
167     ASSERT(!*exception);
168
169     LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
170     return JSValueMakeBoolean(context, controller->pauseAnimationAtTimeOnElementWithId(animationName.get(), time, elementId.get()));
171 }
172
173 static JSValueRef repaintSweepHorizontallyCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
174 {
175     LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
176     controller->setTestRepaintSweepHorizontally();
177     return JSValueMakeUndefined(context);
178 }
179
180 static JSValueRef testRepaintCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
181 {
182     LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
183     controller->setTestRepaint();
184     return JSValueMakeUndefined(context);
185 }
186
187 // Object Finalization
188
189 static void layoutTestControllerObjectFinalize(JSObjectRef object)
190 {
191     LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(object));
192     controller->deref();
193 }
194
195 // Object Creation
196
197 void LayoutTestController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
198 {
199     JSRetainPtr<JSStringRef> layoutTestContollerStr(Adopt, JSStringCreateWithUTF8CString("layoutTestController"));
200     ref();
201
202     JSClassRef classRef = getJSClass();
203     JSValueRef layoutTestContollerObject = JSObjectMake(context, classRef, this);
204     JSClassRelease(classRef);
205
206     JSObjectSetProperty(context, windowObject, layoutTestContollerStr.get(), layoutTestContollerObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
207 }
208
209 JSClassRef LayoutTestController::getJSClass()
210 {
211     static JSStaticFunction* staticFunctions = LayoutTestController::staticFunctions();
212     static JSClassDefinition classDefinition = {
213         0, kJSClassAttributeNone, "LayoutTestController", 0, 0, staticFunctions,
214         0, layoutTestControllerObjectFinalize, 0, 0, 0, 0, 0, 0, 0, 0, 0
215     };
216
217     return JSClassCreate(&classDefinition);
218 }
219
220 JSStaticFunction* LayoutTestController::staticFunctions()
221 {
222     static JSStaticFunction staticFunctions[] = {
223         { "display", displayCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
224         { "dumpAsText", dumpAsTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
225         { "notifyDone", notifyDoneCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
226         { "numberOfActiveAnimations", numberOfActiveAnimationsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
227         { "pauseAnimationAtTimeOnElementWithId", pauseAnimationAtTimeOnElementWithIdCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
228         { "repaintSweepHorizontally", repaintSweepHorizontallyCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
229         { "testRepaint", testRepaintCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
230         { "waitUntilDone", waitUntilDoneCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
231         { 0, 0, 0 }
232     };
233
234     return staticFunctions;
235 }
236
237 } // namespace WTR