Diff
Modified: trunk/Source/WebCore/ChangeLog (216211 => 216212)
--- trunk/Source/WebCore/ChangeLog 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebCore/ChangeLog 2017-05-04 22:28:22 UTC (rev 216212)
@@ -1,3 +1,103 @@
+2017-05-04 Wenson Hsieh <[email protected]>
+
+ [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.
+
+ 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.
+
2017-05-04 Jeremy Jones <[email protected]>
Crash when pointer lock element is removed before pointer lock allowed arrives.
Modified: trunk/Source/WebCore/dom/DocumentMarker.h (216211 => 216212)
--- trunk/Source/WebCore/dom/DocumentMarker.h 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebCore/dom/DocumentMarker.h 2017-05-04 22:28:22 UTC (rev 216212)
@@ -20,6 +20,8 @@
#pragma once
+#include "Node.h"
+
#include <wtf/Forward.h>
#include <wtf/Variant.h>
#include <wtf/text/WTFString.h>
@@ -75,6 +77,8 @@
#endif
// This marker indicates that the user has selected a text candidate.
AcceptedCandidate = 1 << 13,
+ // This marker indicates that the user has initiated a drag with this content.
+ DraggedContent = 1 << 14
};
class MarkerTypes {
@@ -115,6 +119,7 @@
| DictationPhraseWithAlternatives
| DictationResult
#endif
+ | DraggedContent
)
{
}
@@ -132,7 +137,10 @@
RetainPtr<id> metadata;
#endif
};
- using Data = "" DescriptionData, DictationData, DictationAlternativesData>;
+ struct DraggedContentData {
+ RefPtr<Node> targetNode;
+ };
+ using Data = "" DescriptionData, DictationData, DictationAlternativesData, DraggedContentData>;
DocumentMarker(unsigned startOffset, unsigned endOffset, bool isActiveMatch);
DocumentMarker(MarkerType, unsigned startOffset, unsigned endOffset, const String& description = String());
Modified: trunk/Source/WebCore/dom/DocumentMarkerController.cpp (216211 => 216212)
--- trunk/Source/WebCore/dom/DocumentMarkerController.cpp 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebCore/dom/DocumentMarkerController.cpp 2017-05-04 22:28:22 UTC (rev 216212)
@@ -135,6 +135,15 @@
#endif
+void DocumentMarkerController::addDraggedContentMarker(RefPtr<Range> range)
+{
+ for (TextIterator markedText(range.get()); !markedText.atEnd(); markedText.advance()) {
+ RefPtr<Range> textPiece = markedText.range();
+ DocumentMarker::DraggedContentData draggedContentData { markedText.node() };
+ addMarker(&textPiece->startContainer(), { DocumentMarker::DraggedContent, textPiece->startOffset(), textPiece->endOffset(), WTFMove(draggedContentData) });
+ }
+}
+
void DocumentMarkerController::removeMarkers(Range* range, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker)
{
for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) {
@@ -293,6 +302,20 @@
return result;
}
+static bool shouldInsertAsSeparateMarker(const DocumentMarker& newMarker)
+{
+#if PLATFORM(IOS)
+ if (newMarker.type() == DocumentMarker::DictationPhraseWithAlternatives || newMarker.type() == DocumentMarker::DictationResult)
+ return true;
+#endif
+ if (newMarker.type() == DocumentMarker::DraggedContent) {
+ if (auto targetNode = WTF::get<DocumentMarker::DraggedContentData>(newMarker.data()).targetNode)
+ return targetNode->renderer() && targetNode->renderer()->isRenderReplaced();
+ }
+
+ return false;
+}
+
// Markers are stored in order sorted by their start offset.
// Markers of the same type do not overlap each other.
@@ -317,8 +340,7 @@
if (!list) {
list = std::make_unique<MarkerList>();
list->append(RenderedDocumentMarker(newMarker));
-#if PLATFORM(IOS)
- } else if (newMarker.type() == DocumentMarker::DictationPhraseWithAlternatives || newMarker.type() == DocumentMarker::DictationResult) {
+ } else if (shouldInsertAsSeparateMarker(newMarker)) {
// We don't merge dictation markers.
size_t i;
size_t numberOfMarkers = list->size();
@@ -328,7 +350,6 @@
break;
}
list->insert(i, RenderedDocumentMarker(newMarker));
-#endif
} else {
RenderedDocumentMarker toInsert(newMarker);
size_t numMarkers = list->size();
@@ -504,6 +525,9 @@
Vector<RenderedDocumentMarker*> DocumentMarkerController::markersFor(Node* node, DocumentMarker::MarkerTypes markerTypes)
{
+ if (!possiblyHasMarkers(markerTypes))
+ return { };
+
Vector<RenderedDocumentMarker*> result;
MarkerList* list = m_markers.get(node);
if (!list)
Modified: trunk/Source/WebCore/dom/DocumentMarkerController.h (216211 => 216212)
--- trunk/Source/WebCore/dom/DocumentMarkerController.h 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebCore/dom/DocumentMarkerController.h 2017-05-04 22:28:22 UTC (rev 216212)
@@ -59,6 +59,7 @@
void addDictationPhraseWithAlternativesMarker(Range*, const Vector<String>& interpretations);
void addDictationResultMarker(Range*, const RetainPtr<id>& metadata);
#endif
+ void addDraggedContentMarker(RefPtr<Range>);
void copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta);
bool hasMarkers() const
Modified: trunk/Source/WebCore/page/DragController.h (216211 => 216212)
--- trunk/Source/WebCore/page/DragController.h 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebCore/page/DragController.h 2017-05-04 22:28:22 UTC (rev 216212)
@@ -62,6 +62,7 @@
WEBCORE_EXPORT void dragExited(const DragData&);
WEBCORE_EXPORT DragOperation dragUpdated(const DragData&);
WEBCORE_EXPORT bool performDragOperation(const DragData&);
+ WEBCORE_EXPORT void dragCancelled();
bool mouseIsOverFileInput() const { return m_fileInputElementUnderMouse; }
unsigned numberOfItemsToBeAccepted() const { return m_numberOfItemsToBeAccepted; }
Modified: trunk/Source/WebCore/page/DragState.h (216211 => 216212)
--- trunk/Source/WebCore/page/DragState.h 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebCore/page/DragState.h 2017-05-04 22:28:22 UTC (rev 216212)
@@ -34,6 +34,7 @@
struct DragState {
RefPtr<Element> source; // Element that may be a drag source, for the current mouse gesture.
+ RefPtr<Range> draggedContentRange;
bool shouldDispatchEvents;
DragSourceAction type;
RefPtr<DataTransfer> dataTransfer; // Used on only the source side of dragging.
Modified: trunk/Source/WebCore/page/EventHandler.cpp (216211 => 216212)
--- trunk/Source/WebCore/page/EventHandler.cpp 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebCore/page/EventHandler.cpp 2017-05-04 22:28:22 UTC (rev 216212)
@@ -34,6 +34,7 @@
#include "Chrome.h"
#include "ChromeClient.h"
#include "CursorList.h"
+#include "DocumentMarkerController.h"
#include "DragController.h"
#include "DragState.h"
#include "Editing.h"
@@ -3451,6 +3452,60 @@
dragState().dataTransfer = nullptr;
}
+static void repaintContentsOfRange(RefPtr<Range> range)
+{
+ if (!range)
+ return;
+
+ auto* container = range->commonAncestorContainer();
+ if (!container)
+ return;
+
+ // This ensures that all nodes enclosed in this Range are repainted.
+ if (auto rendererToRepaint = container->renderer()) {
+ if (auto* containingRenderer = rendererToRepaint->container())
+ rendererToRepaint = containingRenderer;
+ rendererToRepaint->repaint();
+ }
+}
+
+void EventHandler::dragCancelled()
+{
+#if ENABLE(DATA_INTERACTION)
+ if (auto range = dragState().draggedContentRange) {
+ range->ownerDocument().markers().removeMarkers(DocumentMarker::DraggedContent);
+ repaintContentsOfRange(range);
+ }
+ dragState().draggedContentRange = nullptr;
+#endif
+}
+
+void EventHandler::didStartDrag()
+{
+#if ENABLE(DATA_INTERACTION)
+ auto dragSource = dragState().source;
+ if (!dragSource)
+ return;
+
+ auto* renderer = dragSource->renderer();
+ if (!renderer)
+ return;
+
+ if (dragState().type & DragSourceActionSelection)
+ dragState().draggedContentRange = m_frame.selection().selection().toNormalizedRange();
+ else {
+ Position startPosition(dragSource.get(), Position::PositionIsBeforeAnchor);
+ Position endPosition(dragSource.get(), Position::PositionIsAfterAnchor);
+ dragState().draggedContentRange = Range::create(dragSource->document(), startPosition, endPosition);
+ }
+
+ if (auto range = dragState().draggedContentRange) {
+ range->ownerDocument().markers().addDraggedContentMarker(range.get());
+ repaintContentsOfRange(range);
+ }
+#endif
+}
+
void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
{
// Send a hit test request so that RenderLayer gets a chance to update the :hover and :active pseudoclasses.
@@ -3463,6 +3518,12 @@
dispatchDragSrcEvent(eventNames().dragendEvent, event);
}
invalidateDataTransfer();
+
+ if (auto range = dragState().draggedContentRange) {
+ range->ownerDocument().markers().removeMarkers(DocumentMarker::DraggedContent);
+ repaintContentsOfRange(range);
+ }
+
dragState().source = nullptr;
// In case the drag was ended due to an escape key press we need to ensure
// that consecutive mousemove events don't reinitiate the drag and drop.
@@ -3487,6 +3548,11 @@
return n && !(n & (n - 1));
}
+RefPtr<Element> EventHandler::draggedElement() const
+{
+ return dragState().source;
+}
+
bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDragHysteresis checkDragHysteresis)
{
if (event.event().button() != LeftButton || event.event().type() != PlatformEvent::MouseMoved) {
Modified: trunk/Source/WebCore/page/EventHandler.h (216211 => 216212)
--- trunk/Source/WebCore/page/EventHandler.h 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebCore/page/EventHandler.h 2017-05-04 22:28:22 UTC (rev 216212)
@@ -159,6 +159,7 @@
void cancelDragAndDrop(const PlatformMouseEvent&, DataTransfer&);
bool performDragAndDrop(const PlatformMouseEvent&, DataTransfer&);
void updateDragStateAfterEditDragIfNeeded(Element& rootEditableElement);
+ RefPtr<Element> draggedElement() const;
#endif
void scheduleHoverStateUpdate();
@@ -253,6 +254,8 @@
#if ENABLE(DRAG_SUPPORT)
WEBCORE_EXPORT bool eventMayStartDrag(const PlatformMouseEvent&) const;
+ WEBCORE_EXPORT void didStartDrag();
+ WEBCORE_EXPORT void dragCancelled();
WEBCORE_EXPORT void dragSourceEndedAt(const PlatformMouseEvent&, DragOperation);
#endif
Modified: trunk/Source/WebCore/page/FocusController.cpp (216211 => 216212)
--- trunk/Source/WebCore/page/FocusController.cpp 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebCore/page/FocusController.cpp 2017-05-04 22:28:22 UTC (rev 216212)
@@ -765,6 +765,29 @@
oldFocusedFrame->selection().clear();
}
+static bool shouldClearSelectionWhenChangingFocusedElement(const Page& page, RefPtr<Element> oldFocusedElement, RefPtr<Element> newFocusedElement)
+{
+#if ENABLE(DATA_INTERACTION)
+ if (newFocusedElement || !oldFocusedElement)
+ return true;
+
+ // FIXME: These additional checks should not be necessary. We should consider generally keeping the selection whenever the
+ // focused element is blurred, with no new element taking focus.
+ if (!oldFocusedElement->isRootEditableElement() && !is<HTMLInputElement>(oldFocusedElement.get()) && !is<HTMLTextAreaElement>(oldFocusedElement.get()))
+ return true;
+
+ for (auto ancestor = page.mainFrame().eventHandler().draggedElement(); ancestor; ancestor = ancestor->parentOrShadowHostElement()) {
+ if (ancestor == oldFocusedElement)
+ return false;
+ }
+#else
+ UNUSED_PARAM(page);
+ UNUSED_PARAM(oldFocusedElement);
+ UNUSED_PARAM(newFocusedElement);
+#endif
+ return true;
+}
+
bool FocusController::setFocusedElement(Element* element, Frame& newFocusedFrame, FocusDirection direction)
{
Ref<Frame> protectedNewFocusedFrame = newFocusedFrame;
@@ -781,7 +804,8 @@
m_page.editorClient().willSetInputMethodState();
- clearSelectionIfNeeded(oldFocusedFrame.get(), &newFocusedFrame, element);
+ if (shouldClearSelectionWhenChangingFocusedElement(m_page, oldFocusedElement, element))
+ clearSelectionIfNeeded(oldFocusedFrame.get(), &newFocusedFrame, element);
if (!element) {
if (oldDocument)
Modified: trunk/Source/WebCore/rendering/InlineTextBox.cpp (216211 => 216212)
--- trunk/Source/WebCore/rendering/InlineTextBox.cpp 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebCore/rendering/InlineTextBox.cpp 2017-05-04 22:28:22 UTC (rev 216212)
@@ -552,8 +552,31 @@
textPainter.addTextShadow(textShadow, selectionShadow);
textPainter.addEmphasis(emphasisMark, emphasisMarkOffset, combinedText);
- textPainter.paintText(textRun, length, boxRect, textOrigin, selectionStart, selectionEnd, paintSelectedTextOnly, paintSelectedTextSeparately, paintNonSelectedTextOnly);
+ auto draggedContentRanges = renderer().draggedContentRangesBetweenOffsets(m_start, m_start + m_len);
+ if (!draggedContentRanges.isEmpty() && !paintSelectedTextOnly && !paintNonSelectedTextOnly) {
+ // FIXME: Painting with text effects ranges currently only works if we're not also painting the selection.
+ // In the future, we may want to support this capability, but in the meantime, this isn't required by anything.
+ unsigned currentEnd = 0;
+ for (size_t index = 0; index < draggedContentRanges.size(); ++index) {
+ unsigned previousEnd = index ? std::min(draggedContentRanges[index - 1].second, length) : 0;
+ unsigned currentStart = draggedContentRanges[index].first - m_start;
+ currentEnd = std::min(draggedContentRanges[index].second - m_start, length);
+ if (previousEnd < currentStart)
+ textPainter.paintTextInRange(textRun, boxRect, textOrigin, previousEnd, currentStart);
+
+ if (currentStart < currentEnd) {
+ context.save();
+ context.setAlpha(0.25);
+ textPainter.paintTextInRange(textRun, boxRect, textOrigin, currentStart, currentEnd);
+ context.restore();
+ }
+ }
+ if (currentEnd < length)
+ textPainter.paintTextInRange(textRun, boxRect, textOrigin, currentEnd, length);
+ } else
+ textPainter.paintText(textRun, length, boxRect, textOrigin, selectionStart, selectionEnd, paintSelectedTextOnly, paintSelectedTextSeparately, paintNonSelectedTextOnly);
+
// Paint decorations
TextDecoration textDecorations = lineStyle.textDecorationsInEffect();
if (textDecorations != TextDecorationNone && paintInfo.phase != PaintPhaseSelection) {
Modified: trunk/Source/WebCore/rendering/RenderReplaced.cpp (216211 => 216212)
--- trunk/Source/WebCore/rendering/RenderReplaced.cpp 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebCore/rendering/RenderReplaced.cpp 2017-05-04 22:28:22 UTC (rev 216212)
@@ -24,6 +24,7 @@
#include "config.h"
#include "RenderReplaced.h"
+#include "DocumentMarkerController.h"
#include "FloatRoundedRect.h"
#include "Frame.h"
#include "GraphicsContext.h"
@@ -37,6 +38,7 @@
#include "RenderNamedFlowFragment.h"
#include "RenderTheme.h"
#include "RenderView.h"
+#include "RenderedDocumentMarker.h"
#include "VisiblePosition.h"
#include <wtf/StackStats.h>
@@ -134,6 +136,20 @@
return selectionState() != SelectionNone && !document().printing();
}
+inline static bool draggedContentContainsReplacedElement(const Vector<RenderedDocumentMarker*>& markers, const Element& element)
+{
+ if (markers.isEmpty())
+ return false;
+
+ for (auto* marker : markers) {
+ auto& draggedContentData = WTF::get<DocumentMarker::DraggedContentData>(marker->data());
+ if (draggedContentData.targetNode == &element)
+ return true;
+ }
+
+ return false;
+}
+
void RenderReplaced::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
if (!shouldPaint(paintInfo, paintOffset))
@@ -142,6 +158,14 @@
#ifndef NDEBUG
SetLayoutNeededForbiddenScope scope(this);
#endif
+
+ GraphicsContextStateSaver savedGraphicsContext(paintInfo.context());
+ if (element() && element()->parentOrShadowHostElement()) {
+ auto* parentContainer = element()->parentOrShadowHostElement();
+ if (draggedContentContainsReplacedElement(document().markers().markersFor(parentContainer, DocumentMarker::DraggedContent), *element()))
+ paintInfo.context().setAlpha(0.25);
+ }
+
LayoutPoint adjustedPaintOffset = paintOffset + location();
if (hasVisibleBoxDecorations() && paintInfo.phase == PaintPhaseForeground)
Modified: trunk/Source/WebCore/rendering/RenderText.cpp (216211 => 216212)
--- trunk/Source/WebCore/rendering/RenderText.cpp 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebCore/rendering/RenderText.cpp 2017-05-04 22:28:22 UTC (rev 216212)
@@ -29,6 +29,8 @@
#include "BreakLines.h"
#include "BreakingContext.h"
#include "CharacterProperties.h"
+#include "DocumentMarker.h"
+#include "DocumentMarkerController.h"
#include "EllipsisBox.h"
#include "FloatQuad.h"
#include "Frame.h"
@@ -41,6 +43,7 @@
#include "RenderInline.h"
#include "RenderLayer.h"
#include "RenderView.h"
+#include "RenderedDocumentMarker.h"
#include "Settings.h"
#include "SimpleLineLayoutFunctions.h"
#include "Text.h"
@@ -1063,6 +1066,27 @@
return currPos >= (from + len);
}
+Vector<std::pair<unsigned, unsigned>> RenderText::draggedContentRangesBetweenOffsets(unsigned startOffset, unsigned endOffset) const
+{
+ auto markers = document().markers().markersFor(textNode(), DocumentMarker::DraggedContent);
+ if (markers.isEmpty())
+ return { };
+
+ Vector<std::pair<unsigned, unsigned>> draggedContentRanges;
+ for (auto* marker : markers) {
+ unsigned markerStart = std::max(marker->startOffset(), startOffset);
+ unsigned markerEnd = std::min(marker->endOffset(), endOffset);
+ if (markerStart >= markerEnd || markerStart > endOffset || markerEnd < startOffset)
+ continue;
+
+ std::pair<unsigned, unsigned> draggedContentRange;
+ draggedContentRange.first = markerStart;
+ draggedContentRange.second = markerEnd;
+ draggedContentRanges.append(draggedContentRange);
+ }
+ return draggedContentRanges;
+}
+
IntPoint RenderText::firstRunLocation() const
{
if (auto* layout = simpleLineLayout())
Modified: trunk/Source/WebCore/rendering/RenderText.h (216211 => 216212)
--- trunk/Source/WebCore/rendering/RenderText.h 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebCore/rendering/RenderText.h 2017-05-04 22:28:22 UTC (rev 216212)
@@ -176,6 +176,8 @@
bool canUseSimplifiedTextMeasuring() const { return m_canUseSimplifiedTextMeasuring; }
+ Vector<std::pair<unsigned, unsigned>> draggedContentRangesBetweenOffsets(unsigned startOffset, unsigned endOffset) const;
+
protected:
virtual void computePreferredLogicalWidths(float leadWidth);
void willBeDestroyed() override;
Modified: trunk/Source/WebCore/rendering/TextPainter.cpp (216211 => 216212)
--- trunk/Source/WebCore/rendering/TextPainter.cpp 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebCore/rendering/TextPainter.cpp 2017-05-04 22:28:22 UTC (rev 216212)
@@ -168,6 +168,16 @@
if (m_combinedText)
m_context.concatCTM(rotation(boxRect, Counterclockwise));
}
+
+void TextPainter::paintTextInRange(const TextRun& textRun, const FloatRect& boxRect, const FloatPoint& textOrigin, unsigned start, unsigned end)
+{
+ ASSERT(m_font);
+ ASSERT(start < end);
+
+ GraphicsContextStateSaver stateSaver(m_context, m_textPaintStyle.strokeWidth > 0);
+ updateGraphicsContext(m_context, m_textPaintStyle);
+ paintTextAndEmphasisMarksIfNeeded(textRun, boxRect, textOrigin, start, end, m_textPaintStyle, m_textShadow);
+}
void TextPainter::paintText(const TextRun& textRun, unsigned length, const FloatRect& boxRect, const FloatPoint& textOrigin, unsigned selectionStart, unsigned selectionEnd,
bool paintSelectedTextOnly, bool paintSelectedTextSeparately, bool paintNonSelectedTextOnly)
Modified: trunk/Source/WebCore/rendering/TextPainter.h (216211 => 216212)
--- trunk/Source/WebCore/rendering/TextPainter.h 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebCore/rendering/TextPainter.h 2017-05-04 22:28:22 UTC (rev 216212)
@@ -56,6 +56,7 @@
void addEmphasis(const AtomicString& emphasisMark, float emphasisMarkOffset, RenderCombineText*);
void addTextShadow(const ShadowData* textShadow, const ShadowData* selectionShadow);
+ void paintTextInRange(const TextRun&, const FloatRect& boxRect, const FloatPoint& textOrigin, unsigned start, unsigned end);
void paintText(const TextRun&, unsigned length, const FloatRect& boxRect, const FloatPoint& textOrigin,
unsigned selectionStart = 0, unsigned selectionEnd = 0, bool paintSelectedTextOnly = false, bool paintSelectedTextSeparately = false, bool paintNonSelectedTextOnly = false);
Modified: trunk/Source/WebKit2/ChangeLog (216211 => 216212)
--- trunk/Source/WebKit2/ChangeLog 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebKit2/ChangeLog 2017-05-04 22:28:22 UTC (rev 216212)
@@ -1,3 +1,35 @@
+2017-05-04 Wenson Hsieh <[email protected]>
+
+ [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.
+
+ 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.
+
2017-05-04 Sam Weinig <[email protected]>
Remove support for legacy Notifications
Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp (216211 => 216212)
--- trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp 2017-05-04 22:28:22 UTC (rev 216212)
@@ -1819,7 +1819,7 @@
RefPtr<ShareableBitmap> dragImage = !dragImageHandle.isNull() ? ShareableBitmap::create(dragImageHandle) : nullptr;
m_pageClient.startDrag(WTFMove(selection.selectionData), static_cast<WebCore::DragOperation>(dragOperation), WTFMove(dragImage));
- m_process->send(Messages::WebPage::DidStartDrag(), m_pageID);
+ didStartDrag();
}
#endif
@@ -1830,6 +1830,12 @@
m_process->send(Messages::WebPage::DragEnded(clientPosition, globalPosition, operation), m_pageID);
setDragCaretRect({ });
}
+
+void WebPageProxy::didStartDrag()
+{
+ if (isValid())
+ m_process->send(Messages::WebPage::DidStartDrag(), m_pageID);
+}
void WebPageProxy::dragCancelled()
{
Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.h (216211 => 216212)
--- trunk/Source/WebKit2/UIProcess/WebPageProxy.h 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.h 2017-05-04 22:28:22 UTC (rev 216212)
@@ -841,6 +841,7 @@
void didPerformDragControllerAction(uint64_t dragOperation, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, const WebCore::IntRect& insertionRect, bool isHandlingNonDefaultDrag);
void dragEnded(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition, uint64_t operation);
+ void didStartDrag();
void dragCancelled();
void setDragCaretRect(const WebCore::IntRect&);
#if PLATFORM(COCOA)
Modified: trunk/Source/WebKit2/UIProcess/mac/WebPageProxyMac.mm (216211 => 216212)
--- trunk/Source/WebKit2/UIProcess/mac/WebPageProxyMac.mm 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebKit2/UIProcess/mac/WebPageProxyMac.mm 2017-05-04 22:28:22 UTC (rev 216212)
@@ -274,7 +274,7 @@
if (auto dragImage = ShareableBitmap::create(dragImageHandle))
m_pageClient.setDragImage(clientPosition, WTFMove(dragImage), static_cast<DragSourceAction>(action));
- process().send(Messages::WebPage::DidStartDrag(), m_pageID);
+ didStartDrag();
}
void WebPageProxy::setPromisedDataForImage(const String& pasteboardName, const SharedMemory::Handle& imageHandle, uint64_t imageSize, const String& filename, const String& extension,
Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp (216211 => 216212)
--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp 2017-05-04 22:28:22 UTC (rev 216212)
@@ -3655,6 +3655,18 @@
m_pendingDropExtensionsForFileUpload[i]->consumePermanently();
m_pendingDropExtensionsForFileUpload.clear();
}
+
+void WebPage::didStartDrag()
+{
+ m_isStartingDrag = false;
+ m_page->mainFrame().eventHandler().didStartDrag();
+}
+
+void WebPage::dragCancelled()
+{
+ m_isStartingDrag = false;
+ m_page->mainFrame().eventHandler().dragCancelled();
+}
#endif // ENABLE(DRAG_SUPPORT)
Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h (216211 => 216212)
--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h 2017-05-04 22:28:22 UTC (rev 216212)
@@ -739,8 +739,8 @@
void mayPerformUploadDragDestinationAction();
void willStartDrag() { ASSERT(!m_isStartingDrag); m_isStartingDrag = true; }
- void didStartDrag() { ASSERT(m_isStartingDrag); m_isStartingDrag = false; }
- void dragCancelled() { m_isStartingDrag = false; }
+ void didStartDrag();
+ void dragCancelled();
#endif // ENABLE(DRAG_SUPPORT)
void beginPrinting(uint64_t frameID, const PrintInfo&);
Modified: trunk/Tools/ChangeLog (216211 => 216212)
--- trunk/Tools/ChangeLog 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Tools/ChangeLog 2017-05-04 22:28:22 UTC (rev 216212)
@@ -1,3 +1,36 @@
+2017-05-04 Wenson Hsieh <[email protected]>
+
+ [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.
+
+ 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:]):
+
2017-05-04 Said Abou-Hallawa <[email protected]>
Rename TestRunner.display() to TestRunner::displayAndTrackRepaints()
Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (216211 => 216212)
--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2017-05-04 22:28:22 UTC (rev 216212)
@@ -604,6 +604,7 @@
ECA680CE1E68CC0900731D20 /* StringUtilities.mm in Sources */ = {isa = PBXBuildFile; fileRef = ECA680CD1E68CC0900731D20 /* StringUtilities.mm */; };
F415086D1DA040C50044BE9B /* play-audio-on-click.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F415086C1DA040C10044BE9B /* play-audio-on-click.html */; };
F42DA5161D8CEFE400336F40 /* large-input-field-focus-onload.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F42DA5151D8CEFDB00336F40 /* large-input-field-focus-onload.html */; };
+ F4451C761EB8FD890020C5DA /* two-paragraph-contenteditable.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4451C751EB8FD7C0020C5DA /* two-paragraph-contenteditable.html */; };
F4538EF71E8473E600B5C953 /* large-red-square.png in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4538EF01E846B4100B5C953 /* large-red-square.png */; };
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 */; };
@@ -690,6 +691,7 @@
55226A2F1EBA44B900C36AD0 /* large-red-square-image.html in Copy Resources */,
5797FE331EB15AB100B2F4A0 /* navigation-client-default-crypto.html in Copy Resources */,
0799C34B1EBA3301003B7532 /* disableGetUserMedia.html in Copy Resources */,
+ F4451C761EB8FD890020C5DA /* two-paragraph-contenteditable.html in Copy Resources */,
074994421EA5034B000DA44E /* getUserMedia.html in Copy Resources */,
C9BF06EF1E9C132500595E3E /* autoplay-muted-with-controls.html in Copy Resources */,
F4DEF6ED1E9B4DB60048EF61 /* image-in-link-and-input.html in Copy Resources */,
@@ -1506,6 +1508,7 @@
F3FC3EE213678B7300126A65 /* libgtest.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgtest.a; sourceTree = BUILT_PRODUCTS_DIR; };
F415086C1DA040C10044BE9B /* play-audio-on-click.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "play-audio-on-click.html"; sourceTree = "<group>"; };
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; };
+ F4451C751EB8FD7C0020C5DA /* two-paragraph-contenteditable.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "two-paragraph-contenteditable.html"; sourceTree = "<group>"; };
F4538EF01E846B4100B5C953 /* large-red-square.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "large-red-square.png"; sourceTree = "<group>"; };
F47728981E4AE3AD007ABF6A /* full-page-contenteditable.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "full-page-contenteditable.html"; sourceTree = "<group>"; };
F4856CA21E6498A8009D7EE7 /* attachment-element.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "attachment-element.html"; sourceTree = "<group>"; };
@@ -1966,6 +1969,7 @@
F4F405BB1D4C0CF8007A9707 /* skinny-autoplaying-video-with-audio.html */,
515BE16E1D4288FF00DD7C68 /* StoreBlobToBeDeleted.html */,
2E9896141D8F092B00739892 /* text-and-password-inputs.html */,
+ F4451C751EB8FD7C0020C5DA /* two-paragraph-contenteditable.html */,
51714EB21CF8C761004723C4 /* WebProcessKillIDBCleanup-1.html */,
51714EB31CF8C761004723C4 /* WebProcessKillIDBCleanup-2.html */,
5120C83B1E674E350025B250 /* WebsiteDataStoreCustomPaths.html */,
Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/two-paragraph-contenteditable.html (0 => 216212)
--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/two-paragraph-contenteditable.html (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/two-paragraph-contenteditable.html 2017-05-04 22:28:22 UTC (rev 216212)
@@ -0,0 +1,19 @@
+<meta name="viewport" content="width=device-width">
+<style>
+body, html {
+ padding: 0;
+ margin: 0;
+ width: 100%;
+ height: 100%;
+ font-family: -apple-system;
+ font-size: 1em;
+}
+</style>
+<body id="editor" contenteditable>
+<p id="first">This is the first paragraph. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
+<p id="second">This is the second paragraph. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+</body>
+<script>
+let text = first.childNodes[0];
+getSelection().setBaseAndExtent(text, 0, text, text.data.length);
+</script>
Modified: trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm (216211 => 216212)
--- trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm 2017-05-04 22:28:22 UTC (rev 216212)
@@ -162,9 +162,10 @@
TEST(DataInteractionTests, ContentEditableToContentEditable)
{
RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
- [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
+ RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
- RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+ [webView loadTestPageNamed:@"autofocus-contenteditable"];
+ [dataInteractionSimulator waitForInputSession];
[dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.textContent"].length, 0UL);
@@ -181,9 +182,10 @@
TEST(DataInteractionTests, ContentEditableToTextarea)
{
RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
- [webView synchronouslyLoadTestPageNamed:@"contenteditable-and-textarea"];
+ RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
- RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+ [webView loadTestPageNamed:@"contenteditable-and-textarea"];
+ [dataInteractionSimulator waitForInputSession];
[dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.textContent"].length, 0UL);
@@ -197,12 +199,32 @@
checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypeRTFD, (NSString *)kUTTypeUTF8PlainText);
}
+TEST(DataInteractionTests, ContentEditableMoveParagraphs)
+{
+ RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+ RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+
+ [webView loadTestPageNamed:@"two-paragraph-contenteditable"];
+ [dataInteractionSimulator waitForInputSession];
+ [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(250, 450)];
+
+ NSString *finalTextContent = [webView stringByEvaluatingJavaScript:@"editor.textContent"];
+ NSUInteger firstParagraphOffset = [finalTextContent rangeOfString:@"This is the first paragraph"].location;
+ NSUInteger secondParagraphOffset = [finalTextContent rangeOfString:@"This is the second paragraph"].location;
+
+ EXPECT_FALSE(firstParagraphOffset == NSNotFound);
+ EXPECT_FALSE(secondParagraphOffset == NSNotFound);
+ EXPECT_GT(firstParagraphOffset, secondParagraphOffset);
+ checkSelectionRectsWithLogging(@[ makeCGRectValue(190, 100, 130, 20), makeCGRectValue(0, 120, 320, 100), makeCGRectValue(0, 220, 252, 20) ], [dataInteractionSimulator finalSelectionRects]);
+}
+
TEST(DataInteractionTests, TextAreaToInput)
{
RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
- [webView synchronouslyLoadTestPageNamed:@"textarea-to-input"];
+ RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
- RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+ [webView loadTestPageNamed:@"textarea-to-input"];
+ [dataInteractionSimulator waitForInputSession];
[dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.value"].length, 0UL);
Modified: trunk/Tools/TestWebKitAPI/ios/DataInteractionSimulator.h (216211 => 216212)
--- trunk/Tools/TestWebKitAPI/ios/DataInteractionSimulator.h 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Tools/TestWebKitAPI/ios/DataInteractionSimulator.h 2017-05-04 22:28:22 UTC (rev 216212)
@@ -29,6 +29,7 @@
#import <UIKit/UIItemProvider.h>
#import <UIKit/UIKit.h>
#import <WebKit/WKUIDelegatePrivate.h>
+#import <WebKit/_WKInputDelegate.h>
#import <wtf/BlockPtr.h>
@class MockDataOperationSession;
@@ -48,7 +49,8 @@
DataInteractionPerforming = 4
};
-@interface DataInteractionSimulator : NSObject<WKUIDelegatePrivate> {
+@interface DataInteractionSimulator : NSObject<WKUIDelegatePrivate, _WKInputDelegate> {
+@private
RetainPtr<TestWKWebView> _webView;
RetainPtr<MockDataInteractionSession> _dataInteractionSession;
RetainPtr<MockDataOperationSession> _dataOperationSession;
@@ -59,6 +61,7 @@
CGPoint _startLocation;
CGPoint _endLocation;
+ bool _isDoneWaitingForInputSession;
BOOL _shouldPerformOperation;
double _currentProgress;
bool _isDoneWithCurrentRun;
@@ -67,7 +70,9 @@
- (instancetype)initWithWebView:(TestWKWebView *)webView;
- (void)runFrom:(CGPoint)startLocation to:(CGPoint)endLocation;
+- (void)waitForInputSession;
+@property (nonatomic) BOOL allowsFocusToStartInputSession;
@property (nonatomic) BOOL shouldEnsureUIApplication;
@property (nonatomic) BlockPtr<BOOL(_WKActivatedElementInfo *)> showCustomActionSheetBlock;
@property (nonatomic) BlockPtr<NSArray *(NSArray *)> convertItemProvidersBlock;
Modified: trunk/Tools/TestWebKitAPI/ios/DataInteractionSimulator.mm (216211 => 216212)
--- trunk/Tools/TestWebKitAPI/ios/DataInteractionSimulator.mm 2017-05-04 21:46:39 UTC (rev 216211)
+++ trunk/Tools/TestWebKitAPI/ios/DataInteractionSimulator.mm 2017-05-04 22:28:22 UTC (rev 216212)
@@ -33,6 +33,8 @@
#import <UIKit/UIItemProvider_Private.h>
#import <WebCore/SoftLinking.h>
#import <WebKit/WKWebViewPrivate.h>
+#import <WebKit/_WKFocusedElementInfo.h>
+#import <WebKit/_WKFormInputSession.h>
#import <wtf/RetainPtr.h>
SOFT_LINK_FRAMEWORK(UIKit)
@@ -75,7 +77,9 @@
if (self = [super init]) {
_webView = webView;
_shouldEnsureUIApplication = NO;
+ _isDoneWaitingForInputSession = true;
[_webView setUIDelegate:self];
+ [_webView _setInputDelegate:self];
}
return self;
}
@@ -85,6 +89,9 @@
if ([_webView UIDelegate] == self)
[_webView setUIDelegate:nil];
+ if ([_webView _inputDelegate] == self)
+ [_webView _setInputDelegate:nil];
+
[super dealloc];
}
@@ -217,6 +224,12 @@
}
[_webView _simulateWillBeginDataInteractionWithSession:_dataInteractionSession.get()];
+
+ RetainPtr<WKWebView> retainedWebView = _webView;
+ dispatch_async(dispatch_get_main_queue(), ^() {
+ [retainedWebView resignFirstResponder];
+ });
+
_phase = DataInteractionBegan;
break;
}
@@ -267,6 +280,16 @@
return _phase;
}
+- (void)waitForInputSession
+{
+ _isDoneWaitingForInputSession = false;
+
+ // Waiting for an input session implies that we should allow input sessions to begin.
+ self.allowsFocusToStartInputSession = YES;
+
+ Util::run(&_isDoneWaitingForInputSession);
+}
+
#pragma mark - WKUIDelegatePrivate
- (void)_webView:(WKWebView *)webView dataInteractionOperationWasHandled:(BOOL)handled forSession:(id)session itemProviders:(NSArray<UIItemProvider *> *)itemProviders
@@ -303,6 +326,18 @@
return self.showCustomActionSheetBlock(element);
}
+#pragma mark - _WKInputDelegate
+
+- (BOOL)_webView:(WKWebView *)webView focusShouldStartInputSession:(id <_WKFocusedElementInfo>)info
+{
+ return _allowsFocusToStartInputSession;
+}
+
+- (void)_webView:(WKWebView *)webView didStartInputSession:(id <_WKFormInputSession>)inputSession
+{
+ _isDoneWaitingForInputSession = true;
+}
+
@end
#endif // ENABLE(DATA_INTERACTION)