#include "InjectedBundle.h"
#include "InjectedBundlePage.h"
#include "JSLayoutTestController.h"
-#include <JavaScriptCore/JSRetainPtr.h>
+#include "StringFunctions.h"
+#include <WebKit2/WKBundleBackForwardList.h>
#include <WebKit2/WKBundleFrame.h>
+#include <WebKit2/WKBundleFramePrivate.h>
+#include <WebKit2/WKBundlePagePrivate.h>
+#include <WebKit2/WKBundleScriptWorld.h>
+#include <WebKit2/WKBundlePrivate.h>
#include <WebKit2/WKRetainPtr.h>
-#include <WebKit2/WKStringCF.h>
#include <WebKit2/WebKit2.h>
namespace WTR {
-PassRefPtr<LayoutTestController> LayoutTestController::create(const std::string& testPathOrURL)
+// This is lower than DumpRenderTree's timeout, to make it easier to work through the failures
+// Eventually it should be changed to match.
+const double LayoutTestController::waitToDumpWatchdogTimerInterval = 6;
+
+static JSValueRef propertyValue(JSContextRef context, JSObjectRef object, const char* propertyName)
+{
+ if (!object)
+ return 0;
+ JSRetainPtr<JSStringRef> propertyNameString(Adopt, JSStringCreateWithUTF8CString(propertyName));
+ JSValueRef exception;
+ return JSObjectGetProperty(context, object, propertyNameString.get(), &exception);
+}
+
+static JSObjectRef propertyObject(JSContextRef context, JSObjectRef object, const char* propertyName)
+{
+ JSValueRef value = propertyValue(context, object, propertyName);
+ if (!value || !JSValueIsObject(context, value))
+ return 0;
+ return const_cast<JSObjectRef>(value);
+}
+
+static JSObjectRef getElementById(WKBundleFrameRef frame, JSStringRef elementId)
{
- return adoptRef(new LayoutTestController(testPathOrURL));
+ JSContextRef context = WKBundleFrameGetJavaScriptContext(frame);
+ JSObjectRef document = propertyObject(context, JSContextGetGlobalObject(context), "document");
+ if (!document)
+ return 0;
+ JSValueRef getElementById = propertyObject(context, document, "getElementById");
+ if (!getElementById || !JSValueIsObject(context, getElementById))
+ return 0;
+ JSValueRef elementIdValue = JSValueMakeString(context, elementId);
+ JSValueRef exception;
+ JSValueRef element = JSObjectCallAsFunction(context, const_cast<JSObjectRef>(getElementById), document, 1, &elementIdValue, &exception);
+ if (!element || !JSValueIsObject(context, element))
+ return 0;
+ return const_cast<JSObjectRef>(element);
}
-LayoutTestController::LayoutTestController(const std::string& testPathOrURL)
- : m_dumpAsText(false)
+PassRefPtr<LayoutTestController> LayoutTestController::create()
+{
+ return adoptRef(new LayoutTestController);
+}
+
+LayoutTestController::LayoutTestController()
+ : m_whatToDump(RenderTree)
+ , m_shouldDumpAllFrameScrollPositions(false)
+ , m_shouldDumpBackForwardListsForAllWindows(false)
+ , m_shouldAllowEditing(true)
+ , m_shouldCloseExtraWindows(false)
+ , m_dumpEditingCallbacks(false)
, m_dumpStatusCallbacks(false)
+ , m_dumpTitleChanges(false)
, m_waitToDump(false)
, m_testRepaint(false)
, m_testRepaintSweepHorizontally(false)
- , m_testPathOrURL(testPathOrURL)
{
+ platformInitialize();
}
LayoutTestController::~LayoutTestController()
return JSLayoutTestController::layoutTestControllerClass();
}
-// This is lower than DumpRenderTree's timeout, to make it easier to work through the failures
-// Eventually it should be changed to match.
-static const CFTimeInterval waitToDumpWatchdogInterval = 6.0;
-
void LayoutTestController::display()
{
// FIXME: actually implement, once we want pixel tests
}
-void LayoutTestController::invalidateWaitToDumpWatchdog()
-{
- if (m_waitToDumpWatchdog) {
- CFRunLoopTimerInvalidate(m_waitToDumpWatchdog.get());
- m_waitToDumpWatchdog = 0;
- }
-}
-
-static void waitUntilDoneWatchdogFired(CFRunLoopTimerRef timer, void* info)
-{
- InjectedBundle::shared().layoutTestController()->waitToDumpWatchdogTimerFired();
-}
-
void LayoutTestController::waitUntilDone()
{
m_waitToDump = true;
- if (!m_waitToDumpWatchdog) {
- m_waitToDumpWatchdog.adoptCF(CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + waitToDumpWatchdogInterval,
- 0, 0, 0, waitUntilDoneWatchdogFired, NULL));
- CFRunLoopAddTimer(CFRunLoopGetCurrent(), m_waitToDumpWatchdog.get(), kCFRunLoopCommonModes);
- }
+ initializeWaitToDumpWatchdogTimerIfNeeded();
}
void LayoutTestController::waitToDumpWatchdogTimerFired()
{
- invalidateWaitToDumpWatchdog();
+ invalidateWaitToDumpWatchdogTimer();
const char* message = "FAIL: Timed out waiting for notifyDone to be called\n";
InjectedBundle::shared().os() << message << "\n";
InjectedBundle::shared().done();
unsigned LayoutTestController::numberOfActiveAnimations() const
{
+ // FIXME: Is it OK this works only for the main frame?
+ // FIXME: If this is needed only for the main frame, then why is the function on WKBundleFrame instead of WKBundlePage?
WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
return WKBundleFrameGetNumberOfActiveAnimations(mainFrame);
}
bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId)
{
- RetainPtr<CFStringRef> idCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, elementId));
- WKRetainPtr<WKStringRef> idWK(AdoptWK, WKStringCreateWithCFString(idCF.get()));
- RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, animationName));
- WKRetainPtr<WKStringRef> nameWK(AdoptWK, WKStringCreateWithCFString(nameCF.get()));
+ // FIXME: Is it OK this works only for the main frame?
+ // FIXME: If this is needed only for the main frame, then why is the function on WKBundleFrame instead of WKBundlePage?
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ return WKBundleFramePauseAnimationOnElementWithId(mainFrame, toWK(animationName).get(), toWK(elementId).get(), time);
+}
+JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const
+{
WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
- return WKBundleFramePauseAnimationOnElementWithId(mainFrame, nameWK.get(), idWK.get(), time);
+ WKRetainPtr<WKStringRef> text(AdoptWK, WKBundleFrameCopyLayerTreeAsText(mainFrame));
+ return toJS(text);
+}
+
+void LayoutTestController::addUserScript(JSStringRef source, bool runAtStart, bool allFrames)
+{
+ WKRetainPtr<WKStringRef> sourceWK = toWK(source);
+ WKRetainPtr<WKBundleScriptWorldRef> scriptWorld(AdoptWK, WKBundleScriptWorldCreateWorld());
+
+ WKBundleAddUserScript(InjectedBundle::shared().bundle(), scriptWorld.get(), sourceWK.get(), 0, 0, 0,
+ (runAtStart ? kWKInjectAtDocumentStart : kWKInjectAtDocumentEnd),
+ (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly));
+}
+
+void LayoutTestController::addUserStyleSheet(JSStringRef source, bool allFrames)
+{
+ WKRetainPtr<WKStringRef> sourceWK = toWK(source);
+ WKRetainPtr<WKBundleScriptWorldRef> scriptWorld(AdoptWK, WKBundleScriptWorldCreateWorld());
+
+ WKBundleAddUserStyleSheet(InjectedBundle::shared().bundle(), scriptWorld.get(), sourceWK.get(), 0, 0, 0,
+ (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly));
+}
+
+void LayoutTestController::keepWebHistory()
+{
+ WKBundleSetShouldTrackVisitedLinks(InjectedBundle::shared().bundle(), true);
+}
+
+JSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSValueRef element)
+{
+ // FIXME: Is it OK this works only for the main frame?
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
+ if (!JSValueIsObject(context, element))
+ return JSValueMakeUndefined(context);
+ JSValueRef value = WKBundleFrameGetComputedStyleIncludingVisitedInfo(mainFrame, const_cast<JSObjectRef>(element));
+ if (!value)
+ return JSValueMakeUndefined(context);
+ return value;
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStringRef elementId)
+{
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ JSObjectRef element = getElementById(mainFrame, elementId);
+ if (!element)
+ return 0;
+ WKRetainPtr<WKStringRef> value(AdoptWK, WKBundleFrameCopyCounterValue(mainFrame, const_cast<JSObjectRef>(element)));
+ return toJS(value);
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::markerTextForListItem(JSValueRef element)
+{
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
+ if (!element || !JSValueIsObject(context, element))
+ return 0;
+ WKRetainPtr<WKStringRef> text(AdoptWK, WKBundleFrameCopyMarkerText(mainFrame, const_cast<JSObjectRef>(element)));
+ if (WKStringIsEmpty(text.get()))
+ return 0;
+ return toJS(text);
+}
+
+void LayoutTestController::execCommand(JSStringRef name, JSStringRef argument)
+{
+ WKBundlePageExecuteEditingCommand(InjectedBundle::shared().page()->page(), toWK(name).get(), toWK(argument).get());
+}
+
+bool LayoutTestController::isCommandEnabled(JSStringRef name)
+{
+ return WKBundlePageIsEditingCommandEnabled(InjectedBundle::shared().page()->page(), toWK(name).get());
+}
+
+void LayoutTestController::setCanOpenWindows(bool)
+{
+ // It's not clear if or why any tests require opening windows be forbidden.
+ // For now, just ignore this setting, and if we find later it's needed we can add it.
+}
+
+void LayoutTestController::setXSSAuditorEnabled(bool enabled)
+{
+ WKBundleOverrideXSSAuditorEnabledForTestRunner(InjectedBundle::shared().bundle(), true);
+}
+
+unsigned LayoutTestController::windowCount()
+{
+ return InjectedBundle::shared().pageCount();
+}
+
+void LayoutTestController::clearBackForwardList()
+{
+ WKBundleBackForwardListClear(WKBundlePageGetBackForwardList(InjectedBundle::shared().page()->page()));
}
// Object Creation
void LayoutTestController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
{
- JSRetainPtr<JSStringRef> layoutTestContollerStr(Adopt, JSStringCreateWithUTF8CString("layoutTestController"));
- JSObjectSetProperty(context, windowObject, layoutTestContollerStr.get(), JSWrapper::wrap(context, this), kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
+ setProperty(context, windowObject, "layoutTestController", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
}
} // namespace WTR