Title: [235955] trunk
Revision
235955
Author
m...@apple.com
Date
2018-09-12 15:26:12 -0700 (Wed, 12 Sep 2018)

Log Message

[Cocoa] Complete support for Paste as Quotation
https://bugs.webkit.org/show_bug.cgi?id=189504

Reviewed by Wenson Hsieh.

Source/WebCore:

Tests: editing/pasteboard/4930986-1-paste-as-quotation.html
       editing/pasteboard/4930986-2-paste-as-quotation.html
       editing/pasteboard/4930986-3-paste-as-quotation.html

* editing/Editor.cpp:
  Added ClipboardEventKind::PasteAsQuotation.
(WebCore::eventNameForClipboardEvent): Map PasteAsQuotation to the "paste" DOM event name.
(WebCore::createDataTransferForClipboardEvent): Place the unquoted content in the event.
  This means that currently event handlers can’t emulate pasting as quotation, because they
  neither have the quoted content nor knowledge that quoting has been requested. We could
  change this in the future if needed.
(WebCore::Editor::paste): Updated for change in pasteWithPasteboard’s argument type.
(WebCore::Editor::pasteAsQuotation): Added. Similar to paste, but passes
  PasteOption::AsQuotation to pasteWithPasteboard.
(WebCore::Editor::quoteFragmentForPasting): Added. Quoting for pasting consists of enclosing
  the fragment in a blockquote element with the "type" attribute set to "cite" and the
  "class" attribute set to a well-known value, which is used to trigger special behavior in
  ReplaceSelectionCommand. The behavior includes removing the "class" attribute in the end,
  so eventually, we could stop using this form of in-band signaling.
* editing/Editor.h: Declared PasteOption enum class to encompass the existing allowPlainText
  and MailBlockquoteHandling arguments to pasteWithPasteboard as well as the new AsQuotation
  behavior.

* editing/EditorCommand.cpp:
(WebCore::executePasteAsQuotation): Added. Similar to executing Paste.
(WebCore::createCommandMap): Added an entry for PasteAsQuotation, based on the Paste entry.

* editing/cocoa/EditorCocoa.mm:
(WebCore::Editor::webContentFromPasteboard): Moved from EditorIOS.mm and EditorMac.mm to
  here.

* editing/gtk/EditorGtk.cpp:
(WebCore::Editor::pasteWithPasteboard): Updated for new OptionSet argument, added a call to
  quote the fragment if needed.

* editing/ios/EditorIOS.mm:
(WebCore::Editor::pasteWithPasteboard): Ditto.
(WebCore::Editor::webContentFromPasteboard): Moved to EditorCocoa.mm.

* editing/mac/EditorMac.mm:
(WebCore::Editor::pasteWithPasteboard): Updated for new OptionSet argument, added a call to
  quote the fragment if needed.
(WebCore::Editor::readSelectionFromPasteboard): Updated for new OptionSet argument to
  pasteWithPasteboard.
(WebCore::Editor::webContentFromPasteboard): Moved to EditorCocoa.mm.

* editing/win/EditorWin.cpp:
(WebCore::Editor::pasteWithPasteboard): Updated for new OptionSet argument, added a call to
  quote the fragment if needed.

* editing/wpe/EditorWPE.cpp:
(WebCore::Editor::pasteWithPasteboard): Ditto.

Source/WebKit:

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView canPerformAction:withSender:]): Handle _pasteAsQuotation:. It’s not included
  in FOR_EACH_WKCONTENTVIEW_ACTION, because it’s declared and implemented in the WKPrivate
  category. If we add more actions in the category, it could make sense to fold them into
  a new FOR_EACH_PRIVATE_WKCONTENTVIEW_ACTION.
(-[WKWebView targetForAction:withSender:]): Handle _pasteAsQuotation:.
(-[WKWebView _pasteAsQuotation:]): Send to the WebViewImpl or the WKContentView.
* UIProcess/API/Cocoa/WKWebViewPrivate.h: Declared a new _pasteAsQuotation: action.

* UIProcess/Cocoa/WebViewImpl.mm:
(WebKit::selectorExceptionMap): Added a custom mapping from the new selector to the
  PasteAsQuotation command.

* UIProcess/ios/WKContentViewInteraction.h: Declare methods for the new action.
* UIProcess/ios/WKContentViewInteraction.mm:
  Forward _pasteAsQuotation: to the WKWebView so that clients get a chance to override its
  behavior.
(-[WKContentView _pasteAsQuotationForWebView:]): Send the command to the page.

Tools:

* MiniBrowser/mac/MainMenu.xib: Added a Paste as Quotation command in the Edit menu.

LayoutTests:

Took a few existing tests of the Paste as Quotation behavior and modified them to use the
new PasteAsQuotation command. The only difference in the results is that the blockquote has
the "type" attribute set to "cite".

* editing/pasteboard/4930986-1-paste-as-quotation-expected.txt: Added.
* editing/pasteboard/4930986-1-paste-as-quotation.html: Added.
* editing/pasteboard/4930986-2-paste-as-quotation-expected.txt: Added.
* editing/pasteboard/4930986-2-paste-as-quotation.html: Added.
* editing/pasteboard/4930986-3-paste-as-quotation-expected.txt: Added.
* editing/pasteboard/4930986-3-paste-as-quotation.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (235954 => 235955)


--- trunk/LayoutTests/ChangeLog	2018-09-12 22:16:45 UTC (rev 235954)
+++ trunk/LayoutTests/ChangeLog	2018-09-12 22:26:12 UTC (rev 235955)
@@ -1,3 +1,21 @@
+2018-09-12  Dan Bernstein  <m...@apple.com>
+
+        [Cocoa] Complete support for Paste as Quotation
+        https://bugs.webkit.org/show_bug.cgi?id=189504
+
+        Reviewed by Wenson Hsieh.
+
+        Took a few existing tests of the Paste as Quotation behavior and modified them to use the
+        new PasteAsQuotation command. The only difference in the results is that the blockquote has
+        the "type" attribute set to "cite".
+
+        * editing/pasteboard/4930986-1-paste-as-quotation-expected.txt: Added.
+        * editing/pasteboard/4930986-1-paste-as-quotation.html: Added.
+        * editing/pasteboard/4930986-2-paste-as-quotation-expected.txt: Added.
+        * editing/pasteboard/4930986-2-paste-as-quotation.html: Added.
+        * editing/pasteboard/4930986-3-paste-as-quotation-expected.txt: Added.
+        * editing/pasteboard/4930986-3-paste-as-quotation.html: Added.
+
 2018-09-12  Sihui Liu  <sihui_...@apple.com>
 
         Move IndexedDB to Network Process

Added: trunk/LayoutTests/editing/pasteboard/4930986-1-paste-as-quotation-expected.txt (0 => 235955)


--- trunk/LayoutTests/editing/pasteboard/4930986-1-paste-as-quotation-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/4930986-1-paste-as-quotation-expected.txt	2018-09-12 22:26:12 UTC (rev 235955)
@@ -0,0 +1,2 @@
+This tests to make sure that content that has the document default color is pasted as blue (or whatever the color for quoted content is) during a Paste as Quotation.
+<blockquote type="cite">This text should be blue (it should not be wrapped in a style span).</blockquote>

Added: trunk/LayoutTests/editing/pasteboard/4930986-1-paste-as-quotation.html (0 => 235955)


--- trunk/LayoutTests/editing/pasteboard/4930986-1-paste-as-quotation.html	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/4930986-1-paste-as-quotation.html	2018-09-12 22:26:12 UTC (rev 235955)
@@ -0,0 +1,34 @@
+<html>
+<head>
+<style>
+blockquote {
+    color: blue;
+    border-left: 2px solid blue;
+    margin-left: 0px;
+    padding-left: 10px;
+}
+</style>
+</head>
+<body>
+<div id="description">This tests to make sure that content that has the document default color is pasted as blue (or whatever the color for quoted content is) during a Paste as Quotation.</div>
+<div id="edit" contenteditable="true"></div>
+
+<script>
+document.addEventListener("beforecopy", (event) => event.preventDefault());
+document.addEventListener("copy", (event) => {
+    event.clipboardData.setData("text/html", "<span class='Apple-style-span' style='color: black;'>This text should be blue (it should not be wrapped in a style span).</span>");
+    event.preventDefault();
+});
+document.execCommand("Copy", false);
+
+edit = document.getElementById("edit");
+description = document.getElementById("description");
+edit.focus();
+document.execCommand("PasteAsQuotation", false);
+if (window.testRunner) {
+    window.testRunner.dumpAsText();
+    document.body.innerText = description.innerText + "\n" + edit.innerHTML;
+}
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/editing/pasteboard/4930986-2-paste-as-quotation-expected.txt (0 => 235955)


--- trunk/LayoutTests/editing/pasteboard/4930986-2-paste-as-quotation-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/4930986-2-paste-as-quotation-expected.txt	2018-09-12 22:26:12 UTC (rev 235955)
@@ -0,0 +1,2 @@
+This tests to make sure that content that is colored by the user is pasted with that color during a Paste as Quotation.
+<blockquote type="cite"><span class="Apple-style-span" style="color: red;">This text should be red (it should be wrapped in a style span).</span></blockquote>

Added: trunk/LayoutTests/editing/pasteboard/4930986-2-paste-as-quotation.html (0 => 235955)


--- trunk/LayoutTests/editing/pasteboard/4930986-2-paste-as-quotation.html	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/4930986-2-paste-as-quotation.html	2018-09-12 22:26:12 UTC (rev 235955)
@@ -0,0 +1,34 @@
+<html>
+<head>
+<style>
+blockquote {
+    color: blue;
+    border-left: 2px solid blue;
+    margin-left: 0px;
+    padding-left: 10px;
+}
+</style>
+<script>
+function runTest() {
+    document.addEventListener("beforecopy", (event) => event.preventDefault());
+    document.addEventListener("copy", (event) => {
+        event.clipboardData.setData("text/html", "<span class='Apple-style-span' style='color: black;'><span class='Apple-style-span' style='color: red;'>This text should be red (it should be wrapped in a style span).</span></span>");
+        event.preventDefault();
+    });
+    document.execCommand("Copy", false);
+
+    div = document.getElementById("edit");
+    div.focus();
+    document.execCommand("PasteAsQuotation", false);
+    if (window.testRunner) {
+        window.testRunner.dumpAsText();
+        document.body.innerText = document.getElementById("description").innerText + "\n" + div.innerHTML;
+    }
+}
+</script>
+</head>
+<body _onload_="runTest();">
+<div id="description">This tests to make sure that content that is colored by the user is pasted with that color during a Paste as Quotation.</div>
+<div id="edit" contenteditable="true"></div>
+</body>
+</html>

Added: trunk/LayoutTests/editing/pasteboard/4930986-3-paste-as-quotation-expected.txt (0 => 235955)


--- trunk/LayoutTests/editing/pasteboard/4930986-3-paste-as-quotation-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/4930986-3-paste-as-quotation-expected.txt	2018-09-12 22:26:12 UTC (rev 235955)
@@ -0,0 +1,2 @@
+This tests to make sure that an Apple-paste-as-quotation blockquote can override document default styles even if they are different than the insertion position.
+<blockquote type="cite">This text should have the blockquote color (blue). There should be no style spans around it.</blockquote>

Added: trunk/LayoutTests/editing/pasteboard/4930986-3-paste-as-quotation.html (0 => 235955)


--- trunk/LayoutTests/editing/pasteboard/4930986-3-paste-as-quotation.html	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/4930986-3-paste-as-quotation.html	2018-09-12 22:26:12 UTC (rev 235955)
@@ -0,0 +1,34 @@
+<html>
+<head>
+<style>
+blockquote {
+    color: blue;
+    padding-left: 10px;
+    margin-left: 0px;
+    border-left: 2px solid blue;
+}
+</style>
+</head>
+<body>
+<div id="description">This tests to make sure that an Apple-paste-as-quotation blockquote can override document default styles even if they are different than the insertion position.</div>
+<div id="edit" contenteditable="true" style="color: red;"></div>
+
+<script>
+document.addEventListener("beforecopy", (event) => event.preventDefault());
+document.addEventListener("copy", (event) => {
+    event.clipboardData.setData("text/html", "<span class='Apple-style-span' style='color:black;'>This text should have the blockquote color (blue). There should be no style spans around it.</span>");
+    event.preventDefault();
+});
+document.execCommand("Copy", false);
+
+edit = document.getElementById("edit");
+description = document.getElementById("description");
+edit.focus();
+document.execCommand("PasteAsQuotation", false);
+if (window.testRunner) {
+    window.testRunner.dumpAsText();
+    document.body.innerText = description.innerText + "\n" + edit.innerHTML;
+}
+</script>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (235954 => 235955)


--- trunk/Source/WebCore/ChangeLog	2018-09-12 22:16:45 UTC (rev 235954)
+++ trunk/Source/WebCore/ChangeLog	2018-09-12 22:26:12 UTC (rev 235955)
@@ -1,3 +1,63 @@
+2018-09-12  Dan Bernstein  <m...@apple.com>
+
+        [Cocoa] Complete support for Paste as Quotation
+        https://bugs.webkit.org/show_bug.cgi?id=189504
+
+        Reviewed by Wenson Hsieh.
+
+        Tests: editing/pasteboard/4930986-1-paste-as-quotation.html
+               editing/pasteboard/4930986-2-paste-as-quotation.html
+               editing/pasteboard/4930986-3-paste-as-quotation.html
+
+        * editing/Editor.cpp:
+          Added ClipboardEventKind::PasteAsQuotation.
+        (WebCore::eventNameForClipboardEvent): Map PasteAsQuotation to the "paste" DOM event name.
+        (WebCore::createDataTransferForClipboardEvent): Place the unquoted content in the event.
+          This means that currently event handlers can’t emulate pasting as quotation, because they
+          neither have the quoted content nor knowledge that quoting has been requested. We could
+          change this in the future if needed.
+        (WebCore::Editor::paste): Updated for change in pasteWithPasteboard’s argument type.
+        (WebCore::Editor::pasteAsQuotation): Added. Similar to paste, but passes
+          PasteOption::AsQuotation to pasteWithPasteboard.
+        (WebCore::Editor::quoteFragmentForPasting): Added. Quoting for pasting consists of enclosing
+          the fragment in a blockquote element with the "type" attribute set to "cite" and the
+          "class" attribute set to a well-known value, which is used to trigger special behavior in
+          ReplaceSelectionCommand. The behavior includes removing the "class" attribute in the end,
+          so eventually, we could stop using this form of in-band signaling.
+        * editing/Editor.h: Declared PasteOption enum class to encompass the existing allowPlainText
+          and MailBlockquoteHandling arguments to pasteWithPasteboard as well as the new AsQuotation
+          behavior.
+
+        * editing/EditorCommand.cpp:
+        (WebCore::executePasteAsQuotation): Added. Similar to executing Paste.
+        (WebCore::createCommandMap): Added an entry for PasteAsQuotation, based on the Paste entry.
+
+        * editing/cocoa/EditorCocoa.mm:
+        (WebCore::Editor::webContentFromPasteboard): Moved from EditorIOS.mm and EditorMac.mm to
+          here.
+
+        * editing/gtk/EditorGtk.cpp:
+        (WebCore::Editor::pasteWithPasteboard): Updated for new OptionSet argument, added a call to
+          quote the fragment if needed.
+
+        * editing/ios/EditorIOS.mm:
+        (WebCore::Editor::pasteWithPasteboard): Ditto.
+        (WebCore::Editor::webContentFromPasteboard): Moved to EditorCocoa.mm.
+
+        * editing/mac/EditorMac.mm:
+        (WebCore::Editor::pasteWithPasteboard): Updated for new OptionSet argument, added a call to
+          quote the fragment if needed.
+        (WebCore::Editor::readSelectionFromPasteboard): Updated for new OptionSet argument to
+          pasteWithPasteboard.
+        (WebCore::Editor::webContentFromPasteboard): Moved to EditorCocoa.mm.
+
+        * editing/win/EditorWin.cpp:
+        (WebCore::Editor::pasteWithPasteboard): Updated for new OptionSet argument, added a call to
+          quote the fragment if needed.
+
+        * editing/wpe/EditorWPE.cpp:
+        (WebCore::Editor::pasteWithPasteboard): Ditto.
+
 2018-09-11  Simon Fraser  <simon.fra...@apple.com>
 
         Make GraphicsLayers ref-counted, so their tree can persist when disconnected from RenderLayerBackings

Modified: trunk/Source/WebCore/editing/Editor.cpp (235954 => 235955)


--- trunk/Source/WebCore/editing/Editor.cpp	2018-09-12 22:16:45 UTC (rev 235954)
+++ trunk/Source/WebCore/editing/Editor.cpp	2018-09-12 22:26:12 UTC (rev 235955)
@@ -54,6 +54,7 @@
 #include "FrameView.h"
 #include "GraphicsContext.h"
 #include "HTMLAttachmentElement.h"
+#include "HTMLBRElement.h"
 #include "HTMLCollection.h"
 #include "HTMLFormControlElement.h"
 #include "HTMLFrameOwnerElement.h"
@@ -60,6 +61,7 @@
 #include "HTMLImageElement.h"
 #include "HTMLInputElement.h"
 #include "HTMLNames.h"
+#include "HTMLQuoteElement.h"
 #include "HTMLSpanElement.h"
 #include "HitTestResult.h"
 #include "IndentOutdentCommand.h"
@@ -327,6 +329,7 @@
     Cut,
     Paste,
     PasteAsPlainText,
+    PasteAsQuotation,
     BeforeCopy,
     BeforeCut,
     BeforePaste,
@@ -341,6 +344,7 @@
         return eventNames().cutEvent;
     case ClipboardEventKind::Paste:
     case ClipboardEventKind::PasteAsPlainText:
+    case ClipboardEventKind::PasteAsQuotation:
         return eventNames().pasteEvent;
     case ClipboardEventKind::BeforeCopy:
         return eventNames().beforecopyEvent;
@@ -369,6 +373,7 @@
         }
         FALLTHROUGH;
     case ClipboardEventKind::Paste:
+    case ClipboardEventKind::PasteAsQuotation:
         return DataTransfer::createForCopyAndPaste(document, DataTransfer::StoreMode::Readonly, Pasteboard::createForCopyAndPaste());
     case ClipboardEventKind::BeforeCopy:
     case ClipboardEventKind::BeforeCut:
@@ -1404,7 +1409,7 @@
     updateMarkersForWordsAffectedByEditing(false);
     ResourceCacheValidationSuppressor validationSuppressor(document().cachedResourceLoader());
     if (m_frame.selection().selection().isContentRichlyEditable())
-        pasteWithPasteboard(&pasteboard, true);
+        pasteWithPasteboard(&pasteboard, { PasteOption::AllowPlainText });
     else
         pasteAsPlainTextWithPasteboard(pasteboard);
 }
@@ -1419,6 +1424,40 @@
     pasteAsPlainTextWithPasteboard(*Pasteboard::createForCopyAndPaste());
 }
 
+void Editor::pasteAsQuotation()
+{
+    if (!dispatchClipboardEvent(findEventTargetFromSelection(), ClipboardEventKind::PasteAsQuotation))
+        return;
+    if (!canPaste())
+        return;
+    updateMarkersForWordsAffectedByEditing(false);
+    ResourceCacheValidationSuppressor validationSuppressor(document().cachedResourceLoader());
+    auto pasteboard = Pasteboard::createForCopyAndPaste();
+    if (m_frame.selection().selection().isContentRichlyEditable())
+        pasteWithPasteboard(pasteboard.get(), { PasteOption::AllowPlainText, PasteOption::AsQuotation });
+    else
+        pasteAsPlainTextWithPasteboard(*pasteboard);
+}
+
+void Editor::quoteFragmentForPasting(DocumentFragment& fragment)
+{
+    auto blockQuote = HTMLQuoteElement::create(blockquoteTag, document());
+    blockQuote->setAttributeWithoutSynchronization(typeAttr, AtomicString("cite"));
+    blockQuote->setAttributeWithoutSynchronization(classAttr, AtomicString(ApplePasteAsQuotation));
+
+    auto childNode = fragment.firstChild();
+
+    if (childNode) {
+        while (childNode) {
+            blockQuote->appendChild(*childNode);
+            childNode = fragment.firstChild();
+        }
+    } else
+        blockQuote->appendChild(HTMLBRElement::create(document()));
+
+    fragment.appendChild(blockQuote);
+}
+
 void Editor::performDelete()
 {
     if (!canDelete()) {

Modified: trunk/Source/WebCore/editing/Editor.h (235954 => 235955)


--- trunk/Source/WebCore/editing/Editor.h	2018-09-12 22:16:45 UTC (rev 235954)
+++ trunk/Source/WebCore/editing/Editor.h	2018-09-12 22:26:12 UTC (rev 235955)
@@ -129,6 +129,12 @@
     explicit Editor(Frame&);
     ~Editor();
 
+    enum class PasteOption : uint8_t {
+        AllowPlainText = 1 << 0,
+        IgnoreMailBlockquote = 1 << 1,
+        AsQuotation = 1 << 2,
+    };
+
     WEBCORE_EXPORT EditorClient* client() const;
     WEBCORE_EXPORT TextCheckerClient* textChecker() const;
 
@@ -158,6 +164,7 @@
     WEBCORE_EXPORT void paste();
     void paste(Pasteboard&);
     WEBCORE_EXPORT void pasteAsPlainText();
+    void pasteAsQuotation();
     WEBCORE_EXPORT void performDelete();
 
     WEBCORE_EXPORT void copyURL(const URL&, const String& title);
@@ -519,9 +526,11 @@
     bool canDeleteRange(Range*) const;
     bool canSmartReplaceWithPasteboard(Pasteboard&);
     void pasteAsPlainTextWithPasteboard(Pasteboard&);
-    void pasteWithPasteboard(Pasteboard*, bool allowPlainText, MailBlockquoteHandling = MailBlockquoteHandling::RespectBlockquote);
+    void pasteWithPasteboard(Pasteboard*, OptionSet<PasteOption>);
     String plainTextFromPasteboard(const PasteboardPlainText&);
 
+    void quoteFragmentForPasting(DocumentFragment&);
+
     void revealSelectionAfterEditingOperation(const ScrollAlignment& = ScrollAlignment::alignCenterIfNeeded, RevealExtentOption = DoNotRevealExtent);
     void markMisspellingsOrBadGrammar(const VisibleSelection&, bool checkSpelling, RefPtr<Range>& firstMisspellingRange);
     OptionSet<TextCheckingType> resolveTextCheckingTypeMask(const Node& rootEditableElement, OptionSet<TextCheckingType>);

Modified: trunk/Source/WebCore/editing/EditorCommand.cpp (235954 => 235955)


--- trunk/Source/WebCore/editing/EditorCommand.cpp	2018-09-12 22:16:45 UTC (rev 235954)
+++ trunk/Source/WebCore/editing/EditorCommand.cpp	2018-09-12 22:26:12 UTC (rev 235955)
@@ -926,6 +926,16 @@
     return true;
 }
 
+static bool executePasteAsQuotation(Frame& frame, Event*, EditorCommandSource source, const String&)
+{
+    if (source == CommandFromMenuOrKeyBinding) {
+        UserTypingGestureIndicator typingGestureIndicator(frame);
+        frame.editor().pasteAsQuotation();
+    } else
+        frame.editor().pasteAsQuotation();
+    return true;
+}
+
 static bool executePrint(Frame& frame, Event*, EditorCommandSource, const String&)
 {
     Page* page = frame.page();
@@ -1636,6 +1646,7 @@
         { "Paste", { executePaste, supportedPaste, enabledPaste, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabledPaste } },
         { "PasteAndMatchStyle", { executePasteAndMatchStyle, supportedPaste, enabledPaste, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabledPaste } },
         { "PasteAsPlainText", { executePasteAsPlainText, supportedPaste, enabledPaste, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabledPaste } },
+        { "PasteAsQuotation", { executePasteAsQuotation, supportedPaste, enabledPaste, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabledPaste } },
         { "Print", { executePrint, supported, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
         { "Redo", { executeRedo, supported, enabledRedo, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
         { "RemoveFormat", { executeRemoveFormat, supported, enabledRangeInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },

Modified: trunk/Source/WebCore/editing/cocoa/EditorCocoa.mm (235954 => 235955)


--- trunk/Source/WebCore/editing/cocoa/EditorCocoa.mm	2018-09-12 22:16:45 UTC (rev 235954)
+++ trunk/Source/WebCore/editing/cocoa/EditorCocoa.mm	2018-09-12 22:26:12 UTC (rev 235955)
@@ -291,4 +291,14 @@
     return nullptr;
 }
 
+// FIXME: Should give this function a name that makes it clear it adds resources to the document loader as a side effect.
+// Or refactor so it does not do that.
+RefPtr<DocumentFragment> Editor::webContentFromPasteboard(Pasteboard& pasteboard, Range& context, bool allowPlainText, bool& chosePlainText)
+{
+    WebContentReader reader(m_frame, context, allowPlainText);
+    pasteboard.read(reader);
+    chosePlainText = reader.madeFragmentFromPlainText;
+    return WTFMove(reader.fragment);
 }
+
+}

Modified: trunk/Source/WebCore/editing/gtk/EditorGtk.cpp (235954 => 235955)


--- trunk/Source/WebCore/editing/gtk/EditorGtk.cpp	2018-09-12 22:16:45 UTC (rev 235954)
+++ trunk/Source/WebCore/editing/gtk/EditorGtk.cpp	2018-09-12 22:26:12 UTC (rev 235955)
@@ -86,7 +86,7 @@
     return nullptr;
 }
 
-void Editor::pasteWithPasteboard(Pasteboard* pasteboard, bool allowPlainText, MailBlockquoteHandling mailBlockquoteHandling)
+void Editor::pasteWithPasteboard(Pasteboard* pasteboard, OptionSet<PasteOption> options)
 {
     RefPtr<Range> range = selectedRange();
     if (!range)
@@ -93,9 +93,13 @@
         return;
 
     bool chosePlainText;
-    RefPtr<DocumentFragment> fragment = createFragmentFromPasteboardData(*pasteboard, m_frame, *range, allowPlainText, chosePlainText);
+    RefPtr<DocumentFragment> fragment = createFragmentFromPasteboardData(*pasteboard, m_frame, *range, options.contains(PasteOption::AllowPlainText), chosePlainText);
+
+    if (fragment && options.contains(PasteOption::AsQuotation))
+        quoteFragmentForPasting(*fragment);
+
     if (fragment && shouldInsertFragment(*fragment, range.get(), EditorInsertAction::Pasted))
-        pasteAsFragment(fragment.releaseNonNull(), canSmartReplaceWithPasteboard(*pasteboard), chosePlainText, mailBlockquoteHandling);
+        pasteAsFragment(fragment.releaseNonNull(), canSmartReplaceWithPasteboard(*pasteboard), chosePlainText, options.contains(PasteOption::IgnoreMailBlockquote) ? MailBlockquoteHandling::IgnoreBlockquote : MailBlockquoteHandling::RespectBlockquote);
 }
 
 static const AtomicString& elementURL(Element& element)

Modified: trunk/Source/WebCore/editing/ios/EditorIOS.mm (235954 => 235955)


--- trunk/Source/WebCore/editing/ios/EditorIOS.mm	2018-09-12 22:16:45 UTC (rev 235954)
+++ trunk/Source/WebCore/editing/ios/EditorIOS.mm	2018-09-12 22:26:12 UTC (rev 235955)
@@ -215,19 +215,10 @@
     pasteboard.write(pasteboardImage);
 }
 
-// FIXME: Should give this function a name that makes it clear it adds resources to the document loader as a side effect.
-// Or refactor so it does not do that.
-RefPtr<DocumentFragment> Editor::webContentFromPasteboard(Pasteboard& pasteboard, Range& context, bool allowPlainText, bool& chosePlainText)
+void Editor::pasteWithPasteboard(Pasteboard* pasteboard, OptionSet<PasteOption> options)
 {
-    WebContentReader reader(m_frame, context, allowPlainText);
-    pasteboard.read(reader);
-    chosePlainText = reader.madeFragmentFromPlainText;
-    return WTFMove(reader.fragment);
-}
-
-void Editor::pasteWithPasteboard(Pasteboard* pasteboard, bool allowPlainText, MailBlockquoteHandling mailBlockquoteHandling)
-{
     RefPtr<Range> range = selectedRange();
+    bool allowPlainText = options.contains(PasteOption::AllowPlainText);
     WebContentReader reader(m_frame, *range, allowPlainText);
     int numberOfPasteboardItems = client()->getPasteboardItemsCount();
     for (int i = 0; i < numberOfPasteboardItems; ++i) {
@@ -243,8 +234,11 @@
         fragment = webContentFromPasteboard(*pasteboard, *range, allowPlainText, chosePlainTextIgnored);
     }
 
+    if (fragment && options.contains(PasteOption::AsQuotation))
+        quoteFragmentForPasting(*fragment);
+
     if (fragment && shouldInsertFragment(*fragment, range.get(), EditorInsertAction::Pasted))
-        pasteAsFragment(fragment.releaseNonNull(), canSmartReplaceWithPasteboard(*pasteboard), false, mailBlockquoteHandling);
+        pasteAsFragment(fragment.releaseNonNull(), canSmartReplaceWithPasteboard(*pasteboard), false, options.contains(PasteOption::IgnoreMailBlockquote) ? MailBlockquoteHandling::IgnoreBlockquote : MailBlockquoteHandling::RespectBlockquote);
 }
 
 void Editor::insertDictationPhrases(Vector<Vector<String>>&& dictationPhrases, RetainPtr<id> metadata)

Modified: trunk/Source/WebCore/editing/mac/EditorMac.mm (235954 => 235955)


--- trunk/Source/WebCore/editing/mac/EditorMac.mm	2018-09-12 22:16:45 UTC (rev 235954)
+++ trunk/Source/WebCore/editing/mac/EditorMac.mm	2018-09-12 22:26:12 UTC (rev 235955)
@@ -77,7 +77,7 @@
     [[NSApplication sharedApplication] orderFrontColorPanel:nil];
 }
 
-void Editor::pasteWithPasteboard(Pasteboard* pasteboard, bool allowPlainText, MailBlockquoteHandling mailBlockquoteHandling)
+void Editor::pasteWithPasteboard(Pasteboard* pasteboard, OptionSet<PasteOption> options)
 {
     RefPtr<Range> range = selectedRange();
 
@@ -87,10 +87,13 @@
     ALLOW_DEPRECATED_DECLARATIONS_END
 
     bool chosePlainText;
-    RefPtr<DocumentFragment> fragment = webContentFromPasteboard(*pasteboard, *range, allowPlainText, chosePlainText);
+    RefPtr<DocumentFragment> fragment = webContentFromPasteboard(*pasteboard, *range, options.contains(PasteOption::AllowPlainText), chosePlainText);
 
+    if (fragment && options.contains(PasteOption::AsQuotation))
+        quoteFragmentForPasting(*fragment);
+
     if (fragment && shouldInsertFragment(*fragment, range.get(), EditorInsertAction::Pasted))
-        pasteAsFragment(fragment.releaseNonNull(), canSmartReplaceWithPasteboard(*pasteboard), false, mailBlockquoteHandling);
+        pasteAsFragment(fragment.releaseNonNull(), canSmartReplaceWithPasteboard(*pasteboard), false, options.contains(PasteOption::IgnoreMailBlockquote) ? MailBlockquoteHandling::IgnoreBlockquote : MailBlockquoteHandling::RespectBlockquote );
 
     client()->setInsertionPasteboard(String());
 }
@@ -120,7 +123,7 @@
 {
     Pasteboard pasteboard(pasteboardName);
     if (m_frame.selection().selection().isContentRichlyEditable())
-        pasteWithPasteboard(&pasteboard, true);
+        pasteWithPasteboard(&pasteboard, { PasteOption::AllowPlainText });
     else
         pasteAsPlainTextWithPasteboard(pasteboard);
 }
@@ -276,16 +279,6 @@
     pasteboard.write(pasteboardImage);
 }
 
-// FIXME: Should give this function a name that makes it clear it adds resources to the document loader as a side effect.
-// Or refactor so it does not do that.
-RefPtr<DocumentFragment> Editor::webContentFromPasteboard(Pasteboard& pasteboard, Range& context, bool allowPlainText, bool& chosePlainText)
-{
-    WebContentReader reader(m_frame, context, allowPlainText);
-    pasteboard.read(reader);
-    chosePlainText = reader.madeFragmentFromPlainText;
-    return WTFMove(reader.fragment);
-}
-
 } // namespace WebCore
 
 #endif // PLATFORM(MAC)

Modified: trunk/Source/WebCore/editing/win/EditorWin.cpp (235954 => 235955)


--- trunk/Source/WebCore/editing/win/EditorWin.cpp	2018-09-12 22:16:45 UTC (rev 235954)
+++ trunk/Source/WebCore/editing/win/EditorWin.cpp	2018-09-12 22:26:12 UTC (rev 235955)
@@ -35,7 +35,7 @@
 
 namespace WebCore {
 
-void Editor::pasteWithPasteboard(Pasteboard* pasteboard, bool allowPlainText, MailBlockquoteHandling mailBlockquoteHandling)
+void Editor::pasteWithPasteboard(Pasteboard* pasteboard, OptionSet<PasteOption> options)
 {
     RefPtr<Range> range = selectedRange();
     if (!range)
@@ -42,9 +42,13 @@
         return;
 
     bool chosePlainText;
-    RefPtr<DocumentFragment> fragment = pasteboard->documentFragment(m_frame, *range, allowPlainText, chosePlainText);
+    RefPtr<DocumentFragment> fragment = pasteboard->documentFragment(m_frame, *range, options.contains(PasteOption::AllowPlainText), chosePlainText);
+
+    if (fragment && options.contains(PasteOption::AsQuotation))
+        quoteFragmentForPasting(*fragment);
+
     if (fragment && shouldInsertFragment(*fragment, range.get(), EditorInsertAction::Pasted))
-        pasteAsFragment(fragment.releaseNonNull(), canSmartReplaceWithPasteboard(*pasteboard), chosePlainText, mailBlockquoteHandling);
+        pasteAsFragment(fragment.releaseNonNull(), canSmartReplaceWithPasteboard(*pasteboard), chosePlainText, options.contains(PasteOption::IgnoreMailBlockquote) ? MailBlockquoteHandling::IgnoreBlockquote : MailBlockquoteHandling::RespectBlockquote);
 }
 
 template <typename PlatformDragData>

Modified: trunk/Source/WebCore/editing/wpe/EditorWPE.cpp (235954 => 235955)


--- trunk/Source/WebCore/editing/wpe/EditorWPE.cpp	2018-09-12 22:16:45 UTC (rev 235954)
+++ trunk/Source/WebCore/editing/wpe/EditorWPE.cpp	2018-09-12 22:26:12 UTC (rev 235955)
@@ -73,7 +73,7 @@
     notImplemented();
 }
 
-void Editor::pasteWithPasteboard(Pasteboard* pasteboard, bool allowPlainText, MailBlockquoteHandling mailBlockquoteHandling)
+void Editor::pasteWithPasteboard(Pasteboard* pasteboard, OptionSet<PasteOption> options)
 {
     RefPtr<Range> range = selectedRange();
     if (!range)
@@ -80,9 +80,13 @@
         return;
 
     bool chosePlainText;
-    RefPtr<DocumentFragment> fragment = createFragmentFromPasteboardData(*pasteboard, m_frame, *range, allowPlainText, chosePlainText);
+    RefPtr<DocumentFragment> fragment = createFragmentFromPasteboardData(*pasteboard, m_frame, *range, options.contains(PasteOption::AllowPlainText), chosePlainText);
+
+    if (fragment && options.contains(PasteOption::AsQuotation))
+        quoteFragmentForPasting(*fragment);
+
     if (fragment && shouldInsertFragment(*fragment, range.get(), EditorInsertAction::Pasted))
-        pasteAsFragment(*fragment, canSmartReplaceWithPasteboard(*pasteboard), chosePlainText, mailBlockquoteHandling);
+        pasteAsFragment(*fragment, canSmartReplaceWithPasteboard(*pasteboard), chosePlainText, options.contains(PasteOption::IgnoreMailBlockquote) ? MailBlockquoteHandling::IgnoreBlockquote : MailBlockquoteHandling::RespectBlockquote);
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebKit/ChangeLog (235954 => 235955)


--- trunk/Source/WebKit/ChangeLog	2018-09-12 22:16:45 UTC (rev 235954)
+++ trunk/Source/WebKit/ChangeLog	2018-09-12 22:26:12 UTC (rev 235955)
@@ -1,3 +1,29 @@
+2018-09-12  Dan Bernstein  <m...@apple.com>
+
+        [Cocoa] Complete support for Paste as Quotation
+        https://bugs.webkit.org/show_bug.cgi?id=189504
+
+        Reviewed by Wenson Hsieh.
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView canPerformAction:withSender:]): Handle _pasteAsQuotation:. It’s not included
+          in FOR_EACH_WKCONTENTVIEW_ACTION, because it’s declared and implemented in the WKPrivate
+          category. If we add more actions in the category, it could make sense to fold them into
+          a new FOR_EACH_PRIVATE_WKCONTENTVIEW_ACTION.
+        (-[WKWebView targetForAction:withSender:]): Handle _pasteAsQuotation:.
+        (-[WKWebView _pasteAsQuotation:]): Send to the WebViewImpl or the WKContentView.
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h: Declared a new _pasteAsQuotation: action.
+
+        * UIProcess/Cocoa/WebViewImpl.mm:
+        (WebKit::selectorExceptionMap): Added a custom mapping from the new selector to the
+          PasteAsQuotation command.
+
+        * UIProcess/ios/WKContentViewInteraction.h: Declare methods for the new action.
+        * UIProcess/ios/WKContentViewInteraction.mm:
+          Forward _pasteAsQuotation: to the WKWebView so that clients get a chance to override its
+          behavior.
+        (-[WKContentView _pasteAsQuotationForWebView:]): Send the command to the page.
+
 2018-09-12  Sihui Liu  <sihui_...@apple.com>
 
         Move IndexedDB to Network Process

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm (235954 => 235955)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2018-09-12 22:16:45 UTC (rev 235954)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2018-09-12 22:26:12 UTC (rev 235955)
@@ -1387,6 +1387,8 @@
 
     FOR_EACH_WKCONTENTVIEW_ACTION(FORWARD_CANPERFORMACTION_TO_WKCONTENTVIEW)
 
+    FORWARD_CANPERFORMACTION_TO_WKCONTENTVIEW(_pasteAsQuotation)
+
     #undef FORWARD_CANPERFORMACTION_TO_WKCONTENTVIEW
 
     return [super canPerformAction:action withSender:sender];
@@ -1400,6 +1402,8 @@
 
     FOR_EACH_WKCONTENTVIEW_ACTION(FORWARD_TARGETFORACTION_TO_WKCONTENTVIEW)
 
+    FORWARD_TARGETFORACTION_TO_WKCONTENTVIEW(_pasteAsQuotation)
+
     #undef FORWARD_TARGETFORACTION_TO_WKCONTENTVIEW
 
     return [super targetForAction:action withSender:sender];
@@ -4547,6 +4551,16 @@
 #endif
 }
 
+- (void)_pasteAsQuotation:(id)sender
+{
+#if PLATFORM(MAC)
+    _impl->executeEditCommandForSelector(_cmd);
+#else
+    if (self.usesStandardContentView)
+        [_contentView _pasteAsQuotationForWebView:sender];
+#endif
+}
+
 - (void)_evaluateJavaScriptWithoutUserGesture:(NSString *)_javascript_String completionHandler:(void (^)(id, NSError *))completionHandler
 {
     [self _evaluateJavaScript:_javascript_String forceUserGesture:NO completionHandler:completionHandler];

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h (235954 => 235955)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h	2018-09-12 22:16:45 UTC (rev 235954)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h	2018-09-12 22:26:12 UTC (rev 235955)
@@ -185,6 +185,8 @@
 - (_WKAttachment *)_insertAttachmentWithFileWrapper:(NSFileWrapper *)fileWrapper contentType:(NSString *)contentType options:(_WKAttachmentDisplayOptions *)options completion:(void(^)(BOOL success))completionHandler WK_API_DEPRECATED_WITH_REPLACEMENT("-_insertAttachmentWithFileWrapper:contentType:completion:", macosx(WK_MAC_TBA, WK_MAC_TBA), ios(WK_IOS_TBA, WK_IOS_TBA));
 - (_WKAttachment *)_insertAttachmentWithFileWrapper:(NSFileWrapper *)fileWrapper contentType:(NSString *)contentType completion:(void(^)(BOOL success))completionHandler WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
 
+- (IBAction)_pasteAsQuotation:(id)sender WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+
 #if TARGET_OS_IPHONE
 // DERECATED: The setters of the three following function are deprecated, please use overrideLayoutParameters.
 // Define the smallest size a page take with a regular viewport.

Modified: trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm (235954 => 235955)


--- trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm	2018-09-12 22:16:45 UTC (rev 235954)
+++ trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm	2018-09-12 22:26:12 UTC (rev 235955)
@@ -2624,7 +2624,10 @@
         { @selector(pageUp:), "MovePageUp"_s },
         { @selector(pageUpAndModifySelection:), "MovePageUpAndModifySelection"_s },
         { @selector(scrollPageDown:), "ScrollPageForward"_s },
-        { @selector(scrollPageUp:), "ScrollPageBackward"_s }
+        { @selector(scrollPageUp:), "ScrollPageBackward"_s },
+#if WK_API_ENABLED
+        { @selector(_pasteAsQuotation:), "PasteAsQuotation"_s },
+#endif
     };
 
     for (auto& name : names)

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h (235954 => 235955)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h	2018-09-12 22:16:45 UTC (rev 235954)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h	2018-09-12 22:26:12 UTC (rev 235955)
@@ -316,6 +316,7 @@
 #define DECLARE_WKCONTENTVIEW_ACTION_FOR_WEB_VIEW(_action) \
     - (void)_action ## ForWebView:(id)sender;
 FOR_EACH_WKCONTENTVIEW_ACTION(DECLARE_WKCONTENTVIEW_ACTION_FOR_WEB_VIEW)
+DECLARE_WKCONTENTVIEW_ACTION_FOR_WEB_VIEW(_pasteAsQuotation)
 #undef DECLARE_WKCONTENTVIEW_ACTION_FOR_WEB_VIEW
 
 #if ENABLE(TOUCH_EVENTS)

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (235954 => 235955)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2018-09-12 22:16:45 UTC (rev 235954)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2018-09-12 22:26:12 UTC (rev 235955)
@@ -2161,6 +2161,8 @@
 
 FOR_EACH_WKCONTENTVIEW_ACTION(FORWARD_ACTION_TO_WKWEBVIEW)
 
+FORWARD_ACTION_TO_WKWEBVIEW(_pasteAsQuotation)
+
 #undef FORWARD_ACTION_TO_WKWEBVIEW
 
 - (void)_lookupForWebView:(id)sender
@@ -2462,6 +2464,11 @@
     _page->executeEditCommand("paste"_s);
 }
 
+- (void)_pasteAsQuotationForWebView:(id)sender
+{
+    _page->executeEditCommand("PasteAsQuotation"_s);
+}
+
 - (void)selectForWebView:(id)sender
 {
     [_textSelectionAssistant selectWord];

Modified: trunk/Tools/ChangeLog (235954 => 235955)


--- trunk/Tools/ChangeLog	2018-09-12 22:16:45 UTC (rev 235954)
+++ trunk/Tools/ChangeLog	2018-09-12 22:26:12 UTC (rev 235955)
@@ -1,3 +1,12 @@
+2018-09-12  Dan Bernstein  <m...@apple.com>
+
+        [Cocoa] Complete support for Paste as Quotation
+        https://bugs.webkit.org/show_bug.cgi?id=189504
+
+        Reviewed by Wenson Hsieh.
+
+        * MiniBrowser/mac/MainMenu.xib: Added a Paste as Quotation command in the Edit menu.
+
 2018-09-12  Sihui Liu  <sihui_...@apple.com>
 
         Move IndexedDB to Network Process

Modified: trunk/Tools/MiniBrowser/mac/MainMenu.xib (235954 => 235955)


--- trunk/Tools/MiniBrowser/mac/MainMenu.xib	2018-09-12 22:16:45 UTC (rev 235954)
+++ trunk/Tools/MiniBrowser/mac/MainMenu.xib	2018-09-12 22:26:12 UTC (rev 235955)
@@ -197,6 +197,11 @@
                                     <action selector="paste:" target="-1" id="226"/>
                                 </connections>
                             </menuItem>
+                            <menuItem title="Paste as Quotation" keyEquivalent="V" id="8Ng-DB-z0Y">
+                                <connections>
+                                    <action selector="_pasteAsQuotation:" target="-1" id="6Mn-XC-2qO"/>
+                                </connections>
+                            </menuItem>
                             <menuItem title="Paste and Match Style" keyEquivalent="V" id="485">
                                 <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
                                 <connections>
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to