Diff
Modified: trunk/Source/WebCore/ChangeLog (200659 => 200660)
--- trunk/Source/WebCore/ChangeLog 2016-05-11 00:16:14 UTC (rev 200659)
+++ trunk/Source/WebCore/ChangeLog 2016-05-11 00:20:10 UTC (rev 200660)
@@ -1,3 +1,15 @@
+2016-05-10 Enrica Casucci <[email protected]>
+
+ Numerous block selection issues on iOS.
+ https://bugs.webkit.org/show_bug.cgi?id=157490
+ rdar://problem/25717977
+ rdar://problem/23042215
+
+ Reviewed by Tim Horton.
+
+ * rendering/style/RenderStyle.h:
+ Exporting method.
+
2016-05-10 Sam Weinig <[email protected]>
Tweak underline style for data detected links
Modified: trunk/Source/WebCore/rendering/style/RenderStyle.h (200659 => 200660)
--- trunk/Source/WebCore/rendering/style/RenderStyle.h 2016-05-11 00:16:14 UTC (rev 200659)
+++ trunk/Source/WebCore/rendering/style/RenderStyle.h 2016-05-11 00:20:10 UTC (rev 200660)
@@ -757,7 +757,7 @@
bool hasExplicitlySetDirection() const { return noninherited_flags.hasExplicitlySetDirection(); }
const Length& specifiedLineHeight() const;
- Length lineHeight() const;
+ WEBCORE_EXPORT Length lineHeight() const;
int computedLineHeight() const;
EWhiteSpace whiteSpace() const { return static_cast<EWhiteSpace>(inherited_flags._white_space); }
Modified: trunk/Source/WebKit2/ChangeLog (200659 => 200660)
--- trunk/Source/WebKit2/ChangeLog 2016-05-11 00:16:14 UTC (rev 200659)
+++ trunk/Source/WebKit2/ChangeLog 2016-05-11 00:20:10 UTC (rev 200660)
@@ -1,3 +1,46 @@
+2016-05-10 Enrica Casucci <[email protected]>
+
+ Numerous block selection issues on iOS.
+ https://bugs.webkit.org/show_bug.cgi?id=157490
+ rdar://problem/25717977
+ rdar://problem/23042215
+
+ Reviewed by Tim Horton.
+
+ This patch fixes a number of issues with block selection on iOS.
+ We no longer eagerly choose block selection vs text selection and we
+ make sure we are capable of switching back to text selection from block
+ under every circumstance. The patch also fixes the logic used to decide
+ when to switch to block selection. It now computes the rectangle for the
+ paragraph containing the initial text selection to decide when we are
+ actually dragging outside the boundaries of the paragraph block.
+
+ * UIProcess/WebPageProxy.h:
+ * UIProcess/WebPageProxy.messages.in:
+ * UIProcess/ios/WKContentViewInteraction.mm:
+ (selectionChangedWithGesture):
+ (selectionChangedWithTouch):
+ (-[WKContentView changeSelectionWithTouchAt:withSelectionTouch:baseIsStart:]):
+ * UIProcess/ios/WebPageProxyIOS.mm:
+ (WebKit::WebPageProxy::gestureCallback):
+ (WebKit::WebPageProxy::touchesCallback):
+ (WebKit::WebPageProxy::autocorrectionDataCallback):
+ (WebKit::WebPageProxy::selectWithGesture):
+ (WebKit::WebPageProxy::updateSelectionWithTouches):
+ * WebProcess/WebPage/WebPage.h:
+ * WebProcess/WebPage/ios/WebPageIOS.mm:
+ (WebKit::selectionBoxForRange):
+ (WebKit::canShrinkToTextSelection):
+ (WebKit::hasCustomLineHeight):
+ (WebKit::WebPage::rangeForWebSelectionAtPosition):
+ (WebKit::WebPage::contractedRangeFromHandle):
+ (WebKit::WebPage::updateBlockSelectionWithTouch):
+ (WebKit::WebPage::clearSelection):
+ (WebKit::WebPage::switchToBlockSelectionAtPoint):
+ (WebKit::WebPage::shouldSwitchToBlockModeForHandle):
+ (WebKit::WebPage::updateSelectionWithTouches):
+ (WebKit::WebPage::selectWithTwoTouches):
+
2016-05-10 Alex Christensen <[email protected]>
Handle _schemeUpgraded delegate callbacks in NSURLSessionDataDelegate
Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.h (200659 => 200660)
--- trunk/Source/WebKit2/UIProcess/WebPageProxy.h 2016-05-11 00:16:14 UTC (rev 200659)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.h 2016-05-11 00:20:10 UTC (rev 200660)
@@ -250,7 +250,7 @@
#if PLATFORM(IOS)
typedef GenericCallback<const WebCore::IntPoint&, uint32_t, uint32_t, uint32_t> GestureCallback;
-typedef GenericCallback<const WebCore::IntPoint&, uint32_t> TouchesCallback;
+typedef GenericCallback<const WebCore::IntPoint&, uint32_t, uint32_t> TouchesCallback;
struct NodeAssistanceArguments {
AssistedNodeInformation m_nodeInformation;
bool m_userIsInteracting;
@@ -475,7 +475,7 @@
void willCommitLayerTree(uint64_t transactionID);
void selectWithGesture(const WebCore::IntPoint, WebCore::TextGranularity, uint32_t gestureType, uint32_t gestureState, bool isInteractingWithAssistedNode, std::function<void (const WebCore::IntPoint&, uint32_t, uint32_t, uint32_t, CallbackBase::Error)>);
- void updateSelectionWithTouches(const WebCore::IntPoint, uint32_t touches, bool baseIsStart, std::function<void (const WebCore::IntPoint&, uint32_t, CallbackBase::Error)>);
+ void updateSelectionWithTouches(const WebCore::IntPoint, uint32_t touches, bool baseIsStart, std::function<void (const WebCore::IntPoint&, uint32_t, uint32_t, CallbackBase::Error)>);
void selectWithTwoTouches(const WebCore::IntPoint from, const WebCore::IntPoint to, uint32_t gestureType, uint32_t gestureState, std::function<void (const WebCore::IntPoint&, uint32_t, uint32_t, uint32_t, CallbackBase::Error)>);
void updateBlockSelectionWithTouch(const WebCore::IntPoint, uint32_t touch, uint32_t handlePosition);
void extendSelection(WebCore::TextGranularity);
@@ -1369,7 +1369,7 @@
#endif
#if PLATFORM(IOS)
void gestureCallback(const WebCore::IntPoint&, uint32_t, uint32_t, uint32_t, uint64_t);
- void touchesCallback(const WebCore::IntPoint&, uint32_t, uint64_t);
+ void touchesCallback(const WebCore::IntPoint&, uint32_t, uint32_t, uint64_t);
void autocorrectionDataCallback(const Vector<WebCore::FloatRect>&, const String&, float, uint64_t, uint64_t);
void autocorrectionContextCallback(const String&, const String&, const String&, const String&, uint64_t, uint64_t, uint64_t);
void selectionContextCallback(const String&, const String&, const String&, uint64_t);
Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.messages.in (200659 => 200660)
--- trunk/Source/WebKit2/UIProcess/WebPageProxy.messages.in 2016-05-11 00:16:14 UTC (rev 200659)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.messages.in 2016-05-11 00:20:10 UTC (rev 200660)
@@ -173,7 +173,7 @@
#endif
#if PLATFORM(IOS)
GestureCallback(WebCore::IntPoint point, uint32_t gestureType, uint32_t gestureState, uint32_t flags, uint64_t callbackID)
- TouchesCallback(WebCore::IntPoint point, uint32_t touches, uint64_t callbackID)
+ TouchesCallback(WebCore::IntPoint point, uint32_t touches, uint32_t flags, uint64_t callbackID)
AutocorrectionDataCallback(Vector<WebCore::FloatRect> textRects, String fontName, double fontSize, uint64_t traits, uint64_t callbackID)
AutocorrectionContextCallback(String beforeText, String markedText, String selectedText, String afterText, uint64_t location, uint64_t length, uint64_t callbackID)
SelectionContextCallback(String selectedText, String beforeText, String afterText, uint64_t callbackID)
Modified: trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm (200659 => 200660)
--- trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm 2016-05-11 00:16:14 UTC (rev 200659)
+++ trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm 2016-05-11 00:20:10 UTC (rev 200660)
@@ -2218,14 +2218,14 @@
[(UIWKTextInteractionAssistant *)[view interactionAssistant] selectionChangedWithGestureAt:(CGPoint)point withGesture:toUIWKGestureType((GestureType)gestureType) withState:toUIGestureRecognizerState(static_cast<GestureRecognizerState>(gestureState)) withFlags:(toUIWKSelectionFlags((SelectionFlags)flags))];
}
-static void selectionChangedWithTouch(WKContentView *view, const WebCore::IntPoint& point, uint32_t touch, WebKit::CallbackBase::Error error)
+static void selectionChangedWithTouch(WKContentView *view, const WebCore::IntPoint& point, uint32_t touch, uint32_t flags, WebKit::CallbackBase::Error error)
{
if (error != WebKit::CallbackBase::Error::None) {
ASSERT_NOT_REACHED();
return;
}
if ([view webSelectionAssistant])
- [(UIWKSelectionAssistant *)[view webSelectionAssistant] selectionChangedWithTouchAt:(CGPoint)point withSelectionTouch:toUIWKSelectionTouch((SelectionTouch)touch)];
+ [(UIWKSelectionAssistant *)[view webSelectionAssistant] selectionChangedWithTouchAt:(CGPoint)point withSelectionTouch:toUIWKSelectionTouch((SelectionTouch)touch) withFlags:static_cast<UIWKSelectionFlags>(flags)];
else
[(UIWKTextInteractionAssistant *)[view interactionAssistant] selectionChangedWithTouchAt:(CGPoint)point withSelectionTouch:toUIWKSelectionTouch((SelectionTouch)touch)];
}
@@ -2255,8 +2255,8 @@
- (void)changeSelectionWithTouchAt:(CGPoint)point withSelectionTouch:(UIWKSelectionTouch)touch baseIsStart:(BOOL)baseIsStart
{
_usingGestureForSelection = YES;
- _page->updateSelectionWithTouches(WebCore::IntPoint(point), static_cast<uint32_t>(toSelectionTouch(touch)), baseIsStart, [self, touch](const WebCore::IntPoint& point, uint32_t touch, WebKit::CallbackBase::Error error) {
- selectionChangedWithTouch(self, point, touch, error);
+ _page->updateSelectionWithTouches(WebCore::IntPoint(point), static_cast<uint32_t>(toSelectionTouch(touch)), baseIsStart, [self, touch](const WebCore::IntPoint& point, uint32_t touch, uint32_t flags, WebKit::CallbackBase::Error error) {
+ selectionChangedWithTouch(self, point, touch, flags, error);
if (touch != UIWKSelectionTouchStarted && touch != UIWKSelectionTouchMoved)
_usingGestureForSelection = NO;
});
Modified: trunk/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm (200659 => 200660)
--- trunk/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm 2016-05-11 00:16:14 UTC (rev 200659)
+++ trunk/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm 2016-05-11 00:20:10 UTC (rev 200660)
@@ -138,7 +138,7 @@
callback->performCallbackWithReturnValue(point, gestureType, gestureState, flags);
}
-void WebPageProxy::touchesCallback(const WebCore::IntPoint& point, uint32_t touches, uint64_t callbackID)
+void WebPageProxy::touchesCallback(const WebCore::IntPoint& point, uint32_t touches, uint32_t flags, uint64_t callbackID)
{
auto callback = m_callbacks.take<TouchesCallback>(callbackID);
if (!callback) {
@@ -146,7 +146,7 @@
return;
}
- callback->performCallbackWithReturnValue(point, touches);
+ callback->performCallbackWithReturnValue(point, touches, flags);
}
void WebPageProxy::autocorrectionDataCallback(const Vector<WebCore::FloatRect>& rects, const String& fontName, float fontSize, uint64_t fontTraits, uint64_t callbackID)
@@ -386,10 +386,10 @@
m_process->send(Messages::WebPage::SelectWithGesture(point, (uint32_t)granularity, gestureType, gestureState, isInteractingWithAssistedNode, callbackID), m_pageID);
}
-void WebPageProxy::updateSelectionWithTouches(const WebCore::IntPoint point, uint32_t touches, bool baseIsStart, std::function<void (const WebCore::IntPoint&, uint32_t, CallbackBase::Error)> callbackFunction)
+void WebPageProxy::updateSelectionWithTouches(const WebCore::IntPoint point, uint32_t touches, bool baseIsStart, std::function<void (const WebCore::IntPoint&, uint32_t, uint32_t, CallbackBase::Error)> callbackFunction)
{
if (!isValid()) {
- callbackFunction(WebCore::IntPoint(), 0, CallbackBase::Error::Unknown);
+ callbackFunction(WebCore::IntPoint(), 0, 0, CallbackBase::Error::Unknown);
return;
}
Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h (200659 => 200660)
--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h 2016-05-11 00:16:14 UTC (rev 200659)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h 2016-05-11 00:20:10 UTC (rev 200660)
@@ -978,6 +978,8 @@
void resetTextAutosizing();
WebCore::VisiblePosition visiblePositionInFocusedNodeForPoint(const WebCore::Frame&, const WebCore::IntPoint&, bool isInteractingWithAssistedNode);
PassRefPtr<WebCore::Range> rangeForGranularityAtPoint(const WebCore::Frame&, const WebCore::IntPoint&, uint32_t granularity, bool isInteractingWithAssistedNode);
+ bool shouldSwitchToBlockModeForHandle(const WebCore::IntPoint& handlePoint, SelectionHandlePosition);
+ RefPtr<WebCore::Range> switchToBlockSelectionAtPoint(const WebCore::IntPoint&, SelectionHandlePosition);
#endif
#if !PLATFORM(COCOA)
static const char* interpretKeyEvent(const WebCore::KeyboardEvent*);
@@ -1409,6 +1411,8 @@
WebCore::FloatSize m_screenSize;
WebCore::FloatSize m_availableScreenSize;
RefPtr<WebCore::Range> m_currentBlockSelection;
+ WebCore::IntRect m_blockRectForTextSelection;
+
RefPtr<WebCore::Range> m_initialSelection;
WebCore::IntSize m_blockSelectionDesiredSize;
WebCore::FloatSize m_maximumUnobscuredSize;
Modified: trunk/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm (200659 => 200660)
--- trunk/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm 2016-05-11 00:16:14 UTC (rev 200659)
+++ trunk/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm 2016-05-11 00:20:10 UTC (rev 200660)
@@ -879,27 +879,57 @@
return boundingRect;
}
+static bool canShrinkToTextSelection(Node* node)
+{
+ if (node && !is<Element>(*node))
+ node = node->parentElement();
+
+ auto* renderer = (node) ? node->renderer() : nullptr;
+ return renderer && renderer->childrenInline() && (is<RenderBlock>(*renderer) && !downcast<RenderBlock>(*renderer).inlineElementContinuation()) && !renderer->isTable();
+}
+
+static bool canShrinkToTextSelection(Range& range)
+{
+ if (range.startContainer().isTextNode() && range.endContainer().isTextNode())
+ return true;
+ return canShrinkToTextSelection(range.commonAncestorContainer());
+}
+
+static bool hasCustomLineHeight(Node& node)
+{
+ auto* renderer = node.renderer();
+ return renderer && renderer->style().lineHeight().isSpecified();
+}
+
PassRefPtr<Range> WebPage::rangeForWebSelectionAtPosition(const IntPoint& point, const VisiblePosition& position, SelectionFlags& flags)
{
HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint((point), HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowUserAgentShadowContent | HitTestRequest::AllowChildFrameContent);
Node* currentNode = result.innerNode();
+ if (!currentNode)
+ return nullptr;
RefPtr<Range> range;
FloatRect boundingRectInScrollViewCoordinates;
+ if (!currentNode->isTextNode() && !canShrinkToTextSelection(currentNode) && hasCustomLineHeight(*currentNode)) {
+ auto* renderer = currentNode->renderer();
+ if (is<RenderBlockFlow>(renderer)) {
+ auto *renderText = downcast<RenderBlockFlow>(renderer)->findClosestTextAtAbsolutePoint(point);
+ if (renderText && renderText->textNode())
+ currentNode = renderText->textNode();
+ }
+ }
+
if (currentNode->isTextNode()) {
range = enclosingTextUnitOfGranularity(position, ParagraphGranularity, DirectionForward);
if (!range || range->collapsed())
range = Range::create(currentNode->document(), position, position);
- if (!range)
- return nullptr;
+ else {
+ m_blockRectForTextSelection = selectionBoxForRange(range.get());
+ range = wordRangeFromPosition(position);
+ }
- boundingRectInScrollViewCoordinates = selectionBoxForRange(range.get());
- boundingRectInScrollViewCoordinates.scale(m_page->pageScaleFactor());
- if (boundingRectInScrollViewCoordinates.width() > m_blockSelectionDesiredSize.width() && boundingRectInScrollViewCoordinates.height() > m_blockSelectionDesiredSize.height())
- return wordRangeFromPosition(position);
-
- currentNode = range->commonAncestorContainer();
+ return range;
}
if (!currentNode->isElementNode())
@@ -1430,6 +1460,8 @@
case SelectionHandlePosition::Top:
case SelectionHandlePosition::Bottom:
isBetterChoice = (copyRect.height() < currentBox.height());
+ if (copyRect.height() == currentBox.height())
+ isBetterChoice = canShrinkToTextSelection(*newRange.get());
break;
case SelectionHandlePosition::Left:
case SelectionHandlePosition::Right:
@@ -1464,12 +1496,7 @@
// there are multiple sub-element blocks beneath us. If we didn't find
// multiple sub-element blocks, don't shrink to a sub-element block.
- Node* node = bestRange->commonAncestorContainer();
- if (!node->isElementNode())
- node = node->parentElement();
-
- RenderObject* renderer = node->renderer();
- if (renderer && renderer->childrenInline() && (is<RenderBlock>(*renderer) && !downcast<RenderBlock>(*renderer).inlineElementContinuation()) && !renderer->isTable())
+ if (canShrinkToTextSelection(*bestRange.get()))
flags = None;
return bestRange;
@@ -1605,18 +1632,59 @@
m_page->focusController().focusedOrMainFrame().selection().clear();
}
+RefPtr<Range> WebPage::switchToBlockSelectionAtPoint(const IntPoint& point, SelectionHandlePosition handlePosition)
+{
+ Frame& frame = m_page->focusController().focusedOrMainFrame();
+ RefPtr<Range> newRange;
+ RefPtr<Range> currentRange = frame.selection().selection().toNormalizedRange();
+ if (currentRange) {
+ Node* currentNode = ¤tRange->startContainer();
+ if (currentNode->isTextNode()) {
+ newRange = enclosingTextUnitOfGranularity(currentRange->startPosition(), ParagraphGranularity, DirectionBackward);
+ if (newRange && newRange->collapsed())
+ newRange = nullptr;
+ }
+
+ if (!newRange && !currentNode->isElementNode())
+ currentNode = currentNode->parentElement();
+
+ if (!newRange && currentNode) {
+ newRange = Range::create(currentNode->document());
+ newRange->selectNodeContents(*currentNode, ASSERT_NO_EXCEPTION);
+ }
+ }
+ return newRange;
+}
+
+bool WebPage::shouldSwitchToBlockModeForHandle(const IntPoint& handlePoint, SelectionHandlePosition handlePosition)
+{
+ switch (handlePosition) {
+ case SelectionHandlePosition::Top:
+ return handlePoint.y() < m_blockRectForTextSelection.y();
+ case SelectionHandlePosition::Right:
+ return handlePoint.x() > m_blockRectForTextSelection.maxX();
+ case SelectionHandlePosition::Bottom:
+ return handlePoint.y() > m_blockRectForTextSelection.maxY();
+ case SelectionHandlePosition::Left:
+ return handlePoint.x() < m_blockRectForTextSelection.x();
+ }
+}
+
void WebPage::updateSelectionWithTouches(const IntPoint& point, uint32_t touches, bool baseIsStart, uint64_t callbackID)
{
Frame& frame = m_page->focusController().focusedOrMainFrame();
- VisiblePosition position = frame.visiblePositionForPoint(frame.view()->rootViewToContents(point));
+ IntPoint pointInDocument = frame.view()->rootViewToContents(point);
+ VisiblePosition position = frame.visiblePositionForPoint(pointInDocument);
if (position.isNull()) {
- send(Messages::WebPageProxy::TouchesCallback(point, touches, callbackID));
+ send(Messages::WebPageProxy::TouchesCallback(point, touches, 0, callbackID));
return;
}
RefPtr<Range> range;
VisiblePosition result;
-
+ SelectionFlags flags = None;
+ SelectionHandlePosition handlePosition = baseIsStart ? SelectionHandlePosition::Bottom : SelectionHandlePosition::Top;
+
switch (static_cast<SelectionTouch>(touches)) {
case SelectionTouch::Started:
case SelectionTouch::EndedNotMoving:
@@ -1640,13 +1708,27 @@
break;
case SelectionTouch::Moved:
- range = rangeForPosition(&frame, position, baseIsStart);
+ if (shouldSwitchToBlockModeForHandle(pointInDocument, handlePosition)) {
+ range = switchToBlockSelectionAtPoint(pointInDocument, handlePosition);
+ flags = IsBlockSelection;
+ } else
+ range = rangeForPosition(&frame, position, baseIsStart);
break;
}
- if (range)
+ if (range && flags != IsBlockSelection)
frame.selection().setSelectedRange(range.get(), position.affinity(), true);
- send(Messages::WebPageProxy::TouchesCallback(point, touches, callbackID));
+ send(Messages::WebPageProxy::TouchesCallback(point, touches, flags, callbackID));
+ if (range && flags == IsBlockSelection) {
+ // We just switched to block selection therefore we need to compute the thresholds.
+ m_currentBlockSelection = range;
+ frame.selection().setSelectedRange(range.get(), position.affinity(), true);
+
+ float growThreshold = 0;
+ float shrinkThreshold = 0;
+ computeExpandAndShrinkThresholdsForHandle(point, handlePosition, growThreshold, shrinkThreshold);
+ send(Messages::WebPageProxy::DidUpdateBlockSelectionWithTouch(static_cast<uint32_t>(SelectionTouch::Started), static_cast<uint32_t>(IsBlockSelection), growThreshold, shrinkThreshold));
+ }
}
void WebPage::selectWithTwoTouches(const WebCore::IntPoint& from, const WebCore::IntPoint& to, uint32_t gestureType, uint32_t gestureState, uint64_t callbackID)
@@ -1781,6 +1863,14 @@
{
const Frame& frame = m_page->focusController().focusedOrMainFrame();
RefPtr<Range> range = rangeForGranularityAtPoint(frame, point, granularity, isInteractingWithAssistedNode);
+ if (!isInteractingWithAssistedNode) {
+ m_blockSelectionDesiredSize.setWidth(blockSelectionStartWidth);
+ m_blockSelectionDesiredSize.setHeight(blockSelectionStartHeight);
+ m_currentBlockSelection = nullptr;
+ RefPtr<Range> paragraphRange = enclosingTextUnitOfGranularity(visiblePositionInFocusedNodeForPoint(frame, point, isInteractingWithAssistedNode), ParagraphGranularity, DirectionForward);
+ if (paragraphRange && !paragraphRange->collapsed())
+ m_blockRectForTextSelection = selectionBoxForRange(paragraphRange.get());
+ }
if (range)
frame.selection().setSelectedRange(range.get(), UPSTREAM, true);