Source/WebCore/ChangeLog

 12012-01-24 Adam Klein <adamk@chromium.org>
 2
 3 Add JSC support for delivering mutations when the outermost script context exits
 4 https://bugs.webkit.org/show_bug.cgi?id=70289
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 The meat of this change is in JSMainThreadExecState, where a counter
 9 is incremented every time WebCore calls into JSC and decremented every
 10 time it returns. When the counter reaches zero, any pending mutations
 11 are delivered (this mirrors very similar code in V8Proxy and V8RecursionScope).
 12
 13 The rest of the changes are of two sorts: compilation/logic fixes for
 14 JSC code when ENABLE(MUTATION_OBSERVERS) is true, and additional
 15 usages of JSMainThreadExecState so as to trigger the above
 16 increment/decrements at the appropriate times.
 17
 18 * bindings/js/JSCustomXPathNSResolver.cpp:
 19 (WebCore::JSCustomXPathNSResolver::lookupNamespaceURI):
 20 Use JSMainThreadExecState instead of JSC::call.
 21 * bindings/js/JSDictionary.cpp:
 22 (WebCore::JSDictionary::convertValue): Add support
 23 for tryGetProperty with a HashMap<AtomicString>.
 24 * bindings/js/JSDictionary.h:
 25 * bindings/js/JSErrorHandler.cpp:
 26 (WebCore::JSErrorHandler::handleEvent):
 27 Use JSMainThreadExecState instead of JSC::call.
 28 * bindings/js/JSHTMLDocumentCustom.cpp:
 29 (WebCore::JSHTMLDocument::open):
 30 Use JSMainThreadExecState instead of JSC::call.
 31 * bindings/js/JSMainThreadExecState.cpp:
 32 (WebCore::JSMainThreadExecState::didLeaveScriptContext):
 33 * bindings/js/JSMainThreadExecState.h:
 34 (WebCore::JSMainThreadExecState::JSMainThreadExecState):
 35 Increment a static recursion level counter.
 36 (WebCore::JSMainThreadExecState::~JSMainThreadExecState):
 37 Decrement a static recursion level counter and, if we are
 38 at zero (the outermost script invocation), deliver any
 39 outstanding mutation records.
 40 * bindings/js/JSNodeFilterCondition.cpp:
 41 (WebCore::JSNodeFilterCondition::acceptNode):
 42 Use JSMainThreadExecState instead of JSC::call.
 43 * bindings/js/JSWebKitMutationObserverCustom.cpp:
 44 (WebCore::JSWebKitMutationObserver::observe):
 45 Fix JSDictionary logic, add support for attributeFilter.
 46
1472012-01-23 Xianzhu Wang <wangxianzhu@chromium.org>
248
349 Basic enhancements to StringBuilder

Source/WebCore/bindings/js/JSCustomXPathNSResolver.cpp

3131#include "ExceptionCode.h"
3232#include "Frame.h"
3333#include "JSDOMWindowCustom.h"
 34#include "JSMainThreadExecState.h"
3435#include "SecurityOrigin.h"
3536#include <runtime/JSLock.h>
3637

@@String JSCustomXPathNSResolver::lookupNamespaceURI(const String& prefix)
8990 args.append(jsString(exec, prefix));
9091
9192 m_globalObject->globalData().timeoutChecker.start();
92  JSValue retval = JSC::call(exec, function, callType, callData, m_customResolver, args);
 93 JSValue retval = JSMainThreadExecState::call(exec, function, callType, callData, m_customResolver, args);
9394 m_globalObject->globalData().timeoutChecker.stop();
9495
9596 String result;

Source/WebCore/bindings/js/JSDictionary.cpp

3434#include "JSTrackCustom.h"
3535#include "SerializedScriptValue.h"
3636#include "ScriptValue.h"
 37#include <wtf/HashMap.h>
3738#include <wtf/MathExtras.h>
 39#include <wtf/text/AtomicString.h>
3840
3941using namespace JSC;
4042

@@void JSDictionary::convertValue(ExecState*, JSValue value, RefPtr<TrackBase>& re
136138}
137139#endif
138140
 141#if ENABLE(MUTATION_OBSERVERS)
 142void JSDictionary::convertValue(ExecState* exec, JSValue value, HashSet<AtomicString>& result)
 143{
 144 result.clear();
 145
 146 if (value.isUndefinedOrNull())
 147 return;
 148
 149 unsigned length;
 150 JSObject* object = toJSSequence(exec, value, length);
 151 if (exec->hadException())
 152 return;
 153
 154 for (unsigned i = 0 ; i < length; ++i) {
 155 JSValue itemValue = object->get(exec, i);
 156 if (exec->hadException())
 157 return;
 158 result.add(ustringToAtomicString(itemValue.toString(exec)));
 159 }
 160}
 161#endif
 162
139163} // namespace WebCore

Source/WebCore/bindings/js/JSDictionary.h

@@private:
8787#if ENABLE(VIDEO_TRACK)
8888 static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<TrackBase>& result);
8989#endif
 90#if ENABLE(MUTATION_OBSERVERS)
 91 static void convertValue(JSC::ExecState*, JSC::JSValue, HashSet<AtomicString>& result);
 92#endif
9093
9194 JSC::ExecState* m_exec;
9295 JSC::JSObject* m_initializerObject;

Source/WebCore/bindings/js/JSErrorHandler.cpp

3636#include "Event.h"
3737#include "EventNames.h"
3838#include "JSEvent.h"
 39#include "JSMainThreadExecState.h"
3940#include <runtime/JSLock.h>
4041
4142using namespace JSC;

@@void JSErrorHandler::handleEvent(ScriptExecutionContext* scriptExecutionContext,
9495 JSValue thisValue = globalObject->methodTable()->toThisObject(globalObject, exec);
9596
9697 globalData.timeoutChecker.start();
97  JSValue returnValue = JSC::call(exec, jsFunction, callType, callData, thisValue, args);
 98 JSValue returnValue = scriptExecutionContext->isDocument()
 99 ? JSMainThreadExecState::call(exec, jsFunction, callType, callData, thisValue, args)
 100 : JSC::call(exec, jsFunction, callType, callData, thisValue, args);
98101 globalData.timeoutChecker.stop();
99102
100103 globalObject->setCurrentEvent(savedEvent);

Source/WebCore/bindings/js/JSHTMLDocumentCustom.cpp

3838#include "JSDOMWindowCustom.h"
3939#include "JSDOMWindowShell.h"
4040#include "JSHTMLCollection.h"
 41#include "JSMainThreadExecState.h"
4142#include "SegmentedString.h"
4243#include "DocumentParser.h"
4344#include <runtime/Error.h>

@@JSValue JSHTMLDocument::open(ExecState* exec)
113114 CallType callType = ::getCallData(function, callData);
114115 if (callType == CallTypeNone)
115116 return throwTypeError(exec);
116  return JSC::call(exec, function, callType, callData, wrapper, ArgList(exec));
 117 return JSMainThreadExecState::call(exec, function, callType, callData, wrapper, ArgList(exec));
117118 }
118119 }
119120 return jsUndefined();

Source/WebCore/bindings/js/JSMainThreadExecState.cpp

2525
2626#include "config.h"
2727#include "JSMainThreadExecState.h"
 28#include "WebKitMutationObserver.h"
2829
2930namespace WebCore {
3031
3132JSC::ExecState* JSMainThreadExecState::s_mainThreadState = 0;
3233
 34#if ENABLE(MUTATION_OBSERVERS)
 35int JSMainThreadExecState::s_recursionLevel = 0;
 36
 37void JSMainThreadExecState::didLeaveScriptContext()
 38{
 39 WebKitMutationObserver::deliverAllMutations();
 40}
 41#endif
 42
3343} // namespace WebCore

Source/WebCore/bindings/js/JSMainThreadExecState.h

@@protected:
6464 {
6565 ASSERT(isMainThread());
6666 s_mainThreadState = exec;
 67
 68#if ENABLE(MUTATION_OBSERVERS)
 69 ASSERT(s_recursionLevel >= 0);
 70 ++s_recursionLevel;
 71#endif
6772 };
68 
 73
6974 ~JSMainThreadExecState()
7075 {
7176 ASSERT(isMainThread());
7277 s_mainThreadState = m_previousState;
 78
 79#if ENABLE(MUTATION_OBSERVERS)
 80 ASSERT(s_recursionLevel > 0);
 81 if (!--s_recursionLevel)
 82 didLeaveScriptContext();
 83#endif
7384 }
7485
7586private:
7687 static JSC::ExecState* s_mainThreadState;
7788 JSC::ExecState* m_previousState;
 89
 90#if ENABLE(MUTATION_OBSERVERS)
 91 static void didLeaveScriptContext();
 92 static int s_recursionLevel;
 93#endif
7894};
7995
8096// Null state prevents origin security checks.

Source/WebCore/bindings/js/JSNodeFilterCondition.cpp

2020#include "config.h"
2121#include "JSNodeFilterCondition.h"
2222
 23#include "JSMainThreadExecState.h"
2324#include "JSNode.h"
2425#include "JSNodeFilter.h"
2526#include "NodeFilter.h"

@@short JSNodeFilterCondition::acceptNode(JSC::ExecState* exec, Node* filterNode)
7273 if (exec->hadException())
7374 return NodeFilter::FILTER_REJECT;
7475
75  JSValue result = JSC::call(exec, function, callType, callData, m_filter.get(), args);
 76 JSValue result = JSMainThreadExecState::call(exec, function, callType, callData, m_filter.get(), args);
7677 if (exec->hadException())
7778 return NodeFilter::FILTER_REJECT;
7879

Source/WebCore/bindings/js/JSWebKitMutationObserverCustom.cpp

4141#include "Node.h"
4242#include "WebKitMutationObserver.h"
4343#include <runtime/Error.h>
 44#include <wtf/HashSet.h>
 45#include <wtf/text/AtomicString.h>
4446
4547using namespace JSC;
4648

@@EncodedJSValue JSC_HOST_CALL JSWebKitMutationObserverConstructor::constructJSWeb
6264 return JSValue::encode(asObject(toJS(exec, jsConstructor->globalObject(), WebKitMutationObserver::create(callback.release()))));
6365}
6466
 67struct BooleanOption {
 68 const char* name;
 69 MutationObserverOptions value;
 70};
 71
 72static const BooleanOption booleanOptions[] = {
 73 { "childList", WebKitMutationObserver::ChildList },
 74 { "attributes", WebKitMutationObserver::Attributes },
 75 { "characterData", WebKitMutationObserver::CharacterData },
 76 { "subtree", WebKitMutationObserver::Subtree },
 77 { "attributeOldValue", WebKitMutationObserver::AttributeOldValue },
 78 { "characterDataOldValue", WebKitMutationObserver::CharacterDataOldValue }
 79};
 80
 81static const size_t numBooleanOptions = sizeof(booleanOptions) / sizeof(BooleanOption);
 82
6583JSValue JSWebKitMutationObserver::observe(ExecState* exec)
6684{
6785 if (exec->argumentCount() < 2)

@@JSValue JSWebKitMutationObserver::observe(ExecState* exec)
7896
7997 JSDictionary dictionary(exec, optionsObject);
8098 MutationObserverOptions options = 0;
81  // FIXME: Add support for parsing of the attributeFilter option.
82  bool option;
83  if (dictionary.tryGetProperty("childList", option) && option)
84  options |= WebKitMutationObserver::ChildList;
85  if (dictionary.tryGetProperty("attributes", option) && option)
86  options |= WebKitMutationObserver::Attributes;
87  if (dictionary.tryGetProperty("subtree", option) && option)
88  options |= WebKitMutationObserver::Subtree;
89  if (dictionary.tryGetProperty("attributeOldValue", option) && option)
90  options |= WebKitMutationObserver::AttributeOldValue;
91  if (dictionary.tryGetProperty("characterDataOldValue", option) && option)
92  options |= WebKitMutationObserver::CharacterDataOldValue;
 99 for (unsigned i = 0; i < numBooleanOptions; ++i) {
 100 bool option = false;
 101 if (!dictionary.tryGetProperty(booleanOptions[i].name, option))
 102 return jsUndefined();
 103 if (option)
 104 options |= booleanOptions[i].value;
 105 }
93106
94  if (exec->hadException())
 107 HashSet<AtomicString> attributeFilter;
 108 if (!dictionary.tryGetProperty("attributeFilter", attributeFilter))
95109 return jsUndefined();
 110 if (!attributeFilter.isEmpty())
 111 options |= WebKitMutationObserver::AttributeFilter;
96112
97113 ExceptionCode ec = 0;
98  impl()->observe(target, options, ec);
 114 impl()->observe(target, options, attributeFilter, ec);
99115 if (ec)
100116 setDOMException(exec, ec);
101117 return jsUndefined();

Tools/ChangeLog

 12012-01-24 Adam Klein <adamk@chromium.org>
 2
 3 Add JSC support for delivering mutations when the outermost script context exits
 4 https://bugs.webkit.org/show_bug.cgi?id=70289
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 * DumpRenderTree/mac/EventSendingController.mm: Add support for
 9 eventSender.scheduleAsynchronousKeyDown.
 10 (+[EventSendingController isSelectorExcludedFromWebScript:]):
 11 (+[EventSendingController webScriptNameForSelector:]):
 12 (-[EventSendingController keyDownWrapper:withModifiers:withLocation:]):
 13 (-[EventSendingController scheduleAsynchronousKeyDown:withModifiers:withLocation:]):
 14 * Scripts/build-webkit: Properly alphabetize --mutation-observers in the --help output.
 15
1162012-01-23 Xianzhu Wang <wangxianzhu@chromium.org>
217
318 Basic enhancements to StringBuilder

Tools/DumpRenderTree/mac/EventSendingController.mm

@@BOOL replayingSavedEvents;
131131 || aSelector == @selector(mouseMoveToX:Y:)
132132 || aSelector == @selector(mouseUp:withModifiers:)
133133 || aSelector == @selector(scheduleAsynchronousClick)
 134 || aSelector == @selector(scheduleAsynchronousKeyDown:withModifiers:withLocation:)
134135 || aSelector == @selector(textZoomIn)
135136 || aSelector == @selector(textZoomOut)
136137 || aSelector == @selector(zoomPageIn)

@@BOOL replayingSavedEvents;
161162 return @"fireKeyboardEventsToElement";
162163 if (aSelector == @selector(keyDown:withModifiers:withLocation:))
163164 return @"keyDown";
 165 if (aSelector == @selector(scheduleAsynchronousKeyDown:withModifiers:withLocation:))
 166 return @"scheduleAsynchronousKeyDown";
164167 if (aSelector == @selector(leapForward:))
165168 return @"leapForward";
166169 if (aSelector == @selector(mouseDown:withModifiers:))

@@static int buildModifierFlags(const WebScriptObject* modifiers)
718721 [[[[mainFrame webView] window] firstResponder] keyUp:event];
719722}
720723
 724- (void)keyDownWrapper:(NSString *)character withModifiers:(WebScriptObject *)modifiers withLocation:(unsigned long)keyLocation
 725{
 726 [self keyDown:character withModifiers:modifiers withLocation:keyLocation];
 727 [character release];
 728 [modifiers release];
 729}
 730
 731- (void)scheduleAsynchronousKeyDown:(NSString *)character withModifiers:(WebScriptObject *)modifiers withLocation:(unsigned long)keyLocation
 732{
 733 NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[EventSendingController instanceMethodSignatureForSelector:@selector(keyDownWrapper:withModifiers:withLocation:)]];
 734 [invocation retainArguments];
 735 [invocation setTarget:self];
 736 [invocation setSelector:@selector(keyDownWrapper:withModifiers:withLocation:)];
 737 [invocation setArgument:&character atIndex:2];
 738 [invocation setArgument:&modifiers atIndex:3];
 739 [invocation setArgument:&keyLocation atIndex:4];
 740 [invocation performSelector:@selector(invoke) withObject:nil afterDelay:0];
 741}
 742
721743- (void)enableDOMUIEventLogging:(WebScriptObject *)node
722744{
723745 NSEnumerator *eventEnumerator = [webkitDomEventNames objectEnumerator];

Tools/Scripts/build-webkit

@@my @features = (
194194 { option => "directory-upload", desc => "Toogle Directory upload support",
195195 define => "ENABLE_DIRECTORY_UPLOAD", default => 0, value => \$directoryUploadSupport },
196196
197  { option => "mutation-observers", desc => "Toggle DOM mutation observer support",
198  define => "ENABLE_MUTATION_OBSERVERS", default => 0, value => \$mutationObserversSupport },
199 
200197 { option => "file-system", desc => "Toggle FileSystem support",
201198 define => "ENABLE_FILE_SYSTEM", default => 0, value => \$fileSystemSupport },
202199

@@my @features = (
272269 { option => "microdata", desc => "Toggle Microdata support",
273270 define => "ENABLE_MICRODATA", default => 0, value => \$microdataSupport },
274271
 272 { option => "mutation-observers", desc => "Toggle DOM mutation observer support",
 273 define => "ENABLE_MUTATION_OBSERVERS", default => 0, value => \$mutationObserversSupport },
 274
275275 { option => "netscape-plugin", desc => "Netscape Plugin support",
276276 define => "ENABLE_NETSCAPE_PLUGIN_API", default => !isEfl(), value => \$netscapePluginSupport },
277277

LayoutTests/ChangeLog

 12012-01-24 Adam Klein <adamk@chromium.org>
 2
 3 Add JSC support for delivering mutations when the outermost script context exits
 4 https://bugs.webkit.org/show_bug.cgi?id=70289
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 With the various fixes in this change, 8/10 tests in fast/mutation
 9 pass under WebKit/Mac. Of the failing tests, only one is due to
 10 a deficiency in the Mac port's code (end-of-task-delivery.html);
 11 the other is due to lack of support for a feature (FILE_SYSTEM)
 12 exercised by the test (non-event-delivery.html).
 13
 14 * fast/mutation/non-event-delivery.html: Made it fail fast if FileSystem support isn't available.
 15 * fast/mutation/observe-attributes.html: Fixed calls to removeEventListener.
 16 * fast/mutation/observe-characterdata.html: ditto.
 17
1182012-01-23 Adam Barth <abarth@webkit.org>
219
320 Update the baselines for a number of tests that use gradients. The new

LayoutTests/fast/mutation/non-event-delivery.html

@@function runNextTest() {
116116
117117description('Test that Mutation Records are delivered following non-event async callbacks.');
118118
119 if (!window.WebKitMutationObserver)
 119if (!window.WebKitMutationObserver) {
120120 testFailed('This test requires ENABLE(MUTATION_OBSERVERS)');
121 else
 121 finishJSTest();
 122} else if (!window.webkitRequestFileSystem) {
 123 testFailed('This test requires ENABLE(FILE_SYSTEM)');
 124 finishJSTest();
 125} else
122126 runNextTest();
123127
124128</script>

LayoutTests/fast/mutation/observe-attributes.html

@@function testOrderingWrtDOMSubtreeModified() {
285285 shouldBe('mutations[0].attributeName', '"foo"');
286286 shouldBe('mutations[1].type', '"attributes"');
287287 shouldBe('mutations[1].attributeName', '"baz"');
288  div.removeEventListener(listener);
 288 div.removeEventListener('DOMSubtreeModified', listener);
289289 document.body.removeChild(div);
290290 observer.disconnect();
291291 debug('');

LayoutTests/fast/mutation/observe-characterdata.html

@@function testOrderingWrtDOMSubtreeModified() {
182182 shouldBe('mutations.length', '2');
183183 shouldBe('mutations[0].type', '"characterData"');
184184 shouldBe('mutations[1].type', '"attributes"');
185  div.removeEventListener(listener);
 185 div.removeEventListener('DOMSubtreeModified', listener);
186186 document.body.removeChild(div);
187187 observer.disconnect();
188188 debug('');