diff options
Diffstat (limited to 'Tools')
19 files changed, 743 insertions, 44 deletions
diff --git a/Tools/ChangeLog b/Tools/ChangeLog index acadd9760..e86900fe5 100644 --- a/Tools/ChangeLog +++ b/Tools/ChangeLog @@ -1,3 +1,155 @@ +2012-05-27 David Barton <dbarton@mathscribe.com> + + [watchlist] Improve MathML rule + https://bugs.webkit.org/show_bug.cgi?id=87592 + + Reviewed by Adam Barth. + + The old rule "filename": r".*mathml" works fine because "filename" is a prefix match, + but if this changed the rule would be slow. We protect against this, clarify the rule, + and make it more similar to existing rules. + + * Scripts/webkitpy/common/config/watchlist: + +2012-05-27 David Barton <dbarton@mathscribe.com> + + [watchlist] Add myself & a rule for MathML + https://bugs.webkit.org/show_bug.cgi?id=87586 + + Reviewed by Adam Barth. + + * Scripts/webkitpy/common/config/watchlist: + +2012-05-26 David Kilzer <ddkilzer@apple.com> + + Use xcrun to find path to nm for Mac port + <http://webkit.org/b/87588> + + Reviewed by Dan Bernstein. + + * Scripts/webkitpy/layout_tests/port/mac.py: + (MacPort.nm_command): Add. Tries to find a path for the nm + command using xcrun. Falls back to returning 'nm'. + * Scripts/webkitpy/layout_tests/port/webkit.py: + (WebKitPort.nm_command): Add. Returns 'nm'. + (WebKitPort._webcore_symbols_string): Call self.nm_command(). + +2012-05-25 Lynn Neir <lynn.neir@skype.net> + + Added windows implementation in DRT for TextInputController, https://bugs.webkit.org/show_bug.cgi?id=32021 + + Reviewed by Eric Seidel. + + * DumpRenderTree/win/DumpRenderTree.vcproj: + * DumpRenderTree/win/FrameLoadDelegate.cpp: + (FrameLoadDelegate::FrameLoadDelegate): + (FrameLoadDelegate::didClearWindowObjectForFrameInStandardWorld): + * DumpRenderTree/win/FrameLoadDelegate.h: + (FrameLoadDelegate): + * DumpRenderTree/win/TextInputController.cpp: Added. + (setMarkedTextCallback): + (hasMarkedTextCallback): + (unmarkTextCallback): + (markedRangeCallback): + (insertTextCallback): + (firstRectForCharacterRangeCallback): + (selectedRangeCallback): + (TextInputController::makeWindowObject): + (TextInputController::getJSClass): + (TextInputController::staticValues): + (TextInputController::staticFunctions): + * DumpRenderTree/win/TextInputController.h: Added. + (TextInputController): + * DumpRenderTree/win/TextInputControllerWin.cpp: Added. + (TextInputController::setMarkedText): + (TextInputController::hasMarkedText): + (TextInputController::unmarkText): + (TextInputController::markedRange): + (TextInputController::insertText): + (TextInputController::firstRectForCharacterRange): + (TextInputController::selectedRange): + +2012-05-25 Dirk Pranke <dpranke@chromium.org> + + webkitpy: change scm.add(), scm.delete() to accept multiple paths + https://bugs.webkit.org/show_bug.cgi?id=87528 + + Reviewed by Ojan Vafai. + + launching git or svn for individual files can be slow; this + change will hand multiple paths at once to git and svn so they + can be added in a batch. + + * Scripts/webkitpy/common/checkout/scm/git.py: + (Git.add_list): + (Git.delete_list): + * Scripts/webkitpy/common/checkout/scm/scm.py: + (SCM.add): + (SCM): + (SCM.add_list): + (SCM.delete): + (SCM.delete_list): + * Scripts/webkitpy/common/checkout/scm/scm_mock.py: + (MockSCM.add): + (MockSCM): + (MockSCM.add_list): + (MockSCM.delete): + (MockSCM.delete_list): + * Scripts/webkitpy/common/checkout/scm/scm_unittest.py: + (_shared_test_exists): + (_shared_test_added_files): + (_test_delete_list): + * Scripts/webkitpy/common/checkout/scm/svn.py: + (SVN.add_list): + (SVN.delete_list): + +2012-05-25 Thiago Marcos P. Santos <thiago.santos@intel.com> + + [NRWT] Add unit testing for perf tests on locked shards + https://bugs.webkit.org/show_bug.cgi?id=87489 + + Reviewed by Dirk Pranke. + + Adding utests that makes sure that perf tests are running in locked + shards and by passing --no-http won't break NRWT (r118421). + + * Scripts/webkitpy/layout_tests/controllers/manager_unittest.py: + (ShardingTests): + (ShardingTests.test_shard_by_dir): + (ShardingTests.test_shard_every_file): + (ShardingTests.test_shard_in_two): + (ShardingTests.test_multiple_locked_shards): + (LockCheckingManager): + (LockCheckingManager.__init__): + (LockCheckingManager.handle_finished_list): + (ManagerTest.test_http_locking): + (ManagerTest): + (ManagerTest.test_perf_locking): + * Scripts/webkitpy/layout_tests/port/test.py: + +2012-05-25 Jessie Berlin <jberlin@apple.com> + + [Win] fast/events/keydown-leftright-keys.html failing since introduction in r118001 + https://bugs.webkit.org/show_bug.cgi?id=87511 + + Reviewed by Alexey Proskuryakov. + + Update the Windows implementation of keyDown to match the Mac one changed in r118001. + + * DumpRenderTree/win/EventSender.cpp: + (keyDownCallback): + +2012-05-25 Ken Buchanan <kenrb@chromium.org> + + Adding Ken Buchanan to committers.py + https://bugs.webkit.org/show_bug.cgi?id=87443 + + Unreviewed. + + Adding self to committers.py as a Committer. + + * Scripts/webkitpy/common/config/committers.py: + 2012-05-25 Csaba Osztrogonác <ossy@webkit.org> [Qt] Buildfix for newer Qt5 diff --git a/Tools/DumpRenderTree/win/DumpRenderTree.vcproj b/Tools/DumpRenderTree/win/DumpRenderTree.vcproj index d22ddfa7d..18137a242 100644 --- a/Tools/DumpRenderTree/win/DumpRenderTree.vcproj +++ b/Tools/DumpRenderTree/win/DumpRenderTree.vcproj @@ -433,6 +433,18 @@ RelativePath=".\LayoutTestControllerWin.cpp" > </File> + <File + RelativePath=".\TextInputController.cpp" + > + </File> + <File + RelativePath=".\TextInputController.h" + > + </File> + <File + RelativePath=".\TextInputControllerWin.cpp" + > + </File> </Filter> <Filter Name="Delegates" diff --git a/Tools/DumpRenderTree/win/EventSender.cpp b/Tools/DumpRenderTree/win/EventSender.cpp index 376c07686..5c0993689 100644 --- a/Tools/DumpRenderTree/win/EventSender.cpp +++ b/Tools/DumpRenderTree/win/EventSender.cpp @@ -475,6 +475,18 @@ static JSValueRef keyDownCallback(JSContextRef context, JSObjectRef function, JS virtualKeyCode = VK_SNAPSHOT; else if (JSStringIsEqualToUTF8CString(character, "menu")) virtualKeyCode = VK_APPS; + else if (JSStringIsEqualToUTF8CString(character, "leftControl")) + virtualKeyCode = VK_LCONTROL; + else if (JSStringIsEqualToUTF8CString(character, "leftShift")) + virtualKeyCode = VK_LSHIFT; + else if (JSStringIsEqualToUTF8CString(character, "leftAlt")) + virtualKeyCode = VK_LMENU; + else if (JSStringIsEqualToUTF8CString(character, "rightControl")) + virtualKeyCode = VK_RCONTROL; + else if (JSStringIsEqualToUTF8CString(character, "rightShift")) + virtualKeyCode = VK_RSHIFT; + else if (JSStringIsEqualToUTF8CString(character, "rightAlt")) + virtualKeyCode = VK_RMENU; else { charCode = JSStringGetCharactersPtr(character)[0]; virtualKeyCode = LOBYTE(VkKeyScan(charCode)); diff --git a/Tools/DumpRenderTree/win/FrameLoadDelegate.cpp b/Tools/DumpRenderTree/win/FrameLoadDelegate.cpp index afc4e5185..dcf5da18c 100644 --- a/Tools/DumpRenderTree/win/FrameLoadDelegate.cpp +++ b/Tools/DumpRenderTree/win/FrameLoadDelegate.cpp @@ -35,6 +35,7 @@ #include "EventSender.h" #include "GCController.h" #include "LayoutTestController.h" +#include "TextInputController.h" #include "WebCoreTestSupport.h" #include "WorkQueueItem.h" #include "WorkQueue.h" @@ -76,6 +77,7 @@ FrameLoadDelegate::FrameLoadDelegate() : m_refCount(1) , m_gcController(adoptPtr(new GCController)) , m_accessibilityController(adoptPtr(new AccessibilityController)) + , m_textInputController(adoptPtr(new TextInputController)) { } @@ -367,6 +369,9 @@ void FrameLoadDelegate::didClearWindowObjectForFrameInStandardWorld(IWebFrame* f m_accessibilityController->makeWindowObject(context, windowObject, &exception); ASSERT(!exception); + m_textInputController->makeWindowObject(context, windowObject, &exception); + ASSERT(!exception); + JSStringRef eventSenderStr = JSStringCreateWithUTF8CString("eventSender"); JSValueRef eventSender = makeEventSender(context, !parentFrame); JSObjectSetProperty(context, windowObject, eventSenderStr, eventSender, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0); diff --git a/Tools/DumpRenderTree/win/FrameLoadDelegate.h b/Tools/DumpRenderTree/win/FrameLoadDelegate.h index 4cd5e1148..c842579f1 100644 --- a/Tools/DumpRenderTree/win/FrameLoadDelegate.h +++ b/Tools/DumpRenderTree/win/FrameLoadDelegate.h @@ -33,6 +33,7 @@ #include <wtf/OwnPtr.h> class AccessibilityController; +class TextInputController; class GCController; class FrameLoadDelegate : public IWebFrameLoadDelegate, public IWebFrameLoadDelegatePrivate2 { @@ -170,6 +171,7 @@ private: ULONG m_refCount; OwnPtr<GCController> m_gcController; OwnPtr<AccessibilityController> m_accessibilityController; + OwnPtr<TextInputController> m_textInputController; }; #endif // FrameLoadDelegate_h diff --git a/Tools/DumpRenderTree/win/TextInputController.cpp b/Tools/DumpRenderTree/win/TextInputController.cpp new file mode 100755 index 000000000..c54dd17de --- /dev/null +++ b/Tools/DumpRenderTree/win/TextInputController.cpp @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2007, 2008, 2009, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2010 Joone Hur <joone@kldp.org> + * + * 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "TextInputController.h" + +#include <JavaScriptCore/JSRetainPtr.h> +#include <wtf/RefPtr.h> + +// Static Functions + +static JSValueRef setMarkedTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 3) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> str(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + double from = JSValueToNumber(context, arguments[1], exception); + ASSERT(!*exception); + + double length = JSValueToNumber(context, arguments[2], exception); + ASSERT(!*exception); + + TextInputController* controller = static_cast<TextInputController*>(JSObjectGetPrivate(thisObject)); + + if (controller) + controller->setMarkedText(str.get(), from, length); + + return JSValueMakeUndefined(context); +} + +static JSValueRef hasMarkedTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + TextInputController* controller = static_cast<TextInputController*>(JSObjectGetPrivate(thisObject)); + + if (controller) + return JSValueMakeBoolean(context, controller->hasMarkedText()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef unmarkTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + TextInputController* controller = static_cast<TextInputController*>(JSObjectGetPrivate(thisObject)); + if (controller) + controller->unmarkText(); + + return JSValueMakeUndefined(context); +} + +static JSValueRef markedRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + TextInputController* controller = static_cast<TextInputController*>(JSObjectGetPrivate(thisObject)); + if (controller) { + vector<int> range = controller->markedRange(); + if (range.size() == 2) { + JSValueRef argumentsArrayValues[] = { JSValueMakeNumber(context, range[0]), JSValueMakeNumber(context, range[1]) }; + JSObjectRef result = JSObjectMakeArray(context, sizeof(argumentsArrayValues) / sizeof(JSValueRef), argumentsArrayValues, exception); + ASSERT(!*exception); + return result; + } + } + + return JSValueMakeUndefined(context); +} + +static JSValueRef insertTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> str(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + TextInputController* controller = static_cast<TextInputController*>(JSObjectGetPrivate(thisObject)); + + if (controller) + controller->insertText(str.get()); + + return JSValueMakeUndefined(context); +} + +static JSValueRef firstRectForCharacterRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 2) + return JSValueMakeUndefined(context); + + double start = JSValueToNumber(context, arguments[0], exception); + ASSERT(!*exception); + + double length = JSValueToNumber(context, arguments[1], exception); + ASSERT(!*exception); + + TextInputController* controller = static_cast<TextInputController*>(JSObjectGetPrivate(thisObject)); + + if (controller) { + vector<int> rect = controller->firstRectForCharacterRange(start, length); + if (rect.size() == 4) { + JSValueRef argumentsArrayValues[] = + { + JSValueMakeNumber(context, rect[0]), + JSValueMakeNumber(context, rect[1]), + JSValueMakeNumber(context, rect[2]), + JSValueMakeNumber(context, rect[3]), + }; + JSObjectRef result = JSObjectMakeArray(context, sizeof(argumentsArrayValues) / sizeof(JSValueRef), argumentsArrayValues, exception); + ASSERT(!*exception); + return result; + } + } + + return JSValueMakeUndefined(context); +} + +static JSValueRef selectedRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + TextInputController* controller = static_cast<TextInputController*>(JSObjectGetPrivate(thisObject)); + + if (controller) { + vector<int> rect = controller->selectedRange(); + if (rect.size() == 2) { + JSValueRef argumentsArrayValues[] = { + JSValueMakeNumber(context, rect[0]), + JSValueMakeNumber(context, rect[1]), + }; + JSObjectRef result = JSObjectMakeArray(context, sizeof(argumentsArrayValues) / sizeof(JSValueRef), argumentsArrayValues, exception); + ASSERT(!*exception); + return result; + } + } + + return JSValueMakeUndefined(context); +} + +// Object Creation + +void TextInputController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception) +{ + JSRetainPtr<JSStringRef> textInputContollerStr(Adopt, JSStringCreateWithUTF8CString("textInputController")); + + JSClassRef classRef = getJSClass(); + JSValueRef textInputContollerObject = JSObjectMake(context, classRef, this); + JSClassRelease(classRef); + + JSObjectSetProperty(context, windowObject, textInputContollerStr.get(), textInputContollerObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception); +} + +JSClassRef TextInputController::getJSClass() +{ + static JSStaticValue* staticValues = TextInputController::staticValues(); + static JSStaticFunction* staticFunctions = TextInputController::staticFunctions(); + static JSClassDefinition classDefinition = + { + 0, kJSClassAttributeNone, "TextInputController", 0, staticValues, staticFunctions, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + return JSClassCreate(&classDefinition); +} + +JSStaticValue* TextInputController::staticValues() +{ + static JSStaticValue staticValues[] = + { + { 0, 0, 0, 0 } + }; + return staticValues; +} + +JSStaticFunction* TextInputController::staticFunctions() +{ + static JSStaticFunction staticFunctions[] = { + { "setMarkedText", setMarkedTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "hasMarkedText", hasMarkedTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "unmarkText", unmarkTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "markedRange", markedRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "insertText", insertTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "firstRectForCharacterRange", firstRectForCharacterRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "selectedRange", selectedRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { 0, 0, 0 } + }; + + return staticFunctions; +} diff --git a/Tools/DumpRenderTree/win/TextInputController.h b/Tools/DumpRenderTree/win/TextInputController.h new file mode 100755 index 000000000..1c28e60ce --- /dev/null +++ b/Tools/DumpRenderTree/win/TextInputController.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2007, 2008, 2009 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 TextInputController_h +#define TextInputController_h + +#include <JavaScriptCore/JSContextRef.h> +#include <JavaScriptCore/JSObjectRef.h> +#include <JavaScriptCore/JSStringRef.h> +#include <JavaScriptCore/JSValueRef.h> +#include <vector> +#include <wtf/PassRefPtr.h> + +using namespace std; + +class TextInputController { +public: + void makeWindowObject(JSContextRef, JSObjectRef windowObject, JSValueRef* exception); + + void setMarkedText(JSStringRef text, unsigned int from, unsigned int length); + bool hasMarkedText(); + void unmarkText(); + vector<int> markedRange(); + void insertText(JSStringRef text); + vector<int> firstRectForCharacterRange(unsigned int start, unsigned int length); + vector<int> selectedRange(); + +private: + static JSClassRef getJSClass(); + static JSStaticValue* staticValues(); + static JSStaticFunction* staticFunctions(); +}; + +#endif // TextInputController_h diff --git a/Tools/DumpRenderTree/win/TextInputControllerWin.cpp b/Tools/DumpRenderTree/win/TextInputControllerWin.cpp new file mode 100755 index 000000000..f4674e5dd --- /dev/null +++ b/Tools/DumpRenderTree/win/TextInputControllerWin.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2009, 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "TextInputController.h" + +#include "DumpRenderTree.h" +#include <WebCore/COMPtr.h> +#include <WebKit/WebKit.h> +#include <comutil.h> +#include <string> + +using namespace std; + +void TextInputController::setMarkedText(JSStringRef text, unsigned int from, unsigned int length) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebViewPrivate> viewPrivate; + if (FAILED(webView->QueryInterface(&viewPrivate))) + return; + + _bstr_t bstr(wstring(JSStringGetCharactersPtr(text), JSStringGetLength(text)).data()); + + viewPrivate->setCompositionForTesting(bstr, from, length); +} + +bool TextInputController::hasMarkedText() +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return false; + + COMPtr<IWebViewPrivate> viewPrivate; + if (FAILED(webView->QueryInterface(&viewPrivate))) + return false; + + BOOL result; + viewPrivate->hasCompositionForTesting(&result); + return result; +} + +void TextInputController::unmarkText() +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebViewPrivate> viewPrivate; + if (FAILED(webView->QueryInterface(&viewPrivate))) + return; + + _bstr_t empty; + viewPrivate->confirmCompositionForTesting(empty); +} + +vector<int> TextInputController::markedRange() +{ + // empty vector + vector<int> result; + + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return result; + + COMPtr<IWebViewPrivate> viewPrivate; + if (FAILED(webView->QueryInterface(&viewPrivate))) + return result; + + unsigned int startPos; + unsigned int length; + if (SUCCEEDED(viewPrivate->compositionRangeForTesting(&startPos, &length))) { + result.resize(2); + result[0] = startPos; + result[1] = length; + } + + return result; +} + +void TextInputController::insertText(JSStringRef text) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebViewPrivate> viewPrivate; + if (FAILED(webView->QueryInterface(&viewPrivate))) + return; + + _bstr_t bstr(wstring(JSStringGetCharactersPtr(text), JSStringGetLength(text)).data()); + + viewPrivate->confirmCompositionForTesting(bstr); +} + +vector<int> TextInputController::firstRectForCharacterRange(unsigned int start, unsigned int length) +{ + // empty vector + vector<int> result; + + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return result; + + COMPtr<IWebViewPrivate> viewPrivate; + if (FAILED(webView->QueryInterface(&viewPrivate))) + return result; + + RECT resultRECT; + if SUCCEEDED(viewPrivate->firstRectForCharacterRangeForTesting(start, length, &resultRECT)) { + result.resize(4); + result[0] = resultRECT.left; + result[1] = resultRECT.top; + result[2] = resultRECT.right - resultRECT.left; + result[3] = resultRECT.bottom - resultRECT.top; + } + + return result; +} + +vector<int> TextInputController::selectedRange() +{ + // empty vector + vector<int> result; + + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return result; + + COMPtr<IWebViewPrivate> viewPrivate; + if (FAILED(webView->QueryInterface(&viewPrivate))) + return result; + + unsigned int startPos; + unsigned int length; + if (SUCCEEDED(viewPrivate->selectedRangeForTesting(&startPos, &length))) { + result.resize(2); + result[0] = startPos; + result[1] = length; + } + + return result; +} diff --git a/Tools/Scripts/webkitpy/common/checkout/scm/git.py b/Tools/Scripts/webkitpy/common/checkout/scm/git.py index c7dbd7ca1..43fdb9c00 100644 --- a/Tools/Scripts/webkitpy/common/checkout/scm/git.py +++ b/Tools/Scripts/webkitpy/common/checkout/scm/git.py @@ -160,11 +160,11 @@ class Git(SCM, SVNRepository): def _status_regexp(self, expected_types): return '^(?P<status>[%s])\t(?P<filename>.+)$' % expected_types - def add(self, path, return_exit_code=False): - return self.run(["git", "add", path], return_exit_code=return_exit_code) + def add_list(self, paths, return_exit_code=False): + return self.run(["git", "add"] + paths, return_exit_code=return_exit_code) - def delete(self, path): - return self.run(["git", "rm", "-f", path]) + def delete_list(self, paths): + return self.run(["git", "rm", "-f"] + paths) def exists(self, path): return_code = self.run(["git", "show", "HEAD:%s" % path], return_exit_code=True, decode_output=False) diff --git a/Tools/Scripts/webkitpy/common/checkout/scm/scm.py b/Tools/Scripts/webkitpy/common/checkout/scm/scm.py index 9ff9e5f77..6b6e6fcf0 100644 --- a/Tools/Scripts/webkitpy/common/checkout/scm/scm.py +++ b/Tools/Scripts/webkitpy/common/checkout/scm/scm.py @@ -154,9 +154,15 @@ class SCM: self._subclass_must_implement() def add(self, path, return_exit_code=False): + self.add_list([path], return_exit_code) + + def add_list(self, paths, return_exit_code=False): self._subclass_must_implement() def delete(self, path): + self.delete_list([path]) + + def delete_list(self, paths): self._subclass_must_implement() def exists(self, path): diff --git a/Tools/Scripts/webkitpy/common/checkout/scm/scm_mock.py b/Tools/Scripts/webkitpy/common/checkout/scm/scm_mock.py index f203cfa1a..8b6c76499 100644 --- a/Tools/Scripts/webkitpy/common/checkout/scm/scm_mock.py +++ b/Tools/Scripts/webkitpy/common/checkout/scm/scm_mock.py @@ -38,7 +38,10 @@ class MockSCM(object): self._executive = executive or MockExecutive() def add(self, destination_path, return_exit_code=False): - self.added_paths.add(destination_path) + self.add_list([destination_path], return_exit_code) + + def add_list(self, destination_paths, return_exit_code=False): + self.added_paths.update(set(destination_paths)) if return_exit_code: return 0 @@ -111,7 +114,11 @@ class MockSCM(object): return "49824" def delete(self, path): + return self.delete_list([path]) + + def delete_list(self, paths): if not self._filesystem: return - if self._filesystem.exists(path): - self._filesystem.remove(path) + for path in paths: + if self._filesystem.exists(path): + self._filesystem.remove(path) diff --git a/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py b/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py index 7ce714a19..802fe2cee 100644 --- a/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py +++ b/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py @@ -315,6 +315,10 @@ class SCMTest(unittest.TestCase): write_into_file_at_path("added_file", "new stuff") self.scm.add("added_file") + write_into_file_at_path("added_file3", "more new stuff") + write_into_file_at_path("added_file4", "more new stuff") + self.scm.add_list(["added_file3", "added_file4"]) + os.mkdir("added_dir") write_into_file_at_path("added_dir/added_file2", "new stuff") self.scm.add("added_dir") @@ -323,12 +327,14 @@ class SCMTest(unittest.TestCase): added_files = self.scm.added_files() if "added_dir" in added_files: added_files.remove("added_dir") - self.assertEqual(added_files, ["added_dir/added_file2", "added_file"]) + self.assertEqual(added_files, ["added_dir/added_file2", "added_file", "added_file3", "added_file4"]) # Test also to make sure clean_working_directory removes added files self.scm.clean_working_directory() self.assertEqual(self.scm.added_files(), []) self.assertFalse(os.path.exists("added_file")) + self.assertFalse(os.path.exists("added_file3")) + self.assertFalse(os.path.exists("added_file4")) self.assertFalse(os.path.exists("added_dir")) def _shared_test_changed_files_for_revision(self): @@ -820,6 +826,12 @@ END self.scm.delete("test_file") self.assertTrue("test_file" in self.scm.deleted_files()) + def test_delete_list(self): + os.chdir(self.svn_checkout_path) + self.scm.delete_list(["test_file", "test_file2"]) + self.assertTrue("test_file" in self.scm.deleted_files()) + self.assertTrue("test_file2" in self.scm.deleted_files()) + def test_delete_recursively(self): self._shared_test_delete_recursively() @@ -1172,7 +1184,7 @@ class GitSVNTest(SCMTest): def _two_local_commits(self): self._one_local_commit() - self._second_local_commt() + self._second_local_commit() def _three_local_commits(self): self._local_commit('test_file_commit0', 'more test content', 'another test commit') @@ -1517,6 +1529,12 @@ class GitSVNTest(SCMTest): self.scm.delete('test_file_commit1') self.assertTrue("test_file_commit1" in self.scm.deleted_files()) + def test_delete_list(self): + self._two_local_commits() + self.scm.delete_list(["test_file_commit1", "test_file_commit2"]) + self.assertTrue("test_file_commit1" in self.scm.deleted_files()) + self.assertTrue("test_file_commit2" in self.scm.deleted_files()) + def test_delete_recursively(self): self._shared_test_delete_recursively() diff --git a/Tools/Scripts/webkitpy/common/checkout/scm/svn.py b/Tools/Scripts/webkitpy/common/checkout/scm/svn.py index 6a2e1319b..3c269175c 100644 --- a/Tools/Scripts/webkitpy/common/checkout/scm/svn.py +++ b/Tools/Scripts/webkitpy/common/checkout/scm/svn.py @@ -178,9 +178,10 @@ class SVN(SCM, SVNRepository): self._add_parent_directories(dirname) self.add(path) - def add(self, path, return_exit_code=False): - self._add_parent_directories(os.path.dirname(os.path.abspath(path))) - return self._run_svn(["add", path], return_exit_code=return_exit_code) + def add_list(self, paths, return_exit_code=False): + for path in paths: + self._add_parent_directories(os.path.dirname(os.path.abspath(path))) + return self._run_svn(["add"] + paths, return_exit_code=return_exit_code) def _delete_parent_directories(self, path): if not self.in_working_directory(path): @@ -192,11 +193,12 @@ class SVN(SCM, SVNRepository): if dirname != path: self._delete_parent_directories(dirname) - def delete(self, path): - abs_path = os.path.abspath(path) - parent, base = os.path.split(abs_path) - result = self._run_svn(["delete", "--force", base], cwd=parent) - self._delete_parent_directories(os.path.dirname(abs_path)) + def delete_list(self, paths): + for path in paths: + abs_path = os.path.abspath(path) + parent, base = os.path.split(abs_path) + result = self._run_svn(["delete", "--force", base], cwd=parent) + self._delete_parent_directories(os.path.dirname(abs_path)) return result def exists(self, path): diff --git a/Tools/Scripts/webkitpy/common/config/committers.py b/Tools/Scripts/webkitpy/common/config/committers.py index 5a3656482..3f99eaddc 100644 --- a/Tools/Scripts/webkitpy/common/config/committers.py +++ b/Tools/Scripts/webkitpy/common/config/committers.py @@ -122,7 +122,6 @@ contributors_who_are_not_committers = [ Contributor("Brian Salomon", "bsalomon@google.com"), Contributor("Commit Queue", "commit-queue@webkit.org"), Contributor("Daniel Sievers", "sievers@chromium.org"), - Contributor("Dave Barton", "dbarton@mathscribe.com"), Contributor("Dave Tharp", "dtharp@codeaurora.org", "dtharp"), Contributor("David Barr", "davidbarr@chromium.org", "barrbrain"), Contributor("David Dorwin", "ddorwin@chromium.org", "ddorwin"), @@ -222,6 +221,7 @@ committers_unable_to_review = [ Committer("Dan Winship", "danw@gnome.org", "danw"), Committer("Dana Jansens", "danakj@chromium.org", "danakj"), Committer("Daniel Cheng", "dcheng@chromium.org", "dcheng"), + Committer("Dave Barton", "dbarton@mathscribe.com", "dbarton"), Committer("David Grogan", ["dgrogan@chromium.org", "dgrogan@google.com"], "dgrogan"), Committer("David Smith", ["catfish.man@gmail.com", "dsmith@webkit.org"], "catfishman"), Committer("Diego Gonzalez", ["diegohcg@webkit.org", "diego.gonzalez@openbossa.org"], "diegohcg"), @@ -287,6 +287,7 @@ committers_unable_to_review = [ Committer("Kaustubh Atrawalkar", ["kaustubh@motorola.com"], "silverroots"), Committer("Keishi Hattori", "keishi@webkit.org", "keishi"), Committer("Kelly Norton", "knorton@google.com"), + Committer("Ken Buchanan", "kenrb@chromium.org", "kenrb"), Committer("Kenichi Ishibashi", "bashi@chromium.org", "bashi"), Committer("Kenji Imasaki", "imasaki@chromium.org", "imasaki"), Committer("Kent Hansen", "kent.hansen@nokia.com", "khansen"), diff --git a/Tools/Scripts/webkitpy/common/config/watchlist b/Tools/Scripts/webkitpy/common/config/watchlist index bd26b2787..ca7b72578 100755 --- a/Tools/Scripts/webkitpy/common/config/watchlist +++ b/Tools/Scripts/webkitpy/common/config/watchlist @@ -154,6 +154,9 @@ }, "Media": { "filename": r"(Source|LayoutTests)/.*([Mm]edia|[Aa]udio|[Vv]ideo)", + }, + "MathML": { + "filename": r"(Source|LayoutTests|Websites)/.*mathml", } }, "CC_RULES": { @@ -173,6 +176,7 @@ "GStreamerGraphics": [ "alexis.menard@openbossa.org", "pnormand@igalia.com", "gns@gnome.org", "mrobinson@webkit.org" ], "GtkWebKit2PublicAPI": [ "cgarcia@igalia.com", "gns@gnome.org", "mrobinson@webkit.org" ], "Loader": [ "japhet@chromium.org" ], + "MathML": [ "dbarton@mathscribe.com" ], "Media": [ "feature-media-reviews@chromium.org", "eric.carlson@apple.com" ], "QtBuildSystem" : [ "vestbo@webkit.org", ], "QtWebKit2PlatformSpecific": [ "alexis.menard@openbossa.org", "zoltan@webkit.org", "cmarcelo@webkit.org" ], diff --git a/Tools/Scripts/webkitpy/layout_tests/controllers/manager_unittest.py b/Tools/Scripts/webkitpy/layout_tests/controllers/manager_unittest.py index a58aac940..63e18ac8a 100644 --- a/Tools/Scripts/webkitpy/layout_tests/controllers/manager_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/controllers/manager_unittest.py @@ -73,6 +73,7 @@ class ShardingTests(unittest.TestCase): "dom/html/level2/html/HTMLAnchorElement03.html", "ietestcenter/Javascript/11.1.5_4-4-c-1.html", "dom/html/level2/html/HTMLAnchorElement06.html", + "perf/object-keys.html", ] def get_shards(self, num_workers, fully_parallel, test_list=None, max_locked_shards=None): @@ -95,7 +96,8 @@ class ShardingTests(unittest.TestCase): ['http/tests/security/view-source-no-refresh.html', 'http/tests/websocket/tests/unicode.htm', 'http/tests/websocket/tests/websocket-protocol-ignored.html', - 'http/tests/xmlhttprequest/supported-xml-content-types.html'])]) + 'http/tests/xmlhttprequest/supported-xml-content-types.html', + 'perf/object-keys.html'])]) self.assertEquals(unlocked, [TestShard('animations', ['animations/keyframes.html']), @@ -113,7 +115,8 @@ class ShardingTests(unittest.TestCase): [TestShard('.', ['http/tests/websocket/tests/unicode.htm']), TestShard('.', ['http/tests/security/view-source-no-refresh.html']), TestShard('.', ['http/tests/websocket/tests/websocket-protocol-ignored.html']), - TestShard('.', ['http/tests/xmlhttprequest/supported-xml-content-types.html'])]) + TestShard('.', ['http/tests/xmlhttprequest/supported-xml-content-types.html']), + TestShard('.', ['perf/object-keys.html'])]), self.assertEquals(unlocked, [TestShard('.', ['animations/keyframes.html']), TestShard('.', ['fast/css/display-none-inline-style-change-crash.html']), @@ -128,7 +131,8 @@ class ShardingTests(unittest.TestCase): ['http/tests/websocket/tests/unicode.htm', 'http/tests/security/view-source-no-refresh.html', 'http/tests/websocket/tests/websocket-protocol-ignored.html', - 'http/tests/xmlhttprequest/supported-xml-content-types.html'])]) + 'http/tests/xmlhttprequest/supported-xml-content-types.html', + 'perf/object-keys.html'])]) self.assertEquals(unlocked, [TestShard('unlocked_tests', ['animations/keyframes.html', @@ -157,7 +161,8 @@ class ShardingTests(unittest.TestCase): 'http/tests/websocket/tests/unicode.htm', 'http/tests/websocket/tests/websocket-protocol-ignored.html']), TestShard('locked_shard_2', - ['http/tests/xmlhttprequest/supported-xml-content-types.html'])]) + ['http/tests/xmlhttprequest/supported-xml-content-types.html', + 'perf/object-keys.html'])]) locked, unlocked = self.get_shards(num_workers=4, fully_parallel=False) self.assertEquals(locked, @@ -165,7 +170,29 @@ class ShardingTests(unittest.TestCase): ['http/tests/security/view-source-no-refresh.html', 'http/tests/websocket/tests/unicode.htm', 'http/tests/websocket/tests/websocket-protocol-ignored.html', - 'http/tests/xmlhttprequest/supported-xml-content-types.html'])]) + 'http/tests/xmlhttprequest/supported-xml-content-types.html', + 'perf/object-keys.html'])]) + + +class LockCheckingManager(Manager): + def __init__(self, port, options, printer, tester, http_lock): + super(LockCheckingManager, self).__init__(port, options, printer) + self._finished_list_called = False + self._tester = tester + self._should_have_http_lock = http_lock + + def handle_finished_list(self, source, list_name, num_tests, elapsed_time): + if not self._finished_list_called: + self._tester.assertEquals(list_name, 'locked_tests') + self._tester.assertTrue(self._remaining_locked_shards) + self._tester.assertTrue(self._has_http_lock is self._should_have_http_lock) + + super(LockCheckingManager, self).handle_finished_list(source, list_name, num_tests, elapsed_time) + + if not self._finished_list_called: + self._tester.assertEquals(self._remaining_locked_shards, []) + self._tester.assertFalse(self._has_http_lock) + self._finished_list_called = True class ManagerTest(unittest.TestCase): @@ -192,30 +219,25 @@ class ManagerTest(unittest.TestCase): self.assertTrue('Baseline search path: test-mac-leopard -> test-mac-snowleopard -> generic' in printer.output) def test_http_locking(tester): - class LockCheckingManager(Manager): - def __init__(self, port, options, printer): - super(LockCheckingManager, self).__init__(port, options, printer) - self._finished_list_called = False - - def handle_finished_list(self, source, list_name, num_tests, elapsed_time): - if not self._finished_list_called: - tester.assertEquals(list_name, 'locked_tests') - tester.assertTrue(self._remaining_locked_shards) - tester.assertTrue(self._has_http_lock) - - super(LockCheckingManager, self).handle_finished_list(source, list_name, num_tests, elapsed_time) - - if not self._finished_list_called: - tester.assertEquals(self._remaining_locked_shards, []) - tester.assertFalse(self._has_http_lock) - self._finished_list_called = True - options, args = run_webkit_tests.parse_args(['--platform=test', '--print=nothing', 'http/tests/passes', 'passes']) host = MockHost() port = host.port_factory.get(port_name=options.platform, options=options) run_webkit_tests._set_up_derived_options(port, options) printer = printing.Printer(port, options, StringIO.StringIO(), StringIO.StringIO()) - manager = LockCheckingManager(port, options, printer) + manager = LockCheckingManager(port, options, printer, tester, True) + manager.collect_tests(args) + manager.parse_expectations() + num_unexpected_results = manager.run() + printer.cleanup() + tester.assertEquals(num_unexpected_results, 0) + + def test_perf_locking(tester): + options, args = run_webkit_tests.parse_args(['--platform=test', '--print=nothing', '--no-http', 'passes', 'perf/']) + host = MockHost() + port = host.port_factory.get(port_name=options.platform, options=options) + run_webkit_tests._set_up_derived_options(port, options) + printer = printing.Printer(port, options, StringIO.StringIO(), StringIO.StringIO()) + manager = LockCheckingManager(port, options, printer, tester, False) manager.collect_tests(args) manager.parse_expectations() num_unexpected_results = manager.run() diff --git a/Tools/Scripts/webkitpy/layout_tests/port/mac.py b/Tools/Scripts/webkitpy/layout_tests/port/mac.py index 9513ae5bd..855217682 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/mac.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/mac.py @@ -1,4 +1,5 @@ # Copyright (C) 2011 Google Inc. All rights reserved. +# Copyright (C) 2012 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 @@ -239,3 +240,10 @@ class MacPort(ApplePort): _log.debug("IOError raised while stopping helper: %s" % str(e)) pass self._helper = None + + def nm_command(self): + try: + return self._executive.run_command(['xcrun', '-find', 'nm']).rstrip() + except ScriptError, e: + _log.warn("xcrun failed; falling back to 'nm'.") + return 'nm' diff --git a/Tools/Scripts/webkitpy/layout_tests/port/test.py b/Tools/Scripts/webkitpy/layout_tests/port/test.py index d2e64b6db..8abd81235 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/test.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/test.py @@ -222,6 +222,10 @@ layer at (0,0) size 800x34 tests.add('platform/test-snow-leopard/http/test.html') tests.add('platform/test-snow-leopard/websocket/test.html') + # For testing if perf tests are running in a locked shard. + tests.add('perf/foo/test.html') + tests.add('perf/foo/test-ref.html') + return tests diff --git a/Tools/Scripts/webkitpy/layout_tests/port/webkit.py b/Tools/Scripts/webkitpy/layout_tests/port/webkit.py index 0965b44a4..d798039ac 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/webkit.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/webkit.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # Copyright (C) 2010 Google Inc. All rights reserved. # Copyright (C) 2010 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>, University of Szeged -# Copyright (C) 2011 Apple Inc. All rights reserved. +# Copyright (C) 2011, 2012 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 @@ -262,12 +262,15 @@ class WebKitPort(Port): """If a port makes certain features available only through runtime flags, it can override this routine to indicate which ones are available.""" return None + def nm_command(self): + return 'nm' + def _webcore_symbols_string(self): webcore_library_path = self._path_to_webcore_library() if not webcore_library_path: return None try: - return self._executive.run_command(['nm', webcore_library_path], error_handler=Executive.ignore_error) + return self._executive.run_command([self.nm_command(), webcore_library_path], error_handler=Executive.ignore_error) except OSError, e: _log.warn("Failed to run nm: %s. Can't determine WebCore supported features." % e) return None |
