Diff
Modified: trunk/Source/WebCore/ChangeLog (262506 => 262507)
--- trunk/Source/WebCore/ChangeLog 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Source/WebCore/ChangeLog 2020-06-03 19:41:50 UTC (rev 262507)
@@ -1,3 +1,101 @@
+2020-06-03 Wenson Hsieh <[email protected]>
+
+ dataTransfer.types is empty when handling the "dragstart" event
+ https://bugs.webkit.org/show_bug.cgi?id=212685
+ <rdar://problem/61368402>
+
+ Reviewed by Andy Estes.
+
+ Implements several currently stubbed methods on StaticPasteboard, so that the DataTransfer provided to the page
+ on the "dragstart" event contains the DOM-exposed data types that will be written to the system pasteboard. This
+ includes "text/html", "text/plain", and "text/uri-list".
+
+ Tests: DragAndDropTests.DataTransferTypesOnDragStartForTextSelection
+ DragAndDropTests.DataTransferTypesOnDragStartForImage
+ DragAndDropTests.DataTransferTypesOnDragStartForLink
+
+ ...as well as several existing tests in DragAndDropTestsIOS.mm that attempt to set pasteboard data during the
+ dragstart event:
+
+ DragAndDropTests.DataTransferSanitizeHTML
+ DragAndDropTests.DataTransferSetDataCannotWritePlatformTypes
+ DragAndDropTests.DataTransferSetDataInvalidURL
+ DragAndDropTests.DataTransferSetDataUnescapedURL
+ DragAndDropTests.DataTransferSetDataValidURL
+
+ * dom/DataTransfer.cpp:
+ (WebCore::DataTransfer::commitToPasteboard):
+
+ Only commit data to the native pasteboard if the page actually tried to write or modify the data. This allows us
+ to preserve existing behavior by allowing DragController to write dragged data to the pasteboard normally in the
+ case where the page didn't specify any custom data. In the case where the page does specify custom data, we will
+ write this custom data *in addition* to any default data that was written to the static pasteboard. While this
+ is a departure from our current behavior (which is to treat the pasteboard as a blank slate that contains only
+ whatever custom data was provided by the page), it matches behavior in both Chrome and Firefox, and is likely
+ more compatible with webpages that don't have UA-specific logic targeting WebKit.
+
+ * editing/cocoa/EditorCocoa.mm:
+ (WebCore::Editor::writeSelectionToPasteboard):
+
+ Avoid calling into the injected bundle (as well as writing a few particular non-web-exposed types, such as web
+ archive data) in the case where we're writing to a static pasteboard (there's no point in doing this for the
+ static pasteboard, and in the worst case, it could confuse some internal clients).
+
+ * editing/ios/EditorIOS.mm:
+ (WebCore::Editor::writeImageToPasteboard): Ditto.
+ * editing/mac/EditorMac.mm:
+ (WebCore::Editor::writeImageToPasteboard):
+
+ Ditto. But additionally, introduce a markup string to PasteboardImage, so that we will expose the "text/html"
+ type when starting a drag on an image element.
+
+ * page/DragController.cpp:
+ (WebCore::DragController::startDrag):
+
+ Only attempt to call into `Pasteboard::writeTrustworthyWebURLsPboardType` in the case where the pasteboard
+ supports this type (i.e. on macOS). This fixes an existing assertion that was hit by my new API test, which
+ attempts to override the contents of the pasteboard with custom data while starting a drag on a link.
+
+ * page/EventHandler.cpp:
+ (WebCore::EventHandler::handleDrag):
+
+ Since the StaticPasteboard contains data before the page has written anything, don't use `Pasteboard::hasData()`
+ to determine whether there's custom data; instead, use the new `hasNonDefaultData()` method on
+ `StaticPasteboard` (see below).
+
+ * platform/Pasteboard.cpp:
+ (WebCore::Pasteboard::canWriteTrustworthyWebURLsPboardType):
+
+ On non-macOS ports, return false.
+
+ * platform/Pasteboard.h:
+ * platform/StaticPasteboard.cpp:
+ (WebCore::StaticPasteboard::hasNonDefaultData const):
+
+ Keep track of whether the page attempted to stage any custom data during "dragstart" by maintaining the set of
+ types written by the page, via calls to `writeString()` and similar. I'm using a set of types here instead of a
+ simple `bool` flag to ensure correctness in the case where the page adds a type, and then later removes that
+ same custom type, such that there is no longer non-default data.
+
+ (WebCore::StaticPasteboard::writeString):
+ (WebCore::StaticPasteboard::writeData):
+ (WebCore::StaticPasteboard::writeStringInCustomData):
+ (WebCore::StaticPasteboard::clear):
+
+ See above.
+
+ (WebCore::StaticPasteboard::writeMarkup):
+ (WebCore::StaticPasteboard::writePlainText):
+ (WebCore::StaticPasteboard::write):
+
+ Implement these methods by writing to the `PasteboardCustomData`. These methods are invoked by our own code
+ rather than the bindings, and should only be used to stage default data types when starting a drag.
+
+ * platform/StaticPasteboard.h:
+ * platform/mac/PasteboardMac.mm:
+ (WebCore::Pasteboard::write):
+ (WebCore::Pasteboard::canWriteTrustworthyWebURLsPboardType):
+
2020-06-03 Jer Noble <[email protected]>
Crash with uncaught exception: *** -[AVSampleBufferAudioRenderer enqueueSampleBuffer:] Sample buffer has media type 'vide' instead of 'soun'
Modified: trunk/Source/WebCore/dom/DataTransfer.cpp (262506 => 262507)
--- trunk/Source/WebCore/dom/DataTransfer.cpp 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Source/WebCore/dom/DataTransfer.cpp 2020-06-03 19:41:50 UTC (rev 262507)
@@ -424,8 +424,8 @@
void DataTransfer::commitToPasteboard(Pasteboard& nativePasteboard)
{
ASSERT(is<StaticPasteboard>(*m_pasteboard) && !is<StaticPasteboard>(nativePasteboard));
- PasteboardCustomData customData = downcast<StaticPasteboard>(*m_pasteboard).takeCustomData();
- if (!customData.hasData()) {
+ auto& staticPasteboard = downcast<StaticPasteboard>(*m_pasteboard);
+ if (!staticPasteboard.hasNonDefaultData()) {
// We clear the platform pasteboard here to ensure that the pasteboard doesn't contain any data
// that may have been written before starting the drag or copying, and after ending the last
// drag session or paste. After pushing the static pasteboard's contents to the platform, the
@@ -434,6 +434,7 @@
return;
}
+ auto customData = staticPasteboard.takeCustomData();
if (RuntimeEnabledFeatures::sharedFeatures().customPasteboardDataEnabled()) {
customData.setOrigin(m_originIdentifier);
nativePasteboard.writeCustomData({ customData });
Modified: trunk/Source/WebCore/editing/cocoa/EditorCocoa.mm (262506 => 262507)
--- trunk/Source/WebCore/editing/cocoa/EditorCocoa.mm 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Source/WebCore/editing/cocoa/EditorCocoa.mm 2020-06-03 19:41:50 UTC (rev 262507)
@@ -119,13 +119,15 @@
PasteboardWebContent content;
content.contentOrigin = m_document.originIdentifierForPasteboard();
content.canSmartCopyOrDelete = canSmartCopyOrDelete();
- content.dataInWebArchiveFormat = selectionInWebArchiveFormat();
- content.dataInRTFDFormat = [string containsAttachments] ? dataInRTFDFormat(string.get()) : nullptr;
- content.dataInRTFFormat = dataInRTFFormat(string.get());
- content.dataInAttributedStringFormat = archivedDataForAttributedString(string.get());
+ if (!pasteboard.isStatic()) {
+ content.dataInWebArchiveFormat = selectionInWebArchiveFormat();
+ content.dataInRTFDFormat = [string containsAttachments] ? dataInRTFDFormat(string.get()) : nullptr;
+ content.dataInRTFFormat = dataInRTFFormat(string.get());
+ content.dataInAttributedStringFormat = archivedDataForAttributedString(string.get());
+ client()->getClientPasteboardDataForRange(selectedRange().get(), content.clientTypes, content.clientData);
+ }
content.dataInHTMLFormat = selectionInHTMLFormat();
content.dataInStringFormat = stringSelectionForPasteboardWithImageAltText();
- client()->getClientPasteboardDataForRange(selectedRange().get(), content.clientTypes, content.clientData);
pasteboard.write(content);
}
Modified: trunk/Source/WebCore/editing/ios/EditorIOS.mm (262506 => 262507)
--- trunk/Source/WebCore/editing/ios/EditorIOS.mm 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Source/WebCore/editing/ios/EditorIOS.mm 2020-06-03 19:41:50 UTC (rev 262507)
@@ -206,10 +206,12 @@
pasteboardImage.resourceMIMEType = pasteboard.resourceMIMEType(cachedImage->response().mimeType());
pasteboardImage.resourceData = cachedImage->resourceBuffer();
- Position beforeImagePosition(&imageElement, Position::PositionIsBeforeAnchor);
- Position afterImagePosition(&imageElement, Position::PositionIsAfterAnchor);
- auto imageRange = Range::create(imageElement.document(), beforeImagePosition, afterImagePosition);
- client()->getClientPasteboardDataForRange(imageRange.ptr(), pasteboardImage.clientTypes, pasteboardImage.clientData);
+ if (!pasteboard.isStatic()) {
+ Position beforeImagePosition(&imageElement, Position::PositionIsBeforeAnchor);
+ Position afterImagePosition(&imageElement, Position::PositionIsAfterAnchor);
+ auto imageRange = Range::create(imageElement.document(), beforeImagePosition, afterImagePosition);
+ client()->getClientPasteboardDataForRange(imageRange.ptr(), pasteboardImage.clientTypes, pasteboardImage.clientData);
+ }
pasteboard.write(pasteboardImage);
}
Modified: trunk/Source/WebCore/editing/mac/EditorMac.mm (262506 => 262507)
--- trunk/Source/WebCore/editing/mac/EditorMac.mm 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Source/WebCore/editing/mac/EditorMac.mm 2020-06-03 19:41:50 UTC (rev 262507)
@@ -250,7 +250,14 @@
return;
ASSERT(cachedImage);
- pasteboardImage.dataInWebArchiveFormat = imageInWebArchiveFormat(imageElement);
+ if (!pasteboard.isStatic())
+ pasteboardImage.dataInWebArchiveFormat = imageInWebArchiveFormat(imageElement);
+
+ if (auto imageRange = makeRangeSelectingNode(imageElement)) {
+ auto serializeComposedTree = m_document.settings().selectionAcrossShadowBoundariesEnabled() ? SerializeComposedTree::Yes : SerializeComposedTree::No;
+ pasteboardImage.dataInHTMLFormat = serializePreservingVisualAppearance(VisibleSelection { *imageRange }, ResolveURLs::YesExcludingLocalFileURLsForPrivacy, serializeComposedTree);
+ }
+
pasteboardImage.url.url = ""
pasteboardImage.url.title = title;
pasteboardImage.url.userVisibleForm = WTF::userVisibleString(pasteboardImage.url.url);
Modified: trunk/Source/WebCore/page/DragController.cpp (262506 => 262507)
--- trunk/Source/WebCore/page/DragController.cpp 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Source/WebCore/page/DragController.cpp 2020-06-03 19:41:50 UTC (rev 262507)
@@ -1123,7 +1123,7 @@
src.editor().copyURL(linkURL, textContentWithSimplifiedWhiteSpace, dataTransfer.pasteboard());
else
pasteboardWriterData.setURLData(src.editor().pasteboardWriterURL(linkURL, textContentWithSimplifiedWhiteSpace));
- } else {
+ } else if (dataTransfer.pasteboard().canWriteTrustworthyWebURLsPboardType()) {
// Make sure the pasteboard also contains trustworthy link data
// but don't overwrite more general pasteboard types.
PasteboardURL pasteboardURL;
Modified: trunk/Source/WebCore/page/EventHandler.cpp (262506 => 262507)
--- trunk/Source/WebCore/page/EventHandler.cpp 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Source/WebCore/page/EventHandler.cpp 2020-06-03 19:41:50 UTC (rev 262507)
@@ -3872,13 +3872,14 @@
invalidateDataTransfer();
dragState().dataTransfer = DataTransfer::createForDrag();
- HasNonDefaultPasteboardData hasNonDefaultPasteboardData = HasNonDefaultPasteboardData::No;
+ auto hasNonDefaultPasteboardData = HasNonDefaultPasteboardData::No;
if (dragState().shouldDispatchEvents) {
ASSERT(dragState().source);
auto dragStartDataTransfer = DataTransfer::createForDragStartEvent(dragState().source->document());
m_mouseDownMayStartDrag = dispatchDragStartEventOnSourceElement(dragStartDataTransfer);
- hasNonDefaultPasteboardData = dragStartDataTransfer->pasteboard().hasData() ? HasNonDefaultPasteboardData::Yes : HasNonDefaultPasteboardData::No;
+ if (downcast<StaticPasteboard>(dragStartDataTransfer->pasteboard()).hasNonDefaultData())
+ hasNonDefaultPasteboardData = HasNonDefaultPasteboardData::Yes;
dragState().dataTransfer->moveDragState(WTFMove(dragStartDataTransfer));
if (dragState().source && dragState().type == DragSourceActionDHTML && !dragState().dataTransfer->hasDragImage()) {
Modified: trunk/Source/WebCore/platform/Pasteboard.cpp (262506 => 262507)
--- trunk/Source/WebCore/platform/Pasteboard.cpp 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Source/WebCore/platform/Pasteboard.cpp 2020-06-03 19:41:50 UTC (rev 262507)
@@ -103,4 +103,13 @@
return { };
}
+#if !PLATFORM(MAC)
+
+bool Pasteboard::canWriteTrustworthyWebURLsPboardType()
+{
+ return false;
+}
+
+#endif
+
};
Modified: trunk/Source/WebCore/platform/Pasteboard.h (262506 => 262507)
--- trunk/Source/WebCore/platform/Pasteboard.h 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Source/WebCore/platform/Pasteboard.h 2020-06-03 19:41:50 UTC (rev 262507)
@@ -118,6 +118,7 @@
RefPtr<Image> image;
#if PLATFORM(MAC)
RefPtr<SharedBuffer> dataInWebArchiveFormat;
+ String dataInHTMLFormat;
#endif
#if !PLATFORM(WIN)
PasteboardURL url;
@@ -214,6 +215,8 @@
virtual WEBCORE_EXPORT void read(PasteboardWebContentReader&, WebContentReadingPolicy = WebContentReadingPolicy::AnyType, Optional<size_t> itemIndex = WTF::nullopt);
virtual WEBCORE_EXPORT void read(PasteboardFileReader&, Optional<size_t> itemIndex = WTF::nullopt);
+ static bool canWriteTrustworthyWebURLsPboardType();
+
virtual WEBCORE_EXPORT void write(const Color&);
virtual WEBCORE_EXPORT void write(const PasteboardURL&);
virtual WEBCORE_EXPORT void writeTrustworthyWebURLsPboardType(const PasteboardURL&);
@@ -222,7 +225,7 @@
virtual WEBCORE_EXPORT void writeCustomData(const Vector<PasteboardCustomData>&);
- enum class FileContentState { NoFileOrImageData, InMemoryImage, MayContainFilePaths };
+ enum class FileContentState : uint8_t { NoFileOrImageData, InMemoryImage, MayContainFilePaths };
virtual WEBCORE_EXPORT FileContentState fileContentState();
virtual WEBCORE_EXPORT bool canSmartReplace();
Modified: trunk/Source/WebCore/platform/StaticPasteboard.cpp (262506 => 262507)
--- trunk/Source/WebCore/platform/StaticPasteboard.cpp 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Source/WebCore/platform/StaticPasteboard.cpp 2020-06-03 19:41:50 UTC (rev 262507)
@@ -58,28 +58,39 @@
return m_customData.readStringInCustomData(type);
}
+bool StaticPasteboard::hasNonDefaultData() const
+{
+ return !m_nonDefaultDataTypes.isEmpty();
+}
+
void StaticPasteboard::writeString(const String& type, const String& value)
{
+ m_nonDefaultDataTypes.add(type);
m_customData.writeString(type, value);
}
void StaticPasteboard::writeData(const String& type, Ref<SharedBuffer>&& data)
{
+ m_nonDefaultDataTypes.add(type);
m_customData.writeData(type, WTFMove(data));
}
void StaticPasteboard::writeStringInCustomData(const String& type, const String& value)
{
+ m_nonDefaultDataTypes.add(type);
m_customData.writeStringInCustomData(type, value);
}
void StaticPasteboard::clear()
{
+ m_nonDefaultDataTypes.clear();
+ m_fileContentState = Pasteboard::FileContentState::NoFileOrImageData;
m_customData.clear();
}
void StaticPasteboard::clear(const String& type)
{
+ m_nonDefaultDataTypes.remove(type);
m_customData.clear(type);
}
@@ -88,4 +99,60 @@
return std::exchange(m_customData, { });
}
+void StaticPasteboard::writeMarkup(const String& markup)
+{
+ m_customData.writeString("text/html"_s, markup);
}
+
+void StaticPasteboard::writePlainText(const String& text, SmartReplaceOption)
+{
+ m_customData.writeString("text/plain"_s, text);
+}
+
+void StaticPasteboard::write(const PasteboardURL& url)
+{
+ m_customData.writeString("text/uri-list"_s, url.url.string());
+}
+
+void StaticPasteboard::write(const PasteboardImage& image)
+{
+ // FIXME: This should ideally remember the image data, so that when this StaticPasteboard
+ // is committed to the native pasteboard, we'll preserve the image as well. For now, stick
+ // with our existing behavior, which prevents image data from being copied in the case where
+ // any non-default data was written by the page.
+ m_fileContentState = Pasteboard::FileContentState::InMemoryImage;
+
+#if PLATFORM(MAC)
+ if (!image.dataInHTMLFormat.isEmpty())
+ writeMarkup(image.dataInHTMLFormat);
+#else
+ UNUSED_PARAM(image);
+#endif
+
+#if !PLATFORM(WIN)
+ if (Pasteboard::canExposeURLToDOMWhenPasteboardContainsFiles(image.url.url.string()))
+ write(image.url);
+#endif
+}
+
+void StaticPasteboard::write(const PasteboardWebContent& content)
+{
+ String markup;
+ String text;
+
+#if PLATFORM(COCOA)
+ markup = content.dataInHTMLFormat;
+ text = content.dataInStringFormat;
+#elif PLATFORM(GTK) || USE(LIBWPE)
+ markup = content.markup;
+ text = content.text;
+#endif
+
+ if (!markup.isEmpty())
+ writeMarkup(markup);
+
+ if (!text.isEmpty())
+ writePlainText(text, SmartReplaceOption::CannotSmartReplace);
+}
+
+}
Modified: trunk/Source/WebCore/platform/StaticPasteboard.h (262506 => 262507)
--- trunk/Source/WebCore/platform/StaticPasteboard.h 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Source/WebCore/platform/StaticPasteboard.h 2020-06-03 19:41:50 UTC (rev 262507)
@@ -41,6 +41,7 @@
PasteboardCustomData takeCustomData();
+ bool hasNonDefaultData() const;
bool isStatic() const final { return true; }
bool hasData() final;
@@ -59,18 +60,17 @@
void read(PasteboardPlainText&, PlainTextURLReadingPolicy = PlainTextURLReadingPolicy::AllowURL, Optional<size_t> = WTF::nullopt) final { }
void read(PasteboardWebContentReader&, WebContentReadingPolicy, Optional<size_t> = WTF::nullopt) final { }
- void write(const PasteboardURL&) final { }
- void write(const PasteboardImage&) final { }
- void write(const PasteboardWebContent&) final { }
+ void write(const PasteboardURL&) final;
+ void write(const PasteboardImage&) final;
+ void write(const PasteboardWebContent&) final;
+ void writeMarkup(const String&) final;
+ void writePlainText(const String&, SmartReplaceOption) final;
void writeCustomData(const Vector<PasteboardCustomData>&) final { }
- Pasteboard::FileContentState fileContentState() final { return FileContentState::NoFileOrImageData; }
+ Pasteboard::FileContentState fileContentState() final { return m_fileContentState; }
bool canSmartReplace() final { return false; }
- void writeMarkup(const String&) final { }
- void writePlainText(const String&, SmartReplaceOption) final { }
-
#if ENABLE(DRAG_SUPPORT)
void setDragImage(DragImage, const IntPoint&) final { }
#endif
@@ -77,6 +77,8 @@
private:
PasteboardCustomData m_customData;
+ HashSet<String> m_nonDefaultDataTypes;
+ Pasteboard::FileContentState m_fileContentState { Pasteboard::FileContentState::NoFileOrImageData };
};
}
Modified: trunk/Source/WebCore/platform/mac/PasteboardMac.mm (262506 => 262507)
--- trunk/Source/WebCore/platform/mac/PasteboardMac.mm 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Source/WebCore/platform/mac/PasteboardMac.mm 2020-06-03 19:41:50 UTC (rev 262507)
@@ -281,6 +281,8 @@
m_changeCount = platformStrategies()->pasteboardStrategy()->setBufferForType(archiveData.get(), WebArchivePboardType, m_pasteboardName);
m_changeCount = platformStrategies()->pasteboardStrategy()->setBufferForType(archiveData.get(), kUTTypeWebArchive, m_pasteboardName);
}
+ if (!pasteboardImage.dataInHTMLFormat.isEmpty())
+ m_changeCount = platformStrategies()->pasteboardStrategy()->setStringForType(pasteboardImage.dataInHTMLFormat, legacyHTMLPasteboardType(), m_pasteboardName);
writeFileWrapperAsRTFDAttachment(fileWrapper(pasteboardImage), m_pasteboardName, m_changeCount);
}
@@ -789,6 +791,11 @@
}
#endif
+bool Pasteboard::canWriteTrustworthyWebURLsPboardType()
+{
+ return true;
}
+}
+
#endif // PLATFORM(MAC)
Modified: trunk/Tools/ChangeLog (262506 => 262507)
--- trunk/Tools/ChangeLog 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Tools/ChangeLog 2020-06-03 19:41:50 UTC (rev 262507)
@@ -1,3 +1,74 @@
+2020-06-03 Wenson Hsieh <[email protected]>
+
+ dataTransfer.types is empty when handling the "dragstart" event
+ https://bugs.webkit.org/show_bug.cgi?id=212685
+ <rdar://problem/61368402>
+
+ Reviewed by Andy Estes.
+
+ Adds new API tests and test infrastructure to verify that DataTransfer types and data are accessible during
+ the "dragstart" event. See below for more details.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebKitCocoa/DragAndDropTests.mm:
+ (-[TestWKWebView selectElementWithID:]):
+ (-[DragAndDropSimulator dragFromElementWithID:to:]):
+
+ Add a few (very specialized) helper methods to assist with simulating drags over the various elements in the new
+ drag and drop test harness page below (dragstart-data.html).
+
+ (runDragStartDataTestCase):
+
+ Test the following scenarios (split between three API tests) by dumping the resulting DataTransfer types and
+ their data strings, and observing the results:
+
+ - Dragging a normal text selection.
+ - Dragging a normal text selection, and then adding a URL string.
+ - Dragging a normal text selection, and then adding a custom pasteboard type.
+ - Dragging a normal text selection, but then replacing the data with just a URL string.
+ - Dragging a normal text selection, but then replacing the data with just a custom data type.
+ - Dragging an image element.
+ - Dragging an image element, and then overriding the plain text data.
+ - Dragging a link (anchor element).
+ - Dragging a link, and then adding a custom type.
+
+ * TestWebKitAPI/Tests/WebKitCocoa/dragstart-data.html: Added.
+
+ Add a new test harness to help test DataTransfer types when starting a drag. This test page can also be used as
+ a manual test harness, by simply opening the test page, starting drags on the various elements and observing the
+ output in the textarea.
+
+ * TestWebKitAPI/Tests/WebKitCocoa/dump-datatransfer-types.html:
+
+ Tweak this test page to replace the DataTransfer with custom data (rather than simply append it) by calling
+ `DataTransfer.clearData()` prior to writing the custom types.
+
+ * TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm:
+ * TestWebKitAPI/cocoa/TestWKWebView.h:
+ * TestWebKitAPI/cocoa/TestWKWebView.mm:
+ (-[TestWKWebViewHostWindow initWithWebView:contentRect:styleMask:backing:defer:]):
+
+ Add a `__weak` reference on TestWKWebViewHostWindow back to the TestWKWebView, so that we can consult
+ `-eventTimestamp` when synthesizing mouse events on macOS during API tests.
+
+ (-[TestWKWebViewHostWindow _mouseDownAtPoint:simulatePressure:clickCount:]):
+ (-[TestWKWebViewHostWindow _mouseUpAtPoint:clickCount:]):
+ (-[TestWKWebViewHostWindow initWithWebView:frame:]):
+ (-[TestWKWebView _setUpTestWindow:]):
+ (-[TestWKWebView setEventTimestampOffset:]):
+ (-[TestWKWebView eventTimestamp]):
+
+ Add a mechanism to offset synthetic event timestamps by a given time interval (i.e. the event timestamp offset).
+
+ (-[TestWKWebView mouseMoveToPoint:withFlags:]):
+ (-[TestWKWebView _mouseEventWithType:atLocation:]):
+ (-[TestWKWebView typeCharacter:]):
+ * TestWebKitAPI/mac/DragAndDropSimulatorMac.mm:
+ (-[DragAndDropSimulator runFrom:to:]):
+
+ While simulating drag and drop on macOS, use `-setEventTimestampOffset:` to "leap forward" in time, so that the
+ 150 millisecond delay when dragging a text selection doesn't prevent drags from beginning.
+
2020-06-03 Sihui Liu <[email protected]>
Text manipulation sometimes fails to replace text in attributes
Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (262506 => 262507)
--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2020-06-03 19:41:50 UTC (rev 262507)
@@ -1102,6 +1102,7 @@
F469FB241F01804B00401539 /* contenteditable-and-target.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F469FB231F01803500401539 /* contenteditable-and-target.html */; };
F46A095A1ED8A6E600D4AA55 /* apple.gif in Copy Resources */ = {isa = PBXBuildFile; fileRef = F47D30EB1ED28619000482E1 /* apple.gif */; };
F46A095B1ED8A6E600D4AA55 /* gif-and-file-input.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F47D30ED1ED28A6C000482E1 /* gif-and-file-input.html */; };
+ F46BD56924870643008282D6 /* dragstart-data.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F46BD5682487062D008282D6 /* dragstart-data.html */; };
F47728991E4AE3C1007ABF6A /* full-page-contenteditable.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F47728981E4AE3AD007ABF6A /* full-page-contenteditable.html */; };
F47DFB2621A878DF00021FB6 /* data-detectors.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F47DFB2421A8704A00021FB6 /* data-detectors.html */; };
F4811E5921940BDE00A5E0FD /* WKWebViewEditActions.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4811E5821940B4400A5E0FD /* WKWebViewEditActions.mm */; };
@@ -1318,6 +1319,7 @@
5714ECBB1CA8BFE400051AC8 /* DownloadRequestOriginalURLFrame.html in Copy Resources */,
F4A32EC41F05F3850047C544 /* dragstart-change-selection-offscreen.html in Copy Resources */,
F4D5E4E81F0C5D38008C1A49 /* dragstart-clear-selection.html in Copy Resources */,
+ F46BD56924870643008282D6 /* dragstart-data.html in Copy Resources */,
F4194AD11F5A320100ADD83F /* drop-targets.html in Copy Resources */,
2EB29D5E1F762DB90023A5F1 /* dump-datatransfer-types.html in Copy Resources */,
A155022C1E050D0300A24C57 /* duplicate-completion-handler-calls.html in Copy Resources */,
@@ -2767,6 +2769,7 @@
F46849BD1EEF58E400B937FE /* UIPasteboardTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = UIPasteboardTests.mm; sourceTree = "<group>"; };
F46849BF1EEF5EDC00B937FE /* rich-and-plain-text.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "rich-and-plain-text.html"; sourceTree = "<group>"; };
F469FB231F01803500401539 /* contenteditable-and-target.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "contenteditable-and-target.html"; sourceTree = "<group>"; };
+ F46BD5682487062D008282D6 /* dragstart-data.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "dragstart-data.html"; sourceTree = "<group>"; };
F47728981E4AE3AD007ABF6A /* full-page-contenteditable.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "full-page-contenteditable.html"; sourceTree = "<group>"; };
F47D30EB1ED28619000482E1 /* apple.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = apple.gif; sourceTree = "<group>"; };
F47D30ED1ED28A6C000482E1 /* gif-and-file-input.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "gif-and-file-input.html"; sourceTree = "<group>"; };
@@ -3560,6 +3563,7 @@
5714ECBA1CA8BFD100051AC8 /* DownloadRequestOriginalURLFrame.html */,
F4A32EC31F05F3780047C544 /* dragstart-change-selection-offscreen.html */,
F4D5E4E71F0C5D27008C1A49 /* dragstart-clear-selection.html */,
+ F46BD5682487062D008282D6 /* dragstart-data.html */,
F4194AD01F5A2EA500ADD83F /* drop-targets.html */,
2EB29D5D1F762DA50023A5F1 /* dump-datatransfer-types.html */,
A155022B1E050BC500A24C57 /* duplicate-completion-handler-calls.html */,
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/DragAndDropTests.mm (262506 => 262507)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/DragAndDropTests.mm 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/DragAndDropTests.mm 2020-06-03 19:41:50 UTC (rev 262507)
@@ -24,6 +24,7 @@
*/
#import "config.h"
+#import "Test.h"
#if ENABLE(DRAG_SUPPORT) && !PLATFORM(MACCATALYST)
@@ -36,6 +37,33 @@
#import <MobileCoreServices/MobileCoreServices.h>
#endif
+@implementation TestWKWebView (DragAndDropTests)
+
+- (void)selectElementWithID:(NSString *)elementID
+{
+ [self evaluateJavaScript:[NSString stringWithFormat:@"getSelection().selectAllChildren(document.getElementById('%@'))", elementID] completionHandler:nil];
+ [self waitForNextPresentationUpdate];
+}
+
+@end
+
+@implementation DragAndDropSimulator (DragAndDropTests)
+
+- (void)dragFromElementWithID:(NSString *)elementID to:(CGPoint)destination
+{
+ NSArray<NSNumber *> *rectValues = [self.webView objectByEvaluatingJavaScript:[NSString stringWithFormat:@"(() => {"
+ " const element = document.getElementById('%@');"
+ " const bounds = element.getBoundingClientRect();"
+ " return [bounds.left, bounds.top, bounds.width, bounds.height];"
+ "})();", elementID]];
+
+ auto bounds = CGRectMake(rectValues[0].floatValue, rectValues[1].floatValue, rectValues[2].floatValue, rectValues[3].floatValue);
+ auto midPoint = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
+ [self runFrom:midPoint to:destination];
+}
+
+@end
+
TEST(DragAndDropTests, ModernWebArchiveType)
{
NSData *markupData = [@"<strong><i>Hello world</i></strong>" dataUsingEncoding:NSUTF8StringEncoding];
@@ -160,6 +188,127 @@
EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"observedMousedown"].boolValue);
}
+struct DragStartData {
+ BOOL containsFile { NO };
+ NSString *text { nil };
+ NSString *url { nil };
+ NSString *html { nil };
+ NSDictionary<NSString *, NSString *> *customData { nil };
+};
+
+static DragStartData runDragStartDataTestCase(DragAndDropSimulator *simulator, NSString *elementID)
+{
+ auto webView = [simulator webView];
+ NSString *tagName = [webView stringByEvaluatingJavaScript:[NSString stringWithFormat:@"document.getElementById('%@').tagName", elementID]];
+ if (![tagName isEqualToString:@"IMG"] && ![tagName isEqualToString:@"A"])
+ [webView selectElementWithID:elementID];
+
+ [simulator dragFromElementWithID:elementID to:CGPointMake(400, 400)];
+ RetainPtr<NSMutableDictionary<NSString *, NSString *>> allData = adoptNS([[webView objectByEvaluatingJavaScript:@"allData"] mutableCopy]);
+ DragStartData result;
+ result.text = [allData objectForKey:@"text/plain"];
+ result.url = "" objectForKey:@"text/uri-list"];
+ result.html = [allData objectForKey:@"text/html"];
+ result.containsFile = !![allData objectForKey:@"Files"];
+ [allData removeObjectForKey:@"text/plain"];
+ [allData removeObjectForKey:@"text/uri-list"];
+ [allData removeObjectForKey:@"text/html"];
+ [allData removeObjectForKey:@"Files"];
+ if ([allData count])
+ result.customData = allData.autorelease();
+ return result;
+}
+
+TEST(DragAndDropTests, DataTransferTypesOnDragStartForTextSelection)
+{
+ auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebViewFrame:CGRectMake(0, 0, 500, 500)]);
+ [[simulator webView] synchronouslyLoadTestPageNamed:@"dragstart-data"];
+
+ auto result = runDragStartDataTestCase(simulator.get(), @"regular");
+ EXPECT_WK_STREQ("Regular text", result.text);
+ EXPECT_NULL(result.url);
+ EXPECT_TRUE([result.html containsString:@"Regular text"]);
+ EXPECT_NULL(result.customData);
+ EXPECT_FALSE(result.containsFile);
+
+ result = runDragStartDataTestCase(simulator.get(), @"regular-url");
+ EXPECT_WK_STREQ("Regular text + URL data", result.text);
+ EXPECT_WK_STREQ("https://www.google.com", result.url);
+ EXPECT_TRUE([result.html containsString:@"Regular text + URL data"]);
+ EXPECT_NULL(result.customData);
+ EXPECT_FALSE(result.containsFile);
+
+ result = runDragStartDataTestCase(simulator.get(), @"regular-custom");
+ EXPECT_WK_STREQ("Regular text + custom data", result.text);
+ EXPECT_NULL(result.url);
+ EXPECT_TRUE([result.html containsString:@"Regular text + custom data"]);
+ EXPECT_WK_STREQ("Hello world", result.customData[@"text/foo"]);
+ EXPECT_FALSE(result.containsFile);
+
+ result = runDragStartDataTestCase(simulator.get(), @"url");
+ EXPECT_NULL(result.text);
+ EXPECT_WK_STREQ("https://www.google.com", result.url);
+ EXPECT_NULL([result.html containsString:@"Regular text + custom data"]);
+ EXPECT_NULL(result.customData);
+ EXPECT_FALSE(result.containsFile);
+
+ result = runDragStartDataTestCase(simulator.get(), @"custom");
+ EXPECT_NULL(result.text);
+ EXPECT_NULL(result.url);
+ EXPECT_NULL(result.html);
+ EXPECT_WK_STREQ("Hello world", result.customData[@"text/foo"]);
+ EXPECT_FALSE(result.containsFile);
+}
+
+TEST(DragAndDropTests, DataTransferTypesOnDragStartForImage)
+{
+ auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebViewFrame:CGRectMake(0, 0, 500, 500)]);
+ [[simulator webView] synchronouslyLoadTestPageNamed:@"dragstart-data"];
+
+ auto result = runDragStartDataTestCase(simulator.get(), @"image");
+ EXPECT_NULL(result.text);
+ // The URL should be nil here because the image source is a file URL, so we shoud avoid exposing it to the page.
+ EXPECT_NULL(result.url);
+#if PLATFORM(MAC)
+ EXPECT_TRUE([result.html containsString:@"<img"]);
+#else
+ EXPECT_NULL(result.html);
+#endif
+ EXPECT_NULL(result.customData);
+ EXPECT_TRUE(result.containsFile);
+
+ result = runDragStartDataTestCase(simulator.get(), @"image-text");
+ EXPECT_WK_STREQ("This is an image of Cupertino.", result.text);
+ EXPECT_NULL(result.url);
+#if PLATFORM(MAC)
+ EXPECT_TRUE([result.html containsString:@"<img"]);
+#else
+ EXPECT_NULL(result.html);
+#endif
+ EXPECT_NULL(result.customData);
+ EXPECT_TRUE(result.containsFile);
+}
+
+TEST(DragAndDropTests, DataTransferTypesOnDragStartForLink)
+{
+ auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebViewFrame:CGRectMake(0, 0, 500, 800)]);
+ [[simulator webView] synchronouslyLoadTestPageNamed:@"dragstart-data"];
+
+ auto result = runDragStartDataTestCase(simulator.get(), @"link");
+ EXPECT_NULL(result.text);
+ EXPECT_WK_STREQ("https://www.apple.com/", result.url);
+ EXPECT_NULL(result.html);
+ EXPECT_NULL(result.customData);
+ EXPECT_FALSE(result.containsFile);
+
+ result = runDragStartDataTestCase(simulator.get(), @"link-custom");
+ EXPECT_NULL(result.text);
+ EXPECT_WK_STREQ("https://www.apple.com/", result.url);
+ EXPECT_NULL(result.html);
+ EXPECT_WK_STREQ("bar", result.customData[@"text/foo"]);
+ EXPECT_FALSE(result.containsFile);
+}
+
#if ENABLE(INPUT_TYPE_COLOR)
TEST(DragAndDropTests, ColorInputToColorInput)
Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/dragstart-data.html (0 => 262507)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/dragstart-data.html (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/dragstart-data.html 2020-06-03 19:41:50 UTC (rev 262507)
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<html>
+<meta name="viewport" content="width=device-width">
+<head>
+<style>
+body {
+ margin: 0;
+ padding: 0;
+}
+
+h1, a, p {
+ font-size: 20px;
+ font-family: system-ui;
+}
+
+h1 {
+ user-select: all;
+ -webkit-user-select: all;
+}
+
+a {
+ display: inline-block;
+ text-decoration: none;
+}
+
+a:active {
+ color: blue;
+}
+
+textarea {
+ margin: 1em;
+ width: calc(100% - 2em);
+ font-size: 16px;
+ font-family: monospace;
+}
+</style>
+</head>
+<body>
+ <h1 id="regular">Regular text</h1>
+ <h1 id="regular-url">Regular text + URL data</h1>
+ <h1 id="regular-custom">Regular text + custom data</h1>
+ <h1 id="url">URL data only</h1>
+ <h1 id="custom">Custom data only</h1>
+ <img id="image" src=""
+ <img id="image-text" src=""
+ <a id="link" href="" Homepage</a>
+ <a id="link-custom" href="" Homepage</a>
+ <textarea rows="20" readonly id="text-output"></textarea>
+</body>
+<script>
+window.allData = {};
+const textOutput = document.getElementById("text-output");
+
+function collectDataForEvent(event, element)
+{
+ allData = {};
+ for (let type of event.dataTransfer.types)
+ allData[type] = event.dataTransfer.getData(type);
+ textOutput.value = JSON.stringify(allData, null, 4);
+}
+
+const regular = document.getElementById("regular");
+regular.addEventListener("dragstart", event => collectDataForEvent(event, regular));
+
+const regularURL = document.getElementById("regular-url");
+regularURL.addEventListener("dragstart", event => {
+ event.dataTransfer.setData("text/uri-list", "https://www.google.com");
+ collectDataForEvent(event, regularURL);
+});
+
+const regularCustom = document.getElementById("regular-custom");
+regularCustom.addEventListener("dragstart", event => {
+ event.dataTransfer.setData("text/foo", "Hello world");
+ collectDataForEvent(event, regularCustom);
+});
+
+const url = ""
+url.addEventListener("dragstart", event => {
+ event.dataTransfer.clearData();
+ event.dataTransfer.setData("text/uri-list", "https://www.google.com");
+ collectDataForEvent(event, url);
+});
+
+const custom = document.getElementById("custom");
+custom.addEventListener("dragstart", event => {
+ event.dataTransfer.clearData();
+ event.dataTransfer.setData("text/foo", "Hello world");
+ collectDataForEvent(event, custom);
+});
+
+const image = document.getElementById("image");
+image.addEventListener("dragstart", event => collectDataForEvent(event, image));
+
+const imageText = document.getElementById("image-text");
+imageText.addEventListener("dragstart", event => {
+ event.dataTransfer.setData("text/plain", "This is an image of Cupertino.");
+ collectDataForEvent(event, imageText);
+});
+
+const link = document.getElementById("link");
+link.addEventListener("dragstart", event => collectDataForEvent(event, link));
+
+const linkCustom = document.getElementById("link-custom");
+linkCustom.addEventListener("dragstart", event => {
+ event.dataTransfer.setData("text/foo", "bar");
+ collectDataForEvent(event, linkCustom);
+});
+</script>
+</html>
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/dump-datatransfer-types.html (262506 => 262507)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/dump-datatransfer-types.html 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/dump-datatransfer-types.html 2020-06-03 19:41:50 UTC (rev 262507)
@@ -100,6 +100,7 @@
return true;
const pasteboard = event.dataTransfer || event.clipboardData;
+ pasteboard.clearData();
for (const type in customData)
pasteboard.setData(type, customData[type]);
Modified: trunk/Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm (262506 => 262507)
--- trunk/Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm 2020-06-03 19:41:50 UTC (rev 262507)
@@ -78,7 +78,7 @@
return [NSData dataWithContentsOfURL:zipFileURL];
}
-@implementation TestWKWebView (DragAndDropTests)
+@implementation TestWKWebView (DragAndDropTestsIOS)
- (BOOL)editorContainsImageElement
{
Modified: trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h (262506 => 262507)
--- trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h 2020-06-03 19:41:50 UTC (rev 262507)
@@ -130,6 +130,8 @@
- (NSWindow *)hostWindow;
- (void)typeCharacter:(char)character;
- (void)waitForPendingMouseEvents;
+- (void)setEventTimestampOffset:(NSTimeInterval)offset;
+@property (nonatomic, readonly) NSTimeInterval eventTimestamp;
@end
#endif
Modified: trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm (262506 => 262507)
--- trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm 2020-06-03 19:41:50 UTC (rev 262507)
@@ -271,9 +271,11 @@
@implementation TestWKWebViewHostWindow {
BOOL _forceKeyWindow;
+ __weak TestWKWebView *_webView;
}
#if PLATFORM(MAC)
+
static int gEventNumber = 1;
NSEventMask __simulated_forceClickAssociatedEventsMask(id self, SEL _cmd)
@@ -281,6 +283,13 @@
return NSEventMaskPressure | NSEventMaskLeftMouseDown | NSEventMaskLeftMouseUp | NSEventMaskLeftMouseDragged;
}
+- (instancetype)initWithWebView:(TestWKWebView *)webView contentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style backing:(NSBackingStoreType)backingStoreType defer:(BOOL)flag
+{
+ if (self = [super initWithContentRect:contentRect styleMask:style backing:backingStoreType defer:flag])
+ _webView = webView;
+ return self;
+}
+
- (void)_mouseDownAtPoint:(NSPoint)point simulatePressure:(BOOL)simulatePressure clickCount:(NSUInteger)clickCount
{
NSEventType mouseEventType = NSEventTypeLeftMouseDown;
@@ -289,7 +298,7 @@
if (simulatePressure)
modifierFlags |= NSEventMaskPressure;
- NSEvent *event = [NSEvent mouseEventWithType:mouseEventType location:point modifierFlags:modifierFlags timestamp:GetCurrentEventTime() windowNumber:self.windowNumber context:[NSGraphicsContext currentContext] eventNumber:++gEventNumber clickCount:clickCount pressure:simulatePressure];
+ NSEvent *event = [NSEvent mouseEventWithType:mouseEventType location:point modifierFlags:modifierFlags timestamp:_webView.eventTimestamp windowNumber:self.windowNumber context:[NSGraphicsContext currentContext] eventNumber:++gEventNumber clickCount:clickCount pressure:simulatePressure];
if (!simulatePressure) {
[self sendEvent:event];
return;
@@ -309,10 +318,11 @@
- (void)_mouseUpAtPoint:(NSPoint)point clickCount:(NSUInteger)clickCount
{
- [self sendEvent:[NSEvent mouseEventWithType:NSEventTypeLeftMouseUp location:point modifierFlags:0 timestamp:GetCurrentEventTime() windowNumber:self.windowNumber context:[NSGraphicsContext currentContext] eventNumber:++gEventNumber clickCount:clickCount pressure:0]];
+ [self sendEvent:[NSEvent mouseEventWithType:NSEventTypeLeftMouseUp location:point modifierFlags:0 timestamp:_webView.eventTimestamp windowNumber:self.windowNumber context:[NSGraphicsContext currentContext] eventNumber:++gEventNumber clickCount:clickCount pressure:0]];
}
-#endif // PLATFORM(MAC)
+#endif
+
- (BOOL)isKeyWindow
{
return _forceKeyWindow || [super isKeyWindow];
@@ -319,6 +329,7 @@
}
#if PLATFORM(IOS_FAMILY)
+
static NeverDestroyed<RetainPtr<UIWindow>> gOverriddenApplicationKeyWindow;
static NeverDestroyed<std::unique_ptr<InstanceMethodSwizzler>> gApplicationKeyWindowSwizzler;
static NeverDestroyed<std::unique_ptr<InstanceMethodSwizzler>> gSharedApplicationSwizzler;
@@ -345,6 +356,14 @@
{
return gOverriddenApplicationKeyWindow.get().get();
}
+
+- (instancetype)initWithWebView:(TestWKWebView *)webView frame:(CGRect)frame
+{
+ if (self = [super initWithFrame:frame])
+ _webView = webView;
+ return self;
+}
+
#endif
- (void)makeKeyWindow
@@ -388,6 +407,9 @@
std::unique_ptr<ClassMethodSwizzler> _sharedCalloutBarSwizzler;
InputSessionChangeCount _inputSessionChangeCount;
#endif
+#if PLATFORM(MAC)
+ NSTimeInterval _eventTimestampOffset;
+#endif
}
- (instancetype)initWithFrame:(CGRect)frame
@@ -437,7 +459,7 @@
- (void)_setUpTestWindow:(NSRect)frame
{
#if PLATFORM(MAC)
- _hostWindow = adoptNS([[TestWKWebViewHostWindow alloc] initWithContentRect:frame styleMask:(NSWindowStyleMaskBorderless | NSWindowStyleMaskMiniaturizable) backing:NSBackingStoreBuffered defer:NO]);
+ _hostWindow = adoptNS([[TestWKWebViewHostWindow alloc] initWithWebView:self contentRect:frame styleMask:(NSWindowStyleMaskBorderless | NSWindowStyleMaskMiniaturizable) backing:NSBackingStoreBuffered defer:NO]);
[_hostWindow setFrameOrigin:NSMakePoint(0, 0)];
[_hostWindow setIsVisible:YES];
[_hostWindow contentView].wantsLayer = YES;
@@ -444,7 +466,7 @@
[[_hostWindow contentView] addSubview:self];
[_hostWindow makeKeyAndOrderFront:self];
#else
- _hostWindow = adoptNS([[TestWKWebViewHostWindow alloc] initWithFrame:frame]);
+ _hostWindow = adoptNS([[TestWKWebViewHostWindow alloc] initWithWebView:self frame:frame]);
[_hostWindow setHidden:NO];
[_hostWindow addSubview:self];
#endif
@@ -684,7 +706,19 @@
#endif
#if PLATFORM(MAC)
+
@implementation TestWKWebView (MacOnly)
+
+- (void)setEventTimestampOffset:(NSTimeInterval)offset
+{
+ _eventTimestampOffset += offset;
+}
+
+- (NSTimeInterval)eventTimestamp
+{
+ return GetCurrentEventTime() + _eventTimestampOffset;
+}
+
- (void)mouseDownAtPoint:(NSPoint)pointInWindow simulatePressure:(BOOL)simulatePressure
{
[_hostWindow _mouseDownAtPoint:pointInWindow simulatePressure:simulatePressure clickCount:1];
@@ -697,7 +731,7 @@
- (void)mouseMoveToPoint:(NSPoint)pointInWindow withFlags:(NSEventModifierFlags)flags
{
- [self mouseMoved:[self _mouseEventWithType:NSEventTypeMouseMoved atLocation:pointInWindow flags:flags timestamp:GetCurrentEventTime() clickCount:0]];
+ [self mouseMoved:[self _mouseEventWithType:NSEventTypeMouseMoved atLocation:pointInWindow flags:flags timestamp:self.eventTimestamp clickCount:0]];
}
- (void)sendClicksAtPoint:(NSPoint)pointInWindow numberOfClicks:(NSUInteger)numberOfClicks
@@ -725,7 +759,7 @@
- (NSEvent *)_mouseEventWithType:(NSEventType)type atLocation:(NSPoint)pointInWindow
{
- return [self _mouseEventWithType:type atLocation:pointInWindow flags:0 timestamp:GetCurrentEventTime() clickCount:0];
+ return [self _mouseEventWithType:type atLocation:pointInWindow flags:0 timestamp:self.eventTimestamp clickCount:0];
}
- (NSEvent *)_mouseEventWithType:(NSEventType)type atLocation:(NSPoint)locationInWindow flags:(NSEventModifierFlags)flags timestamp:(NSTimeInterval)timestamp clickCount:(NSUInteger)clickCount
@@ -749,8 +783,8 @@
NSString *characterAsString = [NSString stringWithFormat:@"%c" , character];
NSEventType keyDownEventType = NSEventTypeKeyDown;
NSEventType keyUpEventType = NSEventTypeKeyUp;
- [self keyDown:[NSEvent keyEventWithType:keyDownEventType location:NSZeroPoint modifierFlags:0 timestamp:GetCurrentEventTime() windowNumber:[_hostWindow windowNumber] context:nil characters:characterAsString charactersIgnoringModifiers:characterAsString isARepeat:NO keyCode:character]];
- [self keyUp:[NSEvent keyEventWithType:keyUpEventType location:NSZeroPoint modifierFlags:0 timestamp:GetCurrentEventTime() windowNumber:[_hostWindow windowNumber] context:nil characters:characterAsString charactersIgnoringModifiers:characterAsString isARepeat:NO keyCode:character]];
+ [self keyDown:[NSEvent keyEventWithType:keyDownEventType location:NSZeroPoint modifierFlags:0 timestamp:self.eventTimestamp windowNumber:[_hostWindow windowNumber] context:nil characters:characterAsString charactersIgnoringModifiers:characterAsString isARepeat:NO keyCode:character]];
+ [self keyUp:[NSEvent keyEventWithType:keyUpEventType location:NSZeroPoint modifierFlags:0 timestamp:self.eventTimestamp windowNumber:[_hostWindow windowNumber] context:nil characters:characterAsString charactersIgnoringModifiers:characterAsString isARepeat:NO keyCode:character]];
}
- (void)waitForPendingMouseEvents
@@ -763,6 +797,7 @@
}
@end
+
#endif // PLATFORM(MAC)
#if PLATFORM(IOS_FAMILY)
Modified: trunk/Tools/TestWebKitAPI/mac/DragAndDropSimulatorMac.mm (262506 => 262507)
--- trunk/Tools/TestWebKitAPI/mac/DragAndDropSimulatorMac.mm 2020-06-03 19:25:43 UTC (rev 262506)
+++ trunk/Tools/TestWebKitAPI/mac/DragAndDropSimulatorMac.mm 2020-06-03 19:41:50 UTC (rev 262507)
@@ -177,6 +177,8 @@
[_webView mouseEnterAtPoint:_startLocationInWindow];
[_webView mouseMoveToPoint:_startLocationInWindow withFlags:0];
[_webView mouseDownAtPoint:_startLocationInWindow simulatePressure:NO];
+ // Make sure that we exceed the minimum 150ms delay between handling mousedown and drag when dragging a text selection.
+ [_webView setEventTimestampOffset:0.25];
[_webView mouseDragToPoint:[self locationInViewForCurrentProgress]];
[_webView waitForPendingMouseEvents];
@@ -186,6 +188,7 @@
[_webView waitForPendingMouseEvents];
TestWebKitAPI::Util::run(&_doneWaitingForDrop);
+ [_webView setEventTimestampOffset:0];
}
- (void)beginDraggingSessionInWebView:(DragAndDropTestWKWebView *)webView withItems:(NSArray<NSDraggingItem *> *)items source:(id<NSDraggingSource>)source