WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Make DOMFocusIn, DOMFocousOut, focusin, and focusout scoped as well
bug-46936-20101203175016.patch (text/plain), 30.63 KB, created by
Ryosuke Niwa
on 2010-12-03 17:50:17 PST
(
hide
)
Description:
Make DOMFocusIn, DOMFocousOut, focusin, and focusout scoped as well
Filename:
MIME Type:
Creator:
Ryosuke Niwa
Created:
2010-12-03 17:50:17 PST
Size:
30.63 KB
patch
obsolete
>Index: WebCore/ChangeLog >=================================================================== >--- WebCore/ChangeLog (revision 73316) >+++ WebCore/ChangeLog (working copy) >@@ -1,3 +1,56 @@ >+2010-12-03 Ryosuke Niwa <rniwa@webkit.org> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Implemented DOM mutations events as scoped events. A scoped event is an event whose >+ dispatch is done via ScopedEventQueue. The behavior of the queue is controlled by >+ EventQueueScope objects (RAII idiom), which increments and decrements the scoping level >+ on its constructor and destructor respectively. >+ >+ When the scoping level is 0 (initial level), scoped events are dispatched as soon as >+ they are enqueued and act like synchronous events. When the scoping level is greater than 0, >+ however, events are queued in ScopedEventQueue and their dispatches are delayed until >+ the scoping level goes back to 0 (by the destruction of EventQueueScope). >+ >+ All DOM mutation events except DOMFocusIn and DOMFocusOut are treated as scoped events, >+ and a scope object is instantiated in EditCommand::apply to delay dispatches of >+ the mutation events until the completion of each call of EditCommand::doApply. >+ >+ Test: fast/events/mutation/execCommands.html >+ >+ * Android.mk: Added ScopedEventQueue.cpp. >+ * CMakeLists.txt: Ditto. >+ * WebCore.pro: Ditto. >+ * GNUmakefile.am: Added ScopedEventQueue.cpp and ScopedEventQueue.h. >+ * WebCore.gypi: Ditto. >+ * WebCore.xcodeproj/project.pbxproj: Ditto. >+ * dom/ContainerNode.cpp: >+ (WebCore::dispatchChildInsertionEvents): Calls dispatchScopedEvent. >+ (WebCore::dispatchChildRemovalEvents): Ditto. >+ * dom/DOMAllInOne.cpp: Added ScopedEventQueue.cpp. >+ * dom/Element.cpp: >+ (WebCore::Element::dispatchAttrRemovalEvent): Ditto. >+ (WebCore::Element::dispatchAttrAdditionEvent): Ditto. >+ * dom/Node.cpp: >+ (WebCore::Node::dispatchScopedEvent): Added. >+ (WebCore::Node::dispatchSubtreeModifiedEvent): Calls dispatchScopedEvent. >+ * dom/Node.h: >+ * dom/ScopedEventQueue.cpp: Added. >+ (WebCore::ScopedEventQueue::initialize): Added. >+ (WebCore::ScopedEventQueue::dispatchAllEvents): Added. >+ (WebCore::ScopedEventQueue::dispatchEvent): Added. >+ * dom/ScopedEventQueue.h: Added. >+ (WebCore::ScopedEventQueue::~ScopedEventQueue): Added. >+ (WebCore::ScopedEventQueue::ScopedEventQueue): Added. >+ (WebCore::ScopedEventQueue::enqueueEvent): Added. >+ (WebCore::ScopedEventQueue::instance): Added. >+ (WebCore::ScopedEventQueue::incrementScopingLevel): Added. >+ (WebCore::ScopedEventQueue::decrementScopingLevel): Added. >+ (WebCore::EventQueueScope::EventQueueScope): Added. >+ (WebCore::EventQueueScope::~EventQueueScope): Added. >+ * editing/EditCommand.cpp: >+ (WebCore::EditCommand::apply): Instantiates EventQueueScope. >+ > 2010-12-01 Ilya Tikhonovsky <loislo@chromium.org> > > Reviewed by Pavel Feldman. >Index: WebCore/Android.mk >=================================================================== >--- WebCore/Android.mk (revision 73316) >+++ WebCore/Android.mk (working copy) >@@ -165,6 +165,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ > dom/QualifiedName.cpp \ > dom/Range.cpp \ > dom/RegisteredEventListener.cpp \ >+ dom/ScopedEventQueue.cpp \ > dom/ScriptableDocumentParser.cpp \ > dom/ScriptElement.cpp \ > dom/ScriptExecutionContext.cpp \ >Index: WebCore/CMakeLists.txt >=================================================================== >--- WebCore/CMakeLists.txt (revision 73316) >+++ WebCore/CMakeLists.txt (working copy) >@@ -871,6 +871,7 @@ SET(WebCore_SOURCES > dom/QualifiedName.cpp > dom/Range.cpp > dom/RegisteredEventListener.cpp >+ dom/ScopedEventQueue.cpp > dom/ScriptableDocumentParser.cpp > dom/ScriptElement.cpp > dom/ScriptExecutionContext.cpp >Index: WebCore/GNUmakefile.am >=================================================================== >--- WebCore/GNUmakefile.am (revision 73316) >+++ WebCore/GNUmakefile.am (working copy) >@@ -1248,6 +1248,8 @@ webcore_sources += \ > WebCore/dom/RawDataDocumentParser.h \ > WebCore/dom/RegisteredEventListener.cpp \ > WebCore/dom/RegisteredEventListener.h \ >+ WebCore/dom/ScopedEventQueue.cpp \ >+ WebCore/dom/ScopedEventQueue.h \ > WebCore/dom/ScriptableDocumentParser.cpp \ > WebCore/dom/ScriptableDocumentParser.h \ > WebCore/dom/ScriptElement.cpp \ >Index: WebCore/WebCore.gypi >=================================================================== >--- WebCore/WebCore.gypi (revision 73316) >+++ WebCore/WebCore.gypi (working copy) >@@ -1317,6 +1317,8 @@ > 'dom/RawDataDocumentParser.h', > 'dom/RegisteredEventListener.cpp', > 'dom/RegisteredEventListener.h', >+ 'dom/ScopedEventQueue.cpp', >+ 'dom/ScopedEventQueue.h', > 'dom/ScriptableDocumentParser.cpp', > 'dom/ScriptableDocumentParser.h', > 'dom/ScriptElement.cpp', >Index: WebCore/WebCore.pro >=================================================================== >--- WebCore/WebCore.pro (revision 73316) >+++ WebCore/WebCore.pro (working copy) >@@ -762,6 +762,7 @@ SOURCES += \ > dom/Range.cpp \ > dom/RawDataDocumentParser.h \ > dom/RegisteredEventListener.cpp \ >+ dom/ScopedEventQueue.cpp \ > dom/ScriptableDocumentParser.cpp \ > dom/ScriptElement.cpp \ > dom/ScriptExecutionContext.cpp \ >Index: WebCore/WebCore.xcodeproj/project.pbxproj >=================================================================== >--- WebCore/WebCore.xcodeproj/project.pbxproj (revision 73316) >+++ WebCore/WebCore.xcodeproj/project.pbxproj (working copy) >@@ -3023,6 +3023,8 @@ > 9B417065125662B3006B28FC /* ApplyBlockElementCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9B417063125662B3006B28FC /* ApplyBlockElementCommand.cpp */; }; > 9BAB6C6C12550631001626D4 /* EditingStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 9BAB6C6A12550631001626D4 /* EditingStyle.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 9BAB6C6D12550631001626D4 /* EditingStyle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9BAB6C6B12550631001626D4 /* EditingStyle.cpp */; }; >+ 9BD0BF9312A42BF50072FD43 /* ScopedEventQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 9BD0BF9112A42BF50072FD43 /* ScopedEventQueue.h */; }; >+ 9BD0BF9412A42BF50072FD43 /* ScopedEventQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9BD0BF9212A42BF50072FD43 /* ScopedEventQueue.cpp */; }; > 9F0D6B2E121BFEBA006C0288 /* InspectorProfilerAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9F0D6B2C121BFEBA006C0288 /* InspectorProfilerAgent.cpp */; }; > 9F0D6B2F121BFEBA006C0288 /* InspectorProfilerAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F0D6B2D121BFEBA006C0288 /* InspectorProfilerAgent.h */; }; > 9F3B947E12241758005304E7 /* ScriptHeapSnapshot.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F3B947D12241758005304E7 /* ScriptHeapSnapshot.h */; }; >@@ -9153,6 +9155,8 @@ > 9B417063125662B3006B28FC /* ApplyBlockElementCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ApplyBlockElementCommand.cpp; sourceTree = "<group>"; }; > 9BAB6C6A12550631001626D4 /* EditingStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditingStyle.h; sourceTree = "<group>"; }; > 9BAB6C6B12550631001626D4 /* EditingStyle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EditingStyle.cpp; sourceTree = "<group>"; }; >+ 9BD0BF9112A42BF50072FD43 /* ScopedEventQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScopedEventQueue.h; sourceTree = "<group>"; }; >+ 9BD0BF9212A42BF50072FD43 /* ScopedEventQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScopedEventQueue.cpp; sourceTree = "<group>"; }; > 9F0D6B2C121BFEBA006C0288 /* InspectorProfilerAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorProfilerAgent.cpp; sourceTree = "<group>"; }; > 9F0D6B2D121BFEBA006C0288 /* InspectorProfilerAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorProfilerAgent.h; sourceTree = "<group>"; }; > 9F3B947D12241758005304E7 /* ScriptHeapSnapshot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptHeapSnapshot.h; sourceTree = "<group>"; }; >@@ -18423,6 +18427,8 @@ > A84D827B11D333ED00972990 /* RawDataDocumentParser.h */, > 85031B350A44EFC700F992E0 /* RegisteredEventListener.cpp */, > 85031B360A44EFC700F992E0 /* RegisteredEventListener.h */, >+ 9BD0BF9212A42BF50072FD43 /* ScopedEventQueue.cpp */, >+ 9BD0BF9112A42BF50072FD43 /* ScopedEventQueue.h */, > A84D82C011D3474800972990 /* ScriptableDocumentParser.cpp */, > A84D82BF11D3474800972990 /* ScriptableDocumentParser.h */, > 08A484750E5272C500C3FE76 /* ScriptElement.cpp */, >@@ -20822,6 +20828,7 @@ > 5DFE8F570D16477C0076E937 /* ScheduledAction.h in Headers */, > 1CEFC9B90D78DC8C007D2579 /* SchedulePair.h in Headers */, > 5162C7F511F77EFB00612EFE /* SchemeRegistry.h in Headers */, >+ 9BD0BF9312A42BF50072FD43 /* ScopedEventQueue.h in Headers */, > BCEC01BE0C274DAC009F4EC9 /* Screen.h in Headers */, > A84D82C111D3474800972990 /* ScriptableDocumentParser.h in Headers */, > F39BE95C12673BF400E0A674 /* ScriptArguments.h in Headers */, >@@ -23504,6 +23511,7 @@ > 1CEFC9BA0D78DC8C007D2579 /* SchedulePair.cpp in Sources */, > 1CE24F970D7CAF0E007E04C2 /* SchedulePairMac.mm in Sources */, > 5162C7F411F77EFB00612EFE /* SchemeRegistry.cpp in Sources */, >+ 9BD0BF9412A42BF50072FD43 /* ScopedEventQueue.cpp in Sources */, > BCEC01BD0C274DAC009F4EC9 /* Screen.cpp in Sources */, > A84D82C211D3474800972990 /* ScriptableDocumentParser.cpp in Sources */, > F39BE95B12673BF400E0A674 /* ScriptArguments.cpp in Sources */, >Index: WebCore/dom/ContainerNode.cpp >=================================================================== >--- WebCore/dom/ContainerNode.cpp (revision 73316) >+++ WebCore/dom/ContainerNode.cpp (working copy) >@@ -1027,12 +1027,12 @@ static void dispatchChildInsertionEvents > RefPtr<Document> document = child->document(); > > if (c->parentNode() && document->hasListenerType(Document::DOMNODEINSERTED_LISTENER)) >- c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, c->parentNode())); >+ c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, c->parentNode())); > > // dispatch the DOMNodeInsertedIntoDocument event to all descendants > if (c->inDocument() && document->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER)) { > for (; c; c = c->traverseNextNode(child)) >- c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent, false)); >+ c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent, false)); > } > } > >@@ -1049,12 +1049,12 @@ static void dispatchChildRemovalEvents(N > > // dispatch pre-removal mutation events > if (c->parentNode() && document->hasListenerType(Document::DOMNODEREMOVED_LISTENER)) >- c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, c->parentNode())); >+ c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, c->parentNode())); > > // dispatch the DOMNodeRemovedFromDocument event to all descendants > if (c->inDocument() && document->hasListenerType(Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER)) { > for (; c; c = c->traverseNextNode(child)) >- c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent, false)); >+ c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent, false)); > } > } > >Index: WebCore/dom/DOMAllInOne.cpp >=================================================================== >--- WebCore/dom/DOMAllInOne.cpp (revision 73316) >+++ WebCore/dom/DOMAllInOne.cpp (working copy) >@@ -100,6 +100,7 @@ > #include "ProgressEvent.cpp" > #include "Range.cpp" > #include "RegisteredEventListener.cpp" >+#include "ScopedEventQueue.cpp" > #include "ScriptElement.cpp" > #include "ScriptExecutionContext.cpp" > #include "ScriptableDocumentParser.cpp" >Index: WebCore/dom/Element.cpp >=================================================================== >--- WebCore/dom/Element.cpp (revision 73316) >+++ WebCore/dom/Element.cpp (working copy) >@@ -1221,7 +1221,7 @@ void Element::dispatchAttrRemovalEvent(A > if (!document()->hasListenerType(Document::DOMATTRMODIFIED_LISTENER)) > return; > ExceptionCode ec = 0; >- dispatchEvent(MutationEvent::create(DOMAttrModifiedEvent, true, attr, attr->value(), >+ dispatchScopedEvent(MutationEvent::create(DOMAttrModifiedEvent, true, attr, attr->value(), > attr->value(), document()->attrName(attr->id()), MutationEvent::REMOVAL), ec); > #endif > } >@@ -1234,7 +1234,7 @@ void Element::dispatchAttrAdditionEvent( > if (!document()->hasListenerType(Document::DOMATTRMODIFIED_LISTENER)) > return; > ExceptionCode ec = 0; >- dispatchEvent(MutationEvent::create(DOMAttrModifiedEvent, true, attr, attr->value(), >+ dispatchScopedEvent(MutationEvent::create(DOMAttrModifiedEvent, true, attr, attr->value(), > attr->value(), document()->attrName(attr->id()), MutationEvent::ADDITION), ec); > #endif > } >Index: WebCore/dom/Node.cpp >=================================================================== >--- WebCore/dom/Node.cpp (revision 73316) >+++ WebCore/dom/Node.cpp (working copy) >@@ -70,6 +70,7 @@ > #include "ProgressEvent.h" > #include "RegisteredEventListener.h" > #include "RenderBox.h" >+#include "ScopedEventQueue.h" > #include "ScriptController.h" > #include "SelectorNodeList.h" > #include "StaticNodeList.h" >@@ -2562,6 +2563,14 @@ bool Node::dispatchEvent(PassRefPtr<Even > return dispatchGenericEvent(event.release()); > } > >+void Node::dispatchScopedEvent(PassRefPtr<Event> event) >+{ >+ // We need to set the target here because it can go away by the time we actually fire the event. >+ event->setTarget(eventTargetRespectingSVGTargetRules(this)); >+ >+ ScopedEventQueue::instance()->enqueueEvent(event); >+} >+ > static const EventContext* topEventContext(const Vector<EventContext>& ancestors) > { > return ancestors.isEmpty() ? 0 : &ancestors.last(); >@@ -2676,7 +2685,7 @@ void Node::dispatchSubtreeModifiedEvent( > if (!document()->hasListenerType(Document::DOMSUBTREEMODIFIED_LISTENER)) > return; > >- dispatchEvent(MutationEvent::create(eventNames().DOMSubtreeModifiedEvent, true)); >+ dispatchScopedEvent(MutationEvent::create(eventNames().DOMSubtreeModifiedEvent, true)); > } > > void Node::dispatchUIEvent(const AtomicString& eventType, int detail, PassRefPtr<Event> underlyingEvent) >@@ -2686,10 +2695,10 @@ void Node::dispatchUIEvent(const AtomicS > eventType == eventNames().DOMFocusInEvent || eventType == eventNames().DOMFocusOutEvent || eventType == eventNames().DOMActivateEvent); > > bool cancelable = eventType == eventNames().DOMActivateEvent; >- >+ > RefPtr<UIEvent> event = UIEvent::create(eventType, true, cancelable, document()->defaultView(), detail); > event->setUnderlyingEvent(underlyingEvent); >- dispatchEvent(event.release()); >+ dispatchScopedEvent(event.release()); > } > > bool Node::dispatchKeyEvent(const PlatformKeyboardEvent& key) >Index: WebCore/dom/Node.h >=================================================================== >--- WebCore/dom/Node.h (revision 73316) >+++ WebCore/dom/Node.h (working copy) >@@ -517,7 +517,8 @@ public: > virtual void postDispatchEventHandler(Event*, void* /*dataFromPreDispatch*/) { } > > using EventTarget::dispatchEvent; >- virtual bool dispatchEvent(PassRefPtr<Event>); >+ bool dispatchEvent(PassRefPtr<Event>); >+ void dispatchScopedEvent(PassRefPtr<Event>); > > bool dispatchGenericEvent(PassRefPtr<Event>); > virtual void handleLocalEvents(Event*); >Index: WebCore/dom/ScopedEventQueue.cpp >=================================================================== >--- WebCore/dom/ScopedEventQueue.cpp (revision 0) >+++ WebCore/dom/ScopedEventQueue.cpp (revision 0) >@@ -0,0 +1,69 @@ >+/* >+ * Copyright (C) 2010 Google, 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. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR >+ * 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 "ScopedEventQueue.h" >+ >+#include "Event.h" >+#include "EventTarget.h" >+ >+namespace WebCore { >+ >+ScopedEventQueue* ScopedEventQueue::s_instance = 0; >+ >+ScopedEventQueue::ScopedEventQueue() >+ : m_scopingLevel(0) >+{ >+} >+ >+ScopedEventQueue::~ScopedEventQueue() >+{ >+ ASSERT(!m_scopingLevel); >+ ASSERT(!m_queuedEvents.size()); >+} >+ >+void ScopedEventQueue::initialize() >+{ >+ ASSERT(!s_instance); >+ OwnPtr<ScopedEventQueue> instance = adoptPtr(new ScopedEventQueue); >+ s_instance = instance.leakPtr(); >+} >+ >+void ScopedEventQueue::dispatchAllEvents() >+{ >+ Vector<RefPtr<Event> > queuedEvents; >+ queuedEvents.swap(m_queuedEvents); >+ >+ for (size_t i = 0; i < queuedEvents.size(); i++) >+ dispatchEvent(queuedEvents[i].release()); >+} >+ >+void ScopedEventQueue::dispatchEvent(PassRefPtr<Event> event) const >+{ >+ RefPtr<EventTarget> eventTarget = event->target(); >+ eventTarget->dispatchEvent(event); >+} >+ >+} >Index: WebCore/dom/ScopedEventQueue.h >=================================================================== >--- WebCore/dom/ScopedEventQueue.h (revision 0) >+++ WebCore/dom/ScopedEventQueue.h (revision 0) >@@ -0,0 +1,101 @@ >+/* >+ * Copyright (C) 2010 Google, 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. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR >+ * 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 ScopedEventQueue_h >+#define ScopedEventQueue_h >+ >+#include <wtf/Noncopyable.h> >+#include <wtf/PassOwnPtr.h> >+#include <wtf/PassRefPtr.h> >+#include <wtf/Vector.h> >+ >+namespace WebCore { >+ >+class Event; >+ >+class ScopedEventQueue { >+ WTF_MAKE_NONCOPYABLE(ScopedEventQueue); >+ >+public: >+ ~ScopedEventQueue(); >+ >+ void enqueueEvent(PassRefPtr<Event>); >+ void dispatchAllEvents(); >+ static ScopedEventQueue* instance(); >+ >+ void incrementScopingLevel(); >+ void decrementScopingLevel(); >+ >+private: >+ ScopedEventQueue(); >+ static void initialize(); >+ void dispatchEvent(PassRefPtr<Event>) const; >+ >+ Vector<RefPtr<Event> > m_queuedEvents; >+ unsigned m_scopingLevel; >+ >+ static ScopedEventQueue* s_instance; >+}; >+ >+inline void ScopedEventQueue::enqueueEvent(PassRefPtr<Event> event) >+{ >+ if (m_scopingLevel) >+ m_queuedEvents.append(event); >+ else >+ dispatchEvent(event); >+} >+ >+inline ScopedEventQueue* ScopedEventQueue::instance() >+{ >+ if (!s_instance) >+ initialize(); >+ >+ return s_instance; >+} >+ >+inline void ScopedEventQueue::incrementScopingLevel() >+{ >+ m_scopingLevel++; >+} >+ >+inline void ScopedEventQueue::decrementScopingLevel() >+{ >+ ASSERT(m_scopingLevel); >+ m_scopingLevel--; >+ if (!m_scopingLevel) >+ dispatchAllEvents(); >+} >+ >+class EventQueueScope { >+ WTF_MAKE_NONCOPYABLE(EventQueueScope); >+ >+public: >+ EventQueueScope() { ScopedEventQueue::instance()->incrementScopingLevel(); } >+ ~EventQueueScope() { ScopedEventQueue::instance()->decrementScopingLevel(); } >+}; >+ >+} >+ >+#endif // ScopedEventQueue_h >Index: WebCore/editing/EditCommand.cpp >=================================================================== >--- WebCore/editing/EditCommand.cpp (revision 73316) >+++ WebCore/editing/EditCommand.cpp (working copy) >@@ -35,6 +35,7 @@ > #include "Element.h" > #include "EventNames.h" > #include "Frame.h" >+#include "ScopedEventQueue.h" > #include "SelectionController.h" > #include "VisiblePosition.h" > #include "htmlediting.h" >@@ -86,10 +87,13 @@ void EditCommand::apply() > if (isTopLevelCommand()) > updateLayout(); > >- DeleteButtonController* deleteButtonController = frame->editor()->deleteButtonController(); >- deleteButtonController->disable(); >- doApply(); >- deleteButtonController->enable(); >+ { >+ EventQueueScope scope; >+ DeleteButtonController* deleteButtonController = frame->editor()->deleteButtonController(); >+ deleteButtonController->disable(); >+ doApply(); >+ deleteButtonController->enable(); >+ } > > if (isTopLevelCommand()) { > // Only need to call appliedEditing for top-level commands, and TypingCommands do it on their >Index: LayoutTests/ChangeLog >=================================================================== >--- LayoutTests/ChangeLog (revision 73316) >+++ LayoutTests/ChangeLog (working copy) >@@ -1,3 +1,14 @@ >+2010-12-03 Ryosuke Niwa <rniwa@webkit.org> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Added a test to ensure no DOM mutation events are fired while execCommand is in progress. >+ >+ * fast/events/crash-on-mutate-during-drop.html: DOMNodeInserted is fired after BR is detached >+ from the document, and can't be observed. Modify the DOM when text node is inserted. >+ * fast/events/mutation: Added. >+ * fast/events/mutation/execCommands.html: Added. >+ > 2010-12-01 Ilya Tikhonovsky <loislo@chromium.org> > > Reviewed by Pavel Feldman. >Index: LayoutTests/fast/events/crash-on-mutate-during-drop.html >=================================================================== >--- LayoutTests/fast/events/crash-on-mutate-during-drop.html (revision 73316) >+++ LayoutTests/fast/events/crash-on-mutate-during-drop.html (working copy) >@@ -2,7 +2,7 @@ > <head> > <script> > function foo() { >- if (event.type == "DOMNodeInserted" && event.target.nodeName == "BR") >+ if (event.type == "DOMNodeInserted" && event.target.nodeType == 3) > document.body.innerHTML = "PASSED"; > } > >@@ -12,7 +12,7 @@ function runTest() { > > window.layoutTestController.dumpAsText(); > >- document.body.addEventListener("DOMNodeInserted", function() { foo() }, true); >+ document.addEventListener("DOMNodeInserted", function() { foo() }, true); > > // Select the element 'dragSource'. > var selection = window.getSelection(); >Index: LayoutTests/fast/events/scoped/editing-commands-expected.txt >=================================================================== >--- LayoutTests/fast/events/scoped/editing-commands-expected.txt (revision 0) >+++ LayoutTests/fast/events/scoped/editing-commands-expected.txt (revision 0) >@@ -0,0 +1,40 @@ >+This test ensures WebKit does not fire DOM mutation events while execCommand is in progress. >+ >+PASS: execCommand('BackColor', false, 'blue') >+PASS: execCommand('CreateLink', false, 'about:blank') >+PASS: execCommand('Delete', false, null) >+PASS: execCommand('FontName', false, 'Arial') >+PASS: execCommand('FontSize', false, '5') >+PASS: execCommand('FontSizeDelta', false, '5') >+PASS: execCommand('ForeColor', false, 'blue') >+PASS: execCommand('FormatBlock', false, 'pre') >+PASS: execCommand('ForwardDelete', false, null) >+PASS: execCommand('HiliteColor', false, 'red') >+PASS: execCommand('Indent', false, null) >+PASS: execCommand('InsertHTML', false, '<i>hello') >+PASS: execCommand('InsertHorizontalRule', false, null) >+PASS: execCommand('InsertImage', false, '../resources/abe.png') >+PASS: execCommand('InsertLineBreak', false, null) >+PASS: execCommand('InsertNewlineInQuotedContent', false, null) >+PASS: execCommand('InsertOrderedList', false, null) >+PASS: execCommand('InsertParagraph', false, null) >+PASS: execCommand('InsertText', false, 'webkit') >+PASS: execCommand('InsertUnorderedList', false, null) >+PASS: execCommand('Italic', false, null) >+PASS: execCommand('JustifyCenter', false, null) >+PASS: execCommand('JustifyFull', false, null) >+PASS: execCommand('JustifyLeft', false, null) >+PASS: execCommand('JustifyNone', false, null) >+PASS: execCommand('JustifyRight', false, null) >+PASS: execCommand('Outdent', false, null) >+PASS: execCommand('RemoveFormat', false, null) >+PASS: execCommand('Strikethrough', false, null) >+PASS: execCommand('Subscript', false, null) >+PASS: execCommand('Superscript', false, null) >+PASS: execCommand('Transpose', false, null) >+PASS: execCommand('Underline', false, null) >+PASS: execCommand('Unlink', false, null) >+ >+ >+DONE >+ >Index: LayoutTests/fast/events/scoped/editing-commands.html >=================================================================== >--- LayoutTests/fast/events/scoped/editing-commands.html (revision 0) >+++ LayoutTests/fast/events/scoped/editing-commands.html (revision 0) >@@ -0,0 +1,129 @@ >+<!DOCTYPE html> >+<html> >+<body> >+<p>This test ensures WebKit does not fire DOM mutation events while execCommand is in progress.</p> >+<div id="test" contenteditable></div> >+<pre> >+<script> >+ >+if (window.layoutTestController) >+ layoutTestController.dumpAsText(); >+ >+var commands = [ >+ {name: 'BackColor', value: 'blue'}, >+ {name: 'CreateLink', value: 'about:blank'}, >+ {name: 'Delete', value: null}, >+ {name: 'FontName', value: 'Arial'}, >+ {name: 'FontSize', value: '5'}, >+ {name: 'FontSizeDelta', value: '5'}, >+ {name: 'ForeColor', value: 'blue'}, >+ {name: 'FormatBlock', value: 'pre'}, >+ {name: 'ForwardDelete', value: null}, >+ {name: 'HiliteColor', value: 'red'}, >+ {name: 'Indent', value: null}, >+ {name: 'InsertHTML', value: "<i>hello</i>"}, >+ {name: 'InsertHorizontalRule', value: null}, >+ {name: 'InsertImage', value: '../resources/abe.png'}, >+ {name: 'InsertLineBreak', value: null}, >+ {name: 'InsertNewlineInQuotedContent', value: null}, >+ {name: 'InsertOrderedList', value: null}, >+ {name: 'InsertParagraph', value: null}, >+ {name: 'InsertText', value: 'webkit'}, >+ {name: 'InsertUnorderedList', value: null}, >+ {name: 'Italic', value: null}, >+ {name: 'JustifyCenter', value: null}, >+ {name: 'JustifyFull', value: null}, >+ {name: 'JustifyLeft', value: null}, >+ {name: 'JustifyNone', value: null}, >+ {name: 'JustifyRight', value: null}, >+ {name: 'Outdent', value: null}, >+ {name: 'RemoveFormat', value: null}, >+ {name: 'Strikethrough', value: null}, >+ {name: 'Subscript', value: null}, >+ {name: 'Superscript', value: null}, >+ {name: 'Transpose', value: null, selector: function (test) { window.getSelection().setPosition(test.firstChild, 1); }}, >+ {name: 'Underline', value: null}, >+ {name: 'Unlink', value: null}, >+]; >+ >+var events = { >+ 'DOMSubtreeModified': false, >+ 'DOMNodeInserted': false, >+ 'DOMNodeRemoved': false, >+ 'DOMNodeRemovedFromDocument': false, >+ 'DOMNodeInsertedIntoDocument': true, // this event can never be observed. >+ 'DOMFocusIn': false, >+ 'DOMFocusOut': false, >+ 'focusin': false, >+ 'focusout': false, >+}; >+ >+var log = []; >+var test = document.getElementById('test'); >+ >+function addEventListeners(node) { >+ for (var e in events) { >+ node.addEventListener(e, function (event) { >+ log.push(test.innerHTML); >+ events[event.type] = true; >+ }, false); >+ } >+} >+ >+function isLogConsistent() { >+ for (var i= 1; i < log.length; i++) { >+ if (log[0] != log[i]) { >+ console.log(log); >+ return false; >+ } >+ } >+ return true; >+} >+ >+addEventListeners(test); >+ >+var initial = 'hello, <input type="text"><blockquote align="right"><u><a href="about:blank">world</a></u></blockquote>'; >+for (var i = 0; i < commands.length; i++) { >+ test.innerHTML = initial; >+ if (i) >+ document.write("\n"); >+ >+ if (test.innerHTML != initial) { >+ document.write("FAIL: initial innerHTML didn't match"); >+ continue; >+ } >+ >+ if (commands[i].selector) >+ commands[i].selector(test); >+ else { >+ document.getElementsByTagName('input')[0].focus(); >+ window.getSelection().selectAllChildren(test); >+ } >+ addEventListeners(test.childNodes[2]); >+ log = []; // clear log >+ document.execCommand(commands[i].name, false, commands[i].value); >+ >+ var quotedValue = commands[i].value ? "'" + commands[i].value.replace('<', '<') + "'" : null; >+ var action = "execCommand('" + commands[i].name + "', false, " + quotedValue + ")"; >+ >+ if (test.innerHTML == initial || log.length <= 0) >+ document.write('FAIL: ' + action + ' made no change to the DOM.'); >+ else if (!isLogConsistent()) >+ document.write('FAIL: ' + action + ' dispatched events before finalizing the DOM tree.'); >+ else >+ document.write('PASS: ' + action); >+} >+test.style.display = 'none'; >+ >+document.write('\n'); >+for (var e in events) { >+ if (!events[e]) >+ document.write('\nWARNING: ' + e + ' was never observed.'); >+} >+ >+document.write('\n\nDONE'); >+ >+</script> >+</pre> >+</body> >+</html>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
ojan
:
review+
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 46936
:
74066
|
74172
|
75079
| 75584