Title: [217870] trunk/Source
Revision
217870
Author
[email protected]
Date
2017-06-06 19:17:27 -0700 (Tue, 06 Jun 2017)

Log Message

Crash trying to drag the entire text of a long book out of Mail compose view
https://bugs.webkit.org/show_bug.cgi?id=173042
<rdar://problem/32382059>

Reviewed by Simon Fraser.

Source/WebCore:

Creating a TextIndicator that is hundreds of thousands of pixels tall
is not a good idea. We introduced TextIndicatorOptionDoNotClipToVisibleRect
so that (for example) an image that overhangs the edge of the page would
contain the entire image, instead of just the visible fragment.
Instead, rename this option to ExpandClipBeyondVisibleRect, and make it
not unclip *entirely*, but expand the clip significantly (50% in each direction)
beyond the bounds of the current visible rect. Also, make use of exposed
area information for this clipping; otherwise, clients with very large views
inside scrollable areas (like Mail) would still try to create large TextIndicators.

* page/TextIndicator.cpp:
(WebCore::initializeIndicator):
* page/TextIndicator.h:

Source/WebKit2:

* WebProcess/WebPage/ios/FindControllerIOS.mm:
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::didConcludeEditDataInteraction):
Adapt to the new name.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (217869 => 217870)


--- trunk/Source/WebCore/ChangeLog	2017-06-07 00:28:47 UTC (rev 217869)
+++ trunk/Source/WebCore/ChangeLog	2017-06-07 02:17:27 UTC (rev 217870)
@@ -1,3 +1,25 @@
+2017-06-06  Tim Horton  <[email protected]>
+
+        Crash trying to drag the entire text of a long book out of Mail compose view
+        https://bugs.webkit.org/show_bug.cgi?id=173042
+        <rdar://problem/32382059>
+
+        Reviewed by Simon Fraser.
+
+        Creating a TextIndicator that is hundreds of thousands of pixels tall
+        is not a good idea. We introduced TextIndicatorOptionDoNotClipToVisibleRect
+        so that (for example) an image that overhangs the edge of the page would
+        contain the entire image, instead of just the visible fragment.
+        Instead, rename this option to ExpandClipBeyondVisibleRect, and make it
+        not unclip *entirely*, but expand the clip significantly (50% in each direction)
+        beyond the bounds of the current visible rect. Also, make use of exposed
+        area information for this clipping; otherwise, clients with very large views
+        inside scrollable areas (like Mail) would still try to create large TextIndicators.
+
+        * page/TextIndicator.cpp:
+        (WebCore::initializeIndicator):
+        * page/TextIndicator.h:
+
 2017-06-06  Chris Dumez  <[email protected]>
 
         RELEASE_ASSERT(static_cast<size_t>(enumerationValue) < WTF_ARRAY_LENGTH(values)) hit in convertEnumerationToJS<WebCore::History::ScrollRestoration>()

Modified: trunk/Source/WebCore/page/TextIndicator.cpp (217869 => 217870)


--- trunk/Source/WebCore/page/TextIndicator.cpp	2017-06-07 00:28:47 UTC (rev 217869)
+++ trunk/Source/WebCore/page/TextIndicator.cpp	2017-06-07 02:17:27 UTC (rev 217870)
@@ -272,34 +272,42 @@
     else if (data.options & TextIndicatorOptionUseSelectionRectForSizing)
         getSelectionRectsForRange(textRects, range);
 #endif
-    else {
-        if (data.options & TextIndicatorOptionDoNotClipToVisibleRect)
-            frame.selection().getTextRectangles(textRects, textRectHeight);
-        else
-            frame.selection().getClippedVisibleTextRectangles(textRects, textRectHeight);
-    }
+    else
+        frame.selection().getTextRectangles(textRects, textRectHeight);
 
-    if (textRects.isEmpty()) {
-        RenderView* renderView = frame.contentRenderer();
-        if (!renderView)
-            return false;
-        FloatRect boundingRect = range.absoluteBoundingRect();
-        if (data.options & TextIndicatorOptionDoNotClipToVisibleRect)
-            textRects.append(boundingRect);
-        else {
-            // Clip to the visible rect, just like getClippedVisibleTextRectangles does.
-            // FIXME: We really want to clip to the unobscured rect in both cases, I think.
-            // (this seems to work on Mac, but maybe not iOS?)
-            FloatRect visibleContentRect = frame.view()->visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect);
-            textRects.append(intersection(visibleContentRect, boundingRect));
-        }
+    if (textRects.isEmpty())
+        textRects.append(range.absoluteBoundingRect());
+
+    auto frameView = frame.view();
+
+    // Use the exposedContentRect/viewExposedRect instead of visibleContentRect to avoid creating a huge indicator for a large view inside a scroll view.
+    IntRect contentsClipRect;
+#if PLATFORM(IOS)
+    contentsClipRect = enclosingIntRect(frameView->exposedContentRect());
+#else
+    if (auto viewExposedRect = frameView->viewExposedRect())
+        contentsClipRect = frameView->viewToContents(enclosingIntRect(*viewExposedRect));
+    else
+        contentsClipRect = frameView->visibleContentRect();
+#endif
+
+    if (data.options & TextIndicatorOptionExpandClipBeyondVisibleRect) {
+        contentsClipRect.inflateX(contentsClipRect.width() / 2);
+        contentsClipRect.inflateY(contentsClipRect.height() / 2);
     }
 
     FloatRect textBoundingRectInRootViewCoordinates;
     FloatRect textBoundingRectInDocumentCoordinates;
+    Vector<FloatRect> clippedTextRectsInDocumentCoordinates;
     Vector<FloatRect> textRectsInRootViewCoordinates;
     for (const FloatRect& textRect : textRects) {
-        FloatRect textRectInDocumentCoordinatesIncludingMargin = textRect;
+        FloatRect clippedTextRect = intersection(textRect, contentsClipRect);
+        if (clippedTextRect.isEmpty())
+            continue;
+
+        clippedTextRectsInDocumentCoordinates.append(clippedTextRect);
+
+        FloatRect textRectInDocumentCoordinatesIncludingMargin = clippedTextRect;
         textRectInDocumentCoordinatesIncludingMargin.inflateX(margin.width());
         textRectInDocumentCoordinatesIncludingMargin.inflateY(margin.height());
         textBoundingRectInDocumentCoordinates.unite(textRectInDocumentCoordinatesIncludingMargin);
@@ -321,7 +329,7 @@
     data.textBoundingRectInRootViewCoordinates = textBoundingRectInRootViewCoordinates;
     data.textRectsInBoundingRectCoordinates = textRectsInBoundingRectCoordinates;
 
-    return takeSnapshots(data, frame, enclosingIntRect(textBoundingRectInDocumentCoordinates), textRects);
+    return takeSnapshots(data, frame, enclosingIntRect(textBoundingRectInDocumentCoordinates), clippedTextRectsInDocumentCoordinates);
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/page/TextIndicator.h (217869 => 217870)


--- trunk/Source/WebCore/page/TextIndicator.h	2017-06-07 00:28:47 UTC (rev 217869)
+++ trunk/Source/WebCore/page/TextIndicator.h	2017-06-07 02:17:27 UTC (rev 217870)
@@ -78,8 +78,8 @@
     TextIndicatorOptionIncludeMarginIfRangeMatchesSelection = 1 << 6,
 
     // By default, TextIndicator clips the indicated rects to the visible content rect.
-    // If this option is set, do not clip the indicated rects.
-    TextIndicatorOptionDoNotClipToVisibleRect = 1 << 7,
+    // If this option is set, expand the clip rect outward so that slightly offscreen content will be included.
+    TextIndicatorOptionExpandClipBeyondVisibleRect = 1 << 7,
 
     // Include an additional snapshot of everything in view, with the exception of nodes within the currently selected range.
     TextIndicatorOptionIncludeSnapshotOfAllVisibleContentWithoutSelection = 1 << 8,

Modified: trunk/Source/WebKit2/ChangeLog (217869 => 217870)


--- trunk/Source/WebKit2/ChangeLog	2017-06-07 00:28:47 UTC (rev 217869)
+++ trunk/Source/WebKit2/ChangeLog	2017-06-07 02:17:27 UTC (rev 217870)
@@ -1,3 +1,16 @@
+2017-06-06  Tim Horton  <[email protected]>
+
+        Crash trying to drag the entire text of a long book out of Mail compose view
+        https://bugs.webkit.org/show_bug.cgi?id=173042
+        <rdar://problem/32382059>
+
+        Reviewed by Simon Fraser.
+
+        * WebProcess/WebPage/ios/FindControllerIOS.mm:
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::WebPage::didConcludeEditDataInteraction):
+        Adapt to the new name.
+
 2017-06-06  Chris Dumez  <[email protected]>
 
         RELEASE_ASSERT(static_cast<size_t>(enumerationValue) < WTF_ARRAY_LENGTH(values)) hit in convertEnumerationToJS<WebCore::History::ScrollRestoration>()

Modified: trunk/Source/WebKit2/WebProcess/WebPage/ios/FindControllerIOS.mm (217869 => 217870)


--- trunk/Source/WebKit2/WebProcess/WebPage/ios/FindControllerIOS.mm	2017-06-07 00:28:47 UTC (rev 217869)
+++ trunk/Source/WebKit2/WebProcess/WebPage/ios/FindControllerIOS.mm	2017-06-07 02:17:27 UTC (rev 217870)
@@ -50,7 +50,7 @@
 const int totalHorizontalMargin = 2;
 const int totalVerticalMargin = 1;
 
-const TextIndicatorOptions findTextIndicatorOptions = TextIndicatorOptionTightlyFitContent | TextIndicatorOptionIncludeMarginIfRangeMatchesSelection | TextIndicatorOptionDoNotClipToVisibleRect;
+const TextIndicatorOptions findTextIndicatorOptions = TextIndicatorOptionTightlyFitContent | TextIndicatorOptionIncludeMarginIfRangeMatchesSelection | TextIndicatorOptionExpandClipBeyondVisibleRect;
 
 static Color highlightColor()
 {

Modified: trunk/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm (217869 => 217870)


--- trunk/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm	2017-06-07 00:28:47 UTC (rev 217869)
+++ trunk/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm	2017-06-07 02:17:27 UTC (rev 217870)
@@ -635,7 +635,7 @@
 {
     std::optional<TextIndicatorData> textIndicatorData;
 
-    static auto defaultEditDataInteractionTextIndicatorOptions = TextIndicatorOptionIncludeSnapshotOfAllVisibleContentWithoutSelection | TextIndicatorOptionDoNotClipToVisibleRect | TextIndicatorOptionPaintAllContent | TextIndicatorOptionIncludeMarginIfRangeMatchesSelection | TextIndicatorOptionPaintBackgrounds | TextIndicatorOptionComputeEstimatedBackgroundColor| TextIndicatorOptionUseSelectionRectForSizing | TextIndicatorOptionIncludeSnapshotWithSelectionHighlight;
+    static auto defaultEditDataInteractionTextIndicatorOptions = TextIndicatorOptionIncludeSnapshotOfAllVisibleContentWithoutSelection | TextIndicatorOptionExpandClipBeyondVisibleRect | TextIndicatorOptionPaintAllContent | TextIndicatorOptionIncludeMarginIfRangeMatchesSelection | TextIndicatorOptionPaintBackgrounds | TextIndicatorOptionComputeEstimatedBackgroundColor| TextIndicatorOptionUseSelectionRectForSizing | TextIndicatorOptionIncludeSnapshotWithSelectionHighlight;
     auto& frame = m_page->focusController().focusedOrMainFrame();
     if (auto range = frame.selection().selection().toNormalizedRange()) {
         if (auto textIndicator = TextIndicator::createWithRange(*range, defaultEditDataInteractionTextIndicatorOptions, TextIndicatorPresentationTransition::None, FloatSize()))
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to