Reviewed by Darin.
authorap@webkit.org <ap@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Jan 2008 07:31:40 +0000 (07:31 +0000)
committerap@webkit.org <ap@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Jan 2008 07:31:40 +0000 (07:31 +0000)
        <rdar://problem/5463489> A number of layout tests should be using execCommand instead of textInputController

        Added layoutTestController.execCommand to access editor commands that are not available
        via document.execCommand.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@29149 268f45cc-cd09-0410-ab3c-d52691b4dbfc

24 files changed:
LayoutTests/ChangeLog
LayoutTests/editing/deleting/5300379.html
LayoutTests/editing/deleting/delete-to-end-of-paragraph.html
LayoutTests/editing/deleting/smart-delete-003.html
LayoutTests/editing/deleting/smart-delete-004.html
LayoutTests/editing/selection/4947387.html
LayoutTests/editing/selection/5195166-1.html
LayoutTests/editing/selection/5195166-2.html
LayoutTests/editing/selection/select-line.html
LayoutTests/editing/selection/selection-actions.html
LayoutTests/platform/win/Skipped
WebKit/mac/ChangeLog
WebKit/mac/WebView/WebView.mm
WebKit/mac/WebView/WebViewPrivate.h
WebKit/win/ChangeLog
WebKit/win/Interfaces/IWebViewPrivate.idl
WebKit/win/WebView.cpp
WebKit/win/WebView.h
WebKitTools/ChangeLog
WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj
WebKitTools/DumpRenderTree/LayoutTestController.cpp
WebKitTools/DumpRenderTree/LayoutTestController.h
WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm
WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp

index 9a9c07b..8ad6f57 100644 (file)
@@ -1,3 +1,21 @@
+2008-01-03  Alexey Proskuryakov  <ap@webkit.org>
+
+        Reviewed by Darin.
+
+        <rdar://problem/5463489> A number of layout tests should be using execCommand instead of textInputController
+
+        * editing/deleting/5300379.html:
+        * editing/deleting/delete-to-end-of-paragraph.html:
+        * editing/deleting/smart-delete-003.html:
+        * editing/deleting/smart-delete-004.html:
+        * editing/selection/4947387.html:
+        * editing/selection/5195166-1.html:
+        * editing/selection/5195166-2.html:
+        * editing/selection/select-line.html:
+        * editing/selection/selection-actions.html:
+        * platform/win/Skipped:
+        Changed these tests to use layoutTestController.execCommand, so they no longer need to be disabled.
+
 2008-01-03  Oliver Hunt  <oliver@apple.com>
 
         Reviewed by Maciej.
index ea2b344..23c81ac 100644 (file)
@@ -8,11 +8,11 @@ sel = window.getSelection();
 sel.setPosition(div, 0);
 if (window.layoutTestController) {
     // Test to see if deleteWordBackward: hangs.
-    textInputController.doCommand("deleteWordBackward:");
+    layoutTestController.execCommand("DeleteWordBackward");
     document.execCommand("InsertText", false, "Success FAIL");
     // Delete 'FAIL' with deleteWordBackward: to verify that it's not a no-op.
-    textInputController.doCommand("deleteWordBackward:");
-    textInputController.doCommand("deleteBackward:");
+    layoutTestController.execCommand("DeleteWordBackward");
+    layoutTestController.execCommand("DeleteBackward");
 } else {
     document.execCommand("InsertText", false, "To run this test manually.  Delete all this text and then option-delete.  Safari shouldn't hang.");
 }
index 40415a3..3406921 100644 (file)
@@ -16,8 +16,8 @@ function editingTest() {
         
         try {
             // test for 4570218 by using double deleteToEndOfParagraph
-            textInputController.doCommand("deleteToEndOfParagraph:");    
-            textInputController.doCommand("deleteToEndOfParagraph:");    
+            layoutTestController.execCommand("DeleteToEndOfParagraph");    
+            layoutTestController.execCommand("DeleteToEndOfParagraph");    
 
         } catch (ex) {
             document.write("Exception: " + ex.description);
index 2b71d7d..cebcb07 100644 (file)
@@ -14,6 +14,6 @@ if (window.layoutTestController) {
     sel.modify("move", "forward", "word");
     sel.modify("move", "forward", "word");
     sel.modify("extend", "backward", "word");
-    textInputController.doCommand("deleteBackward:");
+    layoutTestController.execCommand("DeleteBackward");
 }
 </script>
index 49ec7e4..580fcf0 100644 (file)
@@ -14,6 +14,6 @@ if (window.layoutTestController) {
     sel.modify("move", "forward", "word");
     sel.modify("move", "forward", "word");
     sel.modify("extend", "backward", "word");
-    textInputController.doCommand("deleteForward:");
+    layoutTestController.execCommand("DeleteForward");
 }
 </script>
index 0f0c84f..98f4e42 100644 (file)
@@ -12,15 +12,15 @@ if (window.layoutTestController) {
     var sel = window.getSelection();
     
     sel.setPosition(text, text.length);
-    textInputController.doCommand("moveToBeginningOfLineAndModifySelection:");
+    layoutTestController.execCommand("MoveToBeginningOfLineAndModifySelection");
     
     sel.setPosition(text, 0);
-    textInputController.doCommand("moveToEndOfLineAndModifySelection:");
+    layoutTestController.execCommand("MoveToEndOfLineAndModifySelection");
 
     sel.setPosition(text, text.length);
-    textInputController.doCommand("moveToBeginningOfParagraphAndModifySelection:");
+    layoutTestController.execCommand("MoveToBeginningOfParagraphAndModifySelection");
     
     sel.setPosition(text, 0);
-    textInputController.doCommand("moveToEndOfParagraphAndModifySelection:");
+    layoutTestController.execCommand("MoveToEndOfParagraphAndModifySelection");
 }
 </script>
index b4398ee..f0ff1a5 100644 (file)
@@ -20,7 +20,7 @@ if (window.layoutTestController) {
     
     selection.setBaseAndExtent(text, 3 + 5, text, 3);
     // Extending this 5 character selection will select 6 characters.
-    textInputController.doCommand("moveForwardAndModifySelection:");
+    layoutTestController.execCommand("MoveForwardAndModifySelection");
     // Extending it in this way flips the base and the extent.
     if (selection.extentOffset - selection.baseOffset != 6)
         log("Failure: Selection isn't the right size.");
index a8eb6ae..28c8c9b 100644 (file)
@@ -14,10 +14,10 @@ if (window.layoutTestController) {
     var text = document.getElementById("div").firstChild;
     var selection = window.getSelection();
     selection.setBaseAndExtent(text, 0, text, 0);
-    textInputController.doCommand("moveForwardAndModifySelection:");
-    textInputController.doCommand("moveForwardAndModifySelection:");
-    textInputController.doCommand("moveForwardAndModifySelection:");
-    textInputController.doCommand("moveBackwardAndModifySelection:");
+    layoutTestController.execCommand("MoveForwardAndModifySelection");
+    layoutTestController.execCommand("MoveForwardAndModifySelection");
+    layoutTestController.execCommand("MoveForwardAndModifySelection");
+    layoutTestController.execCommand("MoveBackwardAndModifySelection");
 } else {
     log("Failure: This test cannot be run manually.")
 }
index 2d10391..369463e 100644 (file)
@@ -10,5 +10,5 @@ var sel = window.getSelection();
 
 sel.setPosition(div, 0);
 if (window.layoutTestController)
-    textInputController.doCommand("selectLine:");
+    layoutTestController.execCommand("SelectLine");
 </script>
index affedaa..1a43484 100644 (file)
@@ -24,37 +24,37 @@ function editingTest() {
     eventSender.mouseMoveTo(x, y);
     eventSender.mouseUp();
     
-    textInputController.doCommand("moveBackward:");
-    textInputController.doCommand("moveBackwardAndModifySelection:");
-    textInputController.doCommand("moveDown:");
-    textInputController.doCommand("moveDownAndModifySelection:");
-    textInputController.doCommand("moveForward:");
-    textInputController.doCommand("moveForwardAndModifySelection:");
-    textInputController.doCommand("moveLeft:");
-    textInputController.doCommand("moveLeftAndModifySelection:");
-    textInputController.doCommand("moveRight:");
-    textInputController.doCommand("moveRightAndModifySelection:");
-    textInputController.doCommand("moveToBeginningOfDocument:");
-    textInputController.doCommand("moveToBeginningOfLine:");
-    textInputController.doCommand("moveToBeginningOfParagraph:");
-    textInputController.doCommand("moveToEndOfDocument:");
-    textInputController.doCommand("moveToEndOfLine:");
-    textInputController.doCommand("moveToEndOfParagraph:");
-    textInputController.doCommand("moveUp:");
-    textInputController.doCommand("moveUpAndModifySelection:");
-    textInputController.doCommand("moveWordBackward:");
-    textInputController.doCommand("moveWordBackwardAndModifySelection:");
-    textInputController.doCommand("moveWordForward:");
-    textInputController.doCommand("moveWordForwardAndModifySelection:");
-    textInputController.doCommand("moveWordLeft:");
-    textInputController.doCommand("moveWordRight:");
-    textInputController.doCommand("moveWordRightAndModifySelection:");
-    textInputController.doCommand("moveWordLeftAndModifySelection:");
-    textInputController.doCommand("pageDown:");
-    textInputController.doCommand("pageUp:");
-    textInputController.doCommand("selectLine:");
-    textInputController.doCommand("selectParagraph:");
-    textInputController.doCommand("selectWord:");
+    layoutTestController.execCommand("MoveBackward");
+    layoutTestController.execCommand("MoveBackwardAndModifySelection");
+    layoutTestController.execCommand("MoveDown");
+    layoutTestController.execCommand("MoveDownAndModifySelection");
+    layoutTestController.execCommand("MoveForward");
+    layoutTestController.execCommand("MoveForwardAndModifySelection");
+    layoutTestController.execCommand("MoveLeft");
+    layoutTestController.execCommand("MoveLeftAndModifySelection");
+    layoutTestController.execCommand("MoveRight");
+    layoutTestController.execCommand("MoveRightAndModifySelection");
+    layoutTestController.execCommand("MoveToBeginningOfDocument");
+    layoutTestController.execCommand("MoveToBeginningOfLine");
+    layoutTestController.execCommand("MoveToBeginningOfParagraph");
+    layoutTestController.execCommand("MoveToEndOfDocument");
+    layoutTestController.execCommand("MoveToEndOfLine");
+    layoutTestController.execCommand("MoveToEndOfParagraph");
+    layoutTestController.execCommand("MoveUp");
+    layoutTestController.execCommand("MoveUpAndModifySelection");
+    layoutTestController.execCommand("MoveWordBackward");
+    layoutTestController.execCommand("MoveWordBackwardAndModifySelection");
+    layoutTestController.execCommand("MoveWordForward");
+    layoutTestController.execCommand("MoveWordForwardAndModifySelection");
+    layoutTestController.execCommand("MoveWordLeft");
+    layoutTestController.execCommand("MoveWordRight");
+    layoutTestController.execCommand("MoveWordRightAndModifySelection");
+    layoutTestController.execCommand("MoveWordLeftAndModifySelection");
+    layoutTestController.execCommand("PageDown");
+    layoutTestController.execCommand("PageUp");
+    layoutTestController.execCommand("SelectLine");
+    layoutTestController.execCommand("SelectParagraph");
+    layoutTestController.execCommand("SelectWord");
 }
 
 </script>
index b882721..75ff1b8 100644 (file)
@@ -447,17 +447,6 @@ editing/selection/caret-rtl.html
 # Caret, RenderBlock
 editing/pasteboard/undoable-fragment-removes.html
 
-# Tests that use textInputController to execute commands.
-editing/deleting/5300379.html
-editing/deleting/delete-to-end-of-paragraph.html
-editing/deleting/smart-delete-003.html
-editing/deleting/smart-delete-004.html
-editing/selection/4947387.html
-editing/selection/5195166-1.html
-editing/selection/5195166-2.html
-editing/selection/select-line.html
-editing/selection/selection-actions.html
-
 ################################################################################
 ######################### All of above may be related ##########################
 ################################################################################
index 60b321e..10db4e4 100644 (file)
@@ -1,3 +1,14 @@
+2008-01-03  Alexey Proskuryakov  <ap@webkit.org>
+
+        Reviewed by Darin.
+
+        <rdar://problem/5463489> A number of layout tests should be using execCommand instead of textInputController
+
+        * WebView/WebView.mm:
+        (-[WebView _executeCoreCommandByName:value:]):
+        * WebView/WebViewPrivate.h:
+        Added an SPI to implement layoutTestController.execCommand.
+
 2008-01-03  Kevin Decker  <kdecker@apple.com>
 
         Reviewed by Darin.
index a80c780..638b315 100644 (file)
@@ -1619,6 +1619,14 @@ WebFrameLoadDelegateImplementationCache* WebViewGetFrameLoadDelegateImplementati
     return _private->catchesDelegateExceptions;
 }
 
+- (void)_executeCoreCommandByName:(NSString *)name value:(NSString *)value
+{
+    Frame* coreFrame = [[[self mainFrame] _bridge] _frame];
+    if (!coreFrame)
+        return;
+    coreFrame->editor()->command(name).execute(value);
+}
+
 @end
 
 @implementation _WebSafeForwarder
index 6c4babb..9c95ab0 100644 (file)
@@ -334,6 +334,9 @@ Could be worth adding to the API.
 - (BOOL)_inFastImageScalingMode;
 - (void)_setUseFastImageScalingMode:(BOOL)flag;
 
+// SPI for DumpRenderTree
+- (void)_executeCoreCommandByName:(NSString *)name value:(NSString *)value;
+
 @end
 
 @interface WebView (WebViewPrintingPrivate)
index 96333ca..36ba021 100644 (file)
@@ -1,3 +1,15 @@
+2008-01-03  Alexey Proskuryakov  <ap@webkit.org>
+
+        Reviewed by Darin.
+
+        <rdar://problem/5463489> A number of layout tests should be using execCommand instead of textInputController
+
+        * Interfaces/IWebViewPrivate.idl:
+        * WebView.cpp:
+        (WebView::executeCoreCommandByName):
+        * WebView.h:
+        Added an SPI to implement layoutTestController.execCommand.
+
 2008-01-03  Ada Chan  <adachan@apple.com>
 
         Replaced the use of editor command "ForwardDelete" with "DeleteForward" to be consistent
index e4f11bd..0cacc09 100644 (file)
@@ -94,6 +94,7 @@ interface IWebViewPrivate : IUnknown
     
     // SPI for DumpRenderTree
     HRESULT updateActiveState();
+    HRESULT executeCoreCommandByName([in] BSTR name, [in] BSTR value);
 
     // Support for displaying multiple text matches.
     HRESULT markAllMatchesForText([in] BSTR search, [in] BOOL caseSensitive, [in] BOOL highlight, [in] UINT limit, [out] UINT* matches);
index dcda391..2b522e5 100644 (file)
@@ -2688,6 +2688,16 @@ HRESULT STDMETHODCALLTYPE WebView::updateActiveState()
     return S_OK;
 }
 
+HRESULT STDMETHODCALLTYPE WebView::executeCoreCommandByName(BSTR bName, BSTR bValue)
+{
+    String name(bName, SysStringLen(bName));
+    String value(bValue, SysStringLen(bValue));
+
+    m_page->focusController()->focusedOrMainFrame()->editor()->command(name).execute(value);
+
+    return S_OK;
+}
+
 HRESULT STDMETHODCALLTYPE WebView::markAllMatchesForText(
     BSTR str, BOOL caseSensitive, BOOL highlight, UINT limit, UINT* matches)
 {
index d01213a..4d15cb4 100644 (file)
@@ -569,6 +569,8 @@ public:
 
     virtual HRESULT STDMETHODCALLTYPE updateActiveState(void);
 
+    virtual HRESULT STDMETHODCALLTYPE executeCoreCommandByName(BSTR name, BSTR value);
+
     virtual HRESULT STDMETHODCALLTYPE markAllMatchesForText(
         BSTR search, BOOL caseSensitive, BOOL highlight, UINT limit, UINT* matches);
 
index de0cccc..3682a27 100644 (file)
@@ -1,3 +1,22 @@
+2008-01-03  Alexey Proskuryakov  <ap@webkit.org>
+
+        Reviewed by Darin.
+
+        <rdar://problem/5463489> A number of layout tests should be using execCommand instead of textInputController
+
+        Added layoutTestController.execCommand to access editor commands that are not available
+        via document.execCommand.
+
+        * DumpRenderTree/LayoutTestController.cpp:
+        (execCommandCallback):
+        (LayoutTestController::staticFunctions):
+        * DumpRenderTree/LayoutTestController.h:
+        * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+        (LayoutTestController::execCommand):
+        * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+        (LayoutTestController::queueLoad):
+        (LayoutTestController::execCommand):
+
 2008-01-03  Alice Liu  <alice.liu@apple.com>
 
         Reviewed by Darin, Mitz.
index 1a59f19..babf749 100644 (file)
                A8B91ADF0CF3B372008F91FF /* DumpRenderTreePasteboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DumpRenderTreePasteboard.h; path = mac/DumpRenderTreePasteboard.h; sourceTree = "<group>"; };
                A8B91BF70CF522B4008F91FF /* CheckedMalloc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckedMalloc.cpp; path = mac/CheckedMalloc.cpp; sourceTree = "<group>"; };
                A8B91BF90CF522B4008F91FF /* CheckedMalloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CheckedMalloc.h; path = mac/CheckedMalloc.h; sourceTree = "<group>"; };
-               AA7F10C20CB3C1030003BDC9 /* AHEM____.TTF */ = {isa = PBXFileReference; lastKnownFileType = file; name = "AHEM____.TTF"; path = "qt/fonts/AHEM____.TTF"; sourceTree = "<group>"; };
+               AA7F10C20CB3C1030003BDC9 /* AHEM____.TTF */ = {isa = PBXFileReference; lastKnownFileType = file; name = AHEM____.TTF; path = qt/fonts/AHEM____.TTF; sourceTree = "<group>"; };
                AE8257EF08D22389000507AB /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; };
                B5A7526708AF4A4A00138E45 /* ImageDiff */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ImageDiff; sourceTree = BUILT_PRODUCTS_DIR; };
                B5A752A108AF5D1F00138E45 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = /System/Library/Frameworks/QuartzCore.framework; sourceTree = "<absolute>"; };
                08FB7793FE84155DC02AAC07 /* Project object */ = {
                        isa = PBXProject;
                        buildConfigurationList = 149C29C308902C6D008A9EFC /* Build configuration list for PBXProject "DumpRenderTree" */;
-                       compatibilityVersion = "Xcode 2.4";
                        hasScannedForEncodings = 1;
                        mainGroup = 08FB7794FE84155DC02AAC07 /* DumpRenderTree */;
                        productRefGroup = 9340995508540CAF007F3BC8 /* Products */;
index 39e7c8f..8183477 100644 (file)
@@ -257,6 +257,31 @@ static JSValueRef encodeHostNameCallback(JSContextRef context, JSObjectRef funct
     return JSValueMakeString(context, encodedHostName.get());
 }
 
+static JSValueRef execCommandCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    // Has Mac & Windows implementations.
+    if (argumentCount < 1)
+        return JSValueMakeUndefined(context);
+
+    JSRetainPtr<JSStringRef> name(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+    ASSERT(!*exception);
+
+    // Ignoring the second parameter (userInterface), as this command emulates a manual action.
+
+    JSRetainPtr<JSStringRef> value;
+    if (argumentCount >= 3) {
+        value.adopt(JSValueToStringCopy(context, arguments[2], exception));
+        ASSERT(!*exception);
+    } else
+        value.adopt(JSStringCreateWithUTF8CString(""));
+
+
+    LayoutTestController* controller = reinterpret_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+    controller->execCommand(name.get(), value.get());
+
+    return JSValueMakeUndefined(context);
+}
+
 static JSValueRef keepWebHistoryCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
 {
     // Has mac implementation
@@ -570,6 +595,7 @@ JSStaticFunction* LayoutTestController::staticFunctions()
         { "dumpSourceAsWebArchive", dumpSourceAsWebArchiveCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "dumpTitleChanges", dumpTitleChangesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "encodeHostName", encodeHostNameCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+        { "execCommand", execCommandCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "keepWebHistory", keepWebHistoryCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "notifyDone", notifyDoneCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "pathToLocalResource", pathToLocalResourceCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
index 10e13b7..91aaae8 100644 (file)
@@ -43,6 +43,7 @@ public:
     void clearBackForwardList();
     JSStringRef copyDecodedHostName(JSStringRef name);
     JSStringRef copyEncodedHostName(JSStringRef name);
+    void execCommand(JSStringRef name, JSStringRef value);
     void display();
     void keepWebHistory();
     void notifyDone();
index 33d0b4b..7194eda 100644 (file)
@@ -237,3 +237,14 @@ int LayoutTestController::windowCount()
 {
     return CFArrayGetCount(allWindowsRef);
 }
+
+void LayoutTestController::execCommand(JSStringRef name, JSStringRef value)
+{
+    RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, name));
+    NSString *nameNS = (NSString *)nameCF.get();
+
+    RetainPtr<CFStringRef> valueCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, value));
+    NSString *valueNS = (NSString *)valueCF.get();
+
+    [[mainFrame webView] _executeCoreCommandByName:nameNS value:valueNS];
+}
index 9de2002..9b13d05 100644 (file)
@@ -200,8 +200,8 @@ void LayoutTestController::queueLoad(JSStringRef url, JSStringRef target)
         responseURL = responseURL.substr(0, lastSlash);
 
     wstring wURL = jsStringRefToWString(url);
-    wstring wAbosuluteURL = responseURL + TEXT("/") + wURL;
-    JSRetainPtr<JSStringRef> jsAbsoluteURL(Adopt, JSStringCreateWithCharacters(wAbosuluteURL.data(), wAbosuluteURL.length()));
+    wstring wAbsoluteURL = responseURL + TEXT("/") + wURL;
+    JSRetainPtr<JSStringRef> jsAbsoluteURL(Adopt, JSStringCreateWithCharacters(wAbsoluteURL.data(), wAbsoluteURL.length()));
 
     WorkQueue::shared()->queue(new LoadItem(jsAbsoluteURL.get(), target));
 }
@@ -504,3 +504,24 @@ int LayoutTestController::windowCount()
     // FIXME: Implement!
     return 1;
 }
+
+void LayoutTestController::execCommand(JSStringRef name, JSStringRef value)
+{
+    wstring wName = jsStringRefToWString(name);
+    wstring wValue = jsStringRefToWString(value);
+
+    COMPtr<IWebView> webView;
+    if (FAILED(frame->webView(&webView)))
+        return;
+
+    COMPtr<IWebViewPrivate> viewPrivate;
+    if (FAILED(webView->QueryInterface(&viewPrivate)))
+        return;
+
+    BSTR nameBSTR = SysAllocStringLen((OLECHAR*)wName.c_str(), wName.length());
+    BSTR valueBSTR = SysAllocStringLen((OLECHAR*)wValue.c_str(), wValue.length());
+    viewPrivate->executeCoreCommandByName(nameBSTR, valueBSTR);
+
+    SysFreeString(nameBSTR);
+    SysFreeString(valueBSTR);
+}