[WK2] Add support for keeping the selection in a focused editable element when draggi...
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 4 May 2017 22:28:22 +0000 (22:28 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 4 May 2017 22:28:22 +0000 (22:28 +0000)
commit3acff53741247cfaecc5b50bcd0dd924083d8b8c
tree00d08d8c745202e5ce42c25807e66d76467fd92b
parent8e8c3bd50ff88d0c568a6c415797ae8ee1473e09
[WK2] Add support for keeping the selection in a focused editable element when dragging begins
https://bugs.webkit.org/show_bug.cgi?id=171585
<rdar://problem/31544320>

Reviewed by Beth Dakin and Zalan Bujtas.

Source/WebCore:

Covered by 4 API tests.

* dom/DocumentMarker.h:

Introduces the DraggedContent DocumentMarker type, which applies to the Range in the DOM that is being used as
a drag source. Also adds DraggedContentData, which contains nodes found by the TextIterator in the process of
finding Ranges to mark.

(WebCore::DocumentMarker::AllMarkers::AllMarkers):
* dom/DocumentMarkerController.cpp:
(WebCore::DocumentMarkerController::addDraggedContentMarker):
(WebCore::shouldInsertAsSeparateMarker):
(WebCore::DocumentMarkerController::addMarker):

When adding DocumentMarkers of type DraggedContent, keep adjacent RenderReplaced elements separate, rather than
merging them into existing RenderedDocumentMarkers. This is because the data for each of these (i.e. the target
node) needs to be preserved.

(WebCore::DocumentMarkerController::markersFor):

Bail and return an empty list if the map of document markers cannot possibly contain a dragged content marker.

* dom/DocumentMarkerController.h:
* page/DragController.h:
* page/DragState.h:

Add draggedContentRange to DragState. This tracks the Range that is being dragged; it is created when the drag
session has begun, and ends when drag session finishes (either via WebPage::dragEnded or WebPage::dragCancelled).

* page/EventHandler.cpp:
(WebCore::repaintContentsOfRange):
(WebCore::EventHandler::dragCancelled):

Called when a drag is cancelled in the UI process without a session ever getting a chance to begin. We use this
as a hook to remove all DraggedContent document markers from the document of the dragged content range.

(WebCore::EventHandler::didStartDrag):

Called when a drag session has begun in the UI process. We use this as a hook to set up document markers for the
Range of content being dragged.

(WebCore::EventHandler::dragSourceEndedAt):

Called when a drag session ends. We use this as a hook to remove all DraggedContent document markers from the
document of the dragged content range.

(WebCore::EventHandler::draggedElement):
* page/EventHandler.h:
* page/FocusController.cpp:
(WebCore::shouldClearSelectionWhenChangingFocusedElement):

Prevent the selection from clearing when the previously focused element is editable and also contains the drag
source element. Ideally, we should experiment with clearing out the selection whenever the element is blurred
(and not have additional restrictions on editability and containing the drag source), but this change is much
riskier.

(WebCore::FocusController::setFocusedElement):
* rendering/InlineTextBox.cpp:
(WebCore::InlineTextBox::paint):

Use RenderText::draggedContentStartEnd to find the range of text (if any) that is dragged content, and paint
these ranges of text at a lower alpha using TextPainter::paintTextInRange.

* rendering/RenderReplaced.cpp:
(WebCore::draggedContentContainsReplacedElement):

Determines whether or not the element being rendered is contained within a dragged content range. Assuming that
the DraggedContent type flag is set in DocumentMarkerController, we first look to see whether or not the
container node is in the document marker map. If so, instead of consulting node offset ranges (since this is, in
the worst-case, linear in the number of sibling nodes per RenderReplaced) we simply check the DraggedContentData
to see if the current element being rendered matches one of the target nodes.

(WebCore::RenderReplaced::paint):

If the element rendered by this RenderReplaced is dragged content, then render it at a low alpha.

* rendering/RenderText.cpp:
(WebCore::RenderText::draggedContentRangesBetweenOffsets):

Determines what range of text, if any, contains dragged content by consulting the Document's DocumentMarkers.

* rendering/RenderText.h:
* rendering/TextPainter.cpp:
(WebCore::TextPainter::paintTextInRange):

Teach TextPainter to only paint a given range in a TextRun.

* rendering/TextPainter.h:

Add TextPainter support for specifying special text offset ranges when rendering a TextRun, such that each
special range in text is rendered after applying some modification to the GraphicsContext.

Source/WebKit2:

Minor adjustments and refactoring in WebKit2. See WebCore ChangeLog for more details.

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::startDrag):
(WebKit::WebPageProxy::didStartDrag):

Factor out code in WebPageProxy that sends a WebPage::DidStartDrag message to the web process into a separate
helper, and tweak the places where we directly send this IPC message to the web process to instead call this
helper.

* UIProcess/WebPageProxy.h:
* UIProcess/mac/WebPageProxyMac.mm:
(WebKit::WebPageProxy::setDragImage):
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::didStartDrag):
(WebKit::WebPage::dragCancelled):

Clear out state in the web process and call out to the EventHandler to handle drag cancellation and the drag
start response from the UI process.

* WebProcess/WebPage/WebPage.h:
(WebKit::WebPage::didStartDrag): Deleted.
(WebKit::WebPage::dragCancelled): Deleted.

Tools:

Adds 1 new unit test and tweaks existing tests to check that when first responder status is lost after beginning
a drag while editing, content is still moved (and not copied) when performing data interaction on a different
element. ContentEditableMoveParagraphs checks that content can be shifted within a single element via a move
operation rather than a copy.

See WebCore ChangeLog for more details.

Tests:  DataInteractionSimulator.ContentEditableToContentEditable
        DataInteractionSimulator.ContentEditableToTextarea
        DataInteractionSimulator.ContentEditableMoveParagraphs
        DataInteractionSimulator.TextAreaToInput

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKit2Cocoa/two-paragraph-contenteditable.html: Added.
* TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
(TestWebKitAPI::TEST):
* TestWebKitAPI/ios/DataInteractionSimulator.h:
* TestWebKitAPI/ios/DataInteractionSimulator.mm:
(-[DataInteractionSimulator initWithWebView:]):
(-[DataInteractionSimulator dealloc]):
(-[DataInteractionSimulator _advanceProgress]):
(-[DataInteractionSimulator waitForInputSession]):
(-[DataInteractionSimulator _webView:focusShouldStartInputSession:]):
(-[DataInteractionSimulator _webView:didStartInputSession:]):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@216212 268f45cc-cd09-0410-ab3c-d52691b4dbfc
27 files changed:
Source/WebCore/ChangeLog
Source/WebCore/dom/DocumentMarker.h
Source/WebCore/dom/DocumentMarkerController.cpp
Source/WebCore/dom/DocumentMarkerController.h
Source/WebCore/page/DragController.h
Source/WebCore/page/DragState.h
Source/WebCore/page/EventHandler.cpp
Source/WebCore/page/EventHandler.h
Source/WebCore/page/FocusController.cpp
Source/WebCore/rendering/InlineTextBox.cpp
Source/WebCore/rendering/RenderReplaced.cpp
Source/WebCore/rendering/RenderText.cpp
Source/WebCore/rendering/RenderText.h
Source/WebCore/rendering/TextPainter.cpp
Source/WebCore/rendering/TextPainter.h
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/WebPageProxy.cpp
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/UIProcess/mac/WebPageProxyMac.mm
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Source/WebKit2/WebProcess/WebPage/WebPage.h
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WebKit2Cocoa/two-paragraph-contenteditable.html [new file with mode: 0644]
Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm
Tools/TestWebKitAPI/ios/DataInteractionSimulator.h
Tools/TestWebKitAPI/ios/DataInteractionSimulator.mm