Diff
Modified: trunk/LayoutTests/ChangeLog (240475 => 240476)
--- trunk/LayoutTests/ChangeLog 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/LayoutTests/ChangeLog 2019-01-25 17:23:06 UTC (rev 240476)
@@ -1,3 +1,48 @@
+2019-01-25 Wenson Hsieh <[email protected]>
+
+ Need a way for _javascript_ (or bundle) code to participate in undo
+ https://bugs.webkit.org/show_bug.cgi?id=190009
+ <rdar://problem/44807048>
+
+ Reviewed by Ryosuke Niwa.
+
+ Add a few new layout tests covering `UndoManager.addItem()`.
+
+ * editing/undo-manager/undo-manager-add-item-exceptions-expected.txt: Added.
+ * editing/undo-manager/undo-manager-add-item-exceptions.html: Added.
+
+ Add a test to verify that we throw exceptions when calling addItem() in a couple of circumstances.
+
+ * 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.undoAndRedoLabels):
+
+ Add a helper method to grab the platform's current undo and redo action names.
+
+ (window.UIHelper):
+
2019-01-25 Devin Rousso <[email protected]>
Web Inspector: improve invalid Audit/Recording JSON error messages
Added: trunk/LayoutTests/editing/undo-manager/undo-manager-add-item-exceptions-expected.txt (0 => 240476)
--- trunk/LayoutTests/editing/undo-manager/undo-manager-add-item-exceptions-expected.txt (rev 0)
+++ trunk/LayoutTests/editing/undo-manager/undo-manager-add-item-exceptions-expected.txt 2019-01-25 17:23:06 UTC (rev 240476)
@@ -0,0 +1,14 @@
+Verifies that UndoManager.addItem() throws _javascript_ exceptions. This test requires WebKitTestRunner.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS firstFrameDocument.undoManager.addItem(item) threw exception SecurityError: A browsing context is required to add an UndoItem.
+PASS document.undoManager.addItem(item) did not throw exception.
+PASS secondFrameDocument.undoManager.addItem(item) threw exception InvalidModificationError: This item has already been added to an UndoManager.
+Performed undo.
+Performed redo.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/editing/undo-manager/undo-manager-add-item-exceptions.html (0 => 240476)
--- trunk/LayoutTests/editing/undo-manager/undo-manager-add-item-exceptions.html (rev 0)
+++ trunk/LayoutTests/editing/undo-manager/undo-manager-add-item-exceptions.html 2019-01-25 17:23:06 UTC (rev 240476)
@@ -0,0 +1,31 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ enableUndoManagerAPI=true ] -->
+<html>
+ <meta charset="utf8">
+ <head>
+ <script src=""
+ <script>
+ addEventListener("load", () => {
+ description("Verifies that UndoManager.addItem() throws _javascript_ exceptions. This test requires WebKitTestRunner.");
+
+ item = new UndoItem({ label: '', undo: () => debug("Performed undo."), redo: () => debug("Performed redo.") });
+
+ const firstFrame = document.getElementById("one");
+ firstFrameDocument = firstFrame.contentDocument;
+ firstFrame.remove();
+
+ secondFrameDocument = document.getElementById("two").contentDocument;
+
+ shouldThrow("firstFrameDocument.undoManager.addItem(item)");
+ shouldNotThrow("document.undoManager.addItem(item)");
+ shouldThrow("secondFrameDocument.undoManager.addItem(item)");
+
+ document.execCommand("Undo");
+ document.execCommand("Redo");
+ });
+ </script>
+ </head>
+ <body>
+ <iframe id="one" srcdoc="<body>One</body>"></iframe>
+ <iframe id="two" srcdoc="<body>Two</body>"></iframe>
+ </body>
+</html>
Added: trunk/LayoutTests/editing/undo-manager/undo-manager-add-item-expected.txt (0 => 240476)
--- trunk/LayoutTests/editing/undo-manager/undo-manager-add-item-expected.txt (rev 0)
+++ trunk/LayoutTests/editing/undo-manager/undo-manager-add-item-expected.txt 2019-01-25 17:23:06 UTC (rev 240476)
@@ -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
Added: trunk/LayoutTests/editing/undo-manager/undo-manager-add-item.html (0 => 240476)
--- trunk/LayoutTests/editing/undo-manager/undo-manager-add-item.html (rev 0)
+++ trunk/LayoutTests/editing/undo-manager/undo-manager-add-item.html 2019-01-25 17:23:06 UTC (rev 240476)
@@ -0,0 +1,93 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ enableUndoManagerAPI=true ] -->
+<html>
+ <head>
+ <script src=""
+ <script src=""
+ <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.undoAndRedoLabels();
+ shouldBeEqualToString("undoName", "mainframe");
+ shouldBeEqualToString("redoName", "");
+
+ debug("After performing undo (mainframe):");
+ document.execCommand("undo");
+ [undoName, redoName] = await UIHelper.undoAndRedoLabels();
+ shouldBeEqualToString("undoName", "");
+ shouldBeEqualToString("redoName", "mainframe");
+
+ debug("After performing redo (mainframe):");
+ document.execCommand("redo");
+ [undoName, redoName] = await UIHelper.undoAndRedoLabels();
+ shouldBeEqualToString("undoName", "mainframe");
+ shouldBeEqualToString("redoName", "");
+
+ const frameWindow = frame.contentWindow;
+
+ debug("After adding an undo item (subframe):");
+ frameWindow.addUndoItem();
+ [undoName, redoName] = await UIHelper.undoAndRedoLabels();
+ shouldBeEqualToString("undoName", "subframe");
+ shouldBeEqualToString("redoName", "");
+
+ debug("After performing undo (subframe):");
+ document.execCommand("undo");
+ [undoName, redoName] = await UIHelper.undoAndRedoLabels();
+ shouldBeEqualToString("undoName", "mainframe");
+ shouldBeEqualToString("redoName", "subframe");
+
+ debug("After performing redo (subframe):");
+ document.execCommand("redo");
+ [undoName, redoName] = await UIHelper.undoAndRedoLabels();
+ shouldBeEqualToString("undoName", "subframe");
+ shouldBeEqualToString("redoName", "");
+
+ finishJSTest();
+ });
+ </script>
+</html>
Added: trunk/LayoutTests/editing/undo-manager/undo-manager-delete-stale-undo-items-expected.txt (0 => 240476)
--- trunk/LayoutTests/editing/undo-manager/undo-manager-delete-stale-undo-items-expected.txt (rev 0)
+++ trunk/LayoutTests/editing/undo-manager/undo-manager-delete-stale-undo-items-expected.txt 2019-01-25 17:23:06 UTC (rev 240476)
@@ -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
+
Added: trunk/LayoutTests/editing/undo-manager/undo-manager-delete-stale-undo-items.html (0 => 240476)
--- trunk/LayoutTests/editing/undo-manager/undo-manager-delete-stale-undo-items.html (rev 0)
+++ trunk/LayoutTests/editing/undo-manager/undo-manager-delete-stale-undo-items.html 2019-01-25 17:23:06 UTC (rev 240476)
@@ -0,0 +1,66 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ enableUndoManagerAPI=true ] -->
+<html>
+ <meta charset="utf8">
+ <head>
+ <script src=""
+ <script src=""
+ <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>
Added: trunk/LayoutTests/editing/undo-manager/undo-manager-item-labels-expected.txt (0 => 240476)
--- trunk/LayoutTests/editing/undo-manager/undo-manager-item-labels-expected.txt (rev 0)
+++ trunk/LayoutTests/editing/undo-manager/undo-manager-item-labels-expected.txt 2019-01-25 17:23:06 UTC (rev 240476)
@@ -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
+
Added: trunk/LayoutTests/editing/undo-manager/undo-manager-item-labels.html (0 => 240476)
--- trunk/LayoutTests/editing/undo-manager/undo-manager-item-labels.html (rev 0)
+++ trunk/LayoutTests/editing/undo-manager/undo-manager-item-labels.html 2019-01-25 17:23:06 UTC (rev 240476)
@@ -0,0 +1,95 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ enableUndoManagerAPI=true ] -->
+<html>
+ <meta charset="utf8">
+ <head>
+ <script src=""
+ <script src=""
+ <script src=""
+ <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.undoAndRedoLabels();
+ 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.undoAndRedoLabels();
+ shouldBeEqualToString("undoName", firstItem.label);
+ shouldBeEqualToString("redoName", "");
+
+ debug("After adding the second UndoItem:");
+ const secondItem = createUndoItemWithLabel("Second 🥈");
+ document.undoManager.addItem(secondItem);
+ [undoName, redoName] = await UIHelper.undoAndRedoLabels();
+ shouldBeEqualToString("undoName", secondItem.label);
+ shouldBeEqualToString("redoName", "");
+
+ debug("After undoing:");
+ document.execCommand("undo");
+ [undoName, redoName] = await UIHelper.undoAndRedoLabels();
+ shouldBeEqualToString("undoName", firstItem.label);
+ shouldBeEqualToString("redoName", secondItem.label);
+
+ debug("After undoing again:");
+ document.execCommand("undo");
+ [undoName, redoName] = await UIHelper.undoAndRedoLabels();
+ shouldBeEqualToString("undoName", "Typing");
+ shouldBeEqualToString("redoName", firstItem.label);
+
+ debug("After redoing:");
+ document.execCommand("redo");
+ [undoName, redoName] = await UIHelper.undoAndRedoLabels();
+ shouldBeEqualToString("undoName", firstItem.label);
+ shouldBeEqualToString("redoName", secondItem.label);
+
+ debug("After redoing again:");
+ document.execCommand("redo");
+ [undoName, redoName] = await UIHelper.undoAndRedoLabels();
+ shouldBeEqualToString("undoName", secondItem.label);
+ shouldBeEqualToString("redoName", "");
+
+ debug("After undoing and then pasting:");
+ document.execCommand("undo");
+ selectAllCommand();
+ copyCommand();
+ pasteCommand();
+ [undoName, redoName] = await UIHelper.undoAndRedoLabels();
+ shouldBeEqualToString("undoName", "Paste");
+ shouldBeEqualToString("redoName", "");
+
+ debug("After undoing the paste command:");
+ document.execCommand("undo");
+ [undoName, redoName] = await UIHelper.undoAndRedoLabels();
+ 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>
Added: trunk/LayoutTests/editing/undo-manager/undo-manager-undo-redo-after-garbage-collection-expected.txt (0 => 240476)
--- trunk/LayoutTests/editing/undo-manager/undo-manager-undo-redo-after-garbage-collection-expected.txt (rev 0)
+++ trunk/LayoutTests/editing/undo-manager/undo-manager-undo-redo-after-garbage-collection-expected.txt 2019-01-25 17:23:06 UTC (rev 240476)
@@ -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
+
Added: trunk/LayoutTests/editing/undo-manager/undo-manager-undo-redo-after-garbage-collection.html (0 => 240476)
--- trunk/LayoutTests/editing/undo-manager/undo-manager-undo-redo-after-garbage-collection.html (rev 0)
+++ trunk/LayoutTests/editing/undo-manager/undo-manager-undo-redo-after-garbage-collection.html 2019-01-25 17:23:06 UTC (rev 240476)
@@ -0,0 +1,35 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ enableUndoManagerAPI=true ] -->
+<html>
+ <meta charset="utf8">
+ <head>
+ <script src=""
+ <script src=""
+ <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>
Modified: trunk/LayoutTests/resources/ui-helper.js (240475 => 240476)
--- trunk/LayoutTests/resources/ui-helper.js 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/LayoutTests/resources/ui-helper.js 2019-01-25 17:23:06 UTC (rev 240476)
@@ -566,4 +566,13 @@
resolve({ x: offsetX, y: offsetY });
}));
}
+
+ static undoAndRedoLabels()
+ {
+ if (!this.isWebKit2())
+ return Promise.resolve();
+
+ const script = "JSON.stringify([uiController.lastUndoLabel, uiController.firstRedoLabel])";
+ return new Promise(resolve => testRunner.runUIScript(script, result => resolve(JSON.parse(result))));
+ }
}
Modified: trunk/Source/WebCore/ChangeLog (240475 => 240476)
--- trunk/Source/WebCore/ChangeLog 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Source/WebCore/ChangeLog 2019-01-25 17:23:06 UTC (rev 240476)
@@ -1,3 +1,46 @@
+2019-01-25 Wenson Hsieh <[email protected]>
+
+ Need a way for _javascript_ (or bundle) code to participate in undo
+ https://bugs.webkit.org/show_bug.cgi?id=190009
+ <rdar://problem/44807048>
+
+ Reviewed by Ryosuke Niwa.
+
+ Finish hooking up `UndoManager::addItems()` to CustomUndoStep.
+
+ Tests: editing/undo-manager/undo-manager-add-item-exceptions.html
+ 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::didRemoveFromUndoManager):
+
+ 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:
+ * page/UndoItem.h:
+ (WebCore::UndoItem::undoManager const):
+ * page/UndoManager.cpp:
+ (WebCore::UndoManager::addItem):
+
+ Create a CustomUndoStep with the given UndoItem, and register it with the platform undo manager.
+
+ * page/UndoManager.h:
+ * page/UndoManager.idl:
+
+ Mark addItem() as capable of throwing exceptions.
+
2019-01-25 Zalan Bujtas <[email protected]>
[LFC][BFC][MarginCollapsing] Add "clear" to static position computation.
Modified: trunk/Source/WebCore/editing/CompositeEditCommand.h (240475 => 240476)
--- trunk/Source/WebCore/editing/CompositeEditCommand.h 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Source/WebCore/editing/CompositeEditCommand.h 2019-01-25 17:23:06 UTC (rev 240476)
@@ -89,6 +89,7 @@
EditCommandComposition(Document&, const VisibleSelection& startingSelection, const VisibleSelection& endingSelection, EditAction);
String label() const final;
+ void didRemoveFromUndoManager() final { }
RefPtr<Document> m_document;
VisibleSelection m_startingSelection;
Modified: trunk/Source/WebCore/editing/CustomUndoStep.cpp (240475 => 240476)
--- trunk/Source/WebCore/editing/CustomUndoStep.cpp 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Source/WebCore/editing/CustomUndoStep.cpp 2019-01-25 17:23:06 UTC (rev 240476)
@@ -74,4 +74,10 @@
return m_undoItem->label();
}
+void CustomUndoStep::didRemoveFromUndoManager()
+{
+ if (auto undoItem = std::exchange(m_undoItem, nullptr))
+ undoItem->invalidate();
+}
+
} // namespace WebCore
Modified: trunk/Source/WebCore/editing/CustomUndoStep.h (240475 => 240476)
--- trunk/Source/WebCore/editing/CustomUndoStep.h 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Source/WebCore/editing/CustomUndoStep.h 2019-01-25 17:23:06 UTC (rev 240476)
@@ -49,6 +49,7 @@
EditAction editingAction() const final { return EditAction::Unspecified; }
String label() const final;
+ void didRemoveFromUndoManager() final;
bool isValid() const;
WeakPtr<UndoItem> m_undoItem;
Modified: trunk/Source/WebCore/editing/Editor.cpp (240475 => 240476)
--- trunk/Source/WebCore/editing/Editor.cpp 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Source/WebCore/editing/Editor.cpp 2019-01-25 17:23:06 UTC (rev 240476)
@@ -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 @@
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())
Modified: trunk/Source/WebCore/editing/Editor.h (240475 => 240476)
--- trunk/Source/WebCore/editing/Editor.h 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Source/WebCore/editing/Editor.h 2019-01-25 17:23:06 UTC (rev 240476)
@@ -58,6 +58,7 @@
class ArchiveResource;
class DataTransfer;
class CompositeEditCommand;
+class CustomUndoStep;
class DeleteButtonController;
class EditCommand;
class EditCommandComposition;
@@ -324,6 +325,8 @@
bool canRedo() const;
void redo();
+ void registerCustomUndoStep(Ref<CustomUndoStep>&&);
+
void didBeginEditing();
void didEndEditing();
void willWriteSelectionToPasteboard(Range*);
Modified: trunk/Source/WebCore/editing/UndoStep.h (240475 => 240476)
--- trunk/Source/WebCore/editing/UndoStep.h 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Source/WebCore/editing/UndoStep.h 2019-01-25 17:23:06 UTC (rev 240476)
@@ -44,6 +44,7 @@
virtual void reapply() = 0;
virtual EditAction editingAction() const = 0;
virtual String label() const = 0;
+ virtual void didRemoveFromUndoManager() = 0;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/page/UndoItem.h (240475 => 240476)
--- trunk/Source/WebCore/page/UndoItem.h 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Source/WebCore/page/UndoItem.h 2019-01-25 17:23:06 UTC (rev 240476)
@@ -55,6 +55,7 @@
Document* document() const;
+ UndoManager* undoManager() const { return m_undoManager.get(); }
void setUndoManager(UndoManager*);
const String& label() const { return m_label; }
Modified: trunk/Source/WebCore/page/UndoManager.cpp (240475 => 240476)
--- trunk/Source/WebCore/page/UndoManager.cpp 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Source/WebCore/page/UndoManager.cpp 2019-01-25 17:23:06 UTC (rev 240476)
@@ -26,6 +26,8 @@
#include "config.h"
#include "UndoManager.h"
+#include "CustomUndoStep.h"
+#include "Frame.h"
#include "UndoItem.h"
#include <wtf/IsoMallocInlines.h>
@@ -40,12 +42,19 @@
UndoManager::~UndoManager() = default;
-void UndoManager::addItem(Ref<UndoItem>&& item)
+ExceptionOr<void> UndoManager::addItem(Ref<UndoItem>&& item)
{
- UNUSED_PARAM(m_document);
+ if (item->undoManager())
+ return Exception { InvalidModificationError, "This item has already been added to an UndoManager"_s };
+ auto frame = makeRefPtr(m_document.frame());
+ if (!frame)
+ return Exception { SecurityError, "A browsing context is required to add an UndoItem"_s };
+
item->setUndoManager(this);
+ frame->editor().registerCustomUndoStep(CustomUndoStep::create(item));
m_items.add(WTFMove(item));
+ return { };
}
void UndoManager::removeItem(UndoItem& item)
Modified: trunk/Source/WebCore/page/UndoManager.h (240475 => 240476)
--- trunk/Source/WebCore/page/UndoManager.h 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Source/WebCore/page/UndoManager.h 2019-01-25 17:23:06 UTC (rev 240476)
@@ -25,6 +25,7 @@
#pragma once
+#include "ExceptionOr.h"
#include <wtf/IsoMalloc.h>
#include <wtf/Ref.h>
#include <wtf/RefCounted.h>
@@ -48,7 +49,7 @@
void removeItem(UndoItem&);
void removeAllItems();
- void addItem(Ref<UndoItem>&&);
+ ExceptionOr<void> addItem(Ref<UndoItem>&&);
Document& document() { return m_document; }
private:
Modified: trunk/Source/WebCore/page/UndoManager.idl (240475 => 240476)
--- trunk/Source/WebCore/page/UndoManager.idl 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Source/WebCore/page/UndoManager.idl 2019-01-25 17:23:06 UTC (rev 240476)
@@ -28,5 +28,5 @@
ImplementationLacksVTable,
GenerateIsReachable=ImplDocument,
] interface UndoManager {
- void addItem(UndoItem item);
+ [MayThrowException] void addItem(UndoItem item);
};
Modified: trunk/Source/WebKit/ChangeLog (240475 => 240476)
--- trunk/Source/WebKit/ChangeLog 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Source/WebKit/ChangeLog 2019-01-25 17:23:06 UTC (rev 240476)
@@ -1,3 +1,21 @@
+2019-01-25 Wenson Hsieh <[email protected]>
+
+ Need a way for _javascript_ (or bundle) code to participate in undo
+ https://bugs.webkit.org/show_bug.cgi?id=190009
+ <rdar://problem/44807048>
+
+ Reviewed by Ryosuke Niwa.
+
+ 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/WebPage.cpp:
+ (WebKit::WebPage::addWebUndoStep):
+ (WebKit::WebPage::removeWebEditCommand):
+ * WebProcess/WebPage/WebUndoStep.h:
+ (WebKit::WebUndoStep::invalidate):
+
2019-01-25 Patrick Griffis <[email protected]>
[GTK][WPE] Add API to add paths to sandbox
Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (240475 => 240476)
--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp 2019-01-25 17:23:06 UTC (rev 240476)
@@ -3791,12 +3791,14 @@
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->didRemoveFromUndoManager();
}
bool WebPage::isAlwaysOnLoggingAllowed() const
Modified: trunk/Source/WebKit/WebProcess/WebPage/WebUndoStep.h (240475 => 240476)
--- trunk/Source/WebKit/WebProcess/WebPage/WebUndoStep.h 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebUndoStep.h 2019-01-25 17:23:06 UTC (rev 240476)
@@ -39,6 +39,8 @@
WebCore::UndoStep& step() const { return m_step.get(); }
WebUndoStepID stepID() const { return m_stepID; }
+ void didRemoveFromUndoManager() { m_step->didRemoveFromUndoManager(); }
+
private:
WebUndoStep(Ref<WebCore::UndoStep>&& step, WebUndoStepID stepID)
: m_step(WTFMove(step))
Modified: trunk/Tools/ChangeLog (240475 => 240476)
--- trunk/Tools/ChangeLog 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Tools/ChangeLog 2019-01-25 17:23:06 UTC (rev 240476)
@@ -1,3 +1,35 @@
+2019-01-25 Wenson Hsieh <[email protected]>
+
+ Need a way for _javascript_ (or bundle) code to participate in undo
+ https://bugs.webkit.org/show_bug.cgi?id=190009
+ <rdar://problem/44807048>
+
+ Reviewed by Ryosuke Niwa.
+
+ 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::lastUndoLabel const):
+ (WTR::UIScriptController::firstRedoLabel const):
+ (WTR::UIScriptController::platformUndoManager const):
+ * DumpRenderTree/mac/UIScriptControllerMac.mm:
+ (WTR::UIScriptController::lastUndoLabel const):
+ (WTR::UIScriptController::firstRedoLabel const):
+ (WTR::UIScriptController::platformUndoManager const):
+ * TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
+ * TestRunnerShared/UIScriptContext/UIScriptController.cpp:
+ (WTR::UIScriptController::lastUndoLabel const):
+ (WTR::UIScriptController::firstRedoLabel const):
+ * TestRunnerShared/UIScriptContext/UIScriptController.h:
+ * WebKitTestRunner/UIScriptControllerCocoa.mm:
+ (WTR::UIScriptController::lastUndoLabel const):
+ (WTR::UIScriptController::firstRedoLabel const):
+ * WebKitTestRunner/ios/UIScriptControllerIOS.mm:
+ (WTR::UIScriptController::platformUndoManager const):
+ * WebKitTestRunner/mac/UIScriptControllerMac.mm:
+ (WTR::UIScriptController::platformUndoManager const):
+
2019-01-25 Zalan Bujtas <[email protected]>
[LFC][BFC][MarginCollapsing] Add "clear" to static position computation.
Modified: trunk/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm (240475 => 240476)
--- trunk/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm 2019-01-25 17:23:06 UTC (rev 240476)
@@ -450,6 +450,21 @@
{
}
+JSRetainPtr<JSStringRef> UIScriptController::lastUndoLabel() const
+{
+ return nullptr;
}
+JSRetainPtr<JSStringRef> UIScriptController::firstRedoLabel() const
+{
+ return nullptr;
+}
+
+NSUndoManager *UIScriptController::platformUndoManager() const
+{
+ return nil;
+}
+
+}
+
#endif // PLATFORM(IOS_FAMILY)
Modified: trunk/Tools/DumpRenderTree/mac/UIScriptControllerMac.mm (240475 => 240476)
--- trunk/Tools/DumpRenderTree/mac/UIScriptControllerMac.mm 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Tools/DumpRenderTree/mac/UIScriptControllerMac.mm 2019-01-25 17:23:06 UTC (rev 240476)
@@ -215,6 +215,21 @@
doAsyncTask(callback);
}
+JSRetainPtr<JSStringRef> UIScriptController::lastUndoLabel() const
+{
+ return nullptr;
}
+JSRetainPtr<JSStringRef> UIScriptController::firstRedoLabel() const
+{
+ return nullptr;
+}
+
+NSUndoManager *UIScriptController::platformUndoManager() const
+{
+ return nil;
+}
+
+}
+
#endif // PLATFORM(MAC)
Modified: trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl (240475 => 240476)
--- trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl 2019-01-25 17:23:06 UTC (rev 240476)
@@ -290,8 +290,11 @@
void makeWindowContentViewFirstResponder();
readonly attribute boolean isWindowContentViewFirstResponder;
+ object attachmentInfo(DOMString attachmentIdentifier);
+
+ // Editing
void drawSquareInEditableImage();
readonly attribute long numberOfStrokesInEditableImage;
-
- object attachmentInfo(DOMString attachmentIdentifier);
+ readonly attribute DOMString lastUndoLabel;
+ readonly attribute DOMString firstRedoLabel;
};
Modified: trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp (240475 => 240476)
--- trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp 2019-01-25 17:23:06 UTC (rev 240476)
@@ -569,6 +569,16 @@
{
}
+JSRetainPtr<JSStringRef> UIScriptController::lastUndoLabel() const
+{
+ return nullptr;
+}
+
+JSRetainPtr<JSStringRef> UIScriptController::firstRedoLabel() const
+{
+ return nullptr;
+}
+
#endif // !PLATFORM(COCOA)
#if !PLATFORM(MAC)
Modified: trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h (240475 => 240476)
--- trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h 2019-01-25 17:23:06 UTC (rev 240476)
@@ -31,6 +31,8 @@
#include <wtf/Optional.h>
#include <wtf/Ref.h>
+OBJC_CLASS NSUndoManager;
+
namespace WebCore {
class FloatRect;
}
@@ -206,6 +208,9 @@
void drawSquareInEditableImage();
long numberOfStrokesInEditableImage();
+ JSRetainPtr<JSStringRef> lastUndoLabel() const;
+ JSRetainPtr<JSStringRef> firstRedoLabel() const;
+
JSObjectRef attachmentInfo(JSStringRef attachmentIdentifier);
private:
@@ -225,6 +230,10 @@
void platformClearAllCallbacks();
void platformPlayBackEventStream(JSStringRef, JSValueRef);
+#if PLATFORM(COCOA)
+ NSUndoManager *platformUndoManager() const;
+#endif
+
JSClassRef wrapperClass() final;
JSObjectRef objectFromRect(const WebCore::FloatRect&) const;
Modified: trunk/Tools/WebKitTestRunner/UIScriptControllerCocoa.mm (240475 => 240476)
--- trunk/Tools/WebKitTestRunner/UIScriptControllerCocoa.mm 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Tools/WebKitTestRunner/UIScriptControllerCocoa.mm 2019-01-25 17:23:06 UTC (rev 240476)
@@ -192,5 +192,15 @@
return nullptr;
#endif
}
-
+
+JSRetainPtr<JSStringRef> UIScriptController::lastUndoLabel() const
+{
+ return JSStringCreateWithCFString((__bridge CFStringRef)platformUndoManager().undoActionName);
+}
+
+JSRetainPtr<JSStringRef> UIScriptController::firstRedoLabel() const
+{
+ return JSStringCreateWithCFString((__bridge CFStringRef)platformUndoManager().redoActionName);
+}
+
} // namespace WTR
Modified: trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm (240475 => 240476)
--- trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm 2019-01-25 17:23:06 UTC (rev 240476)
@@ -971,6 +971,11 @@
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)
Modified: trunk/Tools/WebKitTestRunner/mac/UIScriptControllerMac.mm (240475 => 240476)
--- trunk/Tools/WebKitTestRunner/mac/UIScriptControllerMac.mm 2019-01-25 16:50:18 UTC (rev 240475)
+++ trunk/Tools/WebKitTestRunner/mac/UIScriptControllerMac.mm 2019-01-25 17:23:06 UTC (rev 240476)
@@ -209,4 +209,9 @@
doAsyncTask(callback);
}
+NSUndoManager *UIScriptController::platformUndoManager() const
+{
+ return TestController::singleton().mainWebView()->platformView().undoManager;
+}
+
} // namespace WTR