https://bugs.webkit.org/show_bug.cgi?id=174017
<rdar://problem/
32959782>
Reviewed by Simon Fraser.
Source/WebCore:
We're currenly computing the drag caret rect (for the purposes of presentation at the client layers)
incorrectly, in per-frame document coordinates instead of root view coordinates in the mainframe. This means
drag caret geometry from embedded iframes in the document will show up in the content view with a rect in the
coordinate space of the iframe.
To fix this, we need to convert the drag caret rect to root view coordinates. This patch teaches
DragCaretController to do this, and tweaks WebKit/WebKit2 to use caretRectInRootViewCoordinates.
Test: DataInteractionTests.ExternalSourcePlainTextToIFrame
* editing/FrameSelection.cpp:
(WebCore::DragCaretController::caretRectInRootViewCoordinates):
* editing/FrameSelection.h:
Source/WebKit/mac:
Use root view coordinates when computing the drag caret rect.
* WebView/WebView.mm:
(-[WebView _dataInteractionCaretRect]):
Source/WebKit2:
Send the drag caret rect in root view coordinates over to the UI process.
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _dragCaretRect]):
* UIProcess/API/Cocoa/WKWebViewPrivate.h:
Add basic test plumbing to fetch the current drag caret rect.
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::performDragControllerAction):
Tools:
Add a new test verifying that the drag caret is visually contained within the bounds of an iframe. Before these
changes, the caret would appear outside of the iframe.
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKit2Cocoa/contenteditable-in-iframe.html: Added.
* TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
(checkDragCaretRectIsContainedInRect):
(TestWebKitAPI::TEST):
* TestWebKitAPI/ios/DataInteractionSimulator.h:
* TestWebKitAPI/ios/DataInteractionSimulator.mm:
(-[DataInteractionSimulator _resetSimulatedState]):
(-[DataInteractionSimulator _concludeDataInteractionAndPerformOperationIfNecessary]):
(-[DataInteractionSimulator _advanceProgress]):
(-[DataInteractionSimulator lastKnownDragCaretRect]):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@218998
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2017-06-30 Wenson Hsieh <wenson_hsieh@apple.com>
+
+ [iOS DnD] Drag caret rect is incorrectly computed when dropping in editable content in iframes
+ https://bugs.webkit.org/show_bug.cgi?id=174017
+ <rdar://problem/32959782>
+
+ Reviewed by Simon Fraser.
+
+ We're currenly computing the drag caret rect (for the purposes of presentation at the client layers)
+ incorrectly, in per-frame document coordinates instead of root view coordinates in the mainframe. This means
+ drag caret geometry from embedded iframes in the document will show up in the content view with a rect in the
+ coordinate space of the iframe.
+
+ To fix this, we need to convert the drag caret rect to root view coordinates. This patch teaches
+ DragCaretController to do this, and tweaks WebKit/WebKit2 to use caretRectInRootViewCoordinates.
+
+ Test: DataInteractionTests.ExternalSourcePlainTextToIFrame
+
+ * editing/FrameSelection.cpp:
+ (WebCore::DragCaretController::caretRectInRootViewCoordinates):
+ * editing/FrameSelection.h:
+
2017-06-30 Sam Weinig <sam@webkit.org>
[WebIDL] Replace use of __is_polymorphic with standard std::is_polymorphic<>::value
return isRichlyEditablePosition(m_position.deepEquivalent());
}
+IntRect DragCaretController::caretRectInRootViewCoordinates() const
+{
+ if (!hasCaret())
+ return { };
+
+ if (auto* document = m_position.deepEquivalent().document()) {
+ if (auto* documentView = document->view())
+ return documentView->contentsToRootView(m_position.absoluteCaretBounds());
+ }
+
+ return { };
+}
+
static inline bool shouldAlwaysUseDirectionalSelection(Frame* frame)
{
return !frame || frame->editor().behavior().shouldConsiderSelectionAsDirectional();
const VisiblePosition& caretPosition() { return m_position; }
void setCaretPosition(const VisiblePosition&);
void clear() { setCaretPosition(VisiblePosition()); }
+ WEBCORE_EXPORT IntRect caretRectInRootViewCoordinates() const;
void nodeWillBeRemoved(Node&);
+2017-06-30 Wenson Hsieh <wenson_hsieh@apple.com>
+
+ [iOS DnD] Drag caret rect is incorrectly computed when dropping in editable content in iframes
+ https://bugs.webkit.org/show_bug.cgi?id=174017
+ <rdar://problem/32959782>
+
+ Reviewed by Simon Fraser.
+
+ Use root view coordinates when computing the drag caret rect.
+
+ * WebView/WebView.mm:
+ (-[WebView _dataInteractionCaretRect]):
+
2017-06-28 Simon Fraser <simon.fraser@apple.com>
Mark the GraphicsContext as accelerated when the WebHTMLView's layer is drawing asynchronously
- (CGRect)_dataInteractionCaretRect
{
if (auto* page = _private->page)
- return page->dragCaretController().caretPosition().absoluteCaretBounds();
+ return page->dragCaretController().caretRectInRootViewCoordinates();
return { };
}
+2017-06-30 Wenson Hsieh <wenson_hsieh@apple.com>
+
+ [iOS DnD] Drag caret rect is incorrectly computed when dropping in editable content in iframes
+ https://bugs.webkit.org/show_bug.cgi?id=174017
+ <rdar://problem/32959782>
+
+ Reviewed by Simon Fraser.
+
+ Send the drag caret rect in root view coordinates over to the UI process.
+
+ * UIProcess/API/Cocoa/WKWebView.mm:
+ (-[WKWebView _dragCaretRect]):
+ * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+
+ Add basic test plumbing to fetch the current drag caret rect.
+
+ * WebProcess/WebPage/WebPage.cpp:
+ (WebKit::WebPage::performDragControllerAction):
+
2017-06-30 Youenn Fablet <youenn@apple.com>
Support PeerConnectionStates::BundlePolicy::MaxBundle when setting rtc configuration
#endif
}
+- (CGRect)_dragCaretRect
+{
+#if ENABLE(DRAG_SUPPORT)
+ return _page->currentDragCaretRect();
+#else
+ return CGRectZero;
+#endif
+}
+
- (void)_simulateLongPressActionAtLocation:(CGPoint)location
{
[_contentView _simulateLongPressActionAtLocation:location];
- (void)_simulatePrepareForDataInteractionSession:(id)session completion:(dispatch_block_t)completion WK_API_AVAILABLE(ios(WK_IOS_TBA));
- (void)_simulateLongPressActionAtLocation:(CGPoint)location;
+@property (nonatomic, readonly) CGRect _dragCaretRect WK_API_AVAILABLE(ios(WK_IOS_TBA));
+
- (_WKDraggableElementInfo *)_draggableElementAtPosition:(CGPoint)position WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
- (void)_requestDraggableElementAtPosition:(CGPoint)position completionBlock:(void (^)(_WKDraggableElementInfo *))block WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
switch (action) {
case DragControllerActionEntered: {
DragOperation resolvedDragOperation = m_page->dragController().dragEntered(dragData);
- send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted(), m_page->dragCaretController().caretPosition().absoluteCaretBounds()));
+ send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted(), m_page->dragCaretController().caretRectInRootViewCoordinates()));
break;
}
case DragControllerActionUpdated: {
DragOperation resolvedDragOperation = m_page->dragController().dragUpdated(dragData);
- send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted(), m_page->dragCaretController().caretPosition().absoluteCaretBounds()));
+ send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted(), m_page->dragCaretController().caretRectInRootViewCoordinates()));
break;
}
case DragControllerActionExited:
+2017-06-30 Wenson Hsieh <wenson_hsieh@apple.com>
+
+ [iOS DnD] Drag caret rect is incorrectly computed when dropping in editable content in iframes
+ https://bugs.webkit.org/show_bug.cgi?id=174017
+ <rdar://problem/32959782>
+
+ Reviewed by Simon Fraser.
+
+ Add a new test verifying that the drag caret is visually contained within the bounds of an iframe. Before these
+ changes, the caret would appear outside of the iframe.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebKit2Cocoa/contenteditable-in-iframe.html: Added.
+ * TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
+ (checkDragCaretRectIsContainedInRect):
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/ios/DataInteractionSimulator.h:
+ * TestWebKitAPI/ios/DataInteractionSimulator.mm:
+ (-[DataInteractionSimulator _resetSimulatedState]):
+ (-[DataInteractionSimulator _concludeDataInteractionAndPerformOperationIfNecessary]):
+ (-[DataInteractionSimulator _advanceProgress]):
+ (-[DataInteractionSimulator lastKnownDragCaretRect]):
+
2017-06-30 Jonathan Bedard <jbedard@apple.com>
Add support for different versions of iOS when loading test expectations
F47728991E4AE3C1007ABF6A /* full-page-contenteditable.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F47728981E4AE3AD007ABF6A /* full-page-contenteditable.html */; };
F4856CA31E649EA8009D7EE7 /* attachment-element.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4856CA21E6498A8009D7EE7 /* attachment-element.html */; };
F4A32EC41F05F3850047C544 /* dragstart-change-selection-offscreen.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4A32EC31F05F3780047C544 /* dragstart-change-selection-offscreen.html */; };
+ F4A32ECB1F0643370047C544 /* contenteditable-in-iframe.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4A32ECA1F0642F40047C544 /* contenteditable-in-iframe.html */; };
F4B825D81EF4DBFB006E417F /* compressed-files.zip in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4B825D61EF4DBD4006E417F /* compressed-files.zip */; };
F4BFA68E1E4AD08000154298 /* DragAndDropPasteboardTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4BFA68C1E4AD08000154298 /* DragAndDropPasteboardTests.mm */; };
F4C2AB221DD6D95E00E06D5B /* enormous-video-with-sound.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4C2AB211DD6D94100E06D5B /* enormous-video-with-sound.html */; };
dstSubfolderSpec = 7;
files = (
F4A32EC41F05F3850047C544 /* dragstart-change-selection-offscreen.html in Copy Resources */,
+ F4A32ECB1F0643370047C544 /* contenteditable-in-iframe.html in Copy Resources */,
F469FB241F01804B00401539 /* contenteditable-and-target.html in Copy Resources */,
F4B825D81EF4DBFB006E417F /* compressed-files.zip in Copy Resources */,
F41AB99F1EF4696B0083FA08 /* autofocus-contenteditable.html in Copy Resources */,
F47D30ED1ED28A6C000482E1 /* gif-and-file-input.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "gif-and-file-input.html"; sourceTree = "<group>"; };
F4856CA21E6498A8009D7EE7 /* attachment-element.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "attachment-element.html"; sourceTree = "<group>"; };
F4A32EC31F05F3780047C544 /* dragstart-change-selection-offscreen.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "dragstart-change-selection-offscreen.html"; sourceTree = "<group>"; };
+ F4A32ECA1F0642F40047C544 /* contenteditable-in-iframe.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "contenteditable-in-iframe.html"; sourceTree = "<group>"; };
F4B825D61EF4DBD4006E417F /* compressed-files.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = "compressed-files.zip"; sourceTree = "<group>"; };
F4BFA68C1E4AD08000154298 /* DragAndDropPasteboardTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DragAndDropPasteboardTests.mm; sourceTree = "<group>"; };
F4C2AB211DD6D94100E06D5B /* enormous-video-with-sound.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "enormous-video-with-sound.html"; sourceTree = "<group>"; };
F41AB9971EF4692C0083FA08 /* background-image-link-and-input.html */,
F469FB231F01803500401539 /* contenteditable-and-target.html */,
F41AB99C1EF4692C0083FA08 /* contenteditable-and-textarea.html */,
+ F4A32ECA1F0642F40047C544 /* contenteditable-in-iframe.html */,
F41AB99E1EF4692C0083FA08 /* div-and-large-image.html */,
F4A32EC31F05F3780047C544 /* dragstart-change-selection-offscreen.html */,
F41AB99B1EF4692C0083FA08 /* file-uploading.html */,
--- /dev/null
+<!DOCTYPE html>
+<html>
+<meta name="viewport" content="width=device-width">
+<style>
+body {
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ position: absolute;
+}
+#container {
+ width: calc(100% - 100px);
+ height: calc(100% - 100px);
+ margin: 50px;
+}
+#editor {
+ width: 100%;
+ height: 100%;
+}
+</style>
+<div id="container"><iframe id="editor" src="data:text/html,<body%20contenteditable%20style='width:%20100%;%20height:%20100%;%20margin:%200;'>"></iframe></div>
+</html>
}
}
+static void checkDragCaretRectIsContainedInRect(CGRect caretRect, CGRect containerRect)
+{
+ BOOL contained = CGRectContainsRect(containerRect, caretRect);
+ EXPECT_TRUE(contained);
+ if (!contained)
+ NSLog(@"Expected caret rect: %@ to fit within container rect: %@", NSStringFromCGRect(caretRect), NSStringFromCGRect(containerRect));
+}
+
namespace TestWebKitAPI {
TEST(DataInteractionTests, ImageToContentEditable)
checkSelectionRectsWithLogging(@[ ], [dataInteractionSimulator finalSelectionRects]);
}
+TEST(DataInteractionTests, ExternalSourcePlainTextToIFrame)
+{
+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+ [webView synchronouslyLoadTestPageNamed:@"contenteditable-in-iframe"];
+
+ auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
+ [itemProvider registerObject:@"Hello world" visibility:UIItemProviderRepresentationOptionsVisibilityAll];
+
+ auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+ [simulator setExternalItemProviders:@[ itemProvider.get() ]];
+ [simulator runFrom:CGPointMake(0, 0) to:CGPointMake(160, 250)];
+
+ auto containerLeft = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().left"].floatValue;
+ auto containerTop = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().top"].floatValue;
+ auto containerWidth = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().width"].floatValue;
+ auto containerHeight = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().height"].floatValue;
+ checkDragCaretRectIsContainedInRect([simulator lastKnownDragCaretRect], CGRectMake(containerLeft, containerTop, containerWidth, containerHeight));
+}
+
TEST(DataInteractionTests, ExternalSourceJSONToFileInput)
{
RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
RetainPtr<NSArray *> _finalSelectionRects;
CGPoint _startLocation;
CGPoint _endLocation;
+ CGRect _lastKnownDragCaretRect;
bool _isDoneWaitingForInputSession;
BOOL _shouldPerformOperation;
@property (nonatomic, readonly) NSArray *observedEventNames;
@property (nonatomic, readonly) NSArray *finalSelectionRects;
@property (nonatomic, readonly) DataInteractionPhase phase;
+@property (nonatomic, readonly) CGRect lastKnownDragCaretRect;
@end
_dataInteractionSession = nil;
_dataOperationSession = nil;
_shouldPerformOperation = NO;
+ _lastKnownDragCaretRect = CGRectZero;
}
- (NSArray *)observedEventNames
- (void)_concludeDataInteractionAndPerformOperationIfNecessary
{
+ _lastKnownDragCaretRect = [_webView _dragCaretRect];
if (_shouldPerformOperation) {
[_webView _simulateDataInteractionPerformOperation:_dataOperationSession.get()];
_phase = DataInteractionPerforming;
- (void)_advanceProgress
{
+ _lastKnownDragCaretRect = [_webView _dragCaretRect];
_currentProgress += progressIncrementStep;
CGPoint locationInWindow = self._currentLocation;
[_dataInteractionSession setMockLocationInWindow:locationInWindow];
return _phase;
}
+- (CGRect)lastKnownDragCaretRect
+{
+ return _lastKnownDragCaretRect;
+}
+
- (void)waitForInputSession
{
_isDoneWaitingForInputSession = false;