WebKit Bugzilla
Attachment 359632 Details for
Bug 193111
: [Cocoa] Allow the page to add to the platform undo stack via UndoManager.addItem()
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Part 3
bug-193111-20190119205405.patch (text/plain), 56.39 KB, created by
Wenson Hsieh
on 2019-01-19 20:54:05 PST
(
hide
)
Description:
Part 3
Filename:
MIME Type:
Creator:
Wenson Hsieh
Created:
2019-01-19 20:54:05 PST
Size:
56.39 KB
patch
obsolete
>Subversion Revision: 240198 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index d66c93e96ad4fbca7d671c92cdbf451c824807ad..85ebe28c7d0988b27ca7fe77ed9d247e8552fb37 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,45 @@ >+2019-01-19 Wenson Hsieh <wenson_hsieh@apple.com> >+ >+ [Cocoa] Allow the page to add to the platform undo stack via UndoManager.addItem() >+ https://bugs.webkit.org/show_bug.cgi?id=193111 >+ <rdar://problem/44807048> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Finish hooking up `UndoManager::addItems()` to CustomUndoStep. >+ >+ Tests: editing/undo-manager/undo-manager-add-item.html >+ editing/undo-manager/undo-manager-delete-stale-undo-items.html >+ editing/undo-manager/undo-manager-item-labels.html >+ editing/undo-manager/undo-manager-undo-redo-after-garbage-collection.html >+ >+ * editing/CompositeEditCommand.h: >+ * editing/CustomUndoStep.cpp: >+ (WebCore::CustomUndoStep::invalidate): >+ >+ Add a method to invalidate CustomUndoStep. This clears out the pointer to the undo item, and also invalidates >+ the UndoItem, removing it from its UndoManager. >+ >+ * editing/CustomUndoStep.h: >+ * editing/Editor.cpp: >+ (WebCore::Editor::registerCustomUndoStep): >+ >+ Add a helper method to register a CustomUndoStep as a platform undoable step. >+ >+ * editing/Editor.h: >+ * editing/UndoStep.h: >+ * loader/EmptyClients.cpp: >+ (WebCore::EmptyEditorClient::registerUndoStep): >+ (WebCore::EmptyEditorClient::registerRedoStep): >+ >+ Make these take `Ref<UndoStep>&&` instead of `UndoStep&`. >+ >+ * page/EditorClient.h: >+ * page/UndoManager.cpp: >+ (WebCore::UndoManager::addItem): >+ >+ Create a CustomUndoStep with the given UndoItem, and register it with the platform undo manager. >+ > 2019-01-19 Wenson Hsieh <wenson_hsieh@apple.com> > > Introduce CustomUndoStep.h and CustomUndoStep.cpp >diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog >index 34d43f3ef7c9ae45d5f89b44080f55fa0e49a7a6..2ca4e66f164c374581a19a35bb9fec70bd82fd3c 100644 >--- a/Source/WebKit/ChangeLog >+++ b/Source/WebKit/ChangeLog >@@ -1,3 +1,53 @@ >+2019-01-19 Wenson Hsieh <wenson_hsieh@apple.com> >+ >+ [Cocoa] Allow the page to add to the platform undo stack via UndoManager.addItem() >+ https://bugs.webkit.org/show_bug.cgi?id=193111 >+ <rdar://problem/44807048> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add plumbing to use a custom undo label (defined by an UndoItem) as the action name for NSUndoManager. >+ >+ * UIProcess/Cocoa/WebViewImpl.mm: >+ (WebKit::WebViewImpl::registerEditCommand): >+ * UIProcess/WebEditCommandProxy.cpp: >+ (WebKit::WebEditCommandProxy::WebEditCommandProxy): >+ (WebKit::WebEditCommandProxy::nameForUndoRedo const): >+ >+ Add a helper method to get the undo/redo name for a edit command in the UI process. This prefers the custom name >+ (if specified), and falls back to the `EditAction`. >+ >+ * UIProcess/WebEditCommandProxy.h: >+ (WebKit::WebEditCommandProxy::create): >+ (WebKit::WebEditCommandProxy::invalidate): >+ * UIProcess/WebPageProxy.cpp: >+ (WebKit::WebPageProxy::registerEditCommandForUndo): >+ (WebKit::WebPageProxy::resetState): >+ >+ Take advantage of `std::exchange` instead of copying all the edit commands into a new Vector. >+ >+ * UIProcess/WebPageProxy.h: >+ * UIProcess/WebPageProxy.messages.in: >+ * UIProcess/ios/PageClientImplIOS.mm: >+ (WebKit::PageClientImpl::registerEditCommand): >+ * WebProcess/WebCoreSupport/WebEditorClient.cpp: >+ (WebKit::WebEditorClient::registerUndoStep): >+ (WebKit::WebEditorClient::registerRedoStep): >+ * WebProcess/WebCoreSupport/WebEditorClient.h: >+ >+ MAke the function take a `Ref<UndoStep>&&` instead of an `UndoStep&`. >+ >+ * WebProcess/WebPage/WebPage.cpp: >+ (WebKit::WebPage::addWebUndoStep): >+ (WebKit::WebPage::removeWebEditCommand): >+ >+ Invalidate undo steps when removing them from WebPage. Invalidation is a no-op for editing actions that come >+ from the UA, but for custom undo steps backed by an UndoItem, we clear out the custom undo step's pointer to its >+ UndoItem and additionally disconnect the UndoItem from its UndoManager. >+ >+ * WebProcess/WebPage/WebUndoStep.h: >+ (WebKit::WebUndoStep::invalidate): >+ > 2019-01-18 Tim Horton <timothy_horton@apple.com> > > Adjust WKDrawingView protocol method name >diff --git a/Source/WebKitLegacy/mac/ChangeLog b/Source/WebKitLegacy/mac/ChangeLog >index 1e064fec7bcb0dab0743c3d52cabf1fe3c923b43..90933a29bde0e5b0a537b3929337c9e706e731f8 100644 >--- a/Source/WebKitLegacy/mac/ChangeLog >+++ b/Source/WebKitLegacy/mac/ChangeLog >@@ -1,3 +1,21 @@ >+2019-01-19 Wenson Hsieh <wenson_hsieh@apple.com> >+ >+ [Cocoa] Allow the page to add to the platform undo stack via UndoManager.addItem() >+ https://bugs.webkit.org/show_bug.cgi?id=193111 >+ <rdar://problem/44807048> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Adjust for some changed function parameters. See other ChangeLogs for more detail. >+ >+ * WebCoreSupport/WebEditorClient.h: >+ * WebCoreSupport/WebEditorClient.mm: >+ (-[WebUndoStep initWithUndoStep:]): >+ (+[WebUndoStep stepWithUndoStep:]): >+ (WebEditorClient::registerUndoOrRedoStep): >+ (WebEditorClient::registerUndoStep): >+ (WebEditorClient::registerRedoStep): >+ > 2019-01-18 Eric Carlson <eric.carlson@apple.com> > > Revert r238815, it broke WK1 video fullscreen on Mac >diff --git a/Source/WebCore/editing/CompositeEditCommand.h b/Source/WebCore/editing/CompositeEditCommand.h >index b2fa5d019a463fc6b250a484a2b43967fe2d61f2..2e396c1ba67b928c15a60942b6661581a34aeed9 100644 >--- a/Source/WebCore/editing/CompositeEditCommand.h >+++ b/Source/WebCore/editing/CompositeEditCommand.h >@@ -89,6 +89,7 @@ private: > EditCommandComposition(Document&, const VisibleSelection& startingSelection, const VisibleSelection& endingSelection, EditAction); > > const String& customUndoLabel() const final { return emptyString(); } >+ void invalidate() final { } > > RefPtr<Document> m_document; > VisibleSelection m_startingSelection; >diff --git a/Source/WebCore/editing/CustomUndoStep.cpp b/Source/WebCore/editing/CustomUndoStep.cpp >index ed8e028b7ca793e57abf957e93f5c9f69a5b22a0..a48c1e878495d7b3adce7445026a813abae8ed1d 100644 >--- a/Source/WebCore/editing/CustomUndoStep.cpp >+++ b/Source/WebCore/editing/CustomUndoStep.cpp >@@ -74,4 +74,10 @@ const String& CustomUndoStep::customUndoLabel() const > return m_undoItem->label(); > } > >+void CustomUndoStep::invalidate() >+{ >+ if (auto undoItem = std::exchange(m_undoItem, nullptr)) >+ undoItem->invalidate(); >+} >+ > } // namespace WebCore >diff --git a/Source/WebCore/editing/CustomUndoStep.h b/Source/WebCore/editing/CustomUndoStep.h >index 1b6d906b9b8f63af91272f04decf4b19d977c419..4bb423979119f3c8630a4d748b977856a2cac9cd 100644 >--- a/Source/WebCore/editing/CustomUndoStep.h >+++ b/Source/WebCore/editing/CustomUndoStep.h >@@ -49,6 +49,7 @@ private: > EditAction editingAction() const final { return EditAction::Unspecified; } > const String& customUndoLabel() const final; > >+ void invalidate() final; > bool isValid() const; > > WeakPtr<UndoItem> m_undoItem; >diff --git a/Source/WebCore/editing/Editor.cpp b/Source/WebCore/editing/Editor.cpp >index 5854aeb55a0f24d85855eed1260e3e3d94eaf0a3..20615e872858216e826b534cf0695b55f9e3b450 100644 >--- a/Source/WebCore/editing/Editor.cpp >+++ b/Source/WebCore/editing/Editor.cpp >@@ -39,6 +39,7 @@ > #include "ClipboardEvent.h" > #include "CompositionEvent.h" > #include "CreateLinkCommand.h" >+#include "CustomUndoStep.h" > #include "DataTransfer.h" > #include "DeleteSelectionCommand.h" > #include "DictationAlternative.h" >@@ -1740,6 +1741,13 @@ void Editor::redo() > client()->redo(); > } > >+void Editor::registerCustomUndoStep(Ref<CustomUndoStep>&& undoStep) >+{ >+ ASSERT(RuntimeEnabledFeatures::sharedFeatures().undoManagerAPIEnabled()); >+ if (auto* client = this->client()) >+ client->registerUndoStep(WTFMove(undoStep)); >+} >+ > void Editor::didBeginEditing() > { > if (client()) >diff --git a/Source/WebCore/editing/Editor.h b/Source/WebCore/editing/Editor.h >index 05cc1b82aeac140b40930df6f37ea54955c63f46..4547d4715f9833a867ce7f6a833378c5363d03bb 100644 >--- a/Source/WebCore/editing/Editor.h >+++ b/Source/WebCore/editing/Editor.h >@@ -58,6 +58,7 @@ class AlternativeTextController; > class ArchiveResource; > class DataTransfer; > class CompositeEditCommand; >+class CustomUndoStep; > class DeleteButtonController; > class EditCommand; > class EditCommandComposition; >@@ -324,6 +325,8 @@ public: > bool canRedo() const; > void redo(); > >+ void registerCustomUndoStep(Ref<CustomUndoStep>&&); >+ > void didBeginEditing(); > void didEndEditing(); > void willWriteSelectionToPasteboard(Range*); >diff --git a/Source/WebCore/editing/UndoStep.h b/Source/WebCore/editing/UndoStep.h >index 571bf99ca432b2803809c0cccec79ffa4bb05c22..8b29d7417ab12871364c6b1002d0dbfbc7ee8465 100644 >--- a/Source/WebCore/editing/UndoStep.h >+++ b/Source/WebCore/editing/UndoStep.h >@@ -43,6 +43,8 @@ public: > virtual void reapply() = 0; > virtual EditAction editingAction() const = 0; > virtual const String& customUndoLabel() const = 0; >+ >+ virtual void invalidate() = 0; > }; > > } // namespace WebCore >diff --git a/Source/WebCore/loader/EmptyClients.cpp b/Source/WebCore/loader/EmptyClients.cpp >index a5e5ef758354fec743608a033eb69cd701805b47..ae920f01abf8721c362a5536136aab38d081144c 100644 >--- a/Source/WebCore/loader/EmptyClients.cpp >+++ b/Source/WebCore/loader/EmptyClients.cpp >@@ -186,8 +186,8 @@ private: > void requestCandidatesForSelection(const VisibleSelection&) final { } > void handleAcceptedCandidateWithSoftSpaces(TextCheckingResult) final { } > >- void registerUndoStep(UndoStep&) final; >- void registerRedoStep(UndoStep&) final; >+ void registerUndoStep(Ref<UndoStep>&&) final; >+ void registerRedoStep(Ref<UndoStep>&&) final; > void clearUndoRedoOperations() final { } > > bool canCopyCut(Frame*, bool defaultValue) const final { return defaultValue; } >@@ -507,11 +507,11 @@ void EmptyEditorClient::EmptyTextCheckerClient::requestCheckingOfString(TextChec > { > } > >-void EmptyEditorClient::registerUndoStep(UndoStep&) >+void EmptyEditorClient::registerUndoStep(Ref<UndoStep>&&) > { > } > >-void EmptyEditorClient::registerRedoStep(UndoStep&) >+void EmptyEditorClient::registerRedoStep(Ref<UndoStep>&&) > { > } > >diff --git a/Source/WebCore/page/EditorClient.h b/Source/WebCore/page/EditorClient.h >index 37bf1823a98c2d9e52f3d02cbf5bcffaee358c44..abbf5829c17dcae97d04b2ccfb4e0dd3344d42ac 100644 >--- a/Source/WebCore/page/EditorClient.h >+++ b/Source/WebCore/page/EditorClient.h >@@ -104,8 +104,8 @@ public: > virtual void canceledComposition() = 0; > virtual void didUpdateComposition() = 0; > >- virtual void registerUndoStep(UndoStep&) = 0; >- virtual void registerRedoStep(UndoStep&) = 0; >+ virtual void registerUndoStep(Ref<UndoStep>&&) = 0; >+ virtual void registerRedoStep(Ref<UndoStep>&&) = 0; > virtual void clearUndoRedoOperations() = 0; > > virtual bool canCopyCut(Frame*, bool defaultValue) const = 0; >diff --git a/Source/WebCore/page/UndoManager.cpp b/Source/WebCore/page/UndoManager.cpp >index 1d45ba358be049eada151dab093f1db002355851..bd47778b5c00e3692c2c905ce31e79b9447d1836 100644 >--- a/Source/WebCore/page/UndoManager.cpp >+++ b/Source/WebCore/page/UndoManager.cpp >@@ -26,6 +26,8 @@ > #include "config.h" > #include "UndoManager.h" > >+#include "CustomUndoStep.h" >+#include "Frame.h" > #include "UndoItem.h" > #include <wtf/IsoMallocInlines.h> > >@@ -42,9 +44,15 @@ UndoManager::~UndoManager() = default; > > void UndoManager::addItem(Ref<UndoItem>&& item) > { >- UNUSED_PARAM(m_document); >+ if (m_items.contains(item.ptr())) >+ return; >+ >+ auto frame = makeRefPtr(m_document.frame()); >+ if (!frame) >+ return; > > item->setUndoManager(*this); >+ frame->editor().registerCustomUndoStep(CustomUndoStep::create(item)); > m_items.add(WTFMove(item)); > } > >diff --git a/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm b/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm >index 7d2b12a088ce0e42cff31fc5ebae2923bc0820ec..eec5f2e75f1386adbc2436ff33838a75a0ec6c63 100644 >--- a/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm >+++ b/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm >@@ -2692,7 +2692,7 @@ void WebViewImpl::executeEditCommandForSelector(SEL selector, const String& argu > > void WebViewImpl::registerEditCommand(Ref<WebEditCommandProxy>&& command, UndoOrRedo undoOrRedo) > { >- auto actionName = WebCore::nameForUndoRedo(command->editAction()); >+ auto actionName = command->nameForUndoRedo(); > auto commandObjC = adoptNS([[WKEditCommand alloc] initWithWebEditCommandProxy:WTFMove(command)]); > > NSUndoManager *undoManager = [m_view undoManager]; >diff --git a/Source/WebKit/UIProcess/WebEditCommandProxy.cpp b/Source/WebKit/UIProcess/WebEditCommandProxy.cpp >index 9f83e3c19d86c9f2353a7e957610a1ea5d8584b2..6616f3a8f0a0c956a8aa02df53c9b4654eedb243 100644 >--- a/Source/WebKit/UIProcess/WebEditCommandProxy.cpp >+++ b/Source/WebKit/UIProcess/WebEditCommandProxy.cpp >@@ -36,10 +36,11 @@ > namespace WebKit { > using namespace WebCore; > >-WebEditCommandProxy::WebEditCommandProxy(WebUndoStepID commandID, WebCore::EditAction editAction, WebPageProxy* page) >+WebEditCommandProxy::WebEditCommandProxy(WebUndoStepID commandID, WebCore::EditAction editAction, const String& customUndoLabel, WebPageProxy& page) > : m_commandID(commandID) > , m_editAction(editAction) >- , m_page(page) >+ , m_customUndoLabel(customUndoLabel) >+ , m_page(makeWeakPtr(page)) > { > m_page->addEditCommand(*this); > } >@@ -68,4 +69,9 @@ void WebEditCommandProxy::reapply() > m_page->registerEditCommand(*this, UndoOrRedo::Undo); > } > >+String WebEditCommandProxy::nameForUndoRedo() const >+{ >+ return m_customUndoLabel.isEmpty() ? WebCore::nameForUndoRedo(m_editAction) : m_customUndoLabel; >+} >+ > } // namespace WebKit >diff --git a/Source/WebKit/UIProcess/WebEditCommandProxy.h b/Source/WebKit/UIProcess/WebEditCommandProxy.h >index 716cb58f403dd823196f8642f75f4df3d71aa8ca..7c08114f583db6d51abac933ceb3d429821728d8 100644 >--- a/Source/WebKit/UIProcess/WebEditCommandProxy.h >+++ b/Source/WebKit/UIProcess/WebEditCommandProxy.h >@@ -31,6 +31,7 @@ > #include <wtf/Forward.h> > #include <wtf/RefCounted.h> > #include <wtf/RefPtr.h> >+#include <wtf/WeakPtr.h> > > namespace WebKit { > >@@ -38,26 +39,28 @@ class WebPageProxy; > > class WebEditCommandProxy : public API::ObjectImpl<API::Object::Type::EditCommandProxy> { > public: >- static Ref<WebEditCommandProxy> create(WebUndoStepID commandID, WebCore::EditAction editAction, WebPageProxy* page) >+ static Ref<WebEditCommandProxy> create(WebUndoStepID commandID, WebCore::EditAction editAction, const String& customUndoLabel, WebPageProxy& page) > { >- return adoptRef(*new WebEditCommandProxy(commandID, editAction, page)); >+ return adoptRef(*new WebEditCommandProxy(commandID, editAction, customUndoLabel, page)); > } > ~WebEditCommandProxy(); > > WebUndoStepID commandID() const { return m_commandID; } > WebCore::EditAction editAction() const { return m_editAction; } > >- void invalidate() { m_page = 0; } >+ String nameForUndoRedo() const; >+ void invalidate() { m_page.clear(); } > > void unapply(); > void reapply(); > > private: >- WebEditCommandProxy(WebUndoStepID commandID, WebCore::EditAction, WebPageProxy*); >+ WebEditCommandProxy(WebUndoStepID commandID, WebCore::EditAction, const String& customUndoLabel, WebPageProxy&); > > WebUndoStepID m_commandID; > WebCore::EditAction m_editAction; >- WebPageProxy* m_page; >+ String m_customUndoLabel; >+ WeakPtr<WebPageProxy> m_page; > }; > > } // namespace WebKit >diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp >index b91faaf74493bc9859f4c1d6b437f150e5328f5a..15ec9fb1e91c437dd2eecd2ae99ef6a359b6b7c2 100644 >--- a/Source/WebKit/UIProcess/WebPageProxy.cpp >+++ b/Source/WebKit/UIProcess/WebPageProxy.cpp >@@ -5419,9 +5419,9 @@ void WebPageProxy::compositionWasCanceled() > > // Undo management > >-void WebPageProxy::registerEditCommandForUndo(WebUndoStepID commandID, uint32_t editAction) >+void WebPageProxy::registerEditCommandForUndo(WebUndoStepID commandID, uint32_t editAction, const String& customUndoLabel) > { >- registerEditCommand(WebEditCommandProxy::create(commandID, static_cast<EditAction>(editAction), this), UndoOrRedo::Undo); >+ registerEditCommand(WebEditCommandProxy::create(commandID, static_cast<EditAction>(editAction), customUndoLabel, *this), UndoOrRedo::Undo); > } > > void WebPageProxy::registerInsertionUndoGrouping() >@@ -6632,10 +6632,7 @@ void WebPageProxy::resetState(ResetStateReason resetStateReason) > m_callbacks.invalidate(error); > m_loadDependentStringCallbackIDs.clear(); > >- auto editCommandVector = copyToVector(m_editCommandSet); >- m_editCommandSet.clear(); >- >- for (auto& editCommand : editCommandVector) >+ for (auto& editCommand : std::exchange(m_editCommandSet, { })) > editCommand->invalidate(); > > m_activePopupMenu = nullptr; >diff --git a/Source/WebKit/UIProcess/WebPageProxy.h b/Source/WebKit/UIProcess/WebPageProxy.h >index 2286b35c9fb9794a9e3d7d437b49c38862dfffed..52f0f6168cf6913036eb21c6891c75b081ddf5b9 100644 >--- a/Source/WebKit/UIProcess/WebPageProxy.h >+++ b/Source/WebKit/UIProcess/WebPageProxy.h >@@ -1641,7 +1641,7 @@ private: > void backForwardClear(); > > // Undo management >- void registerEditCommandForUndo(WebUndoStepID commandID, uint32_t editAction); >+ void registerEditCommandForUndo(WebUndoStepID commandID, uint32_t editAction, const String& customUndoLabel); > void registerInsertionUndoGrouping(); > void clearAllEditCommands(); > void canUndoRedo(UndoOrRedo, bool& result); >diff --git a/Source/WebKit/UIProcess/WebPageProxy.messages.in b/Source/WebKit/UIProcess/WebPageProxy.messages.in >index 2d28ee18b69e8295c1f7a813f9cb471bdda48ff2..220eade344be4eb46b44165abb05045145191348 100644 >--- a/Source/WebKit/UIProcess/WebPageProxy.messages.in >+++ b/Source/WebKit/UIProcess/WebPageProxy.messages.in >@@ -233,7 +233,7 @@ messages -> WebPageProxy { > WillGoToBackForwardListItem(struct WebCore::BackForwardItemIdentifier itemID, bool inPageCache) > > # Undo/Redo messages >- RegisterEditCommandForUndo(uint64_t commandID, uint32_t editAction) >+ RegisterEditCommandForUndo(uint64_t commandID, uint32_t editAction, String customUndoLabel) > ClearAllEditCommands() > RegisterInsertionUndoGrouping() > CanUndoRedo(enum:bool WebKit::UndoOrRedo undoOrRedo) -> (bool result) LegacySync >diff --git a/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm b/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm >index b610724f7df8ef0c321a0c642495bac06fa6e343..1647fc5fe5727e6fd35422cf00be8da9ddb8ca99 100644 >--- a/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm >+++ b/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm >@@ -267,7 +267,7 @@ void PageClientImpl::didChangeViewportProperties(const ViewportAttributes&) > > void PageClientImpl::registerEditCommand(Ref<WebEditCommandProxy>&& command, UndoOrRedo undoOrRedo) > { >- auto actionName = WebCore::nameForUndoRedo(command->editAction()); >+ auto actionName = command->nameForUndoRedo(); > auto commandObjC = adoptNS([[WKEditCommand alloc] initWithWebEditCommandProxy:WTFMove(command)]); > > NSUndoManager *undoManager = [m_contentView undoManager]; >diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.cpp >index 0094e356d514b877db1f30b6a68ed2d73c9f1357..8b9fab509a9954b015265b4c5b6b0d921c29c763 100644 >--- a/Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.cpp >+++ b/Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.cpp >@@ -302,22 +302,23 @@ String WebEditorClient::replacementURLForResource(Ref<WebCore::SharedBuffer>&& r > return m_page->injectedBundleEditorClient().replacementURLForResource(*m_page, WTFMove(resourceData), mimeType); > } > >-void WebEditorClient::registerUndoStep(UndoStep& step) >+void WebEditorClient::registerUndoStep(Ref<UndoStep>&& step) > { > // FIXME: Add assertion that the command being reapplied is the same command that is > // being passed to us. > if (m_page->isInRedo()) > return; > >- auto webStep = WebUndoStep::create(step); >+ auto editAction = static_cast<uint32_t>(step->editingAction()); >+ auto customName = step->customUndoLabel(); >+ auto webStep = WebUndoStep::create(WTFMove(step)); > auto stepID = webStep->stepID(); >- auto editAction = static_cast<uint32_t>(webStep->step().editingAction()); > > m_page->addWebUndoStep(stepID, WTFMove(webStep)); >- m_page->send(Messages::WebPageProxy::RegisterEditCommandForUndo(stepID, editAction), m_page->pageID(), IPC::SendOption::DispatchMessageEvenWhenWaitingForSyncReply); >+ m_page->send(Messages::WebPageProxy::RegisterEditCommandForUndo(stepID, editAction, customName), m_page->pageID(), IPC::SendOption::DispatchMessageEvenWhenWaitingForSyncReply); > } > >-void WebEditorClient::registerRedoStep(UndoStep&) >+void WebEditorClient::registerRedoStep(Ref<UndoStep>&&) > { > } > >diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.h b/Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.h >index 4720b71175412a59a229bc47106dab2da3c8756e..f41b086321c1f42825c5ad9ae2d96a9e2d705b6f 100644 >--- a/Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.h >+++ b/Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.h >@@ -85,8 +85,8 @@ private: > void getClientPasteboardDataForRange(WebCore::Range*, Vector<String>& pasteboardTypes, Vector<RefPtr<WebCore::SharedBuffer>>& pasteboardData) final; > String replacementURLForResource(Ref<WebCore::SharedBuffer>&& resourceData, const String& mimeType) final; > >- void registerUndoStep(WebCore::UndoStep&) final; >- void registerRedoStep(WebCore::UndoStep&) final; >+ void registerUndoStep(Ref<WebCore::UndoStep>&&) final; >+ void registerRedoStep(Ref<WebCore::UndoStep>&&) final; > void clearUndoRedoOperations() final; > > bool canCopyCut(WebCore::Frame*, bool defaultValue) const final; >diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.cpp b/Source/WebKit/WebProcess/WebPage/WebPage.cpp >index dd97d6eb07ae252a6ec7ec15fce77a34f215643c..5968a1bf590c0f02f12deb112ca5ab8bbe2da778 100644 >--- a/Source/WebKit/WebProcess/WebPage/WebPage.cpp >+++ b/Source/WebKit/WebProcess/WebPage/WebPage.cpp >@@ -3791,12 +3791,14 @@ WebUndoStep* WebPage::webUndoStep(WebUndoStepID stepID) > > void WebPage::addWebUndoStep(WebUndoStepID stepID, Ref<WebUndoStep>&& entry) > { >- m_undoStepMap.set(stepID, WTFMove(entry)); >+ auto addResult = m_undoStepMap.set(stepID, WTFMove(entry)); >+ ASSERT_UNUSED(addResult, addResult.isNewEntry); > } > > void WebPage::removeWebEditCommand(WebUndoStepID stepID) > { >- m_undoStepMap.remove(stepID); >+ if (auto undoStep = m_undoStepMap.take(stepID)) >+ undoStep->invalidate(); > } > > bool WebPage::isAlwaysOnLoggingAllowed() const >diff --git a/Source/WebKit/WebProcess/WebPage/WebUndoStep.h b/Source/WebKit/WebProcess/WebPage/WebUndoStep.h >index 211fd99e5e6c696fa7c399f7f7edd038ab8a8d8a..47fbf5db606c0d11220733ea8f7291d1e9ffc42b 100644 >--- a/Source/WebKit/WebProcess/WebPage/WebUndoStep.h >+++ b/Source/WebKit/WebProcess/WebPage/WebUndoStep.h >@@ -39,6 +39,8 @@ public: > WebCore::UndoStep& step() const { return m_step.get(); } > WebUndoStepID stepID() const { return m_stepID; } > >+ void invalidate() { m_step->invalidate(); } >+ > private: > WebUndoStep(Ref<WebCore::UndoStep>&& step, WebUndoStepID stepID) > : m_step(WTFMove(step)) >diff --git a/Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.h b/Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.h >index f0f968b7e2b66c891dc14b6c1faaf0b8bbe1d19e..af35db25acbbd4af32827fc2da9ce1287e05b802 100644 >--- a/Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.h >+++ b/Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.h >@@ -114,8 +114,8 @@ private: > void canceledComposition() final; > void didUpdateComposition() final { } > >- void registerUndoStep(WebCore::UndoStep&) final; >- void registerRedoStep(WebCore::UndoStep&) final; >+ void registerUndoStep(Ref<WebCore::UndoStep>&&) final; >+ void registerRedoStep(Ref<WebCore::UndoStep>&&) final; > void clearUndoRedoOperations() final; > > bool canCopyCut(WebCore::Frame*, bool defaultValue) const final; >@@ -172,7 +172,7 @@ private: > void handleAcceptedCandidateWithSoftSpaces(WebCore::TextCheckingResult) final; > #endif > >- void registerUndoOrRedoStep(WebCore::UndoStep&, bool isRedo); >+ void registerUndoOrRedoStep(Ref<WebCore::UndoStep>&&, bool isRedo); > > WebView *m_webView; > RetainPtr<WebEditorUndoTarget> m_undoTarget; >diff --git a/Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.mm b/Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.mm >index ccc33f940fbc9e631fdd98d2ea16b97e156bd0b3..659e7f89269ca7e3a30421bef45a27646f8b038f 100644 >--- a/Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.mm >+++ b/Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.mm >@@ -125,7 +125,7 @@ @interface WebUndoStep : NSObject > RefPtr<UndoStep> m_step; > } > >-+ (WebUndoStep *)stepWithUndoStep:(UndoStep&)step; >++ (WebUndoStep *)stepWithUndoStep:(Ref<UndoStep>&&)step; > - (UndoStep&)step; > > @end >@@ -141,12 +141,12 @@ + (void)initialize > #endif > } > >-- (id)initWithUndoStep:(UndoStep&)step >+- (id)initWithUndoStep:(Ref<UndoStep>&&)step > { > self = [super init]; > if (!self) > return nil; >- m_step = &step; >+ m_step = WTFMove(step); > return self; > } > >@@ -158,9 +158,9 @@ - (void)dealloc > [super dealloc]; > } > >-+ (WebUndoStep *)stepWithUndoStep:(UndoStep&)step >++ (WebUndoStep *)stepWithUndoStep:(Ref<UndoStep>&&)step > { >- return [[[WebUndoStep alloc] initWithUndoStep:step] autorelease]; >+ return [[[WebUndoStep alloc] initWithUndoStep:WTFMove(step)] autorelease]; > } > > - (UndoStep&)step >@@ -589,7 +589,7 @@ bool WebEditorClient::shouldInsertNode(Node *node, Range* replacingRange, Editor > return [[m_webView _editingDelegateForwarder] webView:m_webView shouldInsertNode:kit(node) replacingDOMRange:kit(replacingRange) givenAction:(WebViewInsertAction)givenAction]; > } > >-void WebEditorClient::registerUndoOrRedoStep(UndoStep& step, bool isRedo) >+void WebEditorClient::registerUndoOrRedoStep(Ref<UndoStep>&& step, bool isRedo) > { > NSUndoManager *undoManager = [m_webView undoManager]; > >@@ -601,10 +601,9 @@ void WebEditorClient::registerUndoOrRedoStep(UndoStep& step, bool isRedo) > return; > #endif > >- NSString *actionName = WebCore::nameForUndoRedo(step.editingAction()); >- WebUndoStep *webEntry = [WebUndoStep stepWithUndoStep:step]; >- [undoManager registerUndoWithTarget:m_undoTarget.get() selector:(isRedo ? @selector(redoEditing:) : @selector(undoEditing:)) object:webEntry]; >- if (actionName) >+ String actionName = step->customUndoLabel().isEmpty() ? WebCore::nameForUndoRedo(step->editingAction()) : step->customUndoLabel(); >+ [undoManager registerUndoWithTarget:m_undoTarget.get() selector:(isRedo ? @selector(redoEditing:) : @selector(undoEditing:)) object:[WebUndoStep stepWithUndoStep:WTFMove(step)]]; >+ if (!actionName.isEmpty()) > [undoManager setActionName:actionName]; > m_haveUndoRedoOperations = YES; > } >@@ -629,14 +628,14 @@ void WebEditorClient::updateEditorStateAfterLayoutIfEditabilityChanged() > [m_webView updateTouchBar]; > } > >-void WebEditorClient::registerUndoStep(UndoStep& cmd) >+void WebEditorClient::registerUndoStep(Ref<UndoStep>&& command) > { >- registerUndoOrRedoStep(cmd, false); >+ registerUndoOrRedoStep(WTFMove(command), false); > } > >-void WebEditorClient::registerRedoStep(UndoStep& cmd) >+void WebEditorClient::registerRedoStep(Ref<UndoStep>&& command) > { >- registerUndoOrRedoStep(cmd, true); >+ registerUndoOrRedoStep(WTFMove(command), true); > } > > void WebEditorClient::clearUndoRedoOperations() >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index e9450ea093e26f21ad7717ef264f8f418541c099..6296fefde2b9acfba3a7e1be488ac3c0809f5390 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,35 @@ >+2019-01-19 Wenson Hsieh <wenson_hsieh@apple.com> >+ >+ [Cocoa] Allow the page to add to the platform undo stack via UndoManager.addItem() >+ https://bugs.webkit.org/show_bug.cgi?id=193111 >+ <rdar://problem/44807048> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add UIScriptController helpers to grab the platform undo and redo action labels. Currently only implemented for >+ Cocoa platforms in WebKit2. See other ChangeLogs for more detail. >+ >+ * DumpRenderTree/ios/UIScriptControllerIOS.mm: >+ (WTR::UIScriptController::undoActionName const): >+ (WTR::UIScriptController::redoActionName const): >+ (WTR::UIScriptController::platformUndoManager const): >+ * DumpRenderTree/mac/UIScriptControllerMac.mm: >+ (WTR::UIScriptController::undoActionName const): >+ (WTR::UIScriptController::redoActionName const): >+ (WTR::UIScriptController::platformUndoManager const): >+ * TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl: >+ * TestRunnerShared/UIScriptContext/UIScriptController.cpp: >+ (WTR::UIScriptController::undoActionName const): >+ (WTR::UIScriptController::redoActionName const): >+ * TestRunnerShared/UIScriptContext/UIScriptController.h: >+ * WebKitTestRunner/UIScriptControllerCocoa.mm: >+ (WTR::UIScriptController::undoActionName const): >+ (WTR::UIScriptController::redoActionName const): >+ * WebKitTestRunner/ios/UIScriptControllerIOS.mm: >+ (WTR::UIScriptController::platformUndoManager const): >+ * WebKitTestRunner/mac/UIScriptControllerMac.mm: >+ (WTR::UIScriptController::platformUndoManager const): >+ > 2019-01-18 Zhifei FANG <zhifei_fang@apple.com> > > Disable the run-jsc-stress-test remote host key check [second round]. >diff --git a/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm b/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm >index 8a1125f4ef9198452669e0419c589a8902e8a670..77e3266bd9d843f325775913508dbfa95d558b45 100644 >--- a/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm >+++ b/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm >@@ -450,6 +450,21 @@ void UIScriptController::setKeyboardInputModeIdentifier(JSStringRef) > { > } > >+JSRetainPtr<JSStringRef> UIScriptController::undoActionName() const >+{ >+ return nullptr; >+} >+ >+JSRetainPtr<JSStringRef> UIScriptController::redoActionName() const >+{ >+ return nullptr; >+} >+ >+NSUndoManager *UIScriptController::platformUndoManager() const >+{ >+ return nil; >+} >+ > } > > #endif // PLATFORM(IOS_FAMILY) >diff --git a/Tools/DumpRenderTree/mac/UIScriptControllerMac.mm b/Tools/DumpRenderTree/mac/UIScriptControllerMac.mm >index c445145f33bef0cc1949e3d5aae0f533bee142d7..b806846137aa21f9c6fe63ea35bafbfc213329af 100644 >--- a/Tools/DumpRenderTree/mac/UIScriptControllerMac.mm >+++ b/Tools/DumpRenderTree/mac/UIScriptControllerMac.mm >@@ -215,6 +215,21 @@ void UIScriptController::toggleCapsLock(JSValueRef callback) > doAsyncTask(callback); > } > >+JSRetainPtr<JSStringRef> UIScriptController::undoActionName() const >+{ >+ return nullptr; >+} >+ >+JSRetainPtr<JSStringRef> UIScriptController::redoActionName() const >+{ >+ return nullptr; >+} >+ >+NSUndoManager *UIScriptController::platformUndoManager() const >+{ >+ return nil; >+} >+ > } > > #endif // PLATFORM(MAC) >diff --git a/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl b/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl >index 5424ba8a8cfbe4ad814c0dabe6117337eedf967c..c9a4bbf1c5eb1a5f11dd280214c3cad9e0a5064e 100644 >--- a/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl >+++ b/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl >@@ -290,8 +290,11 @@ interface UIScriptController { > void makeWindowContentViewFirstResponder(); > readonly attribute boolean isWindowContentViewFirstResponder; > >+ object attachmentInfo(DOMString attachmentIdentifier); >+ >+ // Editing > void drawSquareInEditableImage(); > readonly attribute long numberOfStrokesInEditableImage; >- >- object attachmentInfo(DOMString attachmentIdentifier); >+ readonly attribute DOMString undoActionName; >+ readonly attribute DOMString redoActionName; > }; >diff --git a/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp b/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp >index a5baa06cd533200599f3af56893e375f6e0233c1..d163ab87ddb9e21869ca67026307850e51a71c9a 100644 >--- a/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp >+++ b/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp >@@ -245,6 +245,16 @@ void UIScriptController::toggleCapsLock(JSValueRef) > { > } > >+JSRetainPtr<JSStringRef> UIScriptController::undoActionName() const >+{ >+ return nullptr; >+} >+ >+JSRetainPtr<JSStringRef> UIScriptController::redoActionName() const >+{ >+ return nullptr; >+} >+ > #endif // !PLATFORM(COCOA) > > void UIScriptController::playBackEventStream(JSStringRef stream, JSValueRef callback) >@@ -569,6 +579,16 @@ void UIScriptController::overridePreference(JSStringRef, JSStringRef) > { > } > >+JSRetainPtr<JSStringRef> UIScriptController::undoActionName() const >+{ >+ return nullptr; >+} >+ >+JSRetainPtr<JSStringRef> UIScriptController::redoActionName() const >+{ >+ return nullptr; >+} >+ > #endif // !PLATFORM(COCOA) > > #if !PLATFORM(MAC) >diff --git a/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h b/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h >index d3fb1cbb09250a8279dfcb28bbf8c9027f7021cb..ff7a8e9541690d26e036d835d488375ab2720e8f 100644 >--- a/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h >+++ b/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h >@@ -31,6 +31,8 @@ > #include <wtf/Optional.h> > #include <wtf/Ref.h> > >+OBJC_CLASS NSUndoManager; >+ > namespace WebCore { > class FloatRect; > } >@@ -206,6 +208,9 @@ public: > void drawSquareInEditableImage(); > long numberOfStrokesInEditableImage(); > >+ JSRetainPtr<JSStringRef> undoActionName() const; >+ JSRetainPtr<JSStringRef> redoActionName() const; >+ > JSObjectRef attachmentInfo(JSStringRef attachmentIdentifier); > > private: >@@ -225,6 +230,10 @@ private: > void platformClearAllCallbacks(); > void platformPlayBackEventStream(JSStringRef, JSValueRef); > >+#if PLATFORM(COCOA) >+ NSUndoManager *platformUndoManager() const; >+#endif >+ > JSClassRef wrapperClass() final; > > JSObjectRef objectFromRect(const WebCore::FloatRect&) const; >diff --git a/Tools/WebKitTestRunner/UIScriptControllerCocoa.mm b/Tools/WebKitTestRunner/UIScriptControllerCocoa.mm >index a7b98e404b83102294937f646f64ecf8925712f6..73a6c98ae6fecf1a375bdace9ac8bdb03efb364f 100644 >--- a/Tools/WebKitTestRunner/UIScriptControllerCocoa.mm >+++ b/Tools/WebKitTestRunner/UIScriptControllerCocoa.mm >@@ -192,5 +192,15 @@ JSObjectRef UIScriptController::calendarType() const > return nullptr; > #endif > } >- >+ >+JSRetainPtr<JSStringRef> UIScriptController::undoActionName() const >+{ >+ return JSStringCreateWithCFString((__bridge CFStringRef)platformUndoManager().undoActionName); >+} >+ >+JSRetainPtr<JSStringRef> UIScriptController::redoActionName() const >+{ >+ return JSStringCreateWithCFString((__bridge CFStringRef)platformUndoManager().redoActionName); >+} >+ > } // namespace WTR >diff --git a/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm b/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm >index 4aa94290578748cf81bc5355076dfa27a8a81c5d..e654039454ea01978c8ce4505596781bba875fbe 100644 >--- a/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm >+++ b/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm >@@ -971,6 +971,11 @@ JSObjectRef UIScriptController::attachmentInfo(JSStringRef jsAttachmentIdentifie > return JSValueToObject(m_context->jsContext(), [JSValue valueWithObject:attachmentInfoDictionary inContext:[JSContext contextWithJSGlobalContextRef:m_context->jsContext()]].JSValueRef, nullptr); > } > >+NSUndoManager *UIScriptController::platformUndoManager() const >+{ >+ return [(UIView *)[TestController::singleton().mainWebView()->platformView() valueForKeyPath:@"_currentContentView"] undoManager]; >+} >+ > } > > #endif // PLATFORM(IOS_FAMILY) >diff --git a/Tools/WebKitTestRunner/mac/UIScriptControllerMac.mm b/Tools/WebKitTestRunner/mac/UIScriptControllerMac.mm >index 218881152a895cddb6a7f40716f1900a5d77ac3b..757fa06bd78f1833f13b38cbc9b030f93419763f 100644 >--- a/Tools/WebKitTestRunner/mac/UIScriptControllerMac.mm >+++ b/Tools/WebKitTestRunner/mac/UIScriptControllerMac.mm >@@ -209,4 +209,9 @@ void UIScriptController::toggleCapsLock(JSValueRef callback) > doAsyncTask(callback); > } > >+NSUndoManager *UIScriptController::platformUndoManager() const >+{ >+ return TestController::singleton().mainWebView()->platformView().undoManager; >+} >+ > } // namespace WTR >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 3546178a072af9b739ed64f27275b53b1c239a3d..6b753b7a9bf2be9a3775a551c89472f070bdbb77 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,42 @@ >+2019-01-19 Wenson Hsieh <wenson_hsieh@apple.com> >+ >+ [Cocoa] Allow the page to add to the platform undo stack via UndoManager.addItem() >+ https://bugs.webkit.org/show_bug.cgi?id=193111 >+ <rdar://problem/44807048> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add a few new layout tests covering `UndoManager.addItem()`. >+ >+ * editing/undo-manager/undo-manager-add-item-expected.txt: Added. >+ * editing/undo-manager/undo-manager-add-item.html: Added. >+ >+ Add a test that exercises the new API in both the top-level context and a child frame. >+ >+ * editing/undo-manager/undo-manager-delete-stale-undo-items-expected.txt: Added. >+ * editing/undo-manager/undo-manager-delete-stale-undo-items.html: Added. >+ >+ Add a test to verify that after adding undo items, undoing, and then performing other edit actions, garbage >+ collection will destroy JS wrappers for the previously added UndoItems, since these undo items' handlers can no >+ longer be invoked. >+ >+ * editing/undo-manager/undo-manager-item-labels-expected.txt: Added. >+ * editing/undo-manager/undo-manager-item-labels.html: Added. >+ >+ Add a test verifying that the undo and redo action labels are updated correctly when undoing and redoing. >+ >+ * editing/undo-manager/undo-manager-undo-redo-after-garbage-collection-expected.txt: Added. >+ * editing/undo-manager/undo-manager-undo-redo-after-garbage-collection.html: Added. >+ >+ Add a test to verify that triggering garbage collection after adding an undo item without keeping references to >+ the item (or its undo/redo handlers) doesn't break the API. >+ >+ * resources/ui-helper.js: >+ (window.UIHelper.undoAndRedoActionNames): >+ (window.UIHelper): >+ >+ Add a helper method to grab the platform's current undo and redo action names. >+ > 2019-01-18 Justin Fan <justin_fan@apple.com> > > (WIP) [WebGPU] WebGPUProgrammablePassEncoder::setBindGroup prototype >diff --git a/LayoutTests/editing/undo-manager/undo-manager-add-item-expected.txt b/LayoutTests/editing/undo-manager/undo-manager-add-item-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..956da89916c7bf440816a551efeacd7340d8136d >--- /dev/null >+++ b/LayoutTests/editing/undo-manager/undo-manager-add-item-expected.txt >@@ -0,0 +1,32 @@ >+This test verifies that UndoManager.addItem() can be used to add undo items to the platform undo stack. >+ >+ >+After adding an undo item (mainframe): >+PASS undoName is "mainframe" >+PASS redoName is "" >+After performing undo (mainframe): >+** UNDO ** >+PASS undoName is "" >+PASS redoName is "mainframe" >+After performing redo (mainframe): >+** REDO ** >+PASS undoName is "mainframe" >+PASS redoName is "" >+After adding an undo item (subframe): >+PASS undoName is "subframe" >+PASS redoName is "" >+After performing undo (subframe): >+PASS undoName is "mainframe" >+PASS redoName is "subframe" >+After performing redo (subframe): >+PASS undoName is "subframe" >+PASS redoName is "" >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >+ >+-------- >+Frame: '<!--frame1-->' >+-------- >+UNDO, REDO >diff --git a/LayoutTests/editing/undo-manager/undo-manager-add-item.html b/LayoutTests/editing/undo-manager/undo-manager-add-item.html >new file mode 100644 >index 0000000000000000000000000000000000000000..fec61890b1b81ff7e503e8bb35cb858d92a7c592 >--- /dev/null >+++ b/LayoutTests/editing/undo-manager/undo-manager-add-item.html >@@ -0,0 +1,93 @@ >+<!DOCTYPE html> <!-- webkit-test-runner [ enableUndoManagerAPI=true ] --> >+<html> >+ <head> >+ <script src="../../resources/js-test.js"></script> >+ <script src="../../resources/ui-helper.js"></script> >+ <script> >+ function addUndoItem() >+ { >+ document.undoManager.addItem(new UndoItem({ >+ label: "mainframe", >+ undo: () => debug("** UNDO **"), >+ redo: () => debug("** REDO **") >+ })); >+ } >+ </script> >+ </head> >+ <body> >+ <p>This test verifies that <code>UndoManager.addItem()</code> can be used to add undo items to the platform undo stack.</p> >+ <iframe id="frame" srcdoc=" >+ <body> >+ <pre id='output'></pre> >+ </body> >+ <script> >+ function appendOutput(string) >+ { >+ if (output.textContent.length) >+ output.textContent += ', '; >+ output.textContent += string; >+ } >+ >+ function addUndoItem() >+ { >+ document.undoManager.addItem(new UndoItem({ >+ label: 'subframe', >+ undo: () => appendOutput('UNDO'), >+ redo: () => appendOutput('REDO') >+ })); >+ } >+ </script> >+ "></iframe> >+ <pre id='console'></pre> >+ </body> >+ <script> >+ jsTestIsAsync = true; >+ undoName = null; >+ redoName = null; >+ >+ if (window.testRunner) >+ testRunner.dumpChildFramesAsText(); >+ >+ addEventListener("load", async () => { >+ debug("After adding an undo item (mainframe):"); >+ addUndoItem(); >+ [undoName, redoName] = await UIHelper.undoAndRedoActionNames(); >+ shouldBeEqualToString("undoName", "mainframe"); >+ shouldBeEqualToString("redoName", ""); >+ >+ debug("After performing undo (mainframe):"); >+ document.execCommand("undo"); >+ [undoName, redoName] = await UIHelper.undoAndRedoActionNames(); >+ shouldBeEqualToString("undoName", ""); >+ shouldBeEqualToString("redoName", "mainframe"); >+ >+ debug("After performing redo (mainframe):"); >+ document.execCommand("redo"); >+ [undoName, redoName] = await UIHelper.undoAndRedoActionNames(); >+ shouldBeEqualToString("undoName", "mainframe"); >+ shouldBeEqualToString("redoName", ""); >+ >+ const frameWindow = frame.contentWindow; >+ >+ debug("After adding an undo item (subframe):"); >+ frameWindow.addUndoItem(); >+ [undoName, redoName] = await UIHelper.undoAndRedoActionNames(); >+ shouldBeEqualToString("undoName", "subframe"); >+ shouldBeEqualToString("redoName", ""); >+ >+ debug("After performing undo (subframe):"); >+ document.execCommand("undo"); >+ [undoName, redoName] = await UIHelper.undoAndRedoActionNames(); >+ shouldBeEqualToString("undoName", "mainframe"); >+ shouldBeEqualToString("redoName", "subframe"); >+ >+ debug("After performing redo (subframe):"); >+ document.execCommand("redo"); >+ [undoName, redoName] = await UIHelper.undoAndRedoActionNames(); >+ shouldBeEqualToString("undoName", "subframe"); >+ shouldBeEqualToString("redoName", ""); >+ >+ finishJSTest(); >+ }); >+ </script> >+</html> >diff --git a/LayoutTests/editing/undo-manager/undo-manager-delete-stale-undo-items-expected.txt b/LayoutTests/editing/undo-manager/undo-manager-delete-stale-undo-items-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..77e1cc2da5633ee71a9912a1ce0ebf61acf5ecb8 >--- /dev/null >+++ b/LayoutTests/editing/undo-manager/undo-manager-delete-stale-undo-items-expected.txt >@@ -0,0 +1,10 @@ >+E >+Verifies that JSUndoItems are deleted when they are no longer needed by the platform clipboard. This test requires WebKitTestRunner. >+ >+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". >+ >+PASS objectCountBeforeClearingUndoStack - objectCountAfterClearingUndoStack is >= 580 >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >diff --git a/LayoutTests/editing/undo-manager/undo-manager-delete-stale-undo-items.html b/LayoutTests/editing/undo-manager/undo-manager-delete-stale-undo-items.html >new file mode 100644 >index 0000000000000000000000000000000000000000..e52890056f593656c1d7954e98c80275ae934ca6 >--- /dev/null >+++ b/LayoutTests/editing/undo-manager/undo-manager-delete-stale-undo-items.html >@@ -0,0 +1,66 @@ >+<!DOCTYPE html> <!-- webkit-test-runner [ enableUndoManagerAPI=true ] --> >+<html> >+ <meta charset="utf8"> >+ <head> >+ <script src="../../resources/js-test.js"></script> >+ <script src="../editing.js"></script> >+ <script> >+ jsTestIsAsync = true; >+ >+ function objectCountAfterSimulatingMemoryPressureAndGarbageCollection() { >+ internals.beginSimulatedMemoryPressure(); >+ internals.endSimulatedMemoryPressure(); >+ GCController.collect(); >+ return GCController.getJSObjectCount(); >+ } >+ >+ async function runTest() { >+ description("Verifies that JSUndoItems are deleted when they are no longer needed by the platform clipboard. This test requires WebKitTestRunner."); >+ >+ if (!window.GCController) >+ return; >+ >+ editor = document.getElementById("editor"); >+ editor.focus(); >+ >+ const undoItemCount = 200; >+ >+ for (let i = 0; i < undoItemCount; ++i) { >+ document.undoManager.addItem(new UndoItem({ >+ label: "", >+ undo: () => { }, >+ redo: () => { } >+ })); >+ } >+ >+ for (let i = 0; i < undoItemCount; ++i) >+ document.execCommand("Undo"); >+ >+ objectCountBeforeClearingUndoStack = objectCountAfterSimulatingMemoryPressureAndGarbageCollection(); >+ >+ selectAllCommand(); >+ typeCharacterCommand("E"); >+ >+ // Wait until almost all of the wrappers are collected. For each UndoItem, we expect a total of 3 wrappers: >+ // one each for the undo and redo handlers, and one for the UndoItem itself. However, we also give ourselves >+ // some wiggle room for additional wrappers created when calling some testing helper functions. This is >+ // still a useful test, since it will time out in the case where either our undo items or their undo/redo >+ // handlers are not properly relinquished once they're no longer needed. >+ const minimumNumberOfWrappersToCollectBeforePassing = 3 * undoItemCount - 20; >+ objectCountAfterClearingUndoStack = objectCountBeforeClearingUndoStack; >+ while (objectCountBeforeClearingUndoStack - objectCountAfterClearingUndoStack < minimumNumberOfWrappersToCollectBeforePassing) { >+ await new Promise(resolve => setTimeout(resolve, 100)); >+ objectCountAfterClearingUndoStack = objectCountAfterSimulatingMemoryPressureAndGarbageCollection(); >+ } >+ >+ shouldBeGreaterThanOrEqual("objectCountBeforeClearingUndoStack - objectCountAfterClearingUndoStack", `${minimumNumberOfWrappersToCollectBeforePassing}`); >+ finishJSTest(); >+ } >+ </script> >+ </head> >+ <body onload="runTest()"> >+ <div contenteditable id="editor"></div> >+ <pre id="description"></pre> >+ <pre id="console"></pre> >+ </body> >+</html> >diff --git a/LayoutTests/editing/undo-manager/undo-manager-item-labels-expected.txt b/LayoutTests/editing/undo-manager/undo-manager-item-labels-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..d6d75c163a74464f687931bf0aa2cc8cbdd3ce30 >--- /dev/null >+++ b/LayoutTests/editing/undo-manager/undo-manager-item-labels-expected.txt >@@ -0,0 +1,36 @@ >+ >+Verifies that setting the label attribute of UndoItem affects the undo and redo action names in the platform undo manager. >+ >+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". >+ >+After typing: >+PASS undoName is "Typing" >+PASS redoName is "" >+After adding the first UndoItem: >+PASS undoName is "First ð¥" >+PASS redoName is "" >+After adding the second UndoItem: >+PASS undoName is "Second ð¥" >+PASS redoName is "" >+After undoing: >+PASS undoName is "First ð¥" >+PASS redoName is "Second ð¥" >+After undoing again: >+PASS undoName is "Typing" >+PASS redoName is "First ð¥" >+After redoing: >+PASS undoName is "First ð¥" >+PASS redoName is "Second ð¥" >+After redoing again: >+PASS undoName is "Second ð¥" >+PASS redoName is "" >+After undoing and then pasting: >+PASS undoName is "Paste" >+PASS redoName is "" >+After undoing the paste command: >+PASS undoName is "First ð¥" >+PASS redoName is "Paste" >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >diff --git a/LayoutTests/editing/undo-manager/undo-manager-item-labels.html b/LayoutTests/editing/undo-manager/undo-manager-item-labels.html >new file mode 100644 >index 0000000000000000000000000000000000000000..cd61d4c70d7ba20762c3744ff356107fe1e5d4cb >--- /dev/null >+++ b/LayoutTests/editing/undo-manager/undo-manager-item-labels.html >@@ -0,0 +1,95 @@ >+<!DOCTYPE html> <!-- webkit-test-runner [ enableUndoManagerAPI=true ] --> >+<html> >+ <meta charset="utf8"> >+ <head> >+ <script src="../../resources/js-test.js"></script> >+ <script src="../../resources/ui-helper.js"></script> >+ <script src="../editing.js"></script> >+ <script> >+ jsTestIsAsync = true; >+ undoName = null; >+ redoName = null; >+ >+ async function runTest() { >+ description("Verifies that setting the label attribute of UndoItem affects the undo and redo action names " >+ + "in the platform undo manager."); >+ >+ field.focus(); >+ >+ debug("After typing:"); >+ document.execCommand("InsertText", true, "hello"); >+ [undoName, redoName] = await UIHelper.undoAndRedoActionNames(); >+ shouldBeEqualToString("undoName", "Typing"); >+ shouldBeEqualToString("redoName", ""); >+ >+ function createUndoItemWithLabel(labelString) { >+ return new UndoItem({ >+ label: labelString, >+ undo: () => { }, >+ redo: () => { } >+ }); >+ } >+ >+ debug("After adding the first UndoItem:"); >+ const firstItem = createUndoItemWithLabel("First ð¥"); >+ document.undoManager.addItem(firstItem); >+ [undoName, redoName] = await UIHelper.undoAndRedoActionNames(); >+ shouldBeEqualToString("undoName", firstItem.label); >+ shouldBeEqualToString("redoName", ""); >+ >+ debug("After adding the second UndoItem:"); >+ const secondItem = createUndoItemWithLabel("Second ð¥"); >+ document.undoManager.addItem(secondItem); >+ [undoName, redoName] = await UIHelper.undoAndRedoActionNames(); >+ shouldBeEqualToString("undoName", secondItem.label); >+ shouldBeEqualToString("redoName", ""); >+ >+ debug("After undoing:"); >+ document.execCommand("undo"); >+ [undoName, redoName] = await UIHelper.undoAndRedoActionNames(); >+ shouldBeEqualToString("undoName", firstItem.label); >+ shouldBeEqualToString("redoName", secondItem.label); >+ >+ debug("After undoing again:"); >+ document.execCommand("undo"); >+ [undoName, redoName] = await UIHelper.undoAndRedoActionNames(); >+ shouldBeEqualToString("undoName", "Typing"); >+ shouldBeEqualToString("redoName", firstItem.label); >+ >+ debug("After redoing:"); >+ document.execCommand("redo"); >+ [undoName, redoName] = await UIHelper.undoAndRedoActionNames(); >+ shouldBeEqualToString("undoName", firstItem.label); >+ shouldBeEqualToString("redoName", secondItem.label); >+ >+ debug("After redoing again:"); >+ document.execCommand("redo"); >+ [undoName, redoName] = await UIHelper.undoAndRedoActionNames(); >+ shouldBeEqualToString("undoName", secondItem.label); >+ shouldBeEqualToString("redoName", ""); >+ >+ debug("After undoing and then pasting:"); >+ document.execCommand("undo"); >+ selectAllCommand(); >+ copyCommand(); >+ pasteCommand(); >+ [undoName, redoName] = await UIHelper.undoAndRedoActionNames(); >+ shouldBeEqualToString("undoName", "Paste"); >+ shouldBeEqualToString("redoName", ""); >+ >+ debug("After undoing the paste command:"); >+ document.execCommand("undo"); >+ [undoName, redoName] = await UIHelper.undoAndRedoActionNames(); >+ shouldBeEqualToString("undoName", firstItem.label); >+ shouldBeEqualToString("redoName", "Paste"); >+ >+ finishJSTest(); >+ } >+ </script> >+ </head> >+ <body onload="runTest()"> >+ <input id="field"></input> >+ <pre id="description"></pre> >+ <pre id="console"></pre> >+ </body> >+</html> >diff --git a/LayoutTests/editing/undo-manager/undo-manager-undo-redo-after-garbage-collection-expected.txt b/LayoutTests/editing/undo-manager/undo-manager-undo-redo-after-garbage-collection-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..7c9392adc4d3d9059907c7ecb58e15ba2845ca3b >--- /dev/null >+++ b/LayoutTests/editing/undo-manager/undo-manager-undo-redo-after-garbage-collection-expected.txt >@@ -0,0 +1,11 @@ >+After redo >+Verifies that undo and redo callback handlers survive garbage collection. This test requires WebKitTestRunner. >+ >+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". >+ >+PASS text.textContent is "After undo" >+PASS text.textContent is "After redo" >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >diff --git a/LayoutTests/editing/undo-manager/undo-manager-undo-redo-after-garbage-collection.html b/LayoutTests/editing/undo-manager/undo-manager-undo-redo-after-garbage-collection.html >new file mode 100644 >index 0000000000000000000000000000000000000000..cad0ced4cee833cda19cee03cca14b42a4aa4821 >--- /dev/null >+++ b/LayoutTests/editing/undo-manager/undo-manager-undo-redo-after-garbage-collection.html >@@ -0,0 +1,35 @@ >+<!DOCTYPE html> <!-- webkit-test-runner [ enableUndoManagerAPI=true ] --> >+<html> >+ <meta charset="utf8"> >+ <head> >+ <script src="../../resources/js-test.js"></script> >+ <script src="../editing.js"></script> >+ <script> >+ function runTest() { >+ description("Verifies that undo and redo callback handlers survive garbage collection. This test requires WebKitTestRunner."); >+ >+ text = document.getElementById("text"); >+ >+ document.undoManager.addItem(new UndoItem({ >+ label: "Test action", >+ undo: () => text.textContent = "After undo", >+ redo: () => text.textContent = "After redo" >+ })); >+ >+ if (window.GCController) >+ GCController.collect(); >+ >+ document.execCommand("Undo"); >+ shouldBeEqualToString("text.textContent", "After undo"); >+ >+ document.execCommand("Redo"); >+ shouldBeEqualToString("text.textContent", "After redo"); >+ } >+ </script> >+ </head> >+ <body onload="runTest()"> >+ <div id="text">Initial state</div> >+ <pre id="description"></pre> >+ <pre id="console"></pre> >+ </body> >+</html> >diff --git a/LayoutTests/resources/ui-helper.js b/LayoutTests/resources/ui-helper.js >index 1884db7659650572ddcaaafc295b50202be6b564..6e8b7f19a5734d55bfc5b9134e9b84d6209a7a7e 100644 >--- a/LayoutTests/resources/ui-helper.js >+++ b/LayoutTests/resources/ui-helper.js >@@ -566,4 +566,13 @@ window.UIHelper = class UIHelper { > resolve({ x: offsetX, y: offsetY }); > })); > } >+ >+ static undoAndRedoActionNames() >+ { >+ if (!this.isWebKit2()) >+ return Promise.resolve(); >+ >+ const script = "JSON.stringify([uiController.undoActionName, uiController.redoActionName])"; >+ return new Promise(resolve => testRunner.runUIScript(script, result => resolve(JSON.parse(result)))); >+ } > }
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
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 193111
:
358427
|
359498
|
359590
|
359591
|
359592
|
359593
|
359594
|
359631
|
359632
|
359819
|
359832
|
359834