Changeset 252561 in webkit
- Timestamp:
- Nov 18, 2019 1:22:31 PM (4 years ago)
- Location:
- trunk
- Files:
-
- 4 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r252540 r252561 1 2019-11-18 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 [Clipboard API] Add support for Clipboard.writeText() 4 https://bugs.webkit.org/show_bug.cgi?id=204287 5 <rdar://problem/57270440> 6 7 Reviewed by Tim Horton. 8 9 * editing/async-clipboard/clipboard-write-text-expected.txt: Added. 10 * editing/async-clipboard/clipboard-write-text-requires-user-gesture-expected.txt: Added. 11 * editing/async-clipboard/clipboard-write-text-requires-user-gesture.html: Added. 12 13 Add a layout test to verify that `navigator.clipboard.writeText` is gated on user gesture, if the 14 javaScriptCanAccessClipboard preference is disabled. 15 16 * editing/async-clipboard/clipboard-write-text.html: Added. 17 18 Add a layout test to verify that writing text to the clipboard puts a single item on the system clipboard with 19 the type "text/plain", which can be read back using `navigator.clipboard.read`. 20 21 * platform/win/TestExpectations: 22 23 Skip clipboard-write-text.html on Windows, since custom pasteboard data is not implemented there yet. 24 1 25 2019-11-18 Antoine Quint <graouts@apple.com> 2 26 -
trunk/LayoutTests/imported/w3c/ChangeLog
r252537 r252561 1 2019-11-18 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 [Clipboard API] Add support for Clipboard.writeText() 4 https://bugs.webkit.org/show_bug.cgi?id=204287 5 <rdar://problem/57270440> 6 7 Reviewed by Tim Horton. 8 9 Rebaseline a couple of web platform tests. 10 11 * web-platform-tests/clipboard-apis/async-navigator-clipboard-basics.https-expected.txt: 12 * web-platform-tests/clipboard-apis/async-write-text-read-dttext-manual.https-expected.txt: 13 1 14 2019-11-17 Ryosuke Niwa <rniwa@webkit.org> 2 15 -
trunk/LayoutTests/imported/w3c/web-platform-tests/clipboard-apis/async-navigator-clipboard-basics.https-expected.txt
r251279 r252561 5 5 PASS navigator.clipboard.write(null) fails (expect DataTransfer) 6 6 PASS navigator.clipboard.write(DOMString) fails (expect DataTransfer) 7 FAIL navigator.clipboard.writeText(DOMString) succeeds promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported." 7 PASS navigator.clipboard.writeText(DOMString) succeeds 8 8 PASS navigator.clipboard.writeText() fails (expect DOMString) 9 9 FAIL navigator.clipboard.read() succeeds assert_true: expected true got false -
trunk/LayoutTests/imported/w3c/web-platform-tests/clipboard-apis/async-write-text-read-dttext-manual.https-expected.txt
r250856 r252561 1 1 Note: This is a manual test because it writes/reads to the shared system clipboard and thus cannot be run async with other tests that might interact with the clipboard. 2 2 3 Harness Error (TIMEOUT), message = null 3 FAIL Verify write and read clipboard (DOMString) undefined is not an object (evaluating 'data.items.length') 4 4 5 TIMEOUT Verify write and read clipboard (DOMString) Test timed out6 -
trunk/LayoutTests/platform/win/TestExpectations
r252507 r252561 1194 1194 webkit.org/b/203100 editing/async-clipboard/clipboard-write-basic.html [ Skip ] 1195 1195 webkit.org/b/203100 editing/async-clipboard/clipboard-write-items-twice.html [ Skip ] 1196 webkit.org/b/203100 editing/async-clipboard/clipboard-write-text.html [ Skip ] 1196 1197 1197 1198 webkit.org/b/140783 [ Release ] editing/pasteboard/copy-standalone-image.html [ Failure ImageOnlyFailure ] -
trunk/Source/WebCore/ChangeLog
r252554 r252561 1 2019-11-18 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 [Clipboard API] Add support for Clipboard.writeText() 4 https://bugs.webkit.org/show_bug.cgi?id=204287 5 <rdar://problem/57270440> 6 7 Reviewed by Tim Horton. 8 9 Implements the `writeText` method on Clipboard. 10 11 Tests: editing/async-clipboard/clipboard-write-text-requires-user-gesture.html 12 editing/async-clipboard/clipboard-write-text.html 13 14 * Modules/async-clipboard/Clipboard.cpp: 15 (WebCore::shouldProceedWithClipboardWrite): 16 17 Move this helper function further up the file. 18 19 (WebCore::Clipboard::writeText): 20 21 Implement the API, by populating a single PasteboardCustomData and writing it to the system clipboard. 22 1 23 2019-11-18 Antoine Quint <graouts@apple.com> 2 24 -
trunk/Source/WebCore/Modules/async-clipboard/Clipboard.cpp
r252450 r252561 28 28 29 29 #include "ClipboardItem.h" 30 #include "Document.h" 30 31 #include "Frame.h" 31 32 #include "JSBlob.h" … … 45 46 WTF_MAKE_ISO_ALLOCATED_IMPL(Clipboard); 46 47 47 Ref<Clipboard> Clipboard::create(Navigator& navigator)48 {49 return adoptRef(*new Clipboard(navigator));50 }51 52 Clipboard::Clipboard(Navigator& navigator)53 : m_navigator(makeWeakPtr(navigator))54 {55 }56 57 Clipboard::~Clipboard()58 {59 if (auto writer = WTFMove(m_activeItemWriter))60 writer->invalidate();61 }62 63 Navigator* Clipboard::navigator()64 {65 return m_navigator.get();66 }67 68 EventTargetInterface Clipboard::eventTargetInterface() const69 {70 return ClipboardEventTargetInterfaceType;71 }72 73 ScriptExecutionContext* Clipboard::scriptExecutionContext() const74 {75 return m_navigator ? m_navigator->scriptExecutionContext() : nullptr;76 }77 78 void Clipboard::readText(Ref<DeferredPromise>&& promise)79 {80 promise->reject(NotSupportedError);81 }82 83 void Clipboard::writeText(const String& data, Ref<DeferredPromise>&& promise)84 {85 UNUSED_PARAM(data);86 promise->reject(NotSupportedError);87 }88 89 void Clipboard::read(Ref<DeferredPromise>&& promise)90 {91 auto rejectPromiseAndClearActiveSession = [&] {92 m_activeSession = WTF::nullopt;93 promise->reject(NotAllowedError);94 };95 96 auto frame = makeRefPtr(this->frame());97 if (!frame) {98 rejectPromiseAndClearActiveSession();99 return;100 }101 102 auto pasteboard = Pasteboard::createForCopyAndPaste();103 auto changeCountAtStart = pasteboard->changeCount();104 105 if (!frame->requestDOMPasteAccess()) {106 rejectPromiseAndClearActiveSession();107 return;108 }109 110 if (!m_activeSession || m_activeSession->changeCount != changeCountAtStart) {111 auto allInfo = pasteboard->allPasteboardItemInfo();112 if (!allInfo) {113 rejectPromiseAndClearActiveSession();114 return;115 }116 117 Vector<Ref<ClipboardItem>> clipboardItems;118 clipboardItems.reserveInitialCapacity(allInfo->size());119 for (auto& itemInfo : *allInfo)120 clipboardItems.uncheckedAppend(ClipboardItem::create(*this, itemInfo));121 m_activeSession = {{ WTFMove(pasteboard), WTFMove(clipboardItems), changeCountAtStart }};122 }123 124 promise->resolve<IDLSequence<IDLInterface<ClipboardItem>>>(m_activeSession->items);125 }126 127 void Clipboard::getType(ClipboardItem& item, const String& type, Ref<DeferredPromise>&& promise)128 {129 if (!m_activeSession) {130 promise->reject(NotAllowedError);131 return;132 }133 134 auto frame = makeRefPtr(this->frame());135 if (!frame) {136 m_activeSession = WTF::nullopt;137 promise->reject(NotAllowedError);138 return;139 }140 141 auto itemIndex = m_activeSession->items.findMatching([&] (auto& activeItem) {142 return activeItem.ptr() == &item;143 });144 145 if (itemIndex == notFound) {146 promise->reject(NotAllowedError);147 return;148 }149 150 if (!item.types().contains(type)) {151 promise->reject(NotAllowedError);152 return;153 }154 155 String resultAsString;156 157 if (type == "text/uri-list"_s) {158 String title;159 resultAsString = activePasteboard().readURL(itemIndex, title).string();160 }161 162 if (type == "text/plain"_s) {163 PasteboardPlainText plainTextReader;164 activePasteboard().read(plainTextReader, PlainTextURLReadingPolicy::IgnoreURL, itemIndex);165 resultAsString = WTFMove(plainTextReader.text);166 }167 168 if (type == "text/html"_s) {169 WebContentMarkupReader markupReader { *frame };170 activePasteboard().read(markupReader, WebContentReadingPolicy::OnlyRichTextTypes, itemIndex);171 resultAsString = WTFMove(markupReader.markup);172 }173 174 // FIXME: Support reading "image/png" as well as custom data.175 // FIXME: Instead of checking changeCount here, we should send the changeCount over to the UI process to be vetted176 // when attempting to read the data in the first place.177 if (m_activeSession->changeCount != activePasteboard().changeCount()) {178 m_activeSession = WTF::nullopt;179 promise->reject(NotAllowedError);180 return;181 }182 183 if (!resultAsString.isNull())184 promise->resolve<IDLInterface<Blob>>(ClipboardItem::blobFromString(resultAsString, type));185 else186 promise->reject(NotAllowedError);187 }188 189 48 static bool shouldProceedWithClipboardWrite(const Frame& frame) 190 49 { … … 204 63 ASSERT_NOT_REACHED(); 205 64 return false; 65 } 66 67 Ref<Clipboard> Clipboard::create(Navigator& navigator) 68 { 69 return adoptRef(*new Clipboard(navigator)); 70 } 71 72 Clipboard::Clipboard(Navigator& navigator) 73 : m_navigator(makeWeakPtr(navigator)) 74 { 75 } 76 77 Clipboard::~Clipboard() 78 { 79 if (auto writer = WTFMove(m_activeItemWriter)) 80 writer->invalidate(); 81 } 82 83 Navigator* Clipboard::navigator() 84 { 85 return m_navigator.get(); 86 } 87 88 EventTargetInterface Clipboard::eventTargetInterface() const 89 { 90 return ClipboardEventTargetInterfaceType; 91 } 92 93 ScriptExecutionContext* Clipboard::scriptExecutionContext() const 94 { 95 return m_navigator ? m_navigator->scriptExecutionContext() : nullptr; 96 } 97 98 void Clipboard::readText(Ref<DeferredPromise>&& promise) 99 { 100 promise->reject(NotSupportedError); 101 } 102 103 void Clipboard::writeText(const String& data, Ref<DeferredPromise>&& promise) 104 { 105 auto frame = makeRefPtr(this->frame()); 106 auto document = makeRefPtr(frame ? frame->document() : nullptr); 107 if (!document || !frame || !shouldProceedWithClipboardWrite(*frame)) { 108 promise->reject(NotAllowedError); 109 return; 110 } 111 112 PasteboardCustomData customData; 113 customData.writeString("text/plain"_s, data); 114 customData.setOrigin(document->originIdentifierForPasteboard()); 115 Pasteboard::createForCopyAndPaste()->writeCustomData({ WTFMove(customData) }); 116 promise->resolve(); 117 } 118 119 void Clipboard::read(Ref<DeferredPromise>&& promise) 120 { 121 auto rejectPromiseAndClearActiveSession = [&] { 122 m_activeSession = WTF::nullopt; 123 promise->reject(NotAllowedError); 124 }; 125 126 auto frame = makeRefPtr(this->frame()); 127 if (!frame) { 128 rejectPromiseAndClearActiveSession(); 129 return; 130 } 131 132 auto pasteboard = Pasteboard::createForCopyAndPaste(); 133 auto changeCountAtStart = pasteboard->changeCount(); 134 135 if (!frame->requestDOMPasteAccess()) { 136 rejectPromiseAndClearActiveSession(); 137 return; 138 } 139 140 if (!m_activeSession || m_activeSession->changeCount != changeCountAtStart) { 141 auto allInfo = pasteboard->allPasteboardItemInfo(); 142 if (!allInfo) { 143 rejectPromiseAndClearActiveSession(); 144 return; 145 } 146 147 Vector<Ref<ClipboardItem>> clipboardItems; 148 clipboardItems.reserveInitialCapacity(allInfo->size()); 149 for (auto& itemInfo : *allInfo) 150 clipboardItems.uncheckedAppend(ClipboardItem::create(*this, itemInfo)); 151 m_activeSession = {{ WTFMove(pasteboard), WTFMove(clipboardItems), changeCountAtStart }}; 152 } 153 154 promise->resolve<IDLSequence<IDLInterface<ClipboardItem>>>(m_activeSession->items); 155 } 156 157 void Clipboard::getType(ClipboardItem& item, const String& type, Ref<DeferredPromise>&& promise) 158 { 159 if (!m_activeSession) { 160 promise->reject(NotAllowedError); 161 return; 162 } 163 164 auto frame = makeRefPtr(this->frame()); 165 if (!frame) { 166 m_activeSession = WTF::nullopt; 167 promise->reject(NotAllowedError); 168 return; 169 } 170 171 auto itemIndex = m_activeSession->items.findMatching([&] (auto& activeItem) { 172 return activeItem.ptr() == &item; 173 }); 174 175 if (itemIndex == notFound) { 176 promise->reject(NotAllowedError); 177 return; 178 } 179 180 if (!item.types().contains(type)) { 181 promise->reject(NotAllowedError); 182 return; 183 } 184 185 String resultAsString; 186 187 if (type == "text/uri-list"_s) { 188 String title; 189 resultAsString = activePasteboard().readURL(itemIndex, title).string(); 190 } 191 192 if (type == "text/plain"_s) { 193 PasteboardPlainText plainTextReader; 194 activePasteboard().read(plainTextReader, PlainTextURLReadingPolicy::IgnoreURL, itemIndex); 195 resultAsString = WTFMove(plainTextReader.text); 196 } 197 198 if (type == "text/html"_s) { 199 WebContentMarkupReader markupReader { *frame }; 200 activePasteboard().read(markupReader, WebContentReadingPolicy::OnlyRichTextTypes, itemIndex); 201 resultAsString = WTFMove(markupReader.markup); 202 } 203 204 // FIXME: Support reading "image/png" as well as custom data. 205 // FIXME: Instead of checking changeCount here, we should send the changeCount over to the UI process to be vetted 206 // when attempting to read the data in the first place. 207 if (m_activeSession->changeCount != activePasteboard().changeCount()) { 208 m_activeSession = WTF::nullopt; 209 promise->reject(NotAllowedError); 210 return; 211 } 212 213 if (!resultAsString.isNull()) 214 promise->resolve<IDLInterface<Blob>>(ClipboardItem::blobFromString(resultAsString, type)); 215 else 216 promise->reject(NotAllowedError); 206 217 } 207 218
Note: See TracChangeset
for help on using the changeset viewer.