Support InputEvent.dataTransfer for the InputEvent spec
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Oct 2016 20:23:10 +0000 (20:23 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Oct 2016 20:23:10 +0000 (20:23 +0000)
https://bugs.webkit.org/show_bug.cgi?id=163213
<rdar://problem/28700407>

Reviewed by Ryosuke Niwa.

Source/WebCore:

Adds support for the dataTransfer attribute of InputEvent, which contains both HTML and plain text
representations of inserted content corresponding to input types "insertFromPaste", "insertFromDrop" and
"insertReplacementText". The specification calls for the data transfer's drag data item list to contain this
information via two entries with type strings "text/html" and "text/plain". However, WebKit does not yet support
the DataTransfer.items -- in lieu of this, we will provide this information for now via getData("text/plain")
and getData("text/html"), respectively.

To support this attribute, we need a special type of DataTransfer which is readonly and returns canned data
given a type string. To implement this, we introduce StaticPasteboard, a type of Pasteboard which is initialized
with a map of type string to data. When asked for its data via getData, the StaticPasteboard searches its map
for the requested type and returns the result, if any.

An editing command may now create a new DataTransfer via DataTransfer::createForInputEvent from HTML and
plaintext strings, and then vend this information to its dispatched input events by overriding
CompositeEditCommand::inputEventDataTransfer.

Some further work will be needed to ensure that all information exposed via this DataTransfer does not contain
hidden content. To do this, we should create a new Document, "paste" the contents of our copied HTML string into
it, then simulate selecting the content and generating markup from the selection to create a sanitized
DocumentFragment corresponding to the original copied HTML. This will be addressed in a future patch.

Tests: fast/events/input-events-paste-rich-datatransfer.html
       fast/events/input-events-spell-checking-datatransfer.html

* PlatformEfl.cmake:
* PlatformGTK.cmake:
* PlatformWin.cmake:

Add StaticPasteboard.cpp.

* WebCore.xcodeproj/project.pbxproj:
* dom/DataTransfer.cpp:
(WebCore::DataTransfer::DataTransfer):
(WebCore::DataTransfer::createForInputEvent):

Initializes a new DataTransfer for the purposes of input events. This takes a HTML and plain text
representations of the data being inserted and creates a new readonly DataTransfer backed by a StaticPasteboard
that only knows how to map the "text/plain" data type to the given plaintext string and "text/html" to the
given HTML text.

* dom/DataTransfer.h:
* dom/InputEvent.cpp:
(WebCore::InputEvent::create):
(WebCore::InputEvent::InputEvent):
(WebCore::InputEvent::dataTransfer):
* dom/InputEvent.h:
* dom/InputEvent.idl:

Add the InputEvent.dataTransfer attribute.

* dom/Node.cpp:
* editing/CompositeEditCommand.cpp:
(WebCore::CompositeEditCommand::inputEventDataTransfer):

Add a new hook for CompositeEditCommands to vend a DataTransfer for the purposes of input events. By default,
this is null.

* editing/CompositeEditCommand.h:
* editing/Editor.cpp:
(WebCore::dispatchBeforeInputEvent):
(WebCore::dispatchInputEvent):
(WebCore::dispatchBeforeInputEvents):
(WebCore::dispatchInputEvents):
(WebCore::Editor::willApplyEditing):
(WebCore::Editor::appliedEditing):
* editing/ReplaceRangeWithTextCommand.cpp:
(WebCore::ReplaceRangeWithTextCommand::willApplyCommand):
(WebCore::ReplaceRangeWithTextCommand::doApply):
(WebCore::ReplaceRangeWithTextCommand::inputEventDataTransfer):
* editing/ReplaceRangeWithTextCommand.h:
* editing/ReplaceSelectionCommand.cpp:
(WebCore::ReplaceSelectionCommand::willApplyCommand):

Initialize the ReplacementFragment here before applying the command, adjusting the DocumentFragment to be
inserted in the process.

(WebCore::ReplaceSelectionCommand::doApply):
(WebCore::ReplaceSelectionCommand::inputEventDataTransfer):
(WebCore::ReplaceSelectionCommand::ensureReplacementFragment):

Returns the ReplacementFragment used to apply the command, initializing it if necessary and stripping extraneous
nodes off of the document fragment in the process. Since ReplaceSelectionCommand may be used as a top-level
editing command or a child of another CompositeEditCommand such as the ReplaceRangeWithTextCommand, the
ReplacementFragment may be initialized either in willApplyCommand or in doApply.

* editing/ReplaceSelectionCommand.h:
* editing/SpellingCorrectionCommand.cpp:
(WebCore::SpellingCorrectionCommand::willApplyCommand):
(WebCore::SpellingCorrectionCommand::doApply):
(WebCore::SpellingCorrectionCommand::inputEventDataTransfer):
* editing/SpellingCorrectionCommand.h:

Using the replacement text fragment, create and return a DataTransfer for input events.

* platform/Pasteboard.h:
* platform/StaticPasteboard.cpp: Added.
(WebCore::StaticPasteboard::create):
(WebCore::StaticPasteboard::StaticPasteboard):
(WebCore::StaticPasteboard::hasData):
(WebCore::StaticPasteboard::types):
(WebCore::StaticPasteboard::readString):
* platform/StaticPasteboard.h: Copied from Source/WebCore/dom/InputEvent.cpp.
* platform/efl/PasteboardEfl.cpp:
(WebCore::Pasteboard::writeMarkup):
(WebCore::Pasteboard::write):
(WebCore::Pasteboard::read):
* platform/gtk/PasteboardGtk.cpp:
(WebCore::Pasteboard::writeMarkup):
* platform/ios/PasteboardIOS.mm:
(WebCore::Pasteboard::writeMarkup):
* platform/mac/PasteboardMac.mm:
(WebCore::Pasteboard::Pasteboard):
(WebCore::Pasteboard::writeMarkup):
* platform/win/PasteboardWin.cpp:
(WebCore::Pasteboard::write):
(WebCore::Pasteboard::read):

To account for virtual methods on Pasteboard, add implementations for methods that were previously defined but
unimplemented on these platforms.

LayoutTests:

Adds 2 new layout tests verifying that input events dispatched as a result of pasting or spell checking contain
DataTransfers that have rich and plain text representations of the contents being inserted.

* fast/events/input-events-fired-when-typing-expected.txt:
* fast/events/input-events-fired-when-typing.html:
* fast/events/input-events-paste-rich-datatransfer-expected.txt: Added.
* fast/events/input-events-paste-rich-datatransfer.html: Added.
* fast/events/input-events-spell-checking-datatransfer-expected.txt: Added.
* fast/events/input-events-spell-checking-datatransfer.html: Added.
* platform/ios-simulator/TestExpectations:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207841 268f45cc-cd09-0410-ab3c-d52691b4dbfc

36 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/events/input-events-fired-when-typing-expected.txt
LayoutTests/fast/events/input-events-fired-when-typing.html
LayoutTests/fast/events/input-events-paste-rich-datatransfer-expected.txt [new file with mode: 0644]
LayoutTests/fast/events/input-events-paste-rich-datatransfer.html [new file with mode: 0644]
LayoutTests/fast/events/input-events-spell-checking-datatransfer-expected.txt [new file with mode: 0644]
LayoutTests/fast/events/input-events-spell-checking-datatransfer.html [new file with mode: 0644]
LayoutTests/platform/ios-simulator/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/PlatformEfl.cmake
Source/WebCore/PlatformGTK.cmake
Source/WebCore/PlatformWin.cmake
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/dom/DataTransfer.cpp
Source/WebCore/dom/DataTransfer.h
Source/WebCore/dom/InputEvent.cpp
Source/WebCore/dom/InputEvent.h
Source/WebCore/dom/InputEvent.idl
Source/WebCore/dom/Node.cpp
Source/WebCore/editing/CompositeEditCommand.cpp
Source/WebCore/editing/CompositeEditCommand.h
Source/WebCore/editing/Editor.cpp
Source/WebCore/editing/ReplaceRangeWithTextCommand.cpp
Source/WebCore/editing/ReplaceRangeWithTextCommand.h
Source/WebCore/editing/ReplaceSelectionCommand.cpp
Source/WebCore/editing/ReplaceSelectionCommand.h
Source/WebCore/editing/SpellingCorrectionCommand.cpp
Source/WebCore/editing/SpellingCorrectionCommand.h
Source/WebCore/platform/Pasteboard.h
Source/WebCore/platform/StaticPasteboard.cpp [new file with mode: 0644]
Source/WebCore/platform/StaticPasteboard.h [new file with mode: 0644]
Source/WebCore/platform/efl/PasteboardEfl.cpp
Source/WebCore/platform/gtk/PasteboardGtk.cpp
Source/WebCore/platform/ios/PasteboardIOS.mm
Source/WebCore/platform/mac/PasteboardMac.mm
Source/WebCore/platform/win/PasteboardWin.cpp

index 0f77786..2ede345 100644 (file)
@@ -1,3 +1,22 @@
+2016-10-25  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Support InputEvent.dataTransfer for the InputEvent spec
+        https://bugs.webkit.org/show_bug.cgi?id=163213
+        <rdar://problem/28700407>
+
+        Reviewed by Ryosuke Niwa.
+
+        Adds 2 new layout tests verifying that input events dispatched as a result of pasting or spell checking contain
+        DataTransfers that have rich and plain text representations of the contents being inserted.
+
+        * fast/events/input-events-fired-when-typing-expected.txt:
+        * fast/events/input-events-fired-when-typing.html:
+        * fast/events/input-events-paste-rich-datatransfer-expected.txt: Added.
+        * fast/events/input-events-paste-rich-datatransfer.html: Added.
+        * fast/events/input-events-spell-checking-datatransfer-expected.txt: Added.
+        * fast/events/input-events-spell-checking-datatransfer.html: Added.
+        * platform/ios-simulator/TestExpectations:
+
 2016-10-25  Andy Estes  <aestes@apple.com>
 
         Implement rel=noopener
index a5d6d07..f7308d2 100644 (file)
@@ -4,6 +4,7 @@ TEST COMPLETE
 Fired `onbeforeinput`!
 PASS event.__lookupGetter__('inputType') is defined.
 PASS event.__lookupGetter__('data') is defined.
+PASS event.__lookupGetter__('dataTransfer') is defined.
 PASS event.getTargetRanges is defined.
 PASS event.target.id is expectedTargetID
 PASS event.bubbles is true
@@ -12,6 +13,7 @@ PASS event.composed is true
 Fired `oninput`!
 PASS event.__lookupGetter__('inputType') is defined.
 PASS event.__lookupGetter__('data') is defined.
+PASS event.__lookupGetter__('dataTransfer') is defined.
 PASS event.getTargetRanges is defined.
 PASS event.target.id is expectedTargetID
 PASS event.bubbles is true
@@ -20,6 +22,7 @@ PASS event.composed is true
 Fired `onbeforeinput`!
 PASS event.__lookupGetter__('inputType') is defined.
 PASS event.__lookupGetter__('data') is defined.
+PASS event.__lookupGetter__('dataTransfer') is defined.
 PASS event.getTargetRanges is defined.
 PASS event.target.id is expectedTargetID
 PASS event.bubbles is true
@@ -28,6 +31,7 @@ PASS event.composed is true
 Fired `oninput`!
 PASS event.__lookupGetter__('inputType') is defined.
 PASS event.__lookupGetter__('data') is defined.
+PASS event.__lookupGetter__('dataTransfer') is defined.
 PASS event.getTargetRanges is defined.
 PASS event.target.id is expectedTargetID
 PASS event.bubbles is true
index e9c1227..72ee5f7 100644 (file)
@@ -36,6 +36,7 @@
             debug("Fired `oninput`!");
             shouldBeDefined("event.__lookupGetter__('inputType')");
             shouldBeDefined("event.__lookupGetter__('data')");
+            shouldBeDefined("event.__lookupGetter__('dataTransfer')");
             shouldBeDefined("event.getTargetRanges");
             shouldBe("event.target.id", "expectedTargetID");
             shouldBe("event.bubbles", "true");
@@ -48,6 +49,7 @@
             debug("Fired `onbeforeinput`!");
             shouldBeDefined("event.__lookupGetter__('inputType')");
             shouldBeDefined("event.__lookupGetter__('data')");
+            shouldBeDefined("event.__lookupGetter__('dataTransfer')");
             shouldBeDefined("event.getTargetRanges");
             shouldBe("event.target.id", "expectedTargetID");
             shouldBe("event.bubbles", "true");
diff --git a/LayoutTests/fast/events/input-events-paste-rich-datatransfer-expected.txt b/LayoutTests/fast/events/input-events-paste-rich-datatransfer-expected.txt
new file mode 100644 (file)
index 0000000..38c1948
--- /dev/null
@@ -0,0 +1,13 @@
+To manually test this, copy and paste into the first contenteditable. The following contenteditables should reflect the pasted contents.
+
+destination after pasting (text/html):
+| <b>
+|   style="color: rgb(255, 0, 0); font-family: -webkit-standard; font-style: normal; font-variant-caps: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"
+|   "LayoutTests"
+|   <i>
+|     "are"
+|     <u>
+|       "fun!"
+
+destination after pasting (text/plain):
+| "LayoutTestsarefun!"
diff --git a/LayoutTests/fast/events/input-events-paste-rich-datatransfer.html b/LayoutTests/fast/events/input-events-paste-rich-datatransfer.html
new file mode 100644 (file)
index 0000000..170cbc9
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <div id="source" contenteditable onbeforeinput=beforeInput(event)><span style="color:red"><b>LayoutTests<i>are<u>fun!</i></u></b></span></div>
+    <div id="destinationHTML" contenteditable></div>
+    <div id="destinationPlain" contenteditable></div>
+    <script src="../../resources/dump-as-markup.js"></script>
+    <script>
+        Markup.description(`To manually test this, copy and paste into the first contenteditable. The following contenteditables should reflect the pasted contents.`);
+        source.focus();
+        document.execCommand("selectAll", false, null);
+
+        if (window.internals)
+            internals.settings.setInputEventsEnabled(true);
+
+        if (window.testRunner) {
+            testRunner.execCommand("Cut");
+            testRunner.execCommand("Paste");
+        }
+        source.blur();
+
+        Markup.dump("destinationHTML", "destination after pasting (text/html)");
+        Markup.dump("destinationPlain", "destination after pasting (text/plain)");
+
+        function beforeInput(event)
+        {
+            if (event.inputType !== "insertFromPaste")
+                return;
+
+            destinationHTML.innerHTML = event.dataTransfer.getData("text/html");
+            destinationPlain.textContent = event.dataTransfer.getData("text/plain");
+            event.preventDefault();
+        }
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/fast/events/input-events-spell-checking-datatransfer-expected.txt b/LayoutTests/fast/events/input-events-spell-checking-datatransfer-expected.txt
new file mode 100644 (file)
index 0000000..90aa964
--- /dev/null
@@ -0,0 +1,4 @@
+To manually test this, make a typo in the first contenteditable and use spell checking to correct it. The corrected value should appear below.
+
+after autocorrection:
+| "<p>escape me!</p>"
diff --git a/LayoutTests/fast/events/input-events-spell-checking-datatransfer.html b/LayoutTests/fast/events/input-events-spell-checking-datatransfer.html
new file mode 100644 (file)
index 0000000..03e5e9e
--- /dev/null
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <div id="source" contenteditable onbeforeinput=beforeInput(event)></div>
+    <div id="destination" contenteditable></div>
+    <script src="../../resources/dump-as-markup.js"></script>
+    <script>
+        Markup.description(`To manually test this, make a typo in the first contenteditable and use spell checking to correct it. The corrected value should appear below.`);
+        source.focus();
+
+        if (window.internals && window.eventSender) {
+            internals.settings.setInputEventsEnabled(true);
+            eventSender.keyDown("e", []);
+            eventSender.keyDown("s", []);
+            eventSender.keyDown("c", []);
+            internals.handleAcceptedCandidate("<p>escape me!</p>", 0, 3);
+        }
+
+        Markup.dump("destination", "after autocorrection");
+
+        function beforeInput(event)
+        {
+            if (!event.dataTransfer)
+                return;
+
+            destination.innerHTML = event.dataTransfer.getData("text/html");
+            event.preventDefault();
+        }
+    </script>
+</body>
+</html>
\ No newline at end of file
index 60331c9..cbdd9ce 100644 (file)
@@ -1211,6 +1211,8 @@ fast/events/input-events-typing-data.html [ Failure ]
 fast/events/input-events-forecolor-data.html [ Failure ]
 fast/events/input-events-ime-recomposition.html [ Failure ]
 fast/events/input-events-ime-composition.html [ Failure ]
+fast/events/input-events-paste-rich-datatransfer.html [ Failure ]
+fast/events/input-events-spell-checking-datatransfer.html [ Failure ]
 fast/events/before-input-events-prevent-default.html [ Failure ]
 fast/events/before-input-events-prevent-default-in-textfield.html [ Failure ]
 fast/events/before-input-events-different-start-end-elements.html [ Failure ]
index f8cd0eb..27199a5 100644 (file)
@@ -1,3 +1,131 @@
+2016-10-25  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Support InputEvent.dataTransfer for the InputEvent spec
+        https://bugs.webkit.org/show_bug.cgi?id=163213
+        <rdar://problem/28700407>
+
+        Reviewed by Ryosuke Niwa.
+
+        Adds support for the dataTransfer attribute of InputEvent, which contains both HTML and plain text
+        representations of inserted content corresponding to input types "insertFromPaste", "insertFromDrop" and
+        "insertReplacementText". The specification calls for the data transfer's drag data item list to contain this
+        information via two entries with type strings "text/html" and "text/plain". However, WebKit does not yet support
+        the DataTransfer.items -- in lieu of this, we will provide this information for now via getData("text/plain")
+        and getData("text/html"), respectively.
+
+        To support this attribute, we need a special type of DataTransfer which is readonly and returns canned data
+        given a type string. To implement this, we introduce StaticPasteboard, a type of Pasteboard which is initialized
+        with a map of type string to data. When asked for its data via getData, the StaticPasteboard searches its map
+        for the requested type and returns the result, if any.
+
+        An editing command may now create a new DataTransfer via DataTransfer::createForInputEvent from HTML and
+        plaintext strings, and then vend this information to its dispatched input events by overriding
+        CompositeEditCommand::inputEventDataTransfer.
+
+        Some further work will be needed to ensure that all information exposed via this DataTransfer does not contain
+        hidden content. To do this, we should create a new Document, "paste" the contents of our copied HTML string into
+        it, then simulate selecting the content and generating markup from the selection to create a sanitized
+        DocumentFragment corresponding to the original copied HTML. This will be addressed in a future patch.
+
+        Tests: fast/events/input-events-paste-rich-datatransfer.html
+               fast/events/input-events-spell-checking-datatransfer.html
+
+        * PlatformEfl.cmake:
+        * PlatformGTK.cmake:
+        * PlatformWin.cmake:
+
+        Add StaticPasteboard.cpp.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * dom/DataTransfer.cpp:
+        (WebCore::DataTransfer::DataTransfer):
+        (WebCore::DataTransfer::createForInputEvent):
+
+        Initializes a new DataTransfer for the purposes of input events. This takes a HTML and plain text
+        representations of the data being inserted and creates a new readonly DataTransfer backed by a StaticPasteboard
+        that only knows how to map the "text/plain" data type to the given plaintext string and "text/html" to the
+        given HTML text.
+
+        * dom/DataTransfer.h:
+        * dom/InputEvent.cpp:
+        (WebCore::InputEvent::create):
+        (WebCore::InputEvent::InputEvent):
+        (WebCore::InputEvent::dataTransfer):
+        * dom/InputEvent.h:
+        * dom/InputEvent.idl:
+
+        Add the InputEvent.dataTransfer attribute.
+
+        * dom/Node.cpp:
+        * editing/CompositeEditCommand.cpp:
+        (WebCore::CompositeEditCommand::inputEventDataTransfer):
+
+        Add a new hook for CompositeEditCommands to vend a DataTransfer for the purposes of input events. By default,
+        this is null.
+
+        * editing/CompositeEditCommand.h:
+        * editing/Editor.cpp:
+        (WebCore::dispatchBeforeInputEvent):
+        (WebCore::dispatchInputEvent):
+        (WebCore::dispatchBeforeInputEvents):
+        (WebCore::dispatchInputEvents):
+        (WebCore::Editor::willApplyEditing):
+        (WebCore::Editor::appliedEditing):
+        * editing/ReplaceRangeWithTextCommand.cpp:
+        (WebCore::ReplaceRangeWithTextCommand::willApplyCommand):
+        (WebCore::ReplaceRangeWithTextCommand::doApply):
+        (WebCore::ReplaceRangeWithTextCommand::inputEventDataTransfer):
+        * editing/ReplaceRangeWithTextCommand.h:
+        * editing/ReplaceSelectionCommand.cpp:
+        (WebCore::ReplaceSelectionCommand::willApplyCommand):
+
+        Initialize the ReplacementFragment here before applying the command, adjusting the DocumentFragment to be
+        inserted in the process.
+
+        (WebCore::ReplaceSelectionCommand::doApply):
+        (WebCore::ReplaceSelectionCommand::inputEventDataTransfer):
+        (WebCore::ReplaceSelectionCommand::ensureReplacementFragment):
+
+        Returns the ReplacementFragment used to apply the command, initializing it if necessary and stripping extraneous
+        nodes off of the document fragment in the process. Since ReplaceSelectionCommand may be used as a top-level
+        editing command or a child of another CompositeEditCommand such as the ReplaceRangeWithTextCommand, the
+        ReplacementFragment may be initialized either in willApplyCommand or in doApply.
+
+        * editing/ReplaceSelectionCommand.h:
+        * editing/SpellingCorrectionCommand.cpp:
+        (WebCore::SpellingCorrectionCommand::willApplyCommand):
+        (WebCore::SpellingCorrectionCommand::doApply):
+        (WebCore::SpellingCorrectionCommand::inputEventDataTransfer):
+        * editing/SpellingCorrectionCommand.h:
+
+        Using the replacement text fragment, create and return a DataTransfer for input events.
+
+        * platform/Pasteboard.h:
+        * platform/StaticPasteboard.cpp: Added.
+        (WebCore::StaticPasteboard::create):
+        (WebCore::StaticPasteboard::StaticPasteboard):
+        (WebCore::StaticPasteboard::hasData):
+        (WebCore::StaticPasteboard::types):
+        (WebCore::StaticPasteboard::readString):
+        * platform/StaticPasteboard.h: Copied from Source/WebCore/dom/InputEvent.cpp.
+        * platform/efl/PasteboardEfl.cpp:
+        (WebCore::Pasteboard::writeMarkup):
+        (WebCore::Pasteboard::write):
+        (WebCore::Pasteboard::read):
+        * platform/gtk/PasteboardGtk.cpp:
+        (WebCore::Pasteboard::writeMarkup):
+        * platform/ios/PasteboardIOS.mm:
+        (WebCore::Pasteboard::writeMarkup):
+        * platform/mac/PasteboardMac.mm:
+        (WebCore::Pasteboard::Pasteboard):
+        (WebCore::Pasteboard::writeMarkup):
+        * platform/win/PasteboardWin.cpp:
+        (WebCore::Pasteboard::write):
+        (WebCore::Pasteboard::read):
+
+        To account for virtual methods on Pasteboard, add implementations for methods that were previously defined but
+        unimplemented on these platforms.
+
 2016-10-25  Andy Estes  <aestes@apple.com>
 
         Implement rel=noopener
index 83c92af..328fb59 100644 (file)
@@ -87,6 +87,7 @@ list(APPEND WebCore_SOURCES
     page/scrolling/AxisScrollSnapOffsets.cpp
 
     platform/KillRingNone.cpp
+    platform/StaticPasteboard.cpp
 
     platform/audio/efl/AudioBusEfl.cpp
 
index fb5de24..67b5351 100644 (file)
@@ -84,6 +84,7 @@ list(APPEND WebCore_SOURCES
     loader/soup/SubresourceLoaderSoup.cpp
 
     platform/KillRingNone.cpp
+    platform/StaticPasteboard.cpp
     platform/UserAgentQuirks.cpp
 
     platform/audio/glib/AudioBusGLib.cpp
index a38fe19..59f7320 100644 (file)
@@ -60,6 +60,7 @@ list(APPEND WebCore_SOURCES
     platform/Cursor.cpp
     platform/KillRingNone.cpp
     platform/LocalizedStrings.cpp
+    platform/StaticPasteboard.cpp
     platform/VNodeTracker.cpp
 
     platform/audio/PlatformMediaSessionManager.cpp
index 84d8ba2..dbdd047 100644 (file)
                F3F5CF1112ED81A80084C569 /* InspectorConsoleInstrumentation.h in Headers */ = {isa = PBXBuildFile; fileRef = F3F5CF1012ED81A80084C569 /* InspectorConsoleInstrumentation.h */; };
                F40EA8AB1B867E4400CE5581 /* NSScrollingInputFilterSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = F40EA8AA1B867D6500CE5581 /* NSScrollingInputFilterSPI.h */; settings = {ATTRIBUTES = (Private, ); }; };
                F42FFB461984B71600F6837F /* LengthRepeat.h in Headers */ = {isa = PBXBuildFile; fileRef = F42FFB451984B71600F6837F /* LengthRepeat.h */; };
+               F433E9031DBBDBA200EF0D14 /* StaticPasteboard.h in Headers */ = {isa = PBXBuildFile; fileRef = F433E9021DBBDBA200EF0D14 /* StaticPasteboard.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               F433E9051DBBDFCA00EF0D14 /* StaticPasteboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F433E9041DBBDBC200EF0D14 /* StaticPasteboard.cpp */; };
                F44EBBD91DB5D21400277334 /* StaticRange.h in Headers */ = {isa = PBXBuildFile; fileRef = F44EBBD81DB5D21400277334 /* StaticRange.h */; settings = {ATTRIBUTES = (Private, ); }; };
                F44EBBDB1DB5DD9D00277334 /* StaticRange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F44EBBDA1DB5DD9D00277334 /* StaticRange.cpp */; };
                F45C231D1995B73B00A6E2E3 /* AxisScrollSnapOffsets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F45C231B1995B73B00A6E2E3 /* AxisScrollSnapOffsets.cpp */; };
                F3F5CF1012ED81A80084C569 /* InspectorConsoleInstrumentation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorConsoleInstrumentation.h; sourceTree = "<group>"; };
                F40EA8AA1B867D6500CE5581 /* NSScrollingInputFilterSPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSScrollingInputFilterSPI.h; sourceTree = "<group>"; };
                F42FFB451984B71600F6837F /* LengthRepeat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LengthRepeat.h; sourceTree = "<group>"; };
+               F433E9021DBBDBA200EF0D14 /* StaticPasteboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaticPasteboard.h; sourceTree = "<group>"; };
+               F433E9041DBBDBC200EF0D14 /* StaticPasteboard.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = StaticPasteboard.cpp; sourceTree = "<group>"; };
                F44EBBD61DB5D1B600277334 /* StaticRange.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = StaticRange.idl; sourceTree = "<group>"; };
                F44EBBD81DB5D21400277334 /* StaticRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaticRange.h; sourceTree = "<group>"; };
                F44EBBDA1DB5DD9D00277334 /* StaticRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaticRange.cpp; sourceTree = "<group>"; };
                                93309EA0099EB78C0056E581 /* SharedTimer.h */,
                                4B3043C60AE0370300A82647 /* Sound.h */,
                                F587866202DE3B1101EA4122 /* SSLKeyGenerator.h */,
+                               F433E9041DBBDBC200EF0D14 /* StaticPasteboard.cpp */,
+                               F433E9021DBBDBA200EF0D14 /* StaticPasteboard.h */,
                                93B2D8150F9920D2006AE6B2 /* SuddenTermination.h */,
                                97627B9714FB5424002CDCA1 /* Supplementable.h */,
                                CDA07FBB18E0A16A004699FA /* SystemSleepListener.cpp */,
                                079D0868162F20E800DB8658 /* CaptionUserPreferences.h in Headers */,
                                079D086B162F21F900DB8658 /* CaptionUserPreferencesMediaAF.h in Headers */,
                                07B7116D1D899E63009F0FFB /* CaptureDevice.h in Headers */,
+                               F433E9031DBBDBA200EF0D14 /* StaticPasteboard.h in Headers */,
                                07B7116F1D899E63009F0FFB /* CaptureDeviceManager.h in Headers */,
                                99CC0B4F18BE9849006CEBCC /* CapturingInputCursor.h in Headers */,
                                CDC734151977896D0046BFC5 /* CARingBuffer.h in Headers */,
                                41614A781DA6423B004AD06F /* HTTPHeaderValues.cpp in Sources */,
                                514C76720CE923A1007EF3CD /* HTTPParsers.cpp in Sources */,
                                371A67CB11C6C7DB00047B8B /* HyphenationCF.cpp in Sources */,
+                               F433E9051DBBDFCA00EF0D14 /* StaticPasteboard.cpp in Sources */,
                                97E4028F13A696ED00913D67 /* IconController.cpp in Sources */,
                                5126E6BB0A2E3B12005C29FA /* IconDatabase.cpp in Sources */,
                                516953971329A3C800B92D04 /* IconDatabaseBase.cpp in Sources */,
index 642ffa2..f9ec70f 100644 (file)
@@ -36,6 +36,7 @@
 #include "HTMLImageElement.h"
 #include "Image.h"
 #include "Pasteboard.h"
+#include "StaticPasteboard.h"
 
 namespace WebCore {
 
@@ -59,7 +60,7 @@ DataTransfer::DataTransfer(DataTransferAccessPolicy policy, std::unique_ptr<Past
     : m_policy(policy)
     , m_pasteboard(WTFMove(pasteboard))
 #if ENABLE(DRAG_SUPPORT)
-    , m_forDrag(type != CopyAndPaste)
+    , m_forDrag(type == DragAndDrop)
     , m_forFileDrag(forFileDrag)
     , m_dropEffect(ASCIILiteral("uninitialized"))
     , m_effectAllowed(ASCIILiteral("uninitialized"))
@@ -67,7 +68,7 @@ DataTransfer::DataTransfer(DataTransferAccessPolicy policy, std::unique_ptr<Past
 #endif
 {
 #if !ENABLE(DRAG_SUPPORT)
-    ASSERT_UNUSED(type, type == CopyAndPaste);
+    ASSERT_UNUSED(type, type != DragAndDrop);
     ASSERT_UNUSED(forFileDrag, !forFileDrag);
 #endif
 }
@@ -198,6 +199,14 @@ bool DataTransfer::hasStringOfType(const String& type)
     return !type.isNull() && types().contains(type);
 }
 
+Ref<DataTransfer> DataTransfer::createForInputEvent(const String& plainText, const String& htmlText)
+{
+    TypeToStringMap typeToStringMap;
+    typeToStringMap.set(ASCIILiteral("text/plain"), plainText);
+    typeToStringMap.set(ASCIILiteral("text/html"), htmlText);
+    return adoptRef(*new DataTransfer(DataTransferAccessPolicy::Readable, StaticPasteboard::create(WTFMove(typeToStringMap)), InputEvent));
+}
+
 #if !ENABLE(DRAG_SUPPORT)
 
 String DataTransfer::dropEffect() const
index 1e203d8..e883f80 100644 (file)
@@ -45,6 +45,7 @@ namespace WebCore {
     class DataTransfer : public RefCounted<DataTransfer> {
     public:
         static Ref<DataTransfer> createForCopyAndPaste(DataTransferAccessPolicy);
+        static Ref<DataTransfer> createForInputEvent(const String& plainText, const String& htmlText);
 
         WEBCORE_EXPORT ~DataTransfer();
 
@@ -97,7 +98,7 @@ namespace WebCore {
 #endif
 
     private:
-        enum Type { CopyAndPaste, DragAndDrop };
+        enum Type { CopyAndPaste, DragAndDrop, InputEvent };
         DataTransfer(DataTransferAccessPolicy, std::unique_ptr<Pasteboard>, Type = CopyAndPaste, bool forFileDrag = false);
 
 #if ENABLE(DRAG_SUPPORT)
index 460bb1d..a4561fd 100644 (file)
@@ -27,6 +27,7 @@
 #include "InputEvent.h"
 
 #include "DOMWindow.h"
+#include "DataTransfer.h"
 #include "EventNames.h"
 #include "Node.h"
 #include "NotImplemented.h"
 
 namespace WebCore {
 
-InputEvent::InputEvent(const AtomicString& eventType, const String& inputType, bool canBubble, bool cancelable, DOMWindow* view, const String& data, const Vector<RefPtr<StaticRange>>& targetRanges, int detail)
+Ref<InputEvent> InputEvent::create(const AtomicString& eventType, const String& inputType, bool canBubble, bool cancelable, WebCore::DOMWindow *view, const String& data, RefPtr<DataTransfer>&& dataTransfer, const Vector<RefPtr<StaticRange>>& targetRanges, int detail)
+{
+    return adoptRef(*new InputEvent(eventType, inputType, canBubble, cancelable, view, data, WTFMove(dataTransfer), targetRanges, detail));
+}
+
+InputEvent::InputEvent(const AtomicString& eventType, const String& inputType, bool canBubble, bool cancelable, DOMWindow* view, const String& data, RefPtr<DataTransfer>&& dataTransfer, const Vector<RefPtr<StaticRange>>& targetRanges, int detail)
     : UIEvent(eventType, canBubble, cancelable, view, detail)
     , m_inputType(inputType)
     , m_data(data)
+    , m_dataTransfer(dataTransfer)
     , m_targetRanges(targetRanges)
 {
 }
@@ -50,4 +57,9 @@ InputEvent::InputEvent(const AtomicString& eventType, const Init& initializer, I
 {
 }
 
+RefPtr<DataTransfer> InputEvent::dataTransfer() const
+{
+    return m_dataTransfer;
+}
+
 } // namespace WebCore
index cf3a3bc..230fcab 100644 (file)
@@ -35,21 +35,17 @@ class DataTransfer;
 
 class InputEvent final : public UIEvent {
 public:
-    static Ref<InputEvent> create(const AtomicString& eventType, const String& inputType, bool canBubble, bool cancelable, DOMWindow* view, const String& data, const Vector<RefPtr<StaticRange>>& targetRanges, int detail)
-    {
-        return adoptRef(*new InputEvent(eventType, inputType, canBubble, cancelable, view, data, targetRanges, detail));
-    }
-
     struct Init : UIEventInit {
         String data;
     };
 
+    static Ref<InputEvent> create(const AtomicString& eventType, const String& inputType, bool canBubble, bool cancelable, DOMWindow* view, const String& data, RefPtr<DataTransfer>&&, const Vector<RefPtr<StaticRange>>& targetRanges, int detail);
     static Ref<InputEvent> create(const AtomicString& type, const Init& initializer, IsTrusted isTrusted = IsTrusted::No)
     {
         return adoptRef(*new InputEvent(type, initializer, isTrusted));
     }
 
-    InputEvent(const AtomicString& eventType, const String& inputType, bool canBubble, bool cancelable, DOMWindow*, const String& data, const Vector<RefPtr<StaticRange>>& targetRanges, int detail);
+    InputEvent(const AtomicString& eventType, const String& inputType, bool canBubble, bool cancelable, DOMWindow*, const String& data, RefPtr<DataTransfer>&&, const Vector<RefPtr<StaticRange>>& targetRanges, int detail);
     InputEvent(const AtomicString& eventType, const Init&, IsTrusted);
 
     virtual ~InputEvent() { }
@@ -58,11 +54,13 @@ public:
     EventInterface eventInterface() const final { return InputEventInterfaceType; }
     const String& inputType() const { return m_inputType; }
     const String& data() const { return m_data; }
+    RefPtr<DataTransfer> dataTransfer() const;
     const Vector<RefPtr<StaticRange>>& getTargetRanges() { return m_targetRanges; }
 
 private:
     String m_inputType;
     String m_data;
+    RefPtr<DataTransfer> m_dataTransfer;
     Vector<RefPtr<StaticRange>> m_targetRanges;
 };
 
index d6c8880..1f765de 100644 (file)
@@ -29,6 +29,7 @@
 ] interface InputEvent : UIEvent {
     readonly attribute DOMString inputType;
     readonly attribute DOMString? data;
+    readonly attribute DataTransfer? dataTransfer;
 
     sequence<StaticRange> getTargetRanges();
 };
index c39d940..cf9ab7e 100644 (file)
@@ -34,6 +34,7 @@
 #include "ComposedTreeAncestorIterator.h"
 #include "ContainerNodeAlgorithms.h"
 #include "ContextMenuController.h"
+#include "DataTransfer.h"
 #include "DocumentType.h"
 #include "ElementIterator.h"
 #include "ElementRareData.h"
index 9c5079a..5b685f7 100644 (file)
@@ -30,6 +30,7 @@
 #include "AppendNodeCommand.h"
 #include "ApplyStyleCommand.h"
 #include "BreakBlockquoteCommand.h"
+#include "DataTransfer.h"
 #include "DeleteFromTextNodeCommand.h"
 #include "DeleteSelectionCommand.h"
 #include "Document.h"
@@ -399,6 +400,11 @@ Vector<RefPtr<StaticRange>> CompositeEditCommand::targetRangesForBindings() cons
     return targetRanges();
 }
 
+RefPtr<DataTransfer> CompositeEditCommand::inputEventDataTransfer() const
+{
+    return nullptr;
+}
+
 EditCommandComposition* CompositeEditCommand::ensureComposition()
 {
     CompositeEditCommand* command = this;
index 39bfa81..5d845a8 100644 (file)
@@ -35,6 +35,7 @@
 namespace WebCore {
 
 class EditingStyle;
+class DataTransfer;
 class HTMLElement;
 class StaticRange;
 class StyledElement;
@@ -118,6 +119,7 @@ public:
     virtual String inputEventData() const { return { }; }
     virtual bool isBeforeInputEventCancelable() const { return true; }
     Vector<RefPtr<StaticRange>> targetRangesForBindings() const;
+    virtual RefPtr<DataTransfer> inputEventDataTransfer() const;
 
 protected:
     explicit CompositeEditCommand(Document&, EditAction = EditActionUnspecified);
index ea9d865..f952eaf 100644 (file)
 
 namespace WebCore {
 
-static bool dispatchBeforeInputEvent(Element& element, const AtomicString& inputType, const String& data = { }, const Vector<RefPtr<StaticRange>>& targetRanges = { }, bool cancelable = true)
+static bool dispatchBeforeInputEvent(Element& element, const AtomicString& inputType, const String& data = { }, RefPtr<DataTransfer>&& dataTransfer = nullptr, const Vector<RefPtr<StaticRange>>& targetRanges = { }, bool cancelable = true)
 {
     auto* settings = element.document().settings();
     if (!settings || !settings->inputEventsEnabled())
         return true;
 
-    return element.dispatchEvent(InputEvent::create(eventNames().beforeinputEvent, inputType, true, cancelable, element.document().defaultView(), data, targetRanges, 0));
+    return element.dispatchEvent(InputEvent::create(eventNames().beforeinputEvent, inputType, true, cancelable, element.document().defaultView(), data, WTFMove(dataTransfer), targetRanges, 0));
 }
 
-static void dispatchInputEvent(Element& element, const AtomicString& inputType, const String& data = { }, const Vector<RefPtr<StaticRange>>& targetRanges = { })
+static void dispatchInputEvent(Element& element, const AtomicString& inputType, const String& data = { }, RefPtr<DataTransfer>&& dataTransfer = nullptr, const Vector<RefPtr<StaticRange>>& targetRanges = { })
 {
     auto* settings = element.document().settings();
     if (settings && settings->inputEventsEnabled())
-        element.dispatchEvent(InputEvent::create(eventNames().inputEvent, inputType, true, false, element.document().defaultView(), data, targetRanges, 0));
+        element.dispatchEvent(InputEvent::create(eventNames().inputEvent, inputType, true, false, element.document().defaultView(), data, WTFMove(dataTransfer), targetRanges, 0));
     else
         element.dispatchInputEvent();
 }
@@ -1063,22 +1063,22 @@ static void notifyTextFromControls(Element* startRoot, Element* endRoot)
         endingTextControl->didEditInnerTextValue();
 }
 
-static bool dispatchBeforeInputEvents(RefPtr<Element> startRoot, RefPtr<Element> endRoot, const AtomicString& inputTypeName, const String& data = { }, const Vector<RefPtr<StaticRange>>& targetRanges = { }, bool cancelable = true)
+static bool dispatchBeforeInputEvents(RefPtr<Element> startRoot, RefPtr<Element> endRoot, const AtomicString& inputTypeName, const String& data = { }, RefPtr<DataTransfer>&& dataTransfer = nullptr, const Vector<RefPtr<StaticRange>>& targetRanges = { }, bool cancelable = true)
 {
     bool continueWithDefaultBehavior = true;
     if (startRoot)
-        continueWithDefaultBehavior &= dispatchBeforeInputEvent(*startRoot, inputTypeName, data, targetRanges, cancelable);
+        continueWithDefaultBehavior &= dispatchBeforeInputEvent(*startRoot, inputTypeName, data, WTFMove(dataTransfer), targetRanges, cancelable);
     if (endRoot && endRoot != startRoot)
-        continueWithDefaultBehavior &= dispatchBeforeInputEvent(*endRoot, inputTypeName, data, targetRanges, cancelable);
+        continueWithDefaultBehavior &= dispatchBeforeInputEvent(*endRoot, inputTypeName, data, WTFMove(dataTransfer), targetRanges, cancelable);
     return continueWithDefaultBehavior;
 }
 
-static void dispatchInputEvents(RefPtr<Element> startRoot, RefPtr<Element> endRoot, const AtomicString& inputTypeName, const String& data = { }, const Vector<RefPtr<StaticRange>>& targetRanges = { })
+static void dispatchInputEvents(RefPtr<Element> startRoot, RefPtr<Element> endRoot, const AtomicString& inputTypeName, const String& data = { }, RefPtr<DataTransfer>&& dataTransfer = nullptr, const Vector<RefPtr<StaticRange>>& targetRanges = { })
 {
     if (startRoot)
-        dispatchInputEvent(*startRoot, inputTypeName, data, targetRanges);
+        dispatchInputEvent(*startRoot, inputTypeName, data, WTFMove(dataTransfer), targetRanges);
     if (endRoot && endRoot != startRoot)
-        dispatchInputEvent(*endRoot, inputTypeName, data, targetRanges);
+        dispatchInputEvent(*endRoot, inputTypeName, data, WTFMove(dataTransfer), targetRanges);
 }
 
 bool Editor::willApplyEditing(CompositeEditCommand& command, Vector<RefPtr<StaticRange>>&& targetRanges) const
@@ -1087,7 +1087,7 @@ bool Editor::willApplyEditing(CompositeEditCommand& command, Vector<RefPtr<Stati
     if (!composition)
         return true;
 
-    return dispatchBeforeInputEvents(composition->startingRootEditableElement(), composition->endingRootEditableElement(), command.inputEventTypeName(), command.inputEventData(), targetRanges, command.isBeforeInputEventCancelable());
+    return dispatchBeforeInputEvents(composition->startingRootEditableElement(), composition->endingRootEditableElement(), command.inputEventTypeName(), command.inputEventData(), command.inputEventDataTransfer(), targetRanges, command.isBeforeInputEventCancelable());
 }
 
 void Editor::appliedEditing(PassRefPtr<CompositeEditCommand> cmd)
@@ -1106,7 +1106,7 @@ void Editor::appliedEditing(PassRefPtr<CompositeEditCommand> cmd)
     FrameSelection::SetSelectionOptions options = cmd->isDictationCommand() ? FrameSelection::DictationTriggered : 0;
     
     changeSelectionAfterCommand(newSelection, options);
-    dispatchInputEvents(composition->startingRootEditableElement(), composition->endingRootEditableElement(), cmd->inputEventTypeName(), cmd->inputEventData());
+    dispatchInputEvents(composition->startingRootEditableElement(), composition->endingRootEditableElement(), cmd->inputEventTypeName(), cmd->inputEventData(), cmd->inputEventDataTransfer());
 
     updateEditorUINowIfScheduled();
     
index 871c1dd..5b34d06 100644 (file)
@@ -27,6 +27,7 @@
 #include "ReplaceRangeWithTextCommand.h"
 
 #include "AlternativeTextController.h"
+#include "DataTransfer.h"
 #include "Document.h"
 #include "DocumentFragment.h"
 #include "Editor.h"
@@ -46,6 +47,12 @@ ReplaceRangeWithTextCommand::ReplaceRangeWithTextCommand(RefPtr<Range> rangeToBe
 {
 }
 
+bool ReplaceRangeWithTextCommand::willApplyCommand()
+{
+    m_textFragment = createFragmentFromText(*m_rangeToBeReplaced, m_text);
+    return CompositeEditCommand::willApplyCommand();
+}
+
 void ReplaceRangeWithTextCommand::doApply()
 {
     VisibleSelection selection = *m_rangeToBeReplaced;
@@ -61,9 +68,7 @@ void ReplaceRangeWithTextCommand::doApply()
         return;
 
     applyCommandToComposite(SetSelectionCommand::create(selection, FrameSelection::defaultSetSelectionOptions()));
-
-    auto fragment = createFragmentFromText(*m_rangeToBeReplaced, m_text);
-    applyCommandToComposite(ReplaceSelectionCommand::create(document(), WTFMove(fragment), ReplaceSelectionCommand::MatchStyle, EditActionPaste));
+    applyCommandToComposite(ReplaceSelectionCommand::create(document(), WTFMove(m_textFragment), ReplaceSelectionCommand::MatchStyle, EditActionPaste));
 }
 
 String ReplaceRangeWithTextCommand::inputEventData() const
@@ -74,6 +79,14 @@ String ReplaceRangeWithTextCommand::inputEventData() const
     return CompositeEditCommand::inputEventData();
 }
 
+RefPtr<DataTransfer> ReplaceRangeWithTextCommand::inputEventDataTransfer() const
+{
+    if (!isEditingTextAreaOrTextInput())
+        return DataTransfer::createForInputEvent(m_text, createMarkup(*m_textFragment));
+
+    return CompositeEditCommand::inputEventDataTransfer();
+}
+
 Vector<RefPtr<StaticRange>> ReplaceRangeWithTextCommand::targetRanges() const
 {
     RefPtr<StaticRange> range = StaticRange::createFromRange(*m_rangeToBeReplaced);
index a4f2600..098307f 100644 (file)
@@ -30,6 +30,8 @@
 
 namespace WebCore {
 
+class DocumentFragment;
+
 class ReplaceRangeWithTextCommand : public CompositeEditCommand {
 public:
     static Ref<ReplaceRangeWithTextCommand> create(RefPtr<Range> rangeToBeReplaced, const String& text)
@@ -39,11 +41,14 @@ public:
 
 private:
     ReplaceRangeWithTextCommand(RefPtr<Range> rangeToBeReplaced, const String& text);
+    bool willApplyCommand() final;
     void doApply() override;
     String inputEventData() const final;
+    RefPtr<DataTransfer> inputEventDataTransfer() const final;
     Vector<RefPtr<StaticRange>> targetRanges() const final;
 
     RefPtr<Range> m_rangeToBeReplaced;
+    RefPtr<DocumentFragment> m_textFragment;
     String m_text;
 };
 
index cd6f733..75cc029 100644 (file)
@@ -32,6 +32,7 @@
 #include "BeforeTextInsertedEvent.h"
 #include "BreakBlockquoteCommand.h"
 #include "CSSStyleDeclaration.h"
+#include "DataTransfer.h"
 #include "Document.h"
 #include "DocumentFragment.h"
 #include "ElementIterator.h"
@@ -69,6 +70,8 @@ using namespace HTMLNames;
 
 enum EFragmentType { EmptyFragment, SingleTextNodeFragment, TreeFragment };
 
+static void removeHeadContents(ReplacementFragment&);
+
 // --- ReplacementFragment helper class
 
 class ReplacementFragment {
@@ -909,6 +912,14 @@ inline Node* nodeToSplitToAvoidPastingIntoInlineNodesWithStyle(const Position& i
     return highestEnclosingNodeOfType(insertionPos, isInlineNodeWithStyle, CannotCrossEditingBoundary, containgBlock);
 }
 
+bool ReplaceSelectionCommand::willApplyCommand()
+{
+    ensureReplacementFragment();
+    m_documentFragmentPlainText = m_documentFragment->textContent();
+    m_documentFragmentHTMLMarkup = createMarkup(*m_documentFragment);
+    return CompositeEditCommand::willApplyCommand();
+}
+
 void ReplaceSelectionCommand::doApply()
 {
     VisibleSelection selection = endingSelection();
@@ -922,7 +933,7 @@ void ReplaceSelectionCommand::doApply()
     if (!selection.isContentRichlyEditable())
         m_matchStyle = false;
 
-    ReplacementFragment fragment(document(), m_documentFragment.get(), selection);
+    ReplacementFragment& fragment = *ensureReplacementFragment();
     if (performTrivialReplace(fragment))
         return;
     
@@ -1045,8 +1056,6 @@ void ReplaceSelectionCommand::doApply()
     // any work performed after this that queries or uses the typing style.
     frame().selection().clearTypingStyle();
 
-    removeHeadContents(fragment);
-
     // We don't want the destination to end up inside nodes that weren't selected.  To avoid that, we move the
     // position forward without changing the visible position so we're still at the same visible location, but
     // outside of preceding tags.
@@ -1262,6 +1271,14 @@ String ReplaceSelectionCommand::inputEventData() const
     return CompositeEditCommand::inputEventData();
 }
 
+RefPtr<DataTransfer> ReplaceSelectionCommand::inputEventDataTransfer() const
+{
+    if (isEditingTextAreaOrTextInput())
+        return CompositeEditCommand::inputEventDataTransfer();
+
+    return DataTransfer::createForInputEvent(m_documentFragmentPlainText, m_documentFragmentHTMLMarkup);
+}
+
 bool ReplaceSelectionCommand::shouldRemoveEndBR(Node* endBR, const VisiblePosition& originalVisPosBeforeEndBR)
 {
     if (!endBR || !endBR->inDocument())
@@ -1495,6 +1512,16 @@ void ReplaceSelectionCommand::updateNodesInserted(Node *node)
     m_endOfInsertedContent = lastPositionInOrAfterNode(node->lastDescendant());
 }
 
+ReplacementFragment* ReplaceSelectionCommand::ensureReplacementFragment()
+{
+    if (!m_replacementFragment) {
+        m_replacementFragment = std::make_unique<ReplacementFragment>(document(), m_documentFragment.get(), endingSelection());
+        removeHeadContents(*m_replacementFragment);
+    }
+
+    return m_replacementFragment.get();
+}
+
 // During simple pastes, where we're just pasting a text node into a run of text, we insert the text node
 // directly into the text node that holds the selection.  This is much faster than the generalized code in
 // ReplaceSelectionCommand, and works around <https://bugs.webkit.org/show_bug.cgi?id=6148> since we don't 
index 4f8f23d..9903182 100644 (file)
@@ -59,6 +59,8 @@ private:
     ReplaceSelectionCommand(Document&, RefPtr<DocumentFragment>&&, CommandOptions, EditAction);
 
     String inputEventData() const final;
+    RefPtr<DataTransfer> inputEventDataTransfer() const final;
+    bool willApplyCommand() final;
     virtual void doApply();
 
     class InsertedNodes {
@@ -111,6 +113,7 @@ private:
     void completeHTMLReplacement(const Position& lastPositionToSelect);
     void mergeTextNodesAroundPosition(Position&, Position& positionOnlyToBeUpdated);
 
+    ReplacementFragment* ensureReplacementFragment();
     bool performTrivialReplace(const ReplacementFragment&);
 
     VisibleSelection m_visibleSelectionForInsertedText;
@@ -121,6 +124,9 @@ private:
     bool m_smartReplace;
     bool m_matchStyle;
     RefPtr<DocumentFragment> m_documentFragment;
+    std::unique_ptr<ReplacementFragment> m_replacementFragment;
+    String m_documentFragmentHTMLMarkup;
+    String m_documentFragmentPlainText;
     bool m_preventNesting;
     bool m_movingParagraph;
     bool m_sanitizeFragment;
index e20593b..c9bf2c0 100644 (file)
@@ -27,6 +27,7 @@
 #include "SpellingCorrectionCommand.h"
 
 #include "AlternativeTextController.h"
+#include "DataTransfer.h"
 #include "Document.h"
 #include "DocumentFragment.h"
 #include "Editor.h"
@@ -90,6 +91,12 @@ SpellingCorrectionCommand::SpellingCorrectionCommand(PassRefPtr<Range> rangeToBe
 {
 }
 
+bool SpellingCorrectionCommand::willApplyCommand()
+{
+    m_correctionFragment = createFragmentFromText(*m_rangeToBeCorrected, m_correction);
+    return CompositeEditCommand::willApplyCommand();
+}
+
 void SpellingCorrectionCommand::doApply()
 {
     m_corrected = plainText(m_rangeToBeCorrected.get());
@@ -102,14 +109,12 @@ void SpellingCorrectionCommand::doApply()
     if (!m_rangeToBeCorrected)
         return;
 
-    auto fragment = createFragmentFromText(*m_rangeToBeCorrected, m_correction);
-
     applyCommandToComposite(SetSelectionCommand::create(m_selectionToBeCorrected, FrameSelection::defaultSetSelectionOptions() | FrameSelection::SpellCorrectionTriggered));
 #if USE(AUTOCORRECTION_PANEL)
     applyCommandToComposite(SpellingCorrectionRecordUndoCommand::create(document(), m_corrected, m_correction));
 #endif
 
-    applyCommandToComposite(ReplaceSelectionCommand::create(document(), WTFMove(fragment), ReplaceSelectionCommand::MatchStyle, EditActionPaste));
+    applyCommandToComposite(ReplaceSelectionCommand::create(document(), WTFMove(m_correctionFragment), ReplaceSelectionCommand::MatchStyle, EditActionPaste));
 }
 
 String SpellingCorrectionCommand::inputEventData() const
@@ -126,6 +131,14 @@ Vector<RefPtr<StaticRange>> SpellingCorrectionCommand::targetRanges() const
     return { 1, range };
 }
 
+RefPtr<DataTransfer> SpellingCorrectionCommand::inputEventDataTransfer() const
+{
+    if (!isEditingTextAreaOrTextInput())
+        return DataTransfer::createForInputEvent(m_correction, createMarkup(*m_correctionFragment));
+
+    return CompositeEditCommand::inputEventDataTransfer();
+}
+
 bool SpellingCorrectionCommand::shouldRetainAutocorrectionIndicator() const
 {
     return true;
index e55afa0..86cc6da 100644 (file)
@@ -39,14 +39,17 @@ public:
     }
 private:
     SpellingCorrectionCommand(PassRefPtr<Range> rangeToBeCorrected, const String& correction);
+    bool willApplyCommand() final;
     void doApply() override;
     bool shouldRetainAutocorrectionIndicator() const override;
 
     String inputEventData() const final;
     Vector<RefPtr<StaticRange>> targetRanges() const final;
+    RefPtr<DataTransfer> inputEventDataTransfer() const final;
 
     RefPtr<Range> m_rangeToBeCorrected;
     VisibleSelection m_selectionToBeCorrected;
+    RefPtr<DocumentFragment> m_correctionFragment;
     String m_corrected;
     String m_correction;
 };
index ce9ae8e..16c4b59 100644 (file)
@@ -138,7 +138,7 @@ class Pasteboard {
     WTF_MAKE_NONCOPYABLE(Pasteboard); WTF_MAKE_FAST_ALLOCATED;
 public:
     Pasteboard();
-    ~Pasteboard();
+    virtual ~Pasteboard();
 
 #if PLATFORM(GTK)
     explicit Pasteboard(const String& name);
@@ -154,34 +154,34 @@ public:
     WEBCORE_EXPORT static std::unique_ptr<Pasteboard> createForCopyAndPaste();
     static std::unique_ptr<Pasteboard> createPrivate(); // Temporary pasteboard. Can put data on this and then write to another pasteboard with writePasteboard.
 
-    bool hasData();
-    Vector<String> types();
-    String readString(const String& type);
+    virtual bool hasData();
+    virtual Vector<String> types();
+    virtual String readString(const String& type);
 
-    void writeString(const String& type, const String& data);
-    void clear();
-    void clear(const String& type);
+    virtual void writeString(const String& type, const String& data);
+    virtual void clear();
+    virtual void clear(const String& type);
 
-    void read(PasteboardPlainText&);
-    void read(PasteboardWebContentReader&);
+    virtual void read(PasteboardPlainText&);
+    virtual void read(PasteboardWebContentReader&);
 
-    void write(const PasteboardURL&);
-    void write(const PasteboardImage&);
-    void write(const PasteboardWebContent&);
+    virtual void write(const PasteboardURL&);
+    virtual void write(const PasteboardImage&);
+    virtual void write(const PasteboardWebContent&);
 
-    Vector<String> readFilenames();
-    bool canSmartReplace();
+    virtual Vector<String> readFilenames();
+    virtual bool canSmartReplace();
 
-    void writeMarkup(const String& markup);
+    virtual void writeMarkup(const String& markup);
     enum SmartReplaceOption { CanSmartReplace, CannotSmartReplace };
-    WEBCORE_EXPORT void writePlainText(const String&, SmartReplaceOption); // FIXME: Two separate functions would be clearer than one function with an argument.
-    void writePasteboard(const Pasteboard& sourcePasteboard);
+    virtual WEBCORE_EXPORT void writePlainText(const String&, SmartReplaceOption); // FIXME: Two separate functions would be clearer than one function with an argument.
+    virtual void writePasteboard(const Pasteboard& sourcePasteboard);
 
 #if ENABLE(DRAG_SUPPORT)
     static std::unique_ptr<Pasteboard> createForDragAndDrop();
     static std::unique_ptr<Pasteboard> createForDragAndDrop(const DragData&);
 
-    void setDragImage(DragImageRef, const IntPoint& hotSpot);
+    virtual void setDragImage(DragImageRef, const IntPoint& hotSpot);
 #endif
 
 #if PLATFORM(WIN)
diff --git a/Source/WebCore/platform/StaticPasteboard.cpp b/Source/WebCore/platform/StaticPasteboard.cpp
new file mode 100644 (file)
index 0000000..dc34aee
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+* Copyright (C) 2016 Apple Inc. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+* THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "config.h"
+#include "StaticPasteboard.h"
+
+namespace WebCore {
+
+std::unique_ptr<StaticPasteboard> StaticPasteboard::create(TypeToStringMap&& typeToStringMap)
+{
+    return std::make_unique<StaticPasteboard>(WTFMove(typeToStringMap));
+}
+
+StaticPasteboard::StaticPasteboard(TypeToStringMap&& typeToStringMap)
+    : m_typeToStringMap(typeToStringMap)
+{
+}
+
+bool StaticPasteboard::hasData()
+{
+    return !m_typeToStringMap.isEmpty();
+}
+
+Vector<String> StaticPasteboard::types()
+{
+    Vector<String> allTypes(m_typeToStringMap.size());
+    for (auto& type : m_typeToStringMap.keys())
+        allTypes.append(type);
+    return allTypes;
+}
+
+String StaticPasteboard::readString(const String& type)
+{
+    if (!m_typeToStringMap.contains(type))
+        return { };
+    return m_typeToStringMap.get(type);
+}
+
+}
diff --git a/Source/WebCore/platform/StaticPasteboard.h b/Source/WebCore/platform/StaticPasteboard.h
new file mode 100644 (file)
index 0000000..d864792
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "Pasteboard.h"
+#include <wtf/HashMap.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+typedef HashMap<String, String> TypeToStringMap;
+
+class StaticPasteboard final : public Pasteboard {
+public:
+    static std::unique_ptr<StaticPasteboard> create(TypeToStringMap&&);
+
+    StaticPasteboard(TypeToStringMap&&);
+
+    bool hasData() final;
+    Vector<String> types() final;
+    String readString(const String& type) final;
+
+    void writeString(const String&, const String&) final { }
+    void clear() final { }
+    void clear(const String&) final { }
+
+    void read(PasteboardPlainText&) final { }
+    void read(PasteboardWebContentReader&) final { }
+
+    void write(const PasteboardURL&) final { }
+    void write(const PasteboardImage&) final { }
+    void write(const PasteboardWebContent&) final { }
+
+    Vector<String> readFilenames() final { return { }; }
+    bool canSmartReplace() final { return false; }
+
+    void writeMarkup(const String&) final { }
+    void writePlainText(const String&, SmartReplaceOption) final { }
+    void writePasteboard(const Pasteboard&) final { }
+
+#if ENABLE(DRAG_SUPPORT)
+    void setDragImage(DragImageRef, const IntPoint&) final { }
+#endif
+
+private:
+    TypeToStringMap m_typeToStringMap;
+};
+
+}
index 3da81f5..e12dc9a 100644 (file)
@@ -125,4 +125,24 @@ void Pasteboard::writePasteboard(const Pasteboard&)
     notImplemented();
 }
 
+void Pasteboard::writeMarkup(const String&)
+{
+    notImplemented();
+}
+
+void Pasteboard::write(const PasteboardWebContent&)
+{
+    notImplemented();
+}
+
+void Pasteboard::read(PasteboardWebContentReader&)
+{
+    notImplemented();
+}
+
+void Pasteboard::write(const PasteboardImage&)
+{
+    notImplemented();
+}
+
 }
index 5b14ab5..9b04bb0 100644 (file)
@@ -87,6 +87,11 @@ Pasteboard::Pasteboard(const String& name)
 {
 }
 
+Pasteboard::Pasteboard()
+    : m_selectionData(SelectionData::create())
+{
+}
+
 Pasteboard::~Pasteboard()
 {
 }
@@ -271,6 +276,10 @@ void Pasteboard::read(PasteboardPlainText& text)
     text.text = m_selectionData->text();
 }
 
+void Pasteboard::read(PasteboardWebContentReader&)
+{
+}
+
 bool Pasteboard::hasData()
 {
     readFromClipboard();
@@ -333,4 +342,8 @@ Vector<String> Pasteboard::readFilenames()
     return m_selectionData->filenames();
 }
 
+void Pasteboard::writeMarkup(const String&)
+{
+}
+
 }
index 8b018ac..e2761f9 100644 (file)
@@ -88,6 +88,10 @@ Pasteboard::Pasteboard()
 {
 }
 
+void Pasteboard::writeMarkup(const String&)
+{
+}
+
 std::unique_ptr<Pasteboard> Pasteboard::createForCopyAndPaste()
 {
     return std::make_unique<Pasteboard>();
index 1469f4a..e00de7a 100644 (file)
@@ -107,6 +107,12 @@ static Vector<String> writableTypesForImage()
     return types;
 }
 
+Pasteboard::Pasteboard()
+    : m_pasteboardName(emptyString())
+    , m_changeCount(0)
+{
+}
+
 Pasteboard::Pasteboard(const String& pasteboardName)
     : m_pasteboardName(pasteboardName)
     , m_changeCount(platformStrategies()->pasteboardStrategy()->changeCount(m_pasteboardName))
@@ -281,6 +287,10 @@ bool Pasteboard::canSmartReplace()
     return types.contains(WebSmartPastePboardType);
 }
 
+void Pasteboard::writeMarkup(const String&)
+{
+}
+
 void Pasteboard::read(PasteboardPlainText& text)
 {
     PasteboardStrategy& strategy = *platformStrategies()->pasteboardStrategy();
index 2e33517..c3d587a 100644 (file)
@@ -1051,4 +1051,16 @@ void Pasteboard::writeMarkup(const String& markup)
         GlobalFree(medium.hGlobal);
 }
 
+void Pasteboard::write(const PasteboardWebContent&)
+{
+}
+
+void Pasteboard::read(PasteboardWebContentReader&)
+{
+}
+
+void Pasteboard::write(const PasteboardImage&)
+{
+}
+
 } // namespace WebCore