Title: [249698] branches/safari-608-branch
Revision
249698
Author
alanc...@apple.com
Date
2019-09-09 20:20:02 -0700 (Mon, 09 Sep 2019)

Log Message

Cherry-pick r249605. rdar://problem/55182896

    Incorrect selection rect revealed after pasting images in a contenteditable element
    https://bugs.webkit.org/show_bug.cgi?id=201549
    <rdar://problem/50956429>

    Reviewed by Simon Fraser.

    Source/WebCore:

    Editor::replaceSelectionWithFragment currently scrolls to reveal the selection after inserting the given
    DocumentFragment. However, this scrolling occurs before any inserted images have loaded yet, which causes the
    wrong caret rect to be revealed, since all image elements inserted during paste will be empty.

    To fix this, we defer revealing the selection after inserting the fragment until after all images that have
    been inserted are done loading. While waiting for images to load, if any layers which may be scrolled as a
    result of revealing the selection are scrolled, we additionally cancel the deferred selection reveal. See
    comments below for more detail.

    Tests: editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html
           editing/pasteboard/reveal-selection-after-pasting-images.html
           PasteImage.RevealSelectionAfterPastingImage

    * editing/Editing.cpp:
    (WebCore::visibleImageElementsInRangeWithNonLoadedImages):

    Add a new helper to iterate through a range and collect all image elements in that range, that contain cached
    images that have not finished loading yet.

    * editing/Editing.h:
    * editing/Editor.cpp:
    (WebCore::Editor::replaceSelectionWithFragment):

    Instead of always immediately revealing the selection after applying the ReplaceSelectionCommand, collect the
    image elements that were just inserted, and avoid immediately revealing the selection if any of these images
    have non-null cached images, but are not loaded yet. Instead, hold on to these images in a set, remove them once
    they finish loading using the new method below, and once all images are removed, reveal the selection.

    (WebCore::Editor::revealSelectionIfNeededAfterLoadingImageForElement):
    (WebCore::Editor::renderLayerDidScroll):

    Called whenever a scrollable RenderLayer is scrolled (or in the case of FrameView, the root layer). In the case
    where Editor is waiting to reveal the selection, we check to see if the scrolled layer is an ancestor of the
    layer enclosing the start of the selection.

    (WebCore::Editor::respondToChangedSelection):

    If the selection changes between pasting and waiting for pasted images to load, just cancel waiting to reveal
    the selection after pasting.

    * editing/Editor.h:
    * editing/ReplaceSelectionCommand.cpp:
    (WebCore::ReplaceSelectionCommand::insertedContentRange const):

    Add a helper method to grab the Range of content inserted after applying the command.

    * editing/ReplaceSelectionCommand.h:
    * page/FrameView.cpp:
    (WebCore::FrameView::scrollPositionChanged):
    * page/FrameView.h:
    * page/Page.cpp:
    (WebCore::Page::didFinishLoadingImageForElement):

    Notify Editor after an image finishes loading.

    * rendering/RenderLayer.cpp:
    (WebCore::RenderLayer::scrollTo):

    Source/WebKit:

    Tweak some existing logic to use the new visibleImageElementsInRangeWithNonLoadedImages helper function. See
    WebCore for more details.

    * WebProcess/WebPage/ios/WebPageIOS.mm:
    (WebKit::WebPage::didConcludeEditDrag):

    Tools:

    Add an API test to exercise the scenario where we scroll to reveal the selection after pasting an image that was
    directly written to the pasteboard.

    * TestWebKitAPI/Tests/WebKitCocoa/PasteImage.mm:

    LayoutTests:

    Add a couple of new layout tests.

    * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll-expected.txt: Added.
    * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html: Added.

    This test verifies that we don't try to scroll to reveal the caret after pasting, if the scroll position was
    changed before the images finished loading.

    * editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
    * editing/pasteboard/reveal-selection-after-pasting-images.html: Added.
    * platform/ios/editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.

    This test verifies that we reveal the caret after loading multiple pasted images in a selection, and dispatch a
    scroll event in the process.

    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@249605 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Modified Paths

Added Paths

Diff

Modified: branches/safari-608-branch/LayoutTests/ChangeLog (249697 => 249698)


--- branches/safari-608-branch/LayoutTests/ChangeLog	2019-09-10 03:19:56 UTC (rev 249697)
+++ branches/safari-608-branch/LayoutTests/ChangeLog	2019-09-10 03:20:02 UTC (rev 249698)
@@ -1,5 +1,133 @@
 2019-09-09  Kocsen Chung  <kocsen_ch...@apple.com>
 
+        Cherry-pick r249605. rdar://problem/55182896
+
+    Incorrect selection rect revealed after pasting images in a contenteditable element
+    https://bugs.webkit.org/show_bug.cgi?id=201549
+    <rdar://problem/50956429>
+    
+    Reviewed by Simon Fraser.
+    
+    Source/WebCore:
+    
+    Editor::replaceSelectionWithFragment currently scrolls to reveal the selection after inserting the given
+    DocumentFragment. However, this scrolling occurs before any inserted images have loaded yet, which causes the
+    wrong caret rect to be revealed, since all image elements inserted during paste will be empty.
+    
+    To fix this, we defer revealing the selection after inserting the fragment until after all images that have
+    been inserted are done loading. While waiting for images to load, if any layers which may be scrolled as a
+    result of revealing the selection are scrolled, we additionally cancel the deferred selection reveal. See
+    comments below for more detail.
+    
+    Tests: editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html
+           editing/pasteboard/reveal-selection-after-pasting-images.html
+           PasteImage.RevealSelectionAfterPastingImage
+    
+    * editing/Editing.cpp:
+    (WebCore::visibleImageElementsInRangeWithNonLoadedImages):
+    
+    Add a new helper to iterate through a range and collect all image elements in that range, that contain cached
+    images that have not finished loading yet.
+    
+    * editing/Editing.h:
+    * editing/Editor.cpp:
+    (WebCore::Editor::replaceSelectionWithFragment):
+    
+    Instead of always immediately revealing the selection after applying the ReplaceSelectionCommand, collect the
+    image elements that were just inserted, and avoid immediately revealing the selection if any of these images
+    have non-null cached images, but are not loaded yet. Instead, hold on to these images in a set, remove them once
+    they finish loading using the new method below, and once all images are removed, reveal the selection.
+    
+    (WebCore::Editor::revealSelectionIfNeededAfterLoadingImageForElement):
+    (WebCore::Editor::renderLayerDidScroll):
+    
+    Called whenever a scrollable RenderLayer is scrolled (or in the case of FrameView, the root layer). In the case
+    where Editor is waiting to reveal the selection, we check to see if the scrolled layer is an ancestor of the
+    layer enclosing the start of the selection.
+    
+    (WebCore::Editor::respondToChangedSelection):
+    
+    If the selection changes between pasting and waiting for pasted images to load, just cancel waiting to reveal
+    the selection after pasting.
+    
+    * editing/Editor.h:
+    * editing/ReplaceSelectionCommand.cpp:
+    (WebCore::ReplaceSelectionCommand::insertedContentRange const):
+    
+    Add a helper method to grab the Range of content inserted after applying the command.
+    
+    * editing/ReplaceSelectionCommand.h:
+    * page/FrameView.cpp:
+    (WebCore::FrameView::scrollPositionChanged):
+    * page/FrameView.h:
+    * page/Page.cpp:
+    (WebCore::Page::didFinishLoadingImageForElement):
+    
+    Notify Editor after an image finishes loading.
+    
+    * rendering/RenderLayer.cpp:
+    (WebCore::RenderLayer::scrollTo):
+    
+    Source/WebKit:
+    
+    Tweak some existing logic to use the new visibleImageElementsInRangeWithNonLoadedImages helper function. See
+    WebCore for more details.
+    
+    * WebProcess/WebPage/ios/WebPageIOS.mm:
+    (WebKit::WebPage::didConcludeEditDrag):
+    
+    Tools:
+    
+    Add an API test to exercise the scenario where we scroll to reveal the selection after pasting an image that was
+    directly written to the pasteboard.
+    
+    * TestWebKitAPI/Tests/WebKitCocoa/PasteImage.mm:
+    
+    LayoutTests:
+    
+    Add a couple of new layout tests.
+    
+    * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll-expected.txt: Added.
+    * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html: Added.
+    
+    This test verifies that we don't try to scroll to reveal the caret after pasting, if the scroll position was
+    changed before the images finished loading.
+    
+    * editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
+    * editing/pasteboard/reveal-selection-after-pasting-images.html: Added.
+    * platform/ios/editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
+    
+    This test verifies that we reveal the caret after loading multiple pasted images in a selection, and dispatch a
+    scroll event in the process.
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@249605 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2019-09-06  Wenson Hsieh  <wenson_hs...@apple.com>
+
+            Incorrect selection rect revealed after pasting images in a contenteditable element
+            https://bugs.webkit.org/show_bug.cgi?id=201549
+            <rdar://problem/50956429>
+
+            Reviewed by Simon Fraser.
+
+            Add a couple of new layout tests.
+
+            * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll-expected.txt: Added.
+            * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html: Added.
+
+            This test verifies that we don't try to scroll to reveal the caret after pasting, if the scroll position was
+            changed before the images finished loading.
+
+            * editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
+            * editing/pasteboard/reveal-selection-after-pasting-images.html: Added.
+            * platform/ios/editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
+
+            This test verifies that we reveal the caret after loading multiple pasted images in a selection, and dispatch a
+            scroll event in the process.
+
+2019-09-09  Kocsen Chung  <kocsen_ch...@apple.com>
+
         Cherry-pick r249581. rdar://problem/55202922
 
     REGRESSION (iOS 13): If an overflow:hidden with a non-zero scroll position is toggled to overflow:scroll, some other scroll causes its scroll position to get reset

Added: branches/safari-608-branch/LayoutTests/editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll-expected.txt (0 => 249698)


--- branches/safari-608-branch/LayoutTests/editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll-expected.txt	                        (rev 0)
+++ branches/safari-608-branch/LayoutTests/editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll-expected.txt	2019-09-10 03:20:02 UTC (rev 249698)
@@ -0,0 +1,17 @@
+This test verifies that we do not scroll to reveal the selection after pasting images in an editable area, if the page programmatically scrolls the editor. To run the test manually, copy the selected images and paste into the red editable container above. The container's scroll position should remain at 0.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS allImagesAreDoneLoading() became true
+PASS editor.scrollTop is 0
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Here's to the crazy ones, the misfits, the rebels, the trouble makers, the round pegs in the square holes, the ones who see things differently. There not fond of rules, and they have no respect for the status quo, you can quote then, disagree with them, glorify or vilify them, about the only thing you can't do is ignore them. Because they change things. They push the human race forward. And while some may see them as the crazy ones, we see genius. Because the people who are crazy enough to think they can change the world are the ones who do.
+
+
+
+
+
+

Added: branches/safari-608-branch/LayoutTests/editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html (0 => 249698)


--- branches/safari-608-branch/LayoutTests/editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html	                        (rev 0)
+++ branches/safari-608-branch/LayoutTests/editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html	2019-09-10 03:20:02 UTC (rev 249698)
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src=""
+    <script src=""
+    <script>
+        jsTestIsAsync = true;
+        description("This test verifies that we do not scroll to reveal the selection after pasting images in an editable area, if the page programmatically scrolls the editor. To run the test manually, copy the selected images and paste into the red editable container above. The container's scroll position should remain at 0.");
+
+        function allImagesAreDoneLoading() {
+            for (const image of Array.from(document.body.querySelectorAll("img"))) {
+                if (!image.complete)
+                    return false;
+            }
+            return true;
+        }
+
+        addEventListener("load", () => {
+            editor = document.getElementById("editor");
+            images = document.getElementById("images-to-copy");
+            lastLine = document.getElementById("lastLine");
+
+            editor.scrollTo(0, 200);
+            setSelectionCommand(images.firstChild, 0, images.lastChild, 1);
+
+            if (!window.testRunner) {
+                editor.addEventListener("paste", () => setTimeout(() => editor.scrollTo(0, 0)));
+                return;
+            }
+
+            execCopyCommand();
+            setSelectionCommand(lastLine, 0, lastLine, 0);
+            execPasteCommand();
+            editor.scrollTo(0, 0);
+
+            shouldBecomeEqual("allImagesAreDoneLoading()", "true", () => {
+                shouldBe("editor.scrollTop", "0");
+                finishJSTest();
+            });
+        });
+    </script>
+    <style>
+        div#editor {
+            width: 200px;
+            height: 200px;
+            overflow: scroll;
+            border: 1px solid tomato;
+        }
+    </style>
+</head>
+<body>
+    <div id="editor" contenteditable>
+        <span>Here's to the crazy ones, the misfits, the rebels, the trouble makers, the round pegs in the square holes, the ones who see things differently. There not fond of rules, and they have no respect for the status quo, you can quote then, disagree with them, glorify or vilify them, about the only thing you can't do is ignore them. Because they change things. They push the human race forward. And while some may see them as the crazy ones, we see genius. Because the people who are crazy enough to think they can change the world are the ones who do.</span>
+        <div><br id="lastLine"></div>
+    </div>
+    <div id="images-to-copy">
+        <div><img src=""
+        <div><img src=""
+        <div><img src=""
+    </div>
+</body>
+</html>

Added: branches/safari-608-branch/LayoutTests/editing/pasteboard/reveal-selection-after-pasting-images-expected.txt (0 => 249698)


--- branches/safari-608-branch/LayoutTests/editing/pasteboard/reveal-selection-after-pasting-images-expected.txt	                        (rev 0)
+++ branches/safari-608-branch/LayoutTests/editing/pasteboard/reveal-selection-after-pasting-images-expected.txt	2019-09-10 03:20:02 UTC (rev 249698)
@@ -0,0 +1,13 @@
+This test verifies that we scroll to reveal the selection after pasting images in an editable area. To run the test manually, copy the selected images and paste into the red editable container above. The container should scroll to reveal the caret after the last image.
+
+Scrolled after pasting:
+| <div>
+|   <img>
+|     src=""
+| <div>
+|   <img>
+|     src=""
+| <div>
+|   <img>
+|     src=""
+|   <#selection-caret>

Added: branches/safari-608-branch/LayoutTests/editing/pasteboard/reveal-selection-after-pasting-images.html (0 => 249698)


--- branches/safari-608-branch/LayoutTests/editing/pasteboard/reveal-selection-after-pasting-images.html	                        (rev 0)
+++ branches/safari-608-branch/LayoutTests/editing/pasteboard/reveal-selection-after-pasting-images.html	2019-09-10 03:20:02 UTC (rev 249698)
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src=""
+    <script src=""
+    <script>
+        Markup.waitUntilDone();
+        Markup.description("This test verifies that we scroll to reveal the selection after pasting images in an editable area. To run the test manually, copy the selected images and paste into the red editable container above. The container should scroll to reveal the caret after the last image.");
+
+        addEventListener("load", () => {
+            editor = document.getElementById("editor");
+            images = document.getElementById("images-to-copy");
+
+            editor.addEventListener("scroll", () => {
+                Markup.dump(editor, "Scrolled after pasting");
+                Markup.notifyDone();
+            }, { once: true });
+
+            setSelectionCommand(images.firstChild, 0, images.lastChild, 1);
+
+            if (!window.testRunner)
+                return;
+
+            execCopyCommand();
+            editor.focus();
+            execPasteCommand();
+        });
+    </script>
+    <style>
+        div#editor {
+            width: 200px;
+            height: 200px;
+            overflow: scroll;
+            border: 1px solid tomato;
+        }
+    </style>
+</head>
+<body>
+    <div id="editor" contenteditable></div>
+    <div id="images-to-copy">
+        <div><img src=""
+        <div><img src=""
+        <div><img src=""
+    </div>
+</body>
+</html>

Added: branches/safari-608-branch/LayoutTests/platform/ios/editing/pasteboard/reveal-selection-after-pasting-images-expected.txt (0 => 249698)


--- branches/safari-608-branch/LayoutTests/platform/ios/editing/pasteboard/reveal-selection-after-pasting-images-expected.txt	                        (rev 0)
+++ branches/safari-608-branch/LayoutTests/platform/ios/editing/pasteboard/reveal-selection-after-pasting-images-expected.txt	2019-09-10 03:20:02 UTC (rev 249698)
@@ -0,0 +1,16 @@
+This test verifies that we scroll to reveal the selection after pasting images in an editable area. To run the test manually, copy the selected images and paste into the red editable container above. The container should scroll to reveal the caret after the last image.
+
+Scrolled after pasting:
+| <div>
+|   style="-webkit-text-size-adjust: auto;"
+|   <img>
+|     src=""
+| <div>
+|   style="-webkit-text-size-adjust: auto;"
+|   <img>
+|     src=""
+| <div>
+|   style="-webkit-text-size-adjust: auto;"
+|   <img>
+|     src=""
+|   <#selection-caret>

Modified: branches/safari-608-branch/Source/WebCore/ChangeLog (249697 => 249698)


--- branches/safari-608-branch/Source/WebCore/ChangeLog	2019-09-10 03:19:56 UTC (rev 249697)
+++ branches/safari-608-branch/Source/WebCore/ChangeLog	2019-09-10 03:20:02 UTC (rev 249698)
@@ -1,5 +1,176 @@
 2019-09-09  Kocsen Chung  <kocsen_ch...@apple.com>
 
+        Cherry-pick r249605. rdar://problem/55182896
+
+    Incorrect selection rect revealed after pasting images in a contenteditable element
+    https://bugs.webkit.org/show_bug.cgi?id=201549
+    <rdar://problem/50956429>
+    
+    Reviewed by Simon Fraser.
+    
+    Source/WebCore:
+    
+    Editor::replaceSelectionWithFragment currently scrolls to reveal the selection after inserting the given
+    DocumentFragment. However, this scrolling occurs before any inserted images have loaded yet, which causes the
+    wrong caret rect to be revealed, since all image elements inserted during paste will be empty.
+    
+    To fix this, we defer revealing the selection after inserting the fragment until after all images that have
+    been inserted are done loading. While waiting for images to load, if any layers which may be scrolled as a
+    result of revealing the selection are scrolled, we additionally cancel the deferred selection reveal. See
+    comments below for more detail.
+    
+    Tests: editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html
+           editing/pasteboard/reveal-selection-after-pasting-images.html
+           PasteImage.RevealSelectionAfterPastingImage
+    
+    * editing/Editing.cpp:
+    (WebCore::visibleImageElementsInRangeWithNonLoadedImages):
+    
+    Add a new helper to iterate through a range and collect all image elements in that range, that contain cached
+    images that have not finished loading yet.
+    
+    * editing/Editing.h:
+    * editing/Editor.cpp:
+    (WebCore::Editor::replaceSelectionWithFragment):
+    
+    Instead of always immediately revealing the selection after applying the ReplaceSelectionCommand, collect the
+    image elements that were just inserted, and avoid immediately revealing the selection if any of these images
+    have non-null cached images, but are not loaded yet. Instead, hold on to these images in a set, remove them once
+    they finish loading using the new method below, and once all images are removed, reveal the selection.
+    
+    (WebCore::Editor::revealSelectionIfNeededAfterLoadingImageForElement):
+    (WebCore::Editor::renderLayerDidScroll):
+    
+    Called whenever a scrollable RenderLayer is scrolled (or in the case of FrameView, the root layer). In the case
+    where Editor is waiting to reveal the selection, we check to see if the scrolled layer is an ancestor of the
+    layer enclosing the start of the selection.
+    
+    (WebCore::Editor::respondToChangedSelection):
+    
+    If the selection changes between pasting and waiting for pasted images to load, just cancel waiting to reveal
+    the selection after pasting.
+    
+    * editing/Editor.h:
+    * editing/ReplaceSelectionCommand.cpp:
+    (WebCore::ReplaceSelectionCommand::insertedContentRange const):
+    
+    Add a helper method to grab the Range of content inserted after applying the command.
+    
+    * editing/ReplaceSelectionCommand.h:
+    * page/FrameView.cpp:
+    (WebCore::FrameView::scrollPositionChanged):
+    * page/FrameView.h:
+    * page/Page.cpp:
+    (WebCore::Page::didFinishLoadingImageForElement):
+    
+    Notify Editor after an image finishes loading.
+    
+    * rendering/RenderLayer.cpp:
+    (WebCore::RenderLayer::scrollTo):
+    
+    Source/WebKit:
+    
+    Tweak some existing logic to use the new visibleImageElementsInRangeWithNonLoadedImages helper function. See
+    WebCore for more details.
+    
+    * WebProcess/WebPage/ios/WebPageIOS.mm:
+    (WebKit::WebPage::didConcludeEditDrag):
+    
+    Tools:
+    
+    Add an API test to exercise the scenario where we scroll to reveal the selection after pasting an image that was
+    directly written to the pasteboard.
+    
+    * TestWebKitAPI/Tests/WebKitCocoa/PasteImage.mm:
+    
+    LayoutTests:
+    
+    Add a couple of new layout tests.
+    
+    * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll-expected.txt: Added.
+    * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html: Added.
+    
+    This test verifies that we don't try to scroll to reveal the caret after pasting, if the scroll position was
+    changed before the images finished loading.
+    
+    * editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
+    * editing/pasteboard/reveal-selection-after-pasting-images.html: Added.
+    * platform/ios/editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
+    
+    This test verifies that we reveal the caret after loading multiple pasted images in a selection, and dispatch a
+    scroll event in the process.
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@249605 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2019-09-06  Wenson Hsieh  <wenson_hs...@apple.com>
+
+            Incorrect selection rect revealed after pasting images in a contenteditable element
+            https://bugs.webkit.org/show_bug.cgi?id=201549
+            <rdar://problem/50956429>
+
+            Reviewed by Simon Fraser.
+
+            Editor::replaceSelectionWithFragment currently scrolls to reveal the selection after inserting the given
+            DocumentFragment. However, this scrolling occurs before any inserted images have loaded yet, which causes the
+            wrong caret rect to be revealed, since all image elements inserted during paste will be empty.
+
+            To fix this, we defer revealing the selection after inserting the fragment until after all images that have
+            been inserted are done loading. While waiting for images to load, if any layers which may be scrolled as a
+            result of revealing the selection are scrolled, we additionally cancel the deferred selection reveal. See
+            comments below for more detail.
+
+            Tests: editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html
+                   editing/pasteboard/reveal-selection-after-pasting-images.html
+                   PasteImage.RevealSelectionAfterPastingImage
+
+            * editing/Editing.cpp:
+            (WebCore::visibleImageElementsInRangeWithNonLoadedImages):
+
+            Add a new helper to iterate through a range and collect all image elements in that range, that contain cached
+            images that have not finished loading yet.
+
+            * editing/Editing.h:
+            * editing/Editor.cpp:
+            (WebCore::Editor::replaceSelectionWithFragment):
+
+            Instead of always immediately revealing the selection after applying the ReplaceSelectionCommand, collect the
+            image elements that were just inserted, and avoid immediately revealing the selection if any of these images
+            have non-null cached images, but are not loaded yet. Instead, hold on to these images in a set, remove them once
+            they finish loading using the new method below, and once all images are removed, reveal the selection.
+
+            (WebCore::Editor::revealSelectionIfNeededAfterLoadingImageForElement):
+            (WebCore::Editor::renderLayerDidScroll):
+
+            Called whenever a scrollable RenderLayer is scrolled (or in the case of FrameView, the root layer). In the case
+            where Editor is waiting to reveal the selection, we check to see if the scrolled layer is an ancestor of the
+            layer enclosing the start of the selection.
+
+            (WebCore::Editor::respondToChangedSelection):
+
+            If the selection changes between pasting and waiting for pasted images to load, just cancel waiting to reveal
+            the selection after pasting.
+
+            * editing/Editor.h:
+            * editing/ReplaceSelectionCommand.cpp:
+            (WebCore::ReplaceSelectionCommand::insertedContentRange const):
+
+            Add a helper method to grab the Range of content inserted after applying the command.
+
+            * editing/ReplaceSelectionCommand.h:
+            * page/FrameView.cpp:
+            (WebCore::FrameView::scrollPositionChanged):
+            * page/FrameView.h:
+            * page/Page.cpp:
+            (WebCore::Page::didFinishLoadingImageForElement):
+
+            Notify Editor after an image finishes loading.
+
+            * rendering/RenderLayer.cpp:
+            (WebCore::RenderLayer::scrollTo):
+
+2019-09-09  Kocsen Chung  <kocsen_ch...@apple.com>
+
         Cherry-pick r249581. rdar://problem/55202922
 
     REGRESSION (iOS 13): If an overflow:hidden with a non-zero scroll position is toggled to overflow:scroll, some other scroll causes its scroll position to get reset

Modified: branches/safari-608-branch/Source/WebCore/editing/Editing.cpp (249697 => 249698)


--- branches/safari-608-branch/Source/WebCore/editing/Editing.cpp	2019-09-10 03:19:56 UTC (rev 249697)
+++ branches/safari-608-branch/Source/WebCore/editing/Editing.cpp	2019-09-10 03:20:02 UTC (rev 249698)
@@ -27,6 +27,7 @@
 #include "Editing.h"
 
 #include "AXObjectCache.h"
+#include "CachedImage.h"
 #include "Document.h"
 #include "Editor.h"
 #include "Frame.h"
@@ -34,6 +35,7 @@
 #include "HTMLDListElement.h"
 #include "HTMLDivElement.h"
 #include "HTMLElementFactory.h"
+#include "HTMLImageElement.h"
 #include "HTMLInterchange.h"
 #include "HTMLLIElement.h"
 #include "HTMLNames.h"
@@ -1302,4 +1304,19 @@
     return rendererForCaretPainting->localToAbsoluteQuad(FloatRect(localRect), UseTransforms, insideFixed).enclosingBoundingBox();
 }
 
+HashSet<RefPtr<HTMLImageElement>> visibleImageElementsInRangeWithNonLoadedImages(const Range& range)
+{
+    HashSet<RefPtr<HTMLImageElement>> result;
+    for (TextIterator iterator(&range); !iterator.atEnd(); iterator.advance()) {
+        if (!is<HTMLImageElement>(iterator.node()))
+            continue;
+
+        auto& imageElement = downcast<HTMLImageElement>(*iterator.node());
+        auto* cachedImage = imageElement.cachedImage();
+        if (cachedImage && cachedImage->isLoading())
+            result.add(&imageElement);
+    }
+    return result;
+}
+
 } // namespace WebCore

Modified: branches/safari-608-branch/Source/WebCore/editing/Editing.h (249697 => 249698)


--- branches/safari-608-branch/Source/WebCore/editing/Editing.h	2019-09-10 03:19:56 UTC (rev 249697)
+++ branches/safari-608-branch/Source/WebCore/editing/Editing.h	2019-09-10 03:20:02 UTC (rev 249698)
@@ -27,6 +27,7 @@
 
 #include "Position.h"
 #include <wtf/Forward.h>
+#include <wtf/HashSet.h>
 #include <wtf/unicode/CharacterNames.h>
 
 namespace WebCore {
@@ -33,6 +34,7 @@
 
 class Document;
 class HTMLElement;
+class HTMLImageElement;
 class HTMLSpanElement;
 class HTMLTextFormControlElement;
 class RenderBlock;
@@ -102,6 +104,8 @@
 
 bool positionBeforeOrAfterNodeIsCandidate(Node&);
 
+WEBCORE_EXPORT HashSet<RefPtr<HTMLImageElement>> visibleImageElementsInRangeWithNonLoadedImages(const Range&);
+
 // -------------------------------------------------------------------------
 // Position
 // -------------------------------------------------------------------------

Modified: branches/safari-608-branch/Source/WebCore/editing/Editor.cpp (249697 => 249698)


--- branches/safari-608-branch/Source/WebCore/editing/Editor.cpp	2019-09-10 03:19:56 UTC (rev 249697)
+++ branches/safari-608-branch/Source/WebCore/editing/Editor.cpp	2019-09-10 03:20:02 UTC (rev 249698)
@@ -86,6 +86,7 @@
 #include "Range.h"
 #include "RemoveFormatCommand.h"
 #include "RenderBlock.h"
+#include "RenderLayer.h"
 #include "RenderTextControl.h"
 #include "RenderedDocumentMarker.h"
 #include "RenderedPosition.h"
@@ -674,8 +675,14 @@
 
     auto command = ReplaceSelectionCommand::create(document(), &fragment, options, editingAction);
     command->apply();
-    revealSelectionAfterEditingOperation();
 
+    m_imageElementsToLoadBeforeRevealingSelection.clear();
+    if (auto insertionRange = command->insertedContentRange())
+        m_imageElementsToLoadBeforeRevealingSelection = visibleImageElementsInRangeWithNonLoadedImages(*insertionRange);
+
+    if (m_imageElementsToLoadBeforeRevealingSelection.isEmpty())
+        revealSelectionAfterEditingOperation();
+
     selection = m_frame.selection().selection();
     if (selection.isInPasswordField())
         return;
@@ -1571,6 +1578,44 @@
 
 #endif
 
+void Editor::revealSelectionIfNeededAfterLoadingImageForElement(HTMLImageElement& element)
+{
+    if (m_imageElementsToLoadBeforeRevealingSelection.isEmpty())
+        return;
+
+    if (!m_imageElementsToLoadBeforeRevealingSelection.remove(&element))
+        return;
+
+    if (!m_imageElementsToLoadBeforeRevealingSelection.isEmpty())
+        return;
+
+    // FIXME: This should be queued as a task for the next rendering update.
+    document().updateLayout();
+    revealSelectionAfterEditingOperation();
+}
+
+void Editor::renderLayerDidScroll(const RenderLayer& layer)
+{
+    if (m_imageElementsToLoadBeforeRevealingSelection.isEmpty())
+        return;
+
+    auto startContainer = makeRefPtr(m_frame.selection().selection().start().containerNode());
+    if (!startContainer)
+        return;
+
+    auto* startContainerRenderer = startContainer->renderer();
+    if (!startContainerRenderer)
+        return;
+
+    // FIXME: Ideally, this would also cancel deferred selection revealing if the selection is inside a subframe and a parent frame is scrolled.
+    for (auto* enclosingLayer = startContainerRenderer->enclosingLayer(); enclosingLayer; enclosingLayer = enclosingLayer->parent()) {
+        if (enclosingLayer == &layer) {
+            m_imageElementsToLoadBeforeRevealingSelection.clear();
+            break;
+        }
+    }
+}
+
 bool Editor::isContinuousSpellCheckingEnabled() const
 {
     return client() && client()->isContinuousSpellCheckingEnabled();
@@ -3575,6 +3620,7 @@
 #endif
 
     setStartNewKillRingSequence(true);
+    m_imageElementsToLoadBeforeRevealingSelection.clear();
 
     if (m_editorUIUpdateTimer.isActive())
         return;

Modified: branches/safari-608-branch/Source/WebCore/editing/Editor.h (249697 => 249698)


--- branches/safari-608-branch/Source/WebCore/editing/Editor.h	2019-09-10 03:19:56 UTC (rev 249697)
+++ branches/safari-608-branch/Source/WebCore/editing/Editor.h	2019-09-10 03:20:02 UTC (rev 249698)
@@ -72,6 +72,7 @@
 class KillRing;
 class Pasteboard;
 class PasteboardWriterData;
+class RenderLayer;
 class SharedBuffer;
 class Font;
 class SpellCheckRequest;
@@ -183,6 +184,9 @@
     WEBCORE_EXPORT void copyImage(const HitTestResult&);
 #endif
 
+    void renderLayerDidScroll(const RenderLayer&);
+    void revealSelectionIfNeededAfterLoadingImageForElement(HTMLImageElement&);
+
     String readPlainTextFromPasteboard(Pasteboard&);
 
     WEBCORE_EXPORT void indent();
@@ -628,6 +632,7 @@
 #endif
 
     bool m_isGettingDictionaryPopupInfo { false };
+    HashSet<RefPtr<HTMLImageElement>> m_imageElementsToLoadBeforeRevealingSelection;
 };
 
 inline void Editor::setStartNewKillRingSequence(bool flag)

Modified: branches/safari-608-branch/Source/WebCore/editing/ReplaceSelectionCommand.cpp (249697 => 249698)


--- branches/safari-608-branch/Source/WebCore/editing/ReplaceSelectionCommand.cpp	2019-09-10 03:19:56 UTC (rev 249697)
+++ branches/safari-608-branch/Source/WebCore/editing/ReplaceSelectionCommand.cpp	2019-09-10 03:20:02 UTC (rev 249698)
@@ -1675,4 +1675,12 @@
     return true;
 }
 
+RefPtr<Range> ReplaceSelectionCommand::insertedContentRange() const
+{
+    if (auto document = makeRefPtr(m_startOfInsertedContent.document()))
+        return Range::create(*document, m_startOfInsertedContent, m_endOfInsertedContent);
+
+    return nullptr;
+}
+
 } // namespace WebCore

Modified: branches/safari-608-branch/Source/WebCore/editing/ReplaceSelectionCommand.h (249697 => 249698)


--- branches/safari-608-branch/Source/WebCore/editing/ReplaceSelectionCommand.h	2019-09-10 03:19:56 UTC (rev 249697)
+++ branches/safari-608-branch/Source/WebCore/editing/ReplaceSelectionCommand.h	2019-09-10 03:20:02 UTC (rev 249698)
@@ -31,6 +31,7 @@
 namespace WebCore {
 
 class DocumentFragment;
+class Range;
 class ReplacementFragment;
 
 class ReplaceSelectionCommand : public CompositeEditCommand {
@@ -52,6 +53,8 @@
 
     VisibleSelection visibleSelectionForInsertedText() const { return m_visibleSelectionForInsertedText; }
 
+    RefPtr<Range> insertedContentRange() const;
+
 private:
     ReplaceSelectionCommand(Document&, RefPtr<DocumentFragment>&&, OptionSet<CommandOption>, EditAction);
 

Modified: branches/safari-608-branch/Source/WebCore/page/FrameView.cpp (249697 => 249698)


--- branches/safari-608-branch/Source/WebCore/page/FrameView.cpp	2019-09-10 03:19:56 UTC (rev 249697)
+++ branches/safari-608-branch/Source/WebCore/page/FrameView.cpp	2019-09-10 03:20:02 UTC (rev 249698)
@@ -40,6 +40,7 @@
 #include "DeprecatedGlobalSettings.h"
 #include "DocumentLoader.h"
 #include "DocumentMarkerController.h"
+#include "Editor.h"
 #include "EventHandler.h"
 #include "EventNames.h"
 #include "FloatRect.h"
@@ -2457,6 +2458,11 @@
     LOG_WITH_STREAM(Scrolling, stream << "FrameView " << this << " scrollPositionChanged from " << oldPosition << " to " << newPosition << " (scale " << frameScaleFactor() << " )");
     updateLayoutViewport();
     viewportContentsChanged();
+
+    if (auto* renderView = this->renderView()) {
+        if (auto* layer = renderView->layer())
+            frame().editor().renderLayerDidScroll(*layer);
+    }
 }
 
 void FrameView::applyRecursivelyWithVisibleRect(const WTF::Function<void (FrameView& frameView, const IntRect& visibleRect)>& apply)

Modified: branches/safari-608-branch/Source/WebCore/page/FrameView.h (249697 => 249698)


--- branches/safari-608-branch/Source/WebCore/page/FrameView.h	2019-09-10 03:19:56 UTC (rev 249697)
+++ branches/safari-608-branch/Source/WebCore/page/FrameView.h	2019-09-10 03:20:02 UTC (rev 249698)
@@ -664,6 +664,8 @@
     GraphicsLayer* layerForHorizontalScrollbar() const final;
     GraphicsLayer* layerForVerticalScrollbar() const final;
 
+    void renderLayerDidScroll(const RenderLayer&);
+
 protected:
     bool scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect) final;
     void scrollContentsSlowPath(const IntRect& updateRect) final;

Modified: branches/safari-608-branch/Source/WebCore/page/Page.cpp (249697 => 249698)


--- branches/safari-608-branch/Source/WebCore/page/Page.cpp	2019-09-10 03:19:56 UTC (rev 249697)
+++ branches/safari-608-branch/Source/WebCore/page/Page.cpp	2019-09-10 03:20:02 UTC (rev 249698)
@@ -3002,6 +3002,9 @@
 
 void Page::didFinishLoadingImageForElement(HTMLImageElement& element)
 {
+    auto protectedElement = makeRef(element);
+    if (auto frame = makeRefPtr(element.document().frame()))
+        frame->editor().revealSelectionIfNeededAfterLoadingImageForElement(element);
     chrome().client().didFinishLoadingImageForElement(element);
 }
 

Modified: branches/safari-608-branch/Source/WebCore/rendering/RenderLayer.cpp (249697 => 249698)


--- branches/safari-608-branch/Source/WebCore/rendering/RenderLayer.cpp	2019-09-10 03:19:56 UTC (rev 249697)
+++ branches/safari-608-branch/Source/WebCore/rendering/RenderLayer.cpp	2019-09-10 03:20:02 UTC (rev 249698)
@@ -55,6 +55,7 @@
 #include "DocumentEventQueue.h"
 #include "DocumentMarkerController.h"
 #include "DocumentTimeline.h"
+#include "Editor.h"
 #include "Element.h"
 #include "EventHandler.h"
 #include "FEColorMatrix.h"
@@ -2570,6 +2571,7 @@
         view.frameView().didChangeScrollOffset();
 
     view.frameView().viewportContentsChanged();
+    frame.editor().renderLayerDidScroll(*this);
 }
 
 static inline bool frameElementAndViewPermitScroll(HTMLFrameElementBase* frameElementBase, FrameView& frameView)

Modified: branches/safari-608-branch/Source/WebKit/ChangeLog (249697 => 249698)


--- branches/safari-608-branch/Source/WebKit/ChangeLog	2019-09-10 03:19:56 UTC (rev 249697)
+++ branches/safari-608-branch/Source/WebKit/ChangeLog	2019-09-10 03:20:02 UTC (rev 249698)
@@ -1,5 +1,124 @@
 2019-09-09  Kocsen Chung  <kocsen_ch...@apple.com>
 
+        Cherry-pick r249605. rdar://problem/55182896
+
+    Incorrect selection rect revealed after pasting images in a contenteditable element
+    https://bugs.webkit.org/show_bug.cgi?id=201549
+    <rdar://problem/50956429>
+    
+    Reviewed by Simon Fraser.
+    
+    Source/WebCore:
+    
+    Editor::replaceSelectionWithFragment currently scrolls to reveal the selection after inserting the given
+    DocumentFragment. However, this scrolling occurs before any inserted images have loaded yet, which causes the
+    wrong caret rect to be revealed, since all image elements inserted during paste will be empty.
+    
+    To fix this, we defer revealing the selection after inserting the fragment until after all images that have
+    been inserted are done loading. While waiting for images to load, if any layers which may be scrolled as a
+    result of revealing the selection are scrolled, we additionally cancel the deferred selection reveal. See
+    comments below for more detail.
+    
+    Tests: editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html
+           editing/pasteboard/reveal-selection-after-pasting-images.html
+           PasteImage.RevealSelectionAfterPastingImage
+    
+    * editing/Editing.cpp:
+    (WebCore::visibleImageElementsInRangeWithNonLoadedImages):
+    
+    Add a new helper to iterate through a range and collect all image elements in that range, that contain cached
+    images that have not finished loading yet.
+    
+    * editing/Editing.h:
+    * editing/Editor.cpp:
+    (WebCore::Editor::replaceSelectionWithFragment):
+    
+    Instead of always immediately revealing the selection after applying the ReplaceSelectionCommand, collect the
+    image elements that were just inserted, and avoid immediately revealing the selection if any of these images
+    have non-null cached images, but are not loaded yet. Instead, hold on to these images in a set, remove them once
+    they finish loading using the new method below, and once all images are removed, reveal the selection.
+    
+    (WebCore::Editor::revealSelectionIfNeededAfterLoadingImageForElement):
+    (WebCore::Editor::renderLayerDidScroll):
+    
+    Called whenever a scrollable RenderLayer is scrolled (or in the case of FrameView, the root layer). In the case
+    where Editor is waiting to reveal the selection, we check to see if the scrolled layer is an ancestor of the
+    layer enclosing the start of the selection.
+    
+    (WebCore::Editor::respondToChangedSelection):
+    
+    If the selection changes between pasting and waiting for pasted images to load, just cancel waiting to reveal
+    the selection after pasting.
+    
+    * editing/Editor.h:
+    * editing/ReplaceSelectionCommand.cpp:
+    (WebCore::ReplaceSelectionCommand::insertedContentRange const):
+    
+    Add a helper method to grab the Range of content inserted after applying the command.
+    
+    * editing/ReplaceSelectionCommand.h:
+    * page/FrameView.cpp:
+    (WebCore::FrameView::scrollPositionChanged):
+    * page/FrameView.h:
+    * page/Page.cpp:
+    (WebCore::Page::didFinishLoadingImageForElement):
+    
+    Notify Editor after an image finishes loading.
+    
+    * rendering/RenderLayer.cpp:
+    (WebCore::RenderLayer::scrollTo):
+    
+    Source/WebKit:
+    
+    Tweak some existing logic to use the new visibleImageElementsInRangeWithNonLoadedImages helper function. See
+    WebCore for more details.
+    
+    * WebProcess/WebPage/ios/WebPageIOS.mm:
+    (WebKit::WebPage::didConcludeEditDrag):
+    
+    Tools:
+    
+    Add an API test to exercise the scenario where we scroll to reveal the selection after pasting an image that was
+    directly written to the pasteboard.
+    
+    * TestWebKitAPI/Tests/WebKitCocoa/PasteImage.mm:
+    
+    LayoutTests:
+    
+    Add a couple of new layout tests.
+    
+    * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll-expected.txt: Added.
+    * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html: Added.
+    
+    This test verifies that we don't try to scroll to reveal the caret after pasting, if the scroll position was
+    changed before the images finished loading.
+    
+    * editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
+    * editing/pasteboard/reveal-selection-after-pasting-images.html: Added.
+    * platform/ios/editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
+    
+    This test verifies that we reveal the caret after loading multiple pasted images in a selection, and dispatch a
+    scroll event in the process.
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@249605 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2019-09-06  Wenson Hsieh  <wenson_hs...@apple.com>
+
+            Incorrect selection rect revealed after pasting images in a contenteditable element
+            https://bugs.webkit.org/show_bug.cgi?id=201549
+            <rdar://problem/50956429>
+
+            Reviewed by Simon Fraser.
+
+            Tweak some existing logic to use the new visibleImageElementsInRangeWithNonLoadedImages helper function. See
+            WebCore for more details.
+
+            * WebProcess/WebPage/ios/WebPageIOS.mm:
+            (WebKit::WebPage::didConcludeEditDrag):
+
+2019-09-09  Kocsen Chung  <kocsen_ch...@apple.com>
+
         Cherry-pick r249584. rdar://problem/55202935
 
     Marking up a note on iOS results in a PDF with no contents

Modified: branches/safari-608-branch/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm (249697 => 249698)


--- branches/safari-608-branch/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2019-09-10 03:19:56 UTC (rev 249697)
+++ branches/safari-608-branch/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2019-09-10 03:20:02 UTC (rev 249698)
@@ -910,21 +910,9 @@
 
     m_pendingImageElementsForDropSnapshot.clear();
 
-    bool waitingForAnyImageToLoad = false;
     auto frame = makeRef(m_page->focusController().focusedOrMainFrame());
     if (auto selectionRange = frame->selection().selection().toNormalizedRange()) {
-        for (TextIterator iterator(selectionRange.get()); !iterator.atEnd(); iterator.advance()) {
-            auto* node = iterator.node();
-            if (!is<HTMLImageElement>(node))
-                continue;
-
-            auto& imageElement = downcast<HTMLImageElement>(*node);
-            auto* cachedImage = imageElement.cachedImage();
-            if (cachedImage && cachedImage->image() && cachedImage->image()->isNull()) {
-                m_pendingImageElementsForDropSnapshot.add(&imageElement);
-                waitingForAnyImageToLoad = true;
-            }
-        }
+        m_pendingImageElementsForDropSnapshot = visibleImageElementsInRangeWithNonLoadedImages(*selectionRange);
         auto collapsedRange = Range::create(selectionRange->ownerDocument(), selectionRange->endPosition(), selectionRange->endPosition());
         frame->selection().setSelectedRange(collapsedRange.ptr(), DOWNSTREAM, FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
 
@@ -931,7 +919,7 @@
         m_rangeForDropSnapshot = WTFMove(selectionRange);
     }
 
-    if (!waitingForAnyImageToLoad)
+    if (m_pendingImageElementsForDropSnapshot.isEmpty())
         computeAndSendEditDragSnapshot();
 }
 

Modified: branches/safari-608-branch/Tools/ChangeLog (249697 => 249698)


--- branches/safari-608-branch/Tools/ChangeLog	2019-09-10 03:19:56 UTC (rev 249697)
+++ branches/safari-608-branch/Tools/ChangeLog	2019-09-10 03:20:02 UTC (rev 249698)
@@ -1,5 +1,123 @@
 2019-09-09  Kocsen Chung  <kocsen_ch...@apple.com>
 
+        Cherry-pick r249605. rdar://problem/55182896
+
+    Incorrect selection rect revealed after pasting images in a contenteditable element
+    https://bugs.webkit.org/show_bug.cgi?id=201549
+    <rdar://problem/50956429>
+    
+    Reviewed by Simon Fraser.
+    
+    Source/WebCore:
+    
+    Editor::replaceSelectionWithFragment currently scrolls to reveal the selection after inserting the given
+    DocumentFragment. However, this scrolling occurs before any inserted images have loaded yet, which causes the
+    wrong caret rect to be revealed, since all image elements inserted during paste will be empty.
+    
+    To fix this, we defer revealing the selection after inserting the fragment until after all images that have
+    been inserted are done loading. While waiting for images to load, if any layers which may be scrolled as a
+    result of revealing the selection are scrolled, we additionally cancel the deferred selection reveal. See
+    comments below for more detail.
+    
+    Tests: editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html
+           editing/pasteboard/reveal-selection-after-pasting-images.html
+           PasteImage.RevealSelectionAfterPastingImage
+    
+    * editing/Editing.cpp:
+    (WebCore::visibleImageElementsInRangeWithNonLoadedImages):
+    
+    Add a new helper to iterate through a range and collect all image elements in that range, that contain cached
+    images that have not finished loading yet.
+    
+    * editing/Editing.h:
+    * editing/Editor.cpp:
+    (WebCore::Editor::replaceSelectionWithFragment):
+    
+    Instead of always immediately revealing the selection after applying the ReplaceSelectionCommand, collect the
+    image elements that were just inserted, and avoid immediately revealing the selection if any of these images
+    have non-null cached images, but are not loaded yet. Instead, hold on to these images in a set, remove them once
+    they finish loading using the new method below, and once all images are removed, reveal the selection.
+    
+    (WebCore::Editor::revealSelectionIfNeededAfterLoadingImageForElement):
+    (WebCore::Editor::renderLayerDidScroll):
+    
+    Called whenever a scrollable RenderLayer is scrolled (or in the case of FrameView, the root layer). In the case
+    where Editor is waiting to reveal the selection, we check to see if the scrolled layer is an ancestor of the
+    layer enclosing the start of the selection.
+    
+    (WebCore::Editor::respondToChangedSelection):
+    
+    If the selection changes between pasting and waiting for pasted images to load, just cancel waiting to reveal
+    the selection after pasting.
+    
+    * editing/Editor.h:
+    * editing/ReplaceSelectionCommand.cpp:
+    (WebCore::ReplaceSelectionCommand::insertedContentRange const):
+    
+    Add a helper method to grab the Range of content inserted after applying the command.
+    
+    * editing/ReplaceSelectionCommand.h:
+    * page/FrameView.cpp:
+    (WebCore::FrameView::scrollPositionChanged):
+    * page/FrameView.h:
+    * page/Page.cpp:
+    (WebCore::Page::didFinishLoadingImageForElement):
+    
+    Notify Editor after an image finishes loading.
+    
+    * rendering/RenderLayer.cpp:
+    (WebCore::RenderLayer::scrollTo):
+    
+    Source/WebKit:
+    
+    Tweak some existing logic to use the new visibleImageElementsInRangeWithNonLoadedImages helper function. See
+    WebCore for more details.
+    
+    * WebProcess/WebPage/ios/WebPageIOS.mm:
+    (WebKit::WebPage::didConcludeEditDrag):
+    
+    Tools:
+    
+    Add an API test to exercise the scenario where we scroll to reveal the selection after pasting an image that was
+    directly written to the pasteboard.
+    
+    * TestWebKitAPI/Tests/WebKitCocoa/PasteImage.mm:
+    
+    LayoutTests:
+    
+    Add a couple of new layout tests.
+    
+    * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll-expected.txt: Added.
+    * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html: Added.
+    
+    This test verifies that we don't try to scroll to reveal the caret after pasting, if the scroll position was
+    changed before the images finished loading.
+    
+    * editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
+    * editing/pasteboard/reveal-selection-after-pasting-images.html: Added.
+    * platform/ios/editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
+    
+    This test verifies that we reveal the caret after loading multiple pasted images in a selection, and dispatch a
+    scroll event in the process.
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@249605 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2019-09-06  Wenson Hsieh  <wenson_hs...@apple.com>
+
+            Incorrect selection rect revealed after pasting images in a contenteditable element
+            https://bugs.webkit.org/show_bug.cgi?id=201549
+            <rdar://problem/50956429>
+
+            Reviewed by Simon Fraser.
+
+            Add an API test to exercise the scenario where we scroll to reveal the selection after pasting an image that was
+            directly written to the pasteboard.
+
+            * TestWebKitAPI/Tests/WebKitCocoa/PasteImage.mm:
+
+2019-09-09  Kocsen Chung  <kocsen_ch...@apple.com>
+
         Cherry-pick r249584. rdar://problem/55202935
 
     Marking up a note on iOS results in a PDF with no contents

Modified: branches/safari-608-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/PasteImage.mm (249697 => 249698)


--- branches/safari-608-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/PasteImage.mm	2019-09-10 03:19:56 UTC (rev 249697)
+++ branches/safari-608-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/PasteImage.mm	2019-09-10 03:20:02 UTC (rev 249698)
@@ -33,7 +33,7 @@
 #import <wtf/text/WTFString.h>
 
 #if PLATFORM(IOS_FAMILY)
-#include <MobileCoreServices/MobileCoreServices.h>
+#import <MobileCoreServices/MobileCoreServices.h>
 #endif
 
 #if PLATFORM(MAC)
@@ -137,6 +137,21 @@
     EXPECT_WK_STREQ("200", [webView stringByEvaluatingJavaScript:@"imageElement.width"]);
 }
 
+TEST(PasteImage, RevealSelectionAfterPastingImage)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);
+    [webView synchronouslyLoadHTMLString:@"<meta name='viewport' content='width=device-width, initial-scale=1'><body contenteditable>Hello world</body>"];
+    [webView stringByEvaluatingJavaScript:@"document.body.focus()"];
+    [webView _synchronouslyExecuteEditCommand:@"InsertText" argument:@"Hello world"];
+    [webView _synchronouslyExecuteEditCommand:@"InsertParagraph" argument:nil];
+
+    writeImageDataToPasteboard((__bridge NSString *)kUTTypeJPEG, [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"sunset-in-cupertino-600px" ofType:@"jpg" inDirectory:@"TestWebKitAPI.resources"]]);
+    [webView paste:nil];
+
+    while ([[webView stringByEvaluatingJavaScript:@"document.scrollingElement.scrollTop"] doubleValue] <= 0)
+        [NSRunLoop.currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.05]];
+}
+
 #if PLATFORM(MAC)
 void writeBundleFileToPasteboard(id object)
 {
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to