Changeset 216212 in webkit
- Timestamp:
- May 4, 2017 3:28:22 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 26 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r216209 r216212 1 2017-05-04 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 [WK2] Add support for keeping the selection in a focused editable element when dragging begins 4 https://bugs.webkit.org/show_bug.cgi?id=171585 5 <rdar://problem/31544320> 6 7 Reviewed by Beth Dakin and Zalan Bujtas. 8 9 Covered by 4 API tests. 10 11 * dom/DocumentMarker.h: 12 13 Introduces the DraggedContent DocumentMarker type, which applies to the Range in the DOM that is being used as 14 a drag source. Also adds DraggedContentData, which contains nodes found by the TextIterator in the process of 15 finding Ranges to mark. 16 17 (WebCore::DocumentMarker::AllMarkers::AllMarkers): 18 * dom/DocumentMarkerController.cpp: 19 (WebCore::DocumentMarkerController::addDraggedContentMarker): 20 (WebCore::shouldInsertAsSeparateMarker): 21 (WebCore::DocumentMarkerController::addMarker): 22 23 When adding DocumentMarkers of type DraggedContent, keep adjacent RenderReplaced elements separate, rather than 24 merging them into existing RenderedDocumentMarkers. This is because the data for each of these (i.e. the target 25 node) needs to be preserved. 26 27 (WebCore::DocumentMarkerController::markersFor): 28 29 Bail and return an empty list if the map of document markers cannot possibly contain a dragged content marker. 30 31 * dom/DocumentMarkerController.h: 32 * page/DragController.h: 33 * page/DragState.h: 34 35 Add draggedContentRange to DragState. This tracks the Range that is being dragged; it is created when the drag 36 session has begun, and ends when drag session finishes (either via WebPage::dragEnded or WebPage::dragCancelled). 37 38 * page/EventHandler.cpp: 39 (WebCore::repaintContentsOfRange): 40 (WebCore::EventHandler::dragCancelled): 41 42 Called when a drag is cancelled in the UI process without a session ever getting a chance to begin. We use this 43 as a hook to remove all DraggedContent document markers from the document of the dragged content range. 44 45 (WebCore::EventHandler::didStartDrag): 46 47 Called when a drag session has begun in the UI process. We use this as a hook to set up document markers for the 48 Range of content being dragged. 49 50 (WebCore::EventHandler::dragSourceEndedAt): 51 52 Called when a drag session ends. We use this as a hook to remove all DraggedContent document markers from the 53 document of the dragged content range. 54 55 (WebCore::EventHandler::draggedElement): 56 * page/EventHandler.h: 57 * page/FocusController.cpp: 58 (WebCore::shouldClearSelectionWhenChangingFocusedElement): 59 60 Prevent the selection from clearing when the previously focused element is editable and also contains the drag 61 source element. Ideally, we should experiment with clearing out the selection whenever the element is blurred 62 (and not have additional restrictions on editability and containing the drag source), but this change is much 63 riskier. 64 65 (WebCore::FocusController::setFocusedElement): 66 * rendering/InlineTextBox.cpp: 67 (WebCore::InlineTextBox::paint): 68 69 Use RenderText::draggedContentStartEnd to find the range of text (if any) that is dragged content, and paint 70 these ranges of text at a lower alpha using TextPainter::paintTextInRange. 71 72 * rendering/RenderReplaced.cpp: 73 (WebCore::draggedContentContainsReplacedElement): 74 75 Determines whether or not the element being rendered is contained within a dragged content range. Assuming that 76 the DraggedContent type flag is set in DocumentMarkerController, we first look to see whether or not the 77 container node is in the document marker map. If so, instead of consulting node offset ranges (since this is, in 78 the worst-case, linear in the number of sibling nodes per RenderReplaced) we simply check the DraggedContentData 79 to see if the current element being rendered matches one of the target nodes. 80 81 (WebCore::RenderReplaced::paint): 82 83 If the element rendered by this RenderReplaced is dragged content, then render it at a low alpha. 84 85 * rendering/RenderText.cpp: 86 (WebCore::RenderText::draggedContentRangesBetweenOffsets): 87 88 Determines what range of text, if any, contains dragged content by consulting the Document's DocumentMarkers. 89 90 * rendering/RenderText.h: 91 * rendering/TextPainter.cpp: 92 (WebCore::TextPainter::paintTextInRange): 93 94 Teach TextPainter to only paint a given range in a TextRun. 95 96 * rendering/TextPainter.h: 97 98 Add TextPainter support for specifying special text offset ranges when rendering a TextRun, such that each 99 special range in text is rendered after applying some modification to the GraphicsContext. 100 1 101 2017-05-04 Jeremy Jones <jeremyj@apple.com> 2 102 -
trunk/Source/WebCore/dom/DocumentMarker.h
r210216 r216212 20 20 21 21 #pragma once 22 23 #include "Node.h" 22 24 23 25 #include <wtf/Forward.h> … … 76 78 // This marker indicates that the user has selected a text candidate. 77 79 AcceptedCandidate = 1 << 13, 80 // This marker indicates that the user has initiated a drag with this content. 81 DraggedContent = 1 << 14 78 82 }; 79 83 … … 116 120 | DictationResult 117 121 #endif 122 | DraggedContent 118 123 ) 119 124 { … … 133 138 #endif 134 139 }; 135 using Data = Variant<IsActiveMatchData, DescriptionData, DictationData, DictationAlternativesData>; 140 struct DraggedContentData { 141 RefPtr<Node> targetNode; 142 }; 143 using Data = Variant<IsActiveMatchData, DescriptionData, DictationData, DictationAlternativesData, DraggedContentData>; 136 144 137 145 DocumentMarker(unsigned startOffset, unsigned endOffset, bool isActiveMatch); -
trunk/Source/WebCore/dom/DocumentMarkerController.cpp
r216019 r216212 136 136 #endif 137 137 138 void DocumentMarkerController::addDraggedContentMarker(RefPtr<Range> range) 139 { 140 for (TextIterator markedText(range.get()); !markedText.atEnd(); markedText.advance()) { 141 RefPtr<Range> textPiece = markedText.range(); 142 DocumentMarker::DraggedContentData draggedContentData { markedText.node() }; 143 addMarker(&textPiece->startContainer(), { DocumentMarker::DraggedContent, textPiece->startOffset(), textPiece->endOffset(), WTFMove(draggedContentData) }); 144 } 145 } 146 138 147 void DocumentMarkerController::removeMarkers(Range* range, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker) 139 148 { … … 294 303 } 295 304 305 static bool shouldInsertAsSeparateMarker(const DocumentMarker& newMarker) 306 { 307 #if PLATFORM(IOS) 308 if (newMarker.type() == DocumentMarker::DictationPhraseWithAlternatives || newMarker.type() == DocumentMarker::DictationResult) 309 return true; 310 #endif 311 if (newMarker.type() == DocumentMarker::DraggedContent) { 312 if (auto targetNode = WTF::get<DocumentMarker::DraggedContentData>(newMarker.data()).targetNode) 313 return targetNode->renderer() && targetNode->renderer()->isRenderReplaced(); 314 } 315 316 return false; 317 } 318 296 319 // Markers are stored in order sorted by their start offset. 297 320 // Markers of the same type do not overlap each other. … … 318 341 list = std::make_unique<MarkerList>(); 319 342 list->append(RenderedDocumentMarker(newMarker)); 320 #if PLATFORM(IOS) 321 } else if (newMarker.type() == DocumentMarker::DictationPhraseWithAlternatives || newMarker.type() == DocumentMarker::DictationResult) { 343 } else if (shouldInsertAsSeparateMarker(newMarker)) { 322 344 // We don't merge dictation markers. 323 345 size_t i; … … 329 351 } 330 352 list->insert(i, RenderedDocumentMarker(newMarker)); 331 #endif332 353 } else { 333 354 RenderedDocumentMarker toInsert(newMarker); … … 505 526 Vector<RenderedDocumentMarker*> DocumentMarkerController::markersFor(Node* node, DocumentMarker::MarkerTypes markerTypes) 506 527 { 528 if (!possiblyHasMarkers(markerTypes)) 529 return { }; 530 507 531 Vector<RenderedDocumentMarker*> result; 508 532 MarkerList* list = m_markers.get(node); -
trunk/Source/WebCore/dom/DocumentMarkerController.h
r216019 r216212 60 60 void addDictationResultMarker(Range*, const RetainPtr<id>& metadata); 61 61 #endif 62 void addDraggedContentMarker(RefPtr<Range>); 62 63 63 64 void copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta); -
trunk/Source/WebCore/page/DragController.h
r215917 r216212 63 63 WEBCORE_EXPORT DragOperation dragUpdated(const DragData&); 64 64 WEBCORE_EXPORT bool performDragOperation(const DragData&); 65 WEBCORE_EXPORT void dragCancelled(); 65 66 66 67 bool mouseIsOverFileInput() const { return m_fileInputElementUnderMouse; } -
trunk/Source/WebCore/page/DragState.h
r208179 r216212 35 35 struct DragState { 36 36 RefPtr<Element> source; // Element that may be a drag source, for the current mouse gesture. 37 RefPtr<Range> draggedContentRange; 37 38 bool shouldDispatchEvents; 38 39 DragSourceAction type; -
trunk/Source/WebCore/page/EventHandler.cpp
r215872 r216212 35 35 #include "ChromeClient.h" 36 36 #include "CursorList.h" 37 #include "DocumentMarkerController.h" 37 38 #include "DragController.h" 38 39 #include "DragState.h" … … 3452 3453 } 3453 3454 3455 static void repaintContentsOfRange(RefPtr<Range> range) 3456 { 3457 if (!range) 3458 return; 3459 3460 auto* container = range->commonAncestorContainer(); 3461 if (!container) 3462 return; 3463 3464 // This ensures that all nodes enclosed in this Range are repainted. 3465 if (auto rendererToRepaint = container->renderer()) { 3466 if (auto* containingRenderer = rendererToRepaint->container()) 3467 rendererToRepaint = containingRenderer; 3468 rendererToRepaint->repaint(); 3469 } 3470 } 3471 3472 void EventHandler::dragCancelled() 3473 { 3474 #if ENABLE(DATA_INTERACTION) 3475 if (auto range = dragState().draggedContentRange) { 3476 range->ownerDocument().markers().removeMarkers(DocumentMarker::DraggedContent); 3477 repaintContentsOfRange(range); 3478 } 3479 dragState().draggedContentRange = nullptr; 3480 #endif 3481 } 3482 3483 void EventHandler::didStartDrag() 3484 { 3485 #if ENABLE(DATA_INTERACTION) 3486 auto dragSource = dragState().source; 3487 if (!dragSource) 3488 return; 3489 3490 auto* renderer = dragSource->renderer(); 3491 if (!renderer) 3492 return; 3493 3494 if (dragState().type & DragSourceActionSelection) 3495 dragState().draggedContentRange = m_frame.selection().selection().toNormalizedRange(); 3496 else { 3497 Position startPosition(dragSource.get(), Position::PositionIsBeforeAnchor); 3498 Position endPosition(dragSource.get(), Position::PositionIsAfterAnchor); 3499 dragState().draggedContentRange = Range::create(dragSource->document(), startPosition, endPosition); 3500 } 3501 3502 if (auto range = dragState().draggedContentRange) { 3503 range->ownerDocument().markers().addDraggedContentMarker(range.get()); 3504 repaintContentsOfRange(range); 3505 } 3506 #endif 3507 } 3508 3454 3509 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation) 3455 3510 { … … 3464 3519 } 3465 3520 invalidateDataTransfer(); 3521 3522 if (auto range = dragState().draggedContentRange) { 3523 range->ownerDocument().markers().removeMarkers(DocumentMarker::DraggedContent); 3524 repaintContentsOfRange(range); 3525 } 3526 3466 3527 dragState().source = nullptr; 3467 3528 // In case the drag was ended due to an escape key press we need to ensure … … 3486 3547 { 3487 3548 return n && !(n & (n - 1)); 3549 } 3550 3551 RefPtr<Element> EventHandler::draggedElement() const 3552 { 3553 return dragState().source; 3488 3554 } 3489 3555 -
trunk/Source/WebCore/page/EventHandler.h
r215872 r216212 160 160 bool performDragAndDrop(const PlatformMouseEvent&, DataTransfer&); 161 161 void updateDragStateAfterEditDragIfNeeded(Element& rootEditableElement); 162 RefPtr<Element> draggedElement() const; 162 163 #endif 163 164 … … 254 255 WEBCORE_EXPORT bool eventMayStartDrag(const PlatformMouseEvent&) const; 255 256 257 WEBCORE_EXPORT void didStartDrag(); 258 WEBCORE_EXPORT void dragCancelled(); 256 259 WEBCORE_EXPORT void dragSourceEndedAt(const PlatformMouseEvent&, DragOperation); 257 260 #endif -
trunk/Source/WebCore/page/FocusController.cpp
r215173 r216212 766 766 } 767 767 768 static bool shouldClearSelectionWhenChangingFocusedElement(const Page& page, RefPtr<Element> oldFocusedElement, RefPtr<Element> newFocusedElement) 769 { 770 #if ENABLE(DATA_INTERACTION) 771 if (newFocusedElement || !oldFocusedElement) 772 return true; 773 774 // FIXME: These additional checks should not be necessary. We should consider generally keeping the selection whenever the 775 // focused element is blurred, with no new element taking focus. 776 if (!oldFocusedElement->isRootEditableElement() && !is<HTMLInputElement>(oldFocusedElement.get()) && !is<HTMLTextAreaElement>(oldFocusedElement.get())) 777 return true; 778 779 for (auto ancestor = page.mainFrame().eventHandler().draggedElement(); ancestor; ancestor = ancestor->parentOrShadowHostElement()) { 780 if (ancestor == oldFocusedElement) 781 return false; 782 } 783 #else 784 UNUSED_PARAM(page); 785 UNUSED_PARAM(oldFocusedElement); 786 UNUSED_PARAM(newFocusedElement); 787 #endif 788 return true; 789 } 790 768 791 bool FocusController::setFocusedElement(Element* element, Frame& newFocusedFrame, FocusDirection direction) 769 792 { … … 782 805 m_page.editorClient().willSetInputMethodState(); 783 806 784 clearSelectionIfNeeded(oldFocusedFrame.get(), &newFocusedFrame, element); 807 if (shouldClearSelectionWhenChangingFocusedElement(m_page, oldFocusedElement, element)) 808 clearSelectionIfNeeded(oldFocusedFrame.get(), &newFocusedFrame, element); 785 809 786 810 if (!element) { -
trunk/Source/WebCore/rendering/InlineTextBox.cpp
r213614 r216212 553 553 textPainter.addEmphasis(emphasisMark, emphasisMarkOffset, combinedText); 554 554 555 textPainter.paintText(textRun, length, boxRect, textOrigin, selectionStart, selectionEnd, paintSelectedTextOnly, paintSelectedTextSeparately, paintNonSelectedTextOnly); 555 auto draggedContentRanges = renderer().draggedContentRangesBetweenOffsets(m_start, m_start + m_len); 556 if (!draggedContentRanges.isEmpty() && !paintSelectedTextOnly && !paintNonSelectedTextOnly) { 557 // FIXME: Painting with text effects ranges currently only works if we're not also painting the selection. 558 // In the future, we may want to support this capability, but in the meantime, this isn't required by anything. 559 unsigned currentEnd = 0; 560 for (size_t index = 0; index < draggedContentRanges.size(); ++index) { 561 unsigned previousEnd = index ? std::min(draggedContentRanges[index - 1].second, length) : 0; 562 unsigned currentStart = draggedContentRanges[index].first - m_start; 563 currentEnd = std::min(draggedContentRanges[index].second - m_start, length); 564 565 if (previousEnd < currentStart) 566 textPainter.paintTextInRange(textRun, boxRect, textOrigin, previousEnd, currentStart); 567 568 if (currentStart < currentEnd) { 569 context.save(); 570 context.setAlpha(0.25); 571 textPainter.paintTextInRange(textRun, boxRect, textOrigin, currentStart, currentEnd); 572 context.restore(); 573 } 574 } 575 if (currentEnd < length) 576 textPainter.paintTextInRange(textRun, boxRect, textOrigin, currentEnd, length); 577 } else 578 textPainter.paintText(textRun, length, boxRect, textOrigin, selectionStart, selectionEnd, paintSelectedTextOnly, paintSelectedTextSeparately, paintNonSelectedTextOnly); 556 579 557 580 // Paint decorations -
trunk/Source/WebCore/rendering/RenderReplaced.cpp
r214082 r216212 25 25 #include "RenderReplaced.h" 26 26 27 #include "DocumentMarkerController.h" 27 28 #include "FloatRoundedRect.h" 28 29 #include "Frame.h" … … 38 39 #include "RenderTheme.h" 39 40 #include "RenderView.h" 41 #include "RenderedDocumentMarker.h" 40 42 #include "VisiblePosition.h" 41 43 #include <wtf/StackStats.h> … … 135 137 } 136 138 139 inline static bool draggedContentContainsReplacedElement(const Vector<RenderedDocumentMarker*>& markers, const Element& element) 140 { 141 if (markers.isEmpty()) 142 return false; 143 144 for (auto* marker : markers) { 145 auto& draggedContentData = WTF::get<DocumentMarker::DraggedContentData>(marker->data()); 146 if (draggedContentData.targetNode == &element) 147 return true; 148 } 149 150 return false; 151 } 152 137 153 void RenderReplaced::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 138 154 { … … 143 159 SetLayoutNeededForbiddenScope scope(this); 144 160 #endif 161 162 GraphicsContextStateSaver savedGraphicsContext(paintInfo.context()); 163 if (element() && element()->parentOrShadowHostElement()) { 164 auto* parentContainer = element()->parentOrShadowHostElement(); 165 if (draggedContentContainsReplacedElement(document().markers().markersFor(parentContainer, DocumentMarker::DraggedContent), *element())) 166 paintInfo.context().setAlpha(0.25); 167 } 168 145 169 LayoutPoint adjustedPaintOffset = paintOffset + location(); 146 170 -
trunk/Source/WebCore/rendering/RenderText.cpp
r216096 r216212 30 30 #include "BreakingContext.h" 31 31 #include "CharacterProperties.h" 32 #include "DocumentMarker.h" 33 #include "DocumentMarkerController.h" 32 34 #include "EllipsisBox.h" 33 35 #include "FloatQuad.h" … … 42 44 #include "RenderLayer.h" 43 45 #include "RenderView.h" 46 #include "RenderedDocumentMarker.h" 44 47 #include "Settings.h" 45 48 #include "SimpleLineLayoutFunctions.h" … … 1064 1067 } 1065 1068 1069 Vector<std::pair<unsigned, unsigned>> RenderText::draggedContentRangesBetweenOffsets(unsigned startOffset, unsigned endOffset) const 1070 { 1071 auto markers = document().markers().markersFor(textNode(), DocumentMarker::DraggedContent); 1072 if (markers.isEmpty()) 1073 return { }; 1074 1075 Vector<std::pair<unsigned, unsigned>> draggedContentRanges; 1076 for (auto* marker : markers) { 1077 unsigned markerStart = std::max(marker->startOffset(), startOffset); 1078 unsigned markerEnd = std::min(marker->endOffset(), endOffset); 1079 if (markerStart >= markerEnd || markerStart > endOffset || markerEnd < startOffset) 1080 continue; 1081 1082 std::pair<unsigned, unsigned> draggedContentRange; 1083 draggedContentRange.first = markerStart; 1084 draggedContentRange.second = markerEnd; 1085 draggedContentRanges.append(draggedContentRange); 1086 } 1087 return draggedContentRanges; 1088 } 1089 1066 1090 IntPoint RenderText::firstRunLocation() const 1067 1091 { -
trunk/Source/WebCore/rendering/RenderText.h
r213020 r216212 177 177 bool canUseSimplifiedTextMeasuring() const { return m_canUseSimplifiedTextMeasuring; } 178 178 179 Vector<std::pair<unsigned, unsigned>> draggedContentRangesBetweenOffsets(unsigned startOffset, unsigned endOffset) const; 180 179 181 protected: 180 182 virtual void computePreferredLogicalWidths(float leadWidth); -
trunk/Source/WebCore/rendering/TextPainter.cpp
r213614 r216212 169 169 m_context.concatCTM(rotation(boxRect, Counterclockwise)); 170 170 } 171 172 void TextPainter::paintTextInRange(const TextRun& textRun, const FloatRect& boxRect, const FloatPoint& textOrigin, unsigned start, unsigned end) 173 { 174 ASSERT(m_font); 175 ASSERT(start < end); 176 177 GraphicsContextStateSaver stateSaver(m_context, m_textPaintStyle.strokeWidth > 0); 178 updateGraphicsContext(m_context, m_textPaintStyle); 179 paintTextAndEmphasisMarksIfNeeded(textRun, boxRect, textOrigin, start, end, m_textPaintStyle, m_textShadow); 180 } 171 181 172 182 void TextPainter::paintText(const TextRun& textRun, unsigned length, const FloatRect& boxRect, const FloatPoint& textOrigin, unsigned selectionStart, unsigned selectionEnd, -
trunk/Source/WebCore/rendering/TextPainter.h
r213614 r216212 57 57 void addTextShadow(const ShadowData* textShadow, const ShadowData* selectionShadow); 58 58 59 void paintTextInRange(const TextRun&, const FloatRect& boxRect, const FloatPoint& textOrigin, unsigned start, unsigned end); 59 60 void paintText(const TextRun&, unsigned length, const FloatRect& boxRect, const FloatPoint& textOrigin, 60 61 unsigned selectionStart = 0, unsigned selectionEnd = 0, bool paintSelectedTextOnly = false, bool paintSelectedTextSeparately = false, bool paintNonSelectedTextOnly = false); -
trunk/Source/WebKit2/ChangeLog
r216206 r216212 1 2017-05-04 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 [WK2] Add support for keeping the selection in a focused editable element when dragging begins 4 https://bugs.webkit.org/show_bug.cgi?id=171585 5 <rdar://problem/31544320> 6 7 Reviewed by Beth Dakin and Zalan Bujtas. 8 9 Minor adjustments and refactoring in WebKit2. See WebCore ChangeLog for more details. 10 11 * UIProcess/WebPageProxy.cpp: 12 (WebKit::WebPageProxy::startDrag): 13 (WebKit::WebPageProxy::didStartDrag): 14 15 Factor out code in WebPageProxy that sends a WebPage::DidStartDrag message to the web process into a separate 16 helper, and tweak the places where we directly send this IPC message to the web process to instead call this 17 helper. 18 19 * UIProcess/WebPageProxy.h: 20 * UIProcess/mac/WebPageProxyMac.mm: 21 (WebKit::WebPageProxy::setDragImage): 22 * WebProcess/WebPage/WebPage.cpp: 23 (WebKit::WebPage::didStartDrag): 24 (WebKit::WebPage::dragCancelled): 25 26 Clear out state in the web process and call out to the EventHandler to handle drag cancellation and the drag 27 start response from the UI process. 28 29 * WebProcess/WebPage/WebPage.h: 30 (WebKit::WebPage::didStartDrag): Deleted. 31 (WebKit::WebPage::dragCancelled): Deleted. 32 1 33 2017-05-04 Sam Weinig <sam@webkit.org> 2 34 -
trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp
r216197 r216212 1820 1820 m_pageClient.startDrag(WTFMove(selection.selectionData), static_cast<WebCore::DragOperation>(dragOperation), WTFMove(dragImage)); 1821 1821 1822 m_process->send(Messages::WebPage::DidStartDrag(), m_pageID);1822 didStartDrag(); 1823 1823 } 1824 1824 #endif … … 1830 1830 m_process->send(Messages::WebPage::DragEnded(clientPosition, globalPosition, operation), m_pageID); 1831 1831 setDragCaretRect({ }); 1832 } 1833 1834 void WebPageProxy::didStartDrag() 1835 { 1836 if (isValid()) 1837 m_process->send(Messages::WebPage::DidStartDrag(), m_pageID); 1832 1838 } 1833 1839 -
trunk/Source/WebKit2/UIProcess/WebPageProxy.h
r216197 r216212 842 842 void didPerformDragControllerAction(uint64_t dragOperation, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, const WebCore::IntRect& insertionRect, bool isHandlingNonDefaultDrag); 843 843 void dragEnded(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition, uint64_t operation); 844 void didStartDrag(); 844 845 void dragCancelled(); 845 846 void setDragCaretRect(const WebCore::IntRect&); -
trunk/Source/WebKit2/UIProcess/mac/WebPageProxyMac.mm
r213902 r216212 275 275 m_pageClient.setDragImage(clientPosition, WTFMove(dragImage), static_cast<DragSourceAction>(action)); 276 276 277 process().send(Messages::WebPage::DidStartDrag(), m_pageID);277 didStartDrag(); 278 278 } 279 279 -
trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp
r216206 r216212 3656 3656 m_pendingDropExtensionsForFileUpload.clear(); 3657 3657 } 3658 3659 void WebPage::didStartDrag() 3660 { 3661 m_isStartingDrag = false; 3662 m_page->mainFrame().eventHandler().didStartDrag(); 3663 } 3664 3665 void WebPage::dragCancelled() 3666 { 3667 m_isStartingDrag = false; 3668 m_page->mainFrame().eventHandler().dragCancelled(); 3669 } 3658 3670 3659 3671 #endif // ENABLE(DRAG_SUPPORT) -
trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h
r216197 r216212 740 740 741 741 void willStartDrag() { ASSERT(!m_isStartingDrag); m_isStartingDrag = true; } 742 void didStartDrag() { ASSERT(m_isStartingDrag); m_isStartingDrag = false; }743 void dragCancelled() { m_isStartingDrag = false; }742 void didStartDrag(); 743 void dragCancelled(); 744 744 #endif // ENABLE(DRAG_SUPPORT) 745 745 -
trunk/Tools/ChangeLog
r216211 r216212 1 2017-05-04 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 [WK2] Add support for keeping the selection in a focused editable element when dragging begins 4 https://bugs.webkit.org/show_bug.cgi?id=171585 5 <rdar://problem/31544320> 6 7 Reviewed by Beth Dakin and Zalan Bujtas. 8 9 Adds 1 new unit test and tweaks existing tests to check that when first responder status is lost after beginning 10 a drag while editing, content is still moved (and not copied) when performing data interaction on a different 11 element. ContentEditableMoveParagraphs checks that content can be shifted within a single element via a move 12 operation rather than a copy. 13 14 See WebCore ChangeLog for more details. 15 16 Tests: DataInteractionSimulator.ContentEditableToContentEditable 17 DataInteractionSimulator.ContentEditableToTextarea 18 DataInteractionSimulator.ContentEditableMoveParagraphs 19 DataInteractionSimulator.TextAreaToInput 20 21 * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: 22 * TestWebKitAPI/Tests/WebKit2Cocoa/two-paragraph-contenteditable.html: Added. 23 * TestWebKitAPI/Tests/ios/DataInteractionTests.mm: 24 (TestWebKitAPI::TEST): 25 * TestWebKitAPI/ios/DataInteractionSimulator.h: 26 * TestWebKitAPI/ios/DataInteractionSimulator.mm: 27 (-[DataInteractionSimulator initWithWebView:]): 28 (-[DataInteractionSimulator dealloc]): 29 (-[DataInteractionSimulator _advanceProgress]): 30 (-[DataInteractionSimulator waitForInputSession]): 31 (-[DataInteractionSimulator _webView:focusShouldStartInputSession:]): 32 (-[DataInteractionSimulator _webView:didStartInputSession:]): 33 1 34 2017-05-04 Said Abou-Hallawa <sabouhallawa@apple.com> 2 35 -
trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
r216197 r216212 605 605 F415086D1DA040C50044BE9B /* play-audio-on-click.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F415086C1DA040C10044BE9B /* play-audio-on-click.html */; }; 606 606 F42DA5161D8CEFE400336F40 /* large-input-field-focus-onload.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F42DA5151D8CEFDB00336F40 /* large-input-field-focus-onload.html */; }; 607 F4451C761EB8FD890020C5DA /* two-paragraph-contenteditable.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4451C751EB8FD7C0020C5DA /* two-paragraph-contenteditable.html */; }; 607 608 F4538EF71E8473E600B5C953 /* large-red-square.png in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4538EF01E846B4100B5C953 /* large-red-square.png */; }; 608 609 F47728991E4AE3C1007ABF6A /* full-page-contenteditable.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F47728981E4AE3AD007ABF6A /* full-page-contenteditable.html */; }; … … 691 692 5797FE331EB15AB100B2F4A0 /* navigation-client-default-crypto.html in Copy Resources */, 692 693 0799C34B1EBA3301003B7532 /* disableGetUserMedia.html in Copy Resources */, 694 F4451C761EB8FD890020C5DA /* two-paragraph-contenteditable.html in Copy Resources */, 693 695 074994421EA5034B000DA44E /* getUserMedia.html in Copy Resources */, 694 696 C9BF06EF1E9C132500595E3E /* autoplay-muted-with-controls.html in Copy Resources */, … … 1507 1509 F415086C1DA040C10044BE9B /* play-audio-on-click.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "play-audio-on-click.html"; sourceTree = "<group>"; }; 1508 1510 F42DA5151D8CEFDB00336F40 /* large-input-field-focus-onload.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = "large-input-field-focus-onload.html"; path = "Tests/WebKit2Cocoa/large-input-field-focus-onload.html"; sourceTree = SOURCE_ROOT; }; 1511 F4451C751EB8FD7C0020C5DA /* two-paragraph-contenteditable.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "two-paragraph-contenteditable.html"; sourceTree = "<group>"; }; 1509 1512 F4538EF01E846B4100B5C953 /* large-red-square.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "large-red-square.png"; sourceTree = "<group>"; }; 1510 1513 F47728981E4AE3AD007ABF6A /* full-page-contenteditable.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "full-page-contenteditable.html"; sourceTree = "<group>"; }; … … 1967 1970 515BE16E1D4288FF00DD7C68 /* StoreBlobToBeDeleted.html */, 1968 1971 2E9896141D8F092B00739892 /* text-and-password-inputs.html */, 1972 F4451C751EB8FD7C0020C5DA /* two-paragraph-contenteditable.html */, 1969 1973 51714EB21CF8C761004723C4 /* WebProcessKillIDBCleanup-1.html */, 1970 1974 51714EB31CF8C761004723C4 /* WebProcessKillIDBCleanup-2.html */, -
trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm
r216203 r216212 163 163 { 164 164 RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]); 165 [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"]; 166 167 RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]); 165 RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]); 166 167 [webView loadTestPageNamed:@"autofocus-contenteditable"]; 168 [dataInteractionSimulator waitForInputSession]; 168 169 [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)]; 169 170 … … 182 183 { 183 184 RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]); 184 [webView synchronouslyLoadTestPageNamed:@"contenteditable-and-textarea"]; 185 186 RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]); 185 RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]); 186 187 [webView loadTestPageNamed:@"contenteditable-and-textarea"]; 188 [dataInteractionSimulator waitForInputSession]; 187 189 [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)]; 188 190 … … 198 200 } 199 201 202 TEST(DataInteractionTests, ContentEditableMoveParagraphs) 203 { 204 RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]); 205 RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]); 206 207 [webView loadTestPageNamed:@"two-paragraph-contenteditable"]; 208 [dataInteractionSimulator waitForInputSession]; 209 [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(250, 450)]; 210 211 NSString *finalTextContent = [webView stringByEvaluatingJavaScript:@"editor.textContent"]; 212 NSUInteger firstParagraphOffset = [finalTextContent rangeOfString:@"This is the first paragraph"].location; 213 NSUInteger secondParagraphOffset = [finalTextContent rangeOfString:@"This is the second paragraph"].location; 214 215 EXPECT_FALSE(firstParagraphOffset == NSNotFound); 216 EXPECT_FALSE(secondParagraphOffset == NSNotFound); 217 EXPECT_GT(firstParagraphOffset, secondParagraphOffset); 218 checkSelectionRectsWithLogging(@[ makeCGRectValue(190, 100, 130, 20), makeCGRectValue(0, 120, 320, 100), makeCGRectValue(0, 220, 252, 20) ], [dataInteractionSimulator finalSelectionRects]); 219 } 220 200 221 TEST(DataInteractionTests, TextAreaToInput) 201 222 { 202 223 RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]); 203 [webView synchronouslyLoadTestPageNamed:@"textarea-to-input"]; 204 205 RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]); 224 RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]); 225 226 [webView loadTestPageNamed:@"textarea-to-input"]; 227 [dataInteractionSimulator waitForInputSession]; 206 228 [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)]; 207 229 -
trunk/Tools/TestWebKitAPI/ios/DataInteractionSimulator.h
r215962 r216212 30 30 #import <UIKit/UIKit.h> 31 31 #import <WebKit/WKUIDelegatePrivate.h> 32 #import <WebKit/_WKInputDelegate.h> 32 33 #import <wtf/BlockPtr.h> 33 34 … … 49 50 }; 50 51 51 @interface DataInteractionSimulator : NSObject<WKUIDelegatePrivate> { 52 @interface DataInteractionSimulator : NSObject<WKUIDelegatePrivate, _WKInputDelegate> { 53 @private 52 54 RetainPtr<TestWKWebView> _webView; 53 55 RetainPtr<MockDataInteractionSession> _dataInteractionSession; … … 60 62 CGPoint _endLocation; 61 63 64 bool _isDoneWaitingForInputSession; 62 65 BOOL _shouldPerformOperation; 63 66 double _currentProgress; … … 68 71 - (instancetype)initWithWebView:(TestWKWebView *)webView; 69 72 - (void)runFrom:(CGPoint)startLocation to:(CGPoint)endLocation; 73 - (void)waitForInputSession; 70 74 75 @property (nonatomic) BOOL allowsFocusToStartInputSession; 71 76 @property (nonatomic) BOOL shouldEnsureUIApplication; 72 77 @property (nonatomic) BlockPtr<BOOL(_WKActivatedElementInfo *)> showCustomActionSheetBlock; -
trunk/Tools/TestWebKitAPI/ios/DataInteractionSimulator.mm
r215962 r216212 34 34 #import <WebCore/SoftLinking.h> 35 35 #import <WebKit/WKWebViewPrivate.h> 36 #import <WebKit/_WKFocusedElementInfo.h> 37 #import <WebKit/_WKFormInputSession.h> 36 38 #import <wtf/RetainPtr.h> 37 39 … … 76 78 _webView = webView; 77 79 _shouldEnsureUIApplication = NO; 80 _isDoneWaitingForInputSession = true; 78 81 [_webView setUIDelegate:self]; 82 [_webView _setInputDelegate:self]; 79 83 } 80 84 return self; … … 85 89 if ([_webView UIDelegate] == self) 86 90 [_webView setUIDelegate:nil]; 91 92 if ([_webView _inputDelegate] == self) 93 [_webView _setInputDelegate:nil]; 87 94 88 95 [super dealloc]; … … 218 225 219 226 [_webView _simulateWillBeginDataInteractionWithSession:_dataInteractionSession.get()]; 227 228 RetainPtr<WKWebView> retainedWebView = _webView; 229 dispatch_async(dispatch_get_main_queue(), ^() { 230 [retainedWebView resignFirstResponder]; 231 }); 232 220 233 _phase = DataInteractionBegan; 221 234 break; … … 268 281 } 269 282 283 - (void)waitForInputSession 284 { 285 _isDoneWaitingForInputSession = false; 286 287 // Waiting for an input session implies that we should allow input sessions to begin. 288 self.allowsFocusToStartInputSession = YES; 289 290 Util::run(&_isDoneWaitingForInputSession); 291 } 292 270 293 #pragma mark - WKUIDelegatePrivate 271 294 … … 304 327 } 305 328 329 #pragma mark - _WKInputDelegate 330 331 - (BOOL)_webView:(WKWebView *)webView focusShouldStartInputSession:(id <_WKFocusedElementInfo>)info 332 { 333 return _allowsFocusToStartInputSession; 334 } 335 336 - (void)_webView:(WKWebView *)webView didStartInputSession:(id <_WKFormInputSession>)inputSession 337 { 338 _isDoneWaitingForInputSession = true; 339 } 340 306 341 @end 307 342
Note: See TracChangeset
for help on using the changeset viewer.