⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 249698 in webkit


Ignore:
Timestamp:
Sep 9, 2019, 8:20:02 PM (7 years ago)
Author:
Alan Coon
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

Location:
branches/safari-608-branch
Files:
5 added
16 edited

Legend:

Unmodified
Added
Removed
  • branches/safari-608-branch/LayoutTests/ChangeLog

    r249696 r249698  
     12019-09-09  Kocsen Chung  <kocsen_chung@apple.com>
     2
     3        Cherry-pick r249605. rdar://problem/55182896
     4
     5    Incorrect selection rect revealed after pasting images in a contenteditable element
     6    https://bugs.webkit.org/show_bug.cgi?id=201549
     7    <rdar://problem/50956429>
     8   
     9    Reviewed by Simon Fraser.
     10   
     11    Source/WebCore:
     12   
     13    Editor::replaceSelectionWithFragment currently scrolls to reveal the selection after inserting the given
     14    DocumentFragment. However, this scrolling occurs before any inserted images have loaded yet, which causes the
     15    wrong caret rect to be revealed, since all image elements inserted during paste will be empty.
     16   
     17    To fix this, we defer revealing the selection after inserting the fragment until after all images that have
     18    been inserted are done loading. While waiting for images to load, if any layers which may be scrolled as a
     19    result of revealing the selection are scrolled, we additionally cancel the deferred selection reveal. See
     20    comments below for more detail.
     21   
     22    Tests: editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html
     23           editing/pasteboard/reveal-selection-after-pasting-images.html
     24           PasteImage.RevealSelectionAfterPastingImage
     25   
     26    * editing/Editing.cpp:
     27    (WebCore::visibleImageElementsInRangeWithNonLoadedImages):
     28   
     29    Add a new helper to iterate through a range and collect all image elements in that range, that contain cached
     30    images that have not finished loading yet.
     31   
     32    * editing/Editing.h:
     33    * editing/Editor.cpp:
     34    (WebCore::Editor::replaceSelectionWithFragment):
     35   
     36    Instead of always immediately revealing the selection after applying the ReplaceSelectionCommand, collect the
     37    image elements that were just inserted, and avoid immediately revealing the selection if any of these images
     38    have non-null cached images, but are not loaded yet. Instead, hold on to these images in a set, remove them once
     39    they finish loading using the new method below, and once all images are removed, reveal the selection.
     40   
     41    (WebCore::Editor::revealSelectionIfNeededAfterLoadingImageForElement):
     42    (WebCore::Editor::renderLayerDidScroll):
     43   
     44    Called whenever a scrollable RenderLayer is scrolled (or in the case of FrameView, the root layer). In the case
     45    where Editor is waiting to reveal the selection, we check to see if the scrolled layer is an ancestor of the
     46    layer enclosing the start of the selection.
     47   
     48    (WebCore::Editor::respondToChangedSelection):
     49   
     50    If the selection changes between pasting and waiting for pasted images to load, just cancel waiting to reveal
     51    the selection after pasting.
     52   
     53    * editing/Editor.h:
     54    * editing/ReplaceSelectionCommand.cpp:
     55    (WebCore::ReplaceSelectionCommand::insertedContentRange const):
     56   
     57    Add a helper method to grab the Range of content inserted after applying the command.
     58   
     59    * editing/ReplaceSelectionCommand.h:
     60    * page/FrameView.cpp:
     61    (WebCore::FrameView::scrollPositionChanged):
     62    * page/FrameView.h:
     63    * page/Page.cpp:
     64    (WebCore::Page::didFinishLoadingImageForElement):
     65   
     66    Notify Editor after an image finishes loading.
     67   
     68    * rendering/RenderLayer.cpp:
     69    (WebCore::RenderLayer::scrollTo):
     70   
     71    Source/WebKit:
     72   
     73    Tweak some existing logic to use the new visibleImageElementsInRangeWithNonLoadedImages helper function. See
     74    WebCore for more details.
     75   
     76    * WebProcess/WebPage/ios/WebPageIOS.mm:
     77    (WebKit::WebPage::didConcludeEditDrag):
     78   
     79    Tools:
     80   
     81    Add an API test to exercise the scenario where we scroll to reveal the selection after pasting an image that was
     82    directly written to the pasteboard.
     83   
     84    * TestWebKitAPI/Tests/WebKitCocoa/PasteImage.mm:
     85   
     86    LayoutTests:
     87   
     88    Add a couple of new layout tests.
     89   
     90    * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll-expected.txt: Added.
     91    * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html: Added.
     92   
     93    This test verifies that we don't try to scroll to reveal the caret after pasting, if the scroll position was
     94    changed before the images finished loading.
     95   
     96    * editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
     97    * editing/pasteboard/reveal-selection-after-pasting-images.html: Added.
     98    * platform/ios/editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
     99   
     100    This test verifies that we reveal the caret after loading multiple pasted images in a selection, and dispatch a
     101    scroll event in the process.
     102   
     103   
     104    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@249605 268f45cc-cd09-0410-ab3c-d52691b4dbfc
     105
     106    2019-09-06  Wenson Hsieh  <wenson_hsieh@apple.com>
     107
     108            Incorrect selection rect revealed after pasting images in a contenteditable element
     109            https://bugs.webkit.org/show_bug.cgi?id=201549
     110            <rdar://problem/50956429>
     111
     112            Reviewed by Simon Fraser.
     113
     114            Add a couple of new layout tests.
     115
     116            * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll-expected.txt: Added.
     117            * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html: Added.
     118
     119            This test verifies that we don't try to scroll to reveal the caret after pasting, if the scroll position was
     120            changed before the images finished loading.
     121
     122            * editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
     123            * editing/pasteboard/reveal-selection-after-pasting-images.html: Added.
     124            * platform/ios/editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
     125
     126            This test verifies that we reveal the caret after loading multiple pasted images in a selection, and dispatch a
     127            scroll event in the process.
     128
    11292019-09-09  Kocsen Chung  <kocsen_chung@apple.com>
    2130
  • branches/safari-608-branch/Source/WebCore/ChangeLog

    r249696 r249698  
     12019-09-09  Kocsen Chung  <kocsen_chung@apple.com>
     2
     3        Cherry-pick r249605. rdar://problem/55182896
     4
     5    Incorrect selection rect revealed after pasting images in a contenteditable element
     6    https://bugs.webkit.org/show_bug.cgi?id=201549
     7    <rdar://problem/50956429>
     8   
     9    Reviewed by Simon Fraser.
     10   
     11    Source/WebCore:
     12   
     13    Editor::replaceSelectionWithFragment currently scrolls to reveal the selection after inserting the given
     14    DocumentFragment. However, this scrolling occurs before any inserted images have loaded yet, which causes the
     15    wrong caret rect to be revealed, since all image elements inserted during paste will be empty.
     16   
     17    To fix this, we defer revealing the selection after inserting the fragment until after all images that have
     18    been inserted are done loading. While waiting for images to load, if any layers which may be scrolled as a
     19    result of revealing the selection are scrolled, we additionally cancel the deferred selection reveal. See
     20    comments below for more detail.
     21   
     22    Tests: editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html
     23           editing/pasteboard/reveal-selection-after-pasting-images.html
     24           PasteImage.RevealSelectionAfterPastingImage
     25   
     26    * editing/Editing.cpp:
     27    (WebCore::visibleImageElementsInRangeWithNonLoadedImages):
     28   
     29    Add a new helper to iterate through a range and collect all image elements in that range, that contain cached
     30    images that have not finished loading yet.
     31   
     32    * editing/Editing.h:
     33    * editing/Editor.cpp:
     34    (WebCore::Editor::replaceSelectionWithFragment):
     35   
     36    Instead of always immediately revealing the selection after applying the ReplaceSelectionCommand, collect the
     37    image elements that were just inserted, and avoid immediately revealing the selection if any of these images
     38    have non-null cached images, but are not loaded yet. Instead, hold on to these images in a set, remove them once
     39    they finish loading using the new method below, and once all images are removed, reveal the selection.
     40   
     41    (WebCore::Editor::revealSelectionIfNeededAfterLoadingImageForElement):
     42    (WebCore::Editor::renderLayerDidScroll):
     43   
     44    Called whenever a scrollable RenderLayer is scrolled (or in the case of FrameView, the root layer). In the case
     45    where Editor is waiting to reveal the selection, we check to see if the scrolled layer is an ancestor of the
     46    layer enclosing the start of the selection.
     47   
     48    (WebCore::Editor::respondToChangedSelection):
     49   
     50    If the selection changes between pasting and waiting for pasted images to load, just cancel waiting to reveal
     51    the selection after pasting.
     52   
     53    * editing/Editor.h:
     54    * editing/ReplaceSelectionCommand.cpp:
     55    (WebCore::ReplaceSelectionCommand::insertedContentRange const):
     56   
     57    Add a helper method to grab the Range of content inserted after applying the command.
     58   
     59    * editing/ReplaceSelectionCommand.h:
     60    * page/FrameView.cpp:
     61    (WebCore::FrameView::scrollPositionChanged):
     62    * page/FrameView.h:
     63    * page/Page.cpp:
     64    (WebCore::Page::didFinishLoadingImageForElement):
     65   
     66    Notify Editor after an image finishes loading.
     67   
     68    * rendering/RenderLayer.cpp:
     69    (WebCore::RenderLayer::scrollTo):
     70   
     71    Source/WebKit:
     72   
     73    Tweak some existing logic to use the new visibleImageElementsInRangeWithNonLoadedImages helper function. See
     74    WebCore for more details.
     75   
     76    * WebProcess/WebPage/ios/WebPageIOS.mm:
     77    (WebKit::WebPage::didConcludeEditDrag):
     78   
     79    Tools:
     80   
     81    Add an API test to exercise the scenario where we scroll to reveal the selection after pasting an image that was
     82    directly written to the pasteboard.
     83   
     84    * TestWebKitAPI/Tests/WebKitCocoa/PasteImage.mm:
     85   
     86    LayoutTests:
     87   
     88    Add a couple of new layout tests.
     89   
     90    * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll-expected.txt: Added.
     91    * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html: Added.
     92   
     93    This test verifies that we don't try to scroll to reveal the caret after pasting, if the scroll position was
     94    changed before the images finished loading.
     95   
     96    * editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
     97    * editing/pasteboard/reveal-selection-after-pasting-images.html: Added.
     98    * platform/ios/editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
     99   
     100    This test verifies that we reveal the caret after loading multiple pasted images in a selection, and dispatch a
     101    scroll event in the process.
     102   
     103   
     104    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@249605 268f45cc-cd09-0410-ab3c-d52691b4dbfc
     105
     106    2019-09-06  Wenson Hsieh  <wenson_hsieh@apple.com>
     107
     108            Incorrect selection rect revealed after pasting images in a contenteditable element
     109            https://bugs.webkit.org/show_bug.cgi?id=201549
     110            <rdar://problem/50956429>
     111
     112            Reviewed by Simon Fraser.
     113
     114            Editor::replaceSelectionWithFragment currently scrolls to reveal the selection after inserting the given
     115            DocumentFragment. However, this scrolling occurs before any inserted images have loaded yet, which causes the
     116            wrong caret rect to be revealed, since all image elements inserted during paste will be empty.
     117
     118            To fix this, we defer revealing the selection after inserting the fragment until after all images that have
     119            been inserted are done loading. While waiting for images to load, if any layers which may be scrolled as a
     120            result of revealing the selection are scrolled, we additionally cancel the deferred selection reveal. See
     121            comments below for more detail.
     122
     123            Tests: editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html
     124                   editing/pasteboard/reveal-selection-after-pasting-images.html
     125                   PasteImage.RevealSelectionAfterPastingImage
     126
     127            * editing/Editing.cpp:
     128            (WebCore::visibleImageElementsInRangeWithNonLoadedImages):
     129
     130            Add a new helper to iterate through a range and collect all image elements in that range, that contain cached
     131            images that have not finished loading yet.
     132
     133            * editing/Editing.h:
     134            * editing/Editor.cpp:
     135            (WebCore::Editor::replaceSelectionWithFragment):
     136
     137            Instead of always immediately revealing the selection after applying the ReplaceSelectionCommand, collect the
     138            image elements that were just inserted, and avoid immediately revealing the selection if any of these images
     139            have non-null cached images, but are not loaded yet. Instead, hold on to these images in a set, remove them once
     140            they finish loading using the new method below, and once all images are removed, reveal the selection.
     141
     142            (WebCore::Editor::revealSelectionIfNeededAfterLoadingImageForElement):
     143            (WebCore::Editor::renderLayerDidScroll):
     144
     145            Called whenever a scrollable RenderLayer is scrolled (or in the case of FrameView, the root layer). In the case
     146            where Editor is waiting to reveal the selection, we check to see if the scrolled layer is an ancestor of the
     147            layer enclosing the start of the selection.
     148
     149            (WebCore::Editor::respondToChangedSelection):
     150
     151            If the selection changes between pasting and waiting for pasted images to load, just cancel waiting to reveal
     152            the selection after pasting.
     153
     154            * editing/Editor.h:
     155            * editing/ReplaceSelectionCommand.cpp:
     156            (WebCore::ReplaceSelectionCommand::insertedContentRange const):
     157
     158            Add a helper method to grab the Range of content inserted after applying the command.
     159
     160            * editing/ReplaceSelectionCommand.h:
     161            * page/FrameView.cpp:
     162            (WebCore::FrameView::scrollPositionChanged):
     163            * page/FrameView.h:
     164            * page/Page.cpp:
     165            (WebCore::Page::didFinishLoadingImageForElement):
     166
     167            Notify Editor after an image finishes loading.
     168
     169            * rendering/RenderLayer.cpp:
     170            (WebCore::RenderLayer::scrollTo):
     171
    11722019-09-09  Kocsen Chung  <kocsen_chung@apple.com>
    2173
  • branches/safari-608-branch/Source/WebCore/editing/Editing.cpp

    r249695 r249698  
    2828
    2929#include "AXObjectCache.h"
     30#include "CachedImage.h"
    3031#include "Document.h"
    3132#include "Editor.h"
     
    3536#include "HTMLDivElement.h"
    3637#include "HTMLElementFactory.h"
     38#include "HTMLImageElement.h"
    3739#include "HTMLInterchange.h"
    3840#include "HTMLLIElement.h"
     
    13031305}
    13041306
     1307HashSet<RefPtr<HTMLImageElement>> visibleImageElementsInRangeWithNonLoadedImages(const Range& range)
     1308{
     1309    HashSet<RefPtr<HTMLImageElement>> result;
     1310    for (TextIterator iterator(&range); !iterator.atEnd(); iterator.advance()) {
     1311        if (!is<HTMLImageElement>(iterator.node()))
     1312            continue;
     1313
     1314        auto& imageElement = downcast<HTMLImageElement>(*iterator.node());
     1315        auto* cachedImage = imageElement.cachedImage();
     1316        if (cachedImage && cachedImage->isLoading())
     1317            result.add(&imageElement);
     1318    }
     1319    return result;
     1320}
     1321
    13051322} // namespace WebCore
  • branches/safari-608-branch/Source/WebCore/editing/Editing.h

    r246490 r249698  
    2828#include "Position.h"
    2929#include <wtf/Forward.h>
     30#include <wtf/HashSet.h>
    3031#include <wtf/unicode/CharacterNames.h>
    3132
     
    3435class Document;
    3536class HTMLElement;
     37class HTMLImageElement;
    3638class HTMLSpanElement;
    3739class HTMLTextFormControlElement;
     
    103105bool positionBeforeOrAfterNodeIsCandidate(Node&);
    104106
     107WEBCORE_EXPORT HashSet<RefPtr<HTMLImageElement>> visibleImageElementsInRangeWithNonLoadedImages(const Range&);
     108
    105109// -------------------------------------------------------------------------
    106110// Position
  • branches/safari-608-branch/Source/WebCore/editing/Editor.cpp

    r247180 r249698  
    8787#include "RemoveFormatCommand.h"
    8888#include "RenderBlock.h"
     89#include "RenderLayer.h"
    8990#include "RenderTextControl.h"
    9091#include "RenderedDocumentMarker.h"
     
    675676    auto command = ReplaceSelectionCommand::create(document(), &fragment, options, editingAction);
    676677    command->apply();
    677     revealSelectionAfterEditingOperation();
     678
     679    m_imageElementsToLoadBeforeRevealingSelection.clear();
     680    if (auto insertionRange = command->insertedContentRange())
     681        m_imageElementsToLoadBeforeRevealingSelection = visibleImageElementsInRangeWithNonLoadedImages(*insertionRange);
     682
     683    if (m_imageElementsToLoadBeforeRevealingSelection.isEmpty())
     684        revealSelectionAfterEditingOperation();
    678685
    679686    selection = m_frame.selection().selection();
     
    15711578
    15721579#endif
     1580
     1581void Editor::revealSelectionIfNeededAfterLoadingImageForElement(HTMLImageElement& element)
     1582{
     1583    if (m_imageElementsToLoadBeforeRevealingSelection.isEmpty())
     1584        return;
     1585
     1586    if (!m_imageElementsToLoadBeforeRevealingSelection.remove(&element))
     1587        return;
     1588
     1589    if (!m_imageElementsToLoadBeforeRevealingSelection.isEmpty())
     1590        return;
     1591
     1592    // FIXME: This should be queued as a task for the next rendering update.
     1593    document().updateLayout();
     1594    revealSelectionAfterEditingOperation();
     1595}
     1596
     1597void Editor::renderLayerDidScroll(const RenderLayer& layer)
     1598{
     1599    if (m_imageElementsToLoadBeforeRevealingSelection.isEmpty())
     1600        return;
     1601
     1602    auto startContainer = makeRefPtr(m_frame.selection().selection().start().containerNode());
     1603    if (!startContainer)
     1604        return;
     1605
     1606    auto* startContainerRenderer = startContainer->renderer();
     1607    if (!startContainerRenderer)
     1608        return;
     1609
     1610    // FIXME: Ideally, this would also cancel deferred selection revealing if the selection is inside a subframe and a parent frame is scrolled.
     1611    for (auto* enclosingLayer = startContainerRenderer->enclosingLayer(); enclosingLayer; enclosingLayer = enclosingLayer->parent()) {
     1612        if (enclosingLayer == &layer) {
     1613            m_imageElementsToLoadBeforeRevealingSelection.clear();
     1614            break;
     1615        }
     1616    }
     1617}
    15731618
    15741619bool Editor::isContinuousSpellCheckingEnabled() const
     
    35763621
    35773622    setStartNewKillRingSequence(true);
     3623    m_imageElementsToLoadBeforeRevealingSelection.clear();
    35783624
    35793625    if (m_editorUIUpdateTimer.isActive())
  • branches/safari-608-branch/Source/WebCore/editing/Editor.h

    r243195 r249698  
    7373class Pasteboard;
    7474class PasteboardWriterData;
     75class RenderLayer;
    7576class SharedBuffer;
    7677class Font;
     
    183184    WEBCORE_EXPORT void copyImage(const HitTestResult&);
    184185#endif
     186
     187    void renderLayerDidScroll(const RenderLayer&);
     188    void revealSelectionIfNeededAfterLoadingImageForElement(HTMLImageElement&);
    185189
    186190    String readPlainTextFromPasteboard(Pasteboard&);
     
    629633
    630634    bool m_isGettingDictionaryPopupInfo { false };
     635    HashSet<RefPtr<HTMLImageElement>> m_imageElementsToLoadBeforeRevealingSelection;
    631636};
    632637
  • branches/safari-608-branch/Source/WebCore/editing/ReplaceSelectionCommand.cpp

    r246868 r249698  
    16761676}
    16771677
     1678RefPtr<Range> ReplaceSelectionCommand::insertedContentRange() const
     1679{
     1680    if (auto document = makeRefPtr(m_startOfInsertedContent.document()))
     1681        return Range::create(*document, m_startOfInsertedContent, m_endOfInsertedContent);
     1682
     1683    return nullptr;
     1684}
     1685
    16781686} // namespace WebCore
  • branches/safari-608-branch/Source/WebCore/editing/ReplaceSelectionCommand.h

    r243124 r249698  
    3232
    3333class DocumentFragment;
     34class Range;
    3435class ReplacementFragment;
    3536
     
    5253
    5354    VisibleSelection visibleSelectionForInsertedText() const { return m_visibleSelectionForInsertedText; }
     55
     56    RefPtr<Range> insertedContentRange() const;
    5457
    5558private:
  • branches/safari-608-branch/Source/WebCore/page/FrameView.cpp

    r247958 r249698  
    4141#include "DocumentLoader.h"
    4242#include "DocumentMarkerController.h"
     43#include "Editor.h"
    4344#include "EventHandler.h"
    4445#include "EventNames.h"
     
    24582459    updateLayoutViewport();
    24592460    viewportContentsChanged();
     2461
     2462    if (auto* renderView = this->renderView()) {
     2463        if (auto* layer = renderView->layer())
     2464            frame().editor().renderLayerDidScroll(*layer);
     2465    }
    24602466}
    24612467
  • branches/safari-608-branch/Source/WebCore/page/FrameView.h

    r247986 r249698  
    665665    GraphicsLayer* layerForVerticalScrollbar() const final;
    666666
     667    void renderLayerDidScroll(const RenderLayer&);
     668
    667669protected:
    668670    bool scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect) final;
  • branches/safari-608-branch/Source/WebCore/page/Page.cpp

    r247952 r249698  
    30033003void Page::didFinishLoadingImageForElement(HTMLImageElement& element)
    30043004{
     3005    auto protectedElement = makeRef(element);
     3006    if (auto frame = makeRefPtr(element.document().frame()))
     3007        frame->editor().revealSelectionIfNeededAfterLoadingImageForElement(element);
    30053008    chrome().client().didFinishLoadingImageForElement(element);
    30063009}
  • branches/safari-608-branch/Source/WebCore/rendering/RenderLayer.cpp

    r249471 r249698  
    5656#include "DocumentMarkerController.h"
    5757#include "DocumentTimeline.h"
     58#include "Editor.h"
    5859#include "Element.h"
    5960#include "EventHandler.h"
     
    25712572
    25722573    view.frameView().viewportContentsChanged();
     2574    frame.editor().renderLayerDidScroll(*this);
    25732575}
    25742576
  • branches/safari-608-branch/Source/WebKit/ChangeLog

    r249697 r249698  
     12019-09-09  Kocsen Chung  <kocsen_chung@apple.com>
     2
     3        Cherry-pick r249605. rdar://problem/55182896
     4
     5    Incorrect selection rect revealed after pasting images in a contenteditable element
     6    https://bugs.webkit.org/show_bug.cgi?id=201549
     7    <rdar://problem/50956429>
     8   
     9    Reviewed by Simon Fraser.
     10   
     11    Source/WebCore:
     12   
     13    Editor::replaceSelectionWithFragment currently scrolls to reveal the selection after inserting the given
     14    DocumentFragment. However, this scrolling occurs before any inserted images have loaded yet, which causes the
     15    wrong caret rect to be revealed, since all image elements inserted during paste will be empty.
     16   
     17    To fix this, we defer revealing the selection after inserting the fragment until after all images that have
     18    been inserted are done loading. While waiting for images to load, if any layers which may be scrolled as a
     19    result of revealing the selection are scrolled, we additionally cancel the deferred selection reveal. See
     20    comments below for more detail.
     21   
     22    Tests: editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html
     23           editing/pasteboard/reveal-selection-after-pasting-images.html
     24           PasteImage.RevealSelectionAfterPastingImage
     25   
     26    * editing/Editing.cpp:
     27    (WebCore::visibleImageElementsInRangeWithNonLoadedImages):
     28   
     29    Add a new helper to iterate through a range and collect all image elements in that range, that contain cached
     30    images that have not finished loading yet.
     31   
     32    * editing/Editing.h:
     33    * editing/Editor.cpp:
     34    (WebCore::Editor::replaceSelectionWithFragment):
     35   
     36    Instead of always immediately revealing the selection after applying the ReplaceSelectionCommand, collect the
     37    image elements that were just inserted, and avoid immediately revealing the selection if any of these images
     38    have non-null cached images, but are not loaded yet. Instead, hold on to these images in a set, remove them once
     39    they finish loading using the new method below, and once all images are removed, reveal the selection.
     40   
     41    (WebCore::Editor::revealSelectionIfNeededAfterLoadingImageForElement):
     42    (WebCore::Editor::renderLayerDidScroll):
     43   
     44    Called whenever a scrollable RenderLayer is scrolled (or in the case of FrameView, the root layer). In the case
     45    where Editor is waiting to reveal the selection, we check to see if the scrolled layer is an ancestor of the
     46    layer enclosing the start of the selection.
     47   
     48    (WebCore::Editor::respondToChangedSelection):
     49   
     50    If the selection changes between pasting and waiting for pasted images to load, just cancel waiting to reveal
     51    the selection after pasting.
     52   
     53    * editing/Editor.h:
     54    * editing/ReplaceSelectionCommand.cpp:
     55    (WebCore::ReplaceSelectionCommand::insertedContentRange const):
     56   
     57    Add a helper method to grab the Range of content inserted after applying the command.
     58   
     59    * editing/ReplaceSelectionCommand.h:
     60    * page/FrameView.cpp:
     61    (WebCore::FrameView::scrollPositionChanged):
     62    * page/FrameView.h:
     63    * page/Page.cpp:
     64    (WebCore::Page::didFinishLoadingImageForElement):
     65   
     66    Notify Editor after an image finishes loading.
     67   
     68    * rendering/RenderLayer.cpp:
     69    (WebCore::RenderLayer::scrollTo):
     70   
     71    Source/WebKit:
     72   
     73    Tweak some existing logic to use the new visibleImageElementsInRangeWithNonLoadedImages helper function. See
     74    WebCore for more details.
     75   
     76    * WebProcess/WebPage/ios/WebPageIOS.mm:
     77    (WebKit::WebPage::didConcludeEditDrag):
     78   
     79    Tools:
     80   
     81    Add an API test to exercise the scenario where we scroll to reveal the selection after pasting an image that was
     82    directly written to the pasteboard.
     83   
     84    * TestWebKitAPI/Tests/WebKitCocoa/PasteImage.mm:
     85   
     86    LayoutTests:
     87   
     88    Add a couple of new layout tests.
     89   
     90    * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll-expected.txt: Added.
     91    * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html: Added.
     92   
     93    This test verifies that we don't try to scroll to reveal the caret after pasting, if the scroll position was
     94    changed before the images finished loading.
     95   
     96    * editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
     97    * editing/pasteboard/reveal-selection-after-pasting-images.html: Added.
     98    * platform/ios/editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
     99   
     100    This test verifies that we reveal the caret after loading multiple pasted images in a selection, and dispatch a
     101    scroll event in the process.
     102   
     103   
     104    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@249605 268f45cc-cd09-0410-ab3c-d52691b4dbfc
     105
     106    2019-09-06  Wenson Hsieh  <wenson_hsieh@apple.com>
     107
     108            Incorrect selection rect revealed after pasting images in a contenteditable element
     109            https://bugs.webkit.org/show_bug.cgi?id=201549
     110            <rdar://problem/50956429>
     111
     112            Reviewed by Simon Fraser.
     113
     114            Tweak some existing logic to use the new visibleImageElementsInRangeWithNonLoadedImages helper function. See
     115            WebCore for more details.
     116
     117            * WebProcess/WebPage/ios/WebPageIOS.mm:
     118            (WebKit::WebPage::didConcludeEditDrag):
     119
    11202019-09-09  Kocsen Chung  <kocsen_chung@apple.com>
    2121
  • branches/safari-608-branch/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm

    r249471 r249698  
    911911    m_pendingImageElementsForDropSnapshot.clear();
    912912
    913     bool waitingForAnyImageToLoad = false;
    914913    auto frame = makeRef(m_page->focusController().focusedOrMainFrame());
    915914    if (auto selectionRange = frame->selection().selection().toNormalizedRange()) {
    916         for (TextIterator iterator(selectionRange.get()); !iterator.atEnd(); iterator.advance()) {
    917             auto* node = iterator.node();
    918             if (!is<HTMLImageElement>(node))
    919                 continue;
    920 
    921             auto& imageElement = downcast<HTMLImageElement>(*node);
    922             auto* cachedImage = imageElement.cachedImage();
    923             if (cachedImage && cachedImage->image() && cachedImage->image()->isNull()) {
    924                 m_pendingImageElementsForDropSnapshot.add(&imageElement);
    925                 waitingForAnyImageToLoad = true;
    926             }
    927         }
     915        m_pendingImageElementsForDropSnapshot = visibleImageElementsInRangeWithNonLoadedImages(*selectionRange);
    928916        auto collapsedRange = Range::create(selectionRange->ownerDocument(), selectionRange->endPosition(), selectionRange->endPosition());
    929917        frame->selection().setSelectedRange(collapsedRange.ptr(), DOWNSTREAM, FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
     
    932920    }
    933921
    934     if (!waitingForAnyImageToLoad)
     922    if (m_pendingImageElementsForDropSnapshot.isEmpty())
    935923        computeAndSendEditDragSnapshot();
    936924}
  • branches/safari-608-branch/Tools/ChangeLog

    r249697 r249698  
     12019-09-09  Kocsen Chung  <kocsen_chung@apple.com>
     2
     3        Cherry-pick r249605. rdar://problem/55182896
     4
     5    Incorrect selection rect revealed after pasting images in a contenteditable element
     6    https://bugs.webkit.org/show_bug.cgi?id=201549
     7    <rdar://problem/50956429>
     8   
     9    Reviewed by Simon Fraser.
     10   
     11    Source/WebCore:
     12   
     13    Editor::replaceSelectionWithFragment currently scrolls to reveal the selection after inserting the given
     14    DocumentFragment. However, this scrolling occurs before any inserted images have loaded yet, which causes the
     15    wrong caret rect to be revealed, since all image elements inserted during paste will be empty.
     16   
     17    To fix this, we defer revealing the selection after inserting the fragment until after all images that have
     18    been inserted are done loading. While waiting for images to load, if any layers which may be scrolled as a
     19    result of revealing the selection are scrolled, we additionally cancel the deferred selection reveal. See
     20    comments below for more detail.
     21   
     22    Tests: editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html
     23           editing/pasteboard/reveal-selection-after-pasting-images.html
     24           PasteImage.RevealSelectionAfterPastingImage
     25   
     26    * editing/Editing.cpp:
     27    (WebCore::visibleImageElementsInRangeWithNonLoadedImages):
     28   
     29    Add a new helper to iterate through a range and collect all image elements in that range, that contain cached
     30    images that have not finished loading yet.
     31   
     32    * editing/Editing.h:
     33    * editing/Editor.cpp:
     34    (WebCore::Editor::replaceSelectionWithFragment):
     35   
     36    Instead of always immediately revealing the selection after applying the ReplaceSelectionCommand, collect the
     37    image elements that were just inserted, and avoid immediately revealing the selection if any of these images
     38    have non-null cached images, but are not loaded yet. Instead, hold on to these images in a set, remove them once
     39    they finish loading using the new method below, and once all images are removed, reveal the selection.
     40   
     41    (WebCore::Editor::revealSelectionIfNeededAfterLoadingImageForElement):
     42    (WebCore::Editor::renderLayerDidScroll):
     43   
     44    Called whenever a scrollable RenderLayer is scrolled (or in the case of FrameView, the root layer). In the case
     45    where Editor is waiting to reveal the selection, we check to see if the scrolled layer is an ancestor of the
     46    layer enclosing the start of the selection.
     47   
     48    (WebCore::Editor::respondToChangedSelection):
     49   
     50    If the selection changes between pasting and waiting for pasted images to load, just cancel waiting to reveal
     51    the selection after pasting.
     52   
     53    * editing/Editor.h:
     54    * editing/ReplaceSelectionCommand.cpp:
     55    (WebCore::ReplaceSelectionCommand::insertedContentRange const):
     56   
     57    Add a helper method to grab the Range of content inserted after applying the command.
     58   
     59    * editing/ReplaceSelectionCommand.h:
     60    * page/FrameView.cpp:
     61    (WebCore::FrameView::scrollPositionChanged):
     62    * page/FrameView.h:
     63    * page/Page.cpp:
     64    (WebCore::Page::didFinishLoadingImageForElement):
     65   
     66    Notify Editor after an image finishes loading.
     67   
     68    * rendering/RenderLayer.cpp:
     69    (WebCore::RenderLayer::scrollTo):
     70   
     71    Source/WebKit:
     72   
     73    Tweak some existing logic to use the new visibleImageElementsInRangeWithNonLoadedImages helper function. See
     74    WebCore for more details.
     75   
     76    * WebProcess/WebPage/ios/WebPageIOS.mm:
     77    (WebKit::WebPage::didConcludeEditDrag):
     78   
     79    Tools:
     80   
     81    Add an API test to exercise the scenario where we scroll to reveal the selection after pasting an image that was
     82    directly written to the pasteboard.
     83   
     84    * TestWebKitAPI/Tests/WebKitCocoa/PasteImage.mm:
     85   
     86    LayoutTests:
     87   
     88    Add a couple of new layout tests.
     89   
     90    * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll-expected.txt: Added.
     91    * editing/pasteboard/do-not-reveal-selection-after-programmatic-scroll.html: Added.
     92   
     93    This test verifies that we don't try to scroll to reveal the caret after pasting, if the scroll position was
     94    changed before the images finished loading.
     95   
     96    * editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
     97    * editing/pasteboard/reveal-selection-after-pasting-images.html: Added.
     98    * platform/ios/editing/pasteboard/reveal-selection-after-pasting-images-expected.txt: Added.
     99   
     100    This test verifies that we reveal the caret after loading multiple pasted images in a selection, and dispatch a
     101    scroll event in the process.
     102   
     103   
     104    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@249605 268f45cc-cd09-0410-ab3c-d52691b4dbfc
     105
     106    2019-09-06  Wenson Hsieh  <wenson_hsieh@apple.com>
     107
     108            Incorrect selection rect revealed after pasting images in a contenteditable element
     109            https://bugs.webkit.org/show_bug.cgi?id=201549
     110            <rdar://problem/50956429>
     111
     112            Reviewed by Simon Fraser.
     113
     114            Add an API test to exercise the scenario where we scroll to reveal the selection after pasting an image that was
     115            directly written to the pasteboard.
     116
     117            * TestWebKitAPI/Tests/WebKitCocoa/PasteImage.mm:
     118
    11192019-09-09  Kocsen Chung  <kocsen_chung@apple.com>
    2120
  • branches/safari-608-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/PasteImage.mm

    r242339 r249698  
    3434
    3535#if PLATFORM(IOS_FAMILY)
    36 #include <MobileCoreServices/MobileCoreServices.h>
     36#import <MobileCoreServices/MobileCoreServices.h>
    3737#endif
    3838
     
    138138}
    139139
     140TEST(PasteImage, RevealSelectionAfterPastingImage)
     141{
     142    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);
     143    [webView synchronouslyLoadHTMLString:@"<meta name='viewport' content='width=device-width, initial-scale=1'><body contenteditable>Hello world</body>"];
     144    [webView stringByEvaluatingJavaScript:@"document.body.focus()"];
     145    [webView _synchronouslyExecuteEditCommand:@"InsertText" argument:@"Hello world"];
     146    [webView _synchronouslyExecuteEditCommand:@"InsertParagraph" argument:nil];
     147
     148    writeImageDataToPasteboard((__bridge NSString *)kUTTypeJPEG, [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"sunset-in-cupertino-600px" ofType:@"jpg" inDirectory:@"TestWebKitAPI.resources"]]);
     149    [webView paste:nil];
     150
     151    while ([[webView stringByEvaluatingJavaScript:@"document.scrollingElement.scrollTop"] doubleValue] <= 0)
     152        [NSRunLoop.currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.05]];
     153}
     154
    140155#if PLATFORM(MAC)
    141156void writeBundleFileToPasteboard(id object)
Note: See TracChangeset for help on using the changeset viewer.