Title: [219541] trunk
Revision
219541
Author
[email protected]
Date
2017-07-15 21:01:30 -0700 (Sat, 15 Jul 2017)

Log Message

[iOS WK2] Presenting an action sheet on an image map prevents selection UI from updating
https://bugs.webkit.org/show_bug.cgi?id=174539
<rdar://problem/33307395>

Reviewed by Darin Adler.

Source/WebCore:

Currently, if TextIndicator fails to take a snapshot in TextIndicator::createWithRange, we will enter an
inconsistent state in the web process where Editor will continue to ignore selection changes until the next time
Editor::setIgnoreSelectionChanges(false) is called. This causes us to indefinitely defer EditorState updates to
the UI process, which leads to selection UI appearing unresponsive.

To fix this, we introduce a new TemporarySelectionChange object to simplify selection changes and/or
EditorState-update-ignoring behaviors within the scope of a single function. The constructor applies these
temporary changes, and the destructor reverts them as needed to their prior values.

This patch only adopts TemporarySelectionChange in order to fix this bug, but future patches will replace the
remaining places where we temporarily change selection and/or ignore selection with this helper.

Test: ActionSheetTests.ImageMapDoesNotDestroySelection.

* editing/Editor.cpp:
(WebCore::TemporarySelectionChange::TemporarySelectionChange):
(WebCore::TemporarySelectionChange::~TemporarySelectionChange):
* editing/Editor.h:
* editing/FrameSelection.h:
(WebCore::FrameSelection::isUpdateAppearanceEnabled):
* page/TextIndicator.cpp:
(WebCore::TextIndicator::createWithRange):

Source/WebKit:

Small tweak to avoid presenting at the element rect or text rect if the interaction information failed to
capture valid bounds for the element. We instead fall back to presenting at the touch location. This addresses
problems when presenting the action sheet popover on image maps on iPad, where GetPositionInformation fails to
capture correct data about for the <area>.

* UIProcess/ios/WKActionSheetAssistant.mm:
(presentationStyleForView):

Tools:

Adds a new unit test suite to cover action sheet popover presentation.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKit2Cocoa/image-map.html: Added.
* TestWebKitAPI/Tests/ios/ActionSheetTests.mm: Added.
(-[ActionSheetObserver waitForActionSheetAfterBlock:]):

Runs the given block and waits until the UI process has indicated that it will present an action sheet.

(-[ActionSheetObserver _webView:actionsForElement:defaultActions:]):
(TestWebKitAPI::IPadUserInterfaceSwizzler::IPadUserInterfaceSwizzler):

Helper class to alter the behavior of [[UIDevice currentDevice] userInterfaceIdiom] for testing.

(TestWebKitAPI::IPadUserInterfaceSwizzler::padUserInterfaceIdiom):
(TestWebKitAPI::TEST):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (219540 => 219541)


--- trunk/Source/WebCore/ChangeLog	2017-07-16 03:45:04 UTC (rev 219540)
+++ trunk/Source/WebCore/ChangeLog	2017-07-16 04:01:30 UTC (rev 219541)
@@ -1,3 +1,34 @@
+2017-07-15  Wenson Hsieh  <[email protected]>
+
+        [iOS WK2] Presenting an action sheet on an image map prevents selection UI from updating
+        https://bugs.webkit.org/show_bug.cgi?id=174539
+        <rdar://problem/33307395>
+
+        Reviewed by Darin Adler.
+
+        Currently, if TextIndicator fails to take a snapshot in TextIndicator::createWithRange, we will enter an
+        inconsistent state in the web process where Editor will continue to ignore selection changes until the next time
+        Editor::setIgnoreSelectionChanges(false) is called. This causes us to indefinitely defer EditorState updates to
+        the UI process, which leads to selection UI appearing unresponsive.
+
+        To fix this, we introduce a new TemporarySelectionChange object to simplify selection changes and/or
+        EditorState-update-ignoring behaviors within the scope of a single function. The constructor applies these
+        temporary changes, and the destructor reverts them as needed to their prior values.
+
+        This patch only adopts TemporarySelectionChange in order to fix this bug, but future patches will replace the
+        remaining places where we temporarily change selection and/or ignore selection with this helper.
+
+        Test: ActionSheetTests.ImageMapDoesNotDestroySelection.
+
+        * editing/Editor.cpp:
+        (WebCore::TemporarySelectionChange::TemporarySelectionChange):
+        (WebCore::TemporarySelectionChange::~TemporarySelectionChange):
+        * editing/Editor.h:
+        * editing/FrameSelection.h:
+        (WebCore::FrameSelection::isUpdateAppearanceEnabled):
+        * page/TextIndicator.cpp:
+        (WebCore::TextIndicator::createWithRange):
+
 2017-07-15  Myles C. Maxfield  <[email protected]>
 
         Clean up line-height and minimumFontSize functions

Modified: trunk/Source/WebCore/editing/Editor.cpp (219540 => 219541)


--- trunk/Source/WebCore/editing/Editor.cpp	2017-07-16 03:45:04 UTC (rev 219540)
+++ trunk/Source/WebCore/editing/Editor.cpp	2017-07-16 04:01:30 UTC (rev 219541)
@@ -184,6 +184,44 @@
 using namespace WTF;
 using namespace Unicode;
 
+TemporarySelectionChange::TemporarySelectionChange(Frame& frame, std::optional<VisibleSelection> temporarySelection, TemporarySelectionOptions options)
+    : m_frame(frame)
+    , m_options(options)
+    , m_wasIgnoringSelectionChanges(frame.editor().ignoreSelectionChanges())
+#if PLATFORM(IOS)
+    , m_appearanceUpdatesWereEnabled(frame.selection().isUpdateAppearanceEnabled())
+#endif
+{
+#if PLATFORM(IOS)
+    if (options & TemporarySelectionOptionEnableAppearanceUpdates)
+        frame.selection().setUpdateAppearanceEnabled(true);
+#endif
+
+    if (options & TemporarySelectionOptionIgnoreSelectionChanges)
+        frame.editor().setIgnoreSelectionChanges(true);
+
+    if (temporarySelection) {
+        m_selectionToRestore = frame.selection().selection();
+        frame.selection().setSelection(temporarySelection.value());
+    }
+}
+
+TemporarySelectionChange::~TemporarySelectionChange()
+{
+    if (m_selectionToRestore)
+        m_frame->selection().setSelection(m_selectionToRestore.value());
+
+    if (m_options & TemporarySelectionOptionIgnoreSelectionChanges) {
+        auto revealSelection = m_options & TemporarySelectionOptionRevealSelection ? Editor::RevealSelection::Yes : Editor::RevealSelection::No;
+        m_frame->editor().setIgnoreSelectionChanges(m_wasIgnoringSelectionChanges, revealSelection);
+    }
+
+#if PLATFORM(IOS)
+    if (m_options & TemporarySelectionOptionEnableAppearanceUpdates)
+        m_frame->selection().setUpdateAppearanceEnabled(m_appearanceUpdatesWereEnabled);
+#endif
+}
+
 // When an event handler has moved the selection outside of a text control
 // we should use the target control's selection for this editing operation.
 VisibleSelection Editor::selectionForCommand(Event* event)

Modified: trunk/Source/WebCore/editing/Editor.h (219540 => 219541)


--- trunk/Source/WebCore/editing/Editor.h	2017-07-16 03:45:04 UTC (rev 219540)
+++ trunk/Source/WebCore/editing/Editor.h	2017-07-16 04:01:30 UTC (rev 219541)
@@ -102,6 +102,37 @@
 
 #endif
 
+enum TemporarySelectionOption : uint8_t {
+    // By default, no additional options are enabled.
+    TemporarySelectionOptionDefault = 0,
+
+    // Scroll to reveal the selection.
+    TemporarySelectionOptionRevealSelection = 1 << 0,
+
+    // Don't propagate selection changes to the UI process.
+    TemporarySelectionOptionIgnoreSelectionChanges = 1 << 1,
+
+    // Force the render tree to update selection state. Only respected on iOS.
+    TemporarySelectionOptionEnableAppearanceUpdates = 1 << 2
+};
+
+using TemporarySelectionOptions = uint8_t;
+
+class TemporarySelectionChange {
+public:
+    TemporarySelectionChange(Frame&, std::optional<VisibleSelection> = std::nullopt, TemporarySelectionOptions = TemporarySelectionOptionDefault);
+    ~TemporarySelectionChange();
+
+private:
+    Ref<Frame> m_frame;
+    TemporarySelectionOptions m_options;
+    bool m_wasIgnoringSelectionChanges;
+#if PLATFORM(IOS)
+    bool m_appearanceUpdatesWereEnabled;
+#endif
+    std::optional<VisibleSelection> m_selectionToRestore;
+};
+
 class Editor {
     WTF_MAKE_FAST_ALLOCATED;
 public:

Modified: trunk/Source/WebCore/editing/FrameSelection.h (219540 => 219541)


--- trunk/Source/WebCore/editing/FrameSelection.h	2017-07-16 03:45:04 UTC (rev 219540)
+++ trunk/Source/WebCore/editing/FrameSelection.h	2017-07-16 04:01:30 UTC (rev 219541)
@@ -236,6 +236,7 @@
     void setCaretBlinks(bool caretBlinks = true);
     WEBCORE_EXPORT void setCaretColor(const Color&);
     WEBCORE_EXPORT static VisibleSelection wordSelectionContainingCaretSelection(const VisibleSelection&);
+    bool isUpdateAppearanceEnabled() const { return m_updateAppearanceEnabled; }
     void setUpdateAppearanceEnabled(bool enabled) { m_updateAppearanceEnabled = enabled; }
     void suppressScrolling() { ++m_scrollingSuppressCount; }
     void restoreScrolling()

Modified: trunk/Source/WebCore/page/TextIndicator.cpp (219540 => 219541)


--- trunk/Source/WebCore/page/TextIndicator.cpp	2017-07-16 03:45:04 UTC (rev 219540)
+++ trunk/Source/WebCore/page/TextIndicator.cpp	2017-07-16 04:01:30 UTC (rev 219541)
@@ -78,14 +78,14 @@
 
     Ref<Frame> protector(*frame);
 
+    VisibleSelection oldSelection = frame->selection().selection();
+    TemporarySelectionOptions temporarySelectionOptions = TemporarySelectionOptionDefault;
 #if PLATFORM(IOS)
-    frame->editor().setIgnoreSelectionChanges(true);
-    frame->selection().setUpdateAppearanceEnabled(true);
+    temporarySelectionOptions |= TemporarySelectionOptionIgnoreSelectionChanges;
+    temporarySelectionOptions |= TemporarySelectionOptionEnableAppearanceUpdates;
 #endif
+    TemporarySelectionChange selectionChange(*frame, { range }, temporarySelectionOptions);
 
-    VisibleSelection oldSelection = frame->selection().selection();
-    frame->selection().setSelection(range);
-
     TextIndicatorData data;
 
     data.presentationTransition = presentationTransition;
@@ -96,16 +96,7 @@
     if (!initializeIndicator(data, *frame, range, margin, indicatesCurrentSelection))
         return nullptr;
 
-    RefPtr<TextIndicator> indicator = TextIndicator::create(data);
-
-    frame->selection().setSelection(oldSelection);
-
-#if PLATFORM(IOS)
-    frame->editor().setIgnoreSelectionChanges(false, Editor::RevealSelection::No);
-    frame->selection().setUpdateAppearanceEnabled(false);
-#endif
-
-    return indicator;
+    return TextIndicator::create(data);
 }
 
 RefPtr<TextIndicator> TextIndicator::createWithSelectionInFrame(Frame& frame, TextIndicatorOptions options, TextIndicatorPresentationTransition presentationTransition, FloatSize margin)

Modified: trunk/Source/WebKit/ChangeLog (219540 => 219541)


--- trunk/Source/WebKit/ChangeLog	2017-07-16 03:45:04 UTC (rev 219540)
+++ trunk/Source/WebKit/ChangeLog	2017-07-16 04:01:30 UTC (rev 219541)
@@ -1,3 +1,19 @@
+2017-07-15  Wenson Hsieh  <[email protected]>
+
+        [iOS WK2] Presenting an action sheet on an image map prevents selection UI from updating
+        https://bugs.webkit.org/show_bug.cgi?id=174539
+        <rdar://problem/33307395>
+
+        Reviewed by Darin Adler.
+
+        Small tweak to avoid presenting at the element rect or text rect if the interaction information failed to
+        capture valid bounds for the element. We instead fall back to presenting at the touch location. This addresses
+        problems when presenting the action sheet popover on image maps on iPad, where GetPositionInformation fails to
+        capture correct data about for the <area>.
+
+        * UIProcess/ios/WKActionSheetAssistant.mm:
+        (presentationStyleForView):
+
 2017-07-14  Jonathan Bedard  <[email protected]>
 
         Add iOS 11 SPI

Modified: trunk/Source/WebKit/UIProcess/ios/WKActionSheetAssistant.mm (219540 => 219541)


--- trunk/Source/WebKit/UIProcess/ios/WKActionSheetAssistant.mm	2017-07-16 03:45:04 UTC (rev 219540)
+++ trunk/Source/WebKit/UIProcess/ios/WKActionSheetAssistant.mm	2017-07-16 04:01:30 UTC (rev 219541)
@@ -396,6 +396,9 @@
 static WKActionSheetPresentationStyle presentationStyleForView(UIView *view, const InteractionInformationAtPosition& positionInfo, _WKActivatedElementInfo *elementInfo)
 {
     auto apparentElementRect = [view convertRect:positionInfo.bounds toView:view.window];
+    if (CGRectIsEmpty(apparentElementRect))
+        return WKActionSheetPresentAtTouchLocation;
+
     auto windowRect = view.window.bounds;
     apparentElementRect = CGRectIntersection(apparentElementRect, windowRect);
 

Modified: trunk/Tools/ChangeLog (219540 => 219541)


--- trunk/Tools/ChangeLog	2017-07-16 03:45:04 UTC (rev 219540)
+++ trunk/Tools/ChangeLog	2017-07-16 04:01:30 UTC (rev 219541)
@@ -1,3 +1,28 @@
+2017-07-15  Wenson Hsieh  <[email protected]>
+
+        [iOS WK2] Presenting an action sheet on an image map prevents selection UI from updating
+        https://bugs.webkit.org/show_bug.cgi?id=174539
+        <rdar://problem/33307395>
+
+        Reviewed by Darin Adler.
+
+        Adds a new unit test suite to cover action sheet popover presentation.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/image-map.html: Added.
+        * TestWebKitAPI/Tests/ios/ActionSheetTests.mm: Added.
+        (-[ActionSheetObserver waitForActionSheetAfterBlock:]):
+
+        Runs the given block and waits until the UI process has indicated that it will present an action sheet.
+
+        (-[ActionSheetObserver _webView:actionsForElement:defaultActions:]):
+        (TestWebKitAPI::IPadUserInterfaceSwizzler::IPadUserInterfaceSwizzler):
+
+        Helper class to alter the behavior of [[UIDevice currentDevice] userInterfaceIdiom] for testing.
+
+        (TestWebKitAPI::IPadUserInterfaceSwizzler::padUserInterfaceIdiom):
+        (TestWebKitAPI::TEST):
+
 2017-07-15  Sam Weinig  <[email protected]>
 
         [Scripts] Make svn-create-patch work better when called in sub directories

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (219540 => 219541)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2017-07-16 03:45:04 UTC (rev 219540)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2017-07-16 04:01:30 UTC (rev 219541)
@@ -648,6 +648,8 @@
 		F42DA5161D8CEFE400336F40 /* large-input-field-focus-onload.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F42DA5151D8CEFDB00336F40 /* large-input-field-focus-onload.html */; };
 		F4451C761EB8FD890020C5DA /* two-paragraph-contenteditable.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4451C751EB8FD7C0020C5DA /* two-paragraph-contenteditable.html */; };
 		F4538EF71E8473E600B5C953 /* large-red-square.png in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4538EF01E846B4100B5C953 /* large-red-square.png */; };
+		F45B63FB1F197F4A009D38B9 /* image-map.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F45B63FA1F197F33009D38B9 /* image-map.html */; };
+		F45B63FE1F19D410009D38B9 /* ActionSheetTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F45B63FC1F19D410009D38B9 /* ActionSheetTests.mm */; };
 		F46849BE1EEF58E400B937FE /* UIPasteboardTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F46849BD1EEF58E400B937FE /* UIPasteboardTests.mm */; };
 		F46849C01EEF5EF300B937FE /* rich-and-plain-text.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F46849BF1EEF5EDC00B937FE /* rich-and-plain-text.html */; };
 		F469FB241F01804B00401539 /* contenteditable-and-target.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F469FB231F01803500401539 /* contenteditable-and-target.html */; };
@@ -739,6 +741,7 @@
 			dstPath = TestWebKitAPI.resources;
 			dstSubfolderSpec = 7;
 			files = (
+				F45B63FB1F197F4A009D38B9 /* image-map.html in Copy Resources */,
 				F4D5E4E81F0C5D38008C1A49 /* dragstart-clear-selection.html in Copy Resources */,
 				F4A32EC41F05F3850047C544 /* dragstart-change-selection-offscreen.html in Copy Resources */,
 				F4A32ECB1F0643370047C544 /* contenteditable-in-iframe.html in Copy Resources */,
@@ -1631,6 +1634,8 @@
 		F42DA5151D8CEFDB00336F40 /* large-input-field-focus-onload.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = "large-input-field-focus-onload.html"; path = "Tests/WebKit2Cocoa/large-input-field-focus-onload.html"; sourceTree = SOURCE_ROOT; };
 		F4451C751EB8FD7C0020C5DA /* two-paragraph-contenteditable.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "two-paragraph-contenteditable.html"; sourceTree = "<group>"; };
 		F4538EF01E846B4100B5C953 /* large-red-square.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "large-red-square.png"; sourceTree = "<group>"; };
+		F45B63FA1F197F33009D38B9 /* image-map.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "image-map.html"; sourceTree = "<group>"; };
+		F45B63FC1F19D410009D38B9 /* ActionSheetTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ActionSheetTests.mm; sourceTree = "<group>"; };
 		F46849BD1EEF58E400B937FE /* UIPasteboardTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = UIPasteboardTests.mm; sourceTree = "<group>"; };
 		F46849BF1EEF5EDC00B937FE /* rich-and-plain-text.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "rich-and-plain-text.html"; sourceTree = "<group>"; };
 		F469FB231F01803500401539 /* contenteditable-and-target.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "contenteditable-and-target.html"; sourceTree = "<group>"; };
@@ -1994,6 +1999,7 @@
 				7560917719259C59009EF06E /* MemoryCacheAddImageToCacheIOS.mm */,
 				F4D7BCD61EA574DD00C421D3 /* PositionInformationTests.mm */,
 				F46849BD1EEF58E400B937FE /* UIPasteboardTests.mm */,
+				F45B63FC1F19D410009D38B9 /* ActionSheetTests.mm */,
 			);
 			path = ios;
 			sourceTree = "<group>";
@@ -2050,6 +2056,7 @@
 				F41AB99B1EF4692C0083FA08 /* file-uploading.html */,
 				F41AB9991EF4692C0083FA08 /* image-and-contenteditable.html */,
 				F41AB9931EF4692C0083FA08 /* image-and-textarea.html */,
+				F45B63FA1F197F33009D38B9 /* image-map.html */,
 				F41AB9961EF4692C0083FA08 /* link-and-input.html */,
 				F41AB99D1EF4692C0083FA08 /* link-and-target-div.html */,
 				F41AB9941EF4692C0083FA08 /* prevent-operation.html */,
@@ -3041,6 +3048,7 @@
 				07492B3B1DF8B14C00633DE1 /* EnumerateMediaDevices.cpp in Sources */,
 				448D7E471EA6C55500ECC756 /* EnvironmentUtilitiesTest.cpp in Sources */,
 				7CCE7EEF1A411AE600447C4C /* EphemeralSessionPushStateNoHistoryCallback.cpp in Sources */,
+				F45B63FE1F19D410009D38B9 /* ActionSheetTests.mm in Sources */,
 				7CCE7EF01A411AE600447C4C /* EvaluateJavaScript.cpp in Sources */,
 				315118101DB1AE4000176304 /* ExtendedColor.cpp in Sources */,
 				7CCE7EF11A411AE600447C4C /* FailedLoad.cpp in Sources */,

Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/image-map.html (0 => 219541)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/image-map.html	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/image-map.html	2017-07-16 04:01:30 UTC (rev 219541)
@@ -0,0 +1,31 @@
+<head>
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+        <style>
+        body {
+            width: 100%;
+            height: 100%;
+            margin: 0;
+        }
+
+        img {
+            width: 320px;
+            height: 320px;
+        }
+
+        h1 {
+            font-size: 50px;
+        }
+        </style>
+</head>
+
+<body>
+    <img src="" usemap=""
+    <map name="imgmap"><area href="" coords="0,0,400,400" shape="rect"></map>
+    <h1 id="h1">Hello world</h1>
+    <script>
+    function selectTextNode(text)
+    {
+        getSelection().setBaseAndExtent(text, 0, text, text.data.length);
+    }
+    </script>
+</body>

Added: trunk/Tools/TestWebKitAPI/Tests/ios/ActionSheetTests.mm (0 => 219541)


--- trunk/Tools/TestWebKitAPI/Tests/ios/ActionSheetTests.mm	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/ios/ActionSheetTests.mm	2017-07-16 04:01:30 UTC (rev 219541)
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if PLATFORM(IOS)
+
+#import "InstanceMethodSwizzler.h"
+#import "PlatformUtilities.h"
+#import "TestWKWebView.h"
+#import <WebKit/WKUIDelegatePrivate.h>
+#import <WebKit/WKWebViewPrivate.h>
+#import <wtf/RetainPtr.h>
+#import <wtf/SoftLinking.h>
+
+@interface ActionSheetObserver : NSObject<WKUIDelegatePrivate>
+@property (nonatomic) BOOL presentedActionSheet;
+@end
+
+@implementation ActionSheetObserver
+
+- (BOOL)waitForActionSheetAfterBlock:(dispatch_block_t)block
+{
+    _presentedActionSheet = NO;
+    block();
+    while ([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]]) {
+        if (_presentedActionSheet)
+            break;
+    }
+    return _presentedActionSheet;
+}
+
+- (NSArray *)_webView:(ActionSheetObserver *)webView actionsForElement:(_WKActivatedElementInfo *)element defaultActions:(NSArray<_WKElementAction *> *)defaultActions
+{
+    _presentedActionSheet = YES;
+    return defaultActions;
+}
+
+@end
+
+namespace TestWebKitAPI {
+
+class IPadUserInterfaceSwizzler {
+public:
+    IPadUserInterfaceSwizzler()
+        : m_swizzler([UIDevice class], @selector(userInterfaceIdiom), reinterpret_cast<IMP>(padUserInterfaceIdiom))
+    {
+    }
+private:
+    static UIUserInterfaceIdiom padUserInterfaceIdiom()
+    {
+        return UIUserInterfaceIdiomPad;
+    }
+    InstanceMethodSwizzler m_swizzler;
+};
+
+TEST(ActionSheetTests, ImageMapDoesNotDestroySelection)
+{
+    IPadUserInterfaceSwizzler iPadUserInterface;
+
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 1024, 768)]);
+    auto observer = adoptNS([[ActionSheetObserver alloc] init]);
+    [webView setUIDelegate:observer.get()];
+    [webView synchronouslyLoadTestPageNamed:@"image-map"];
+    [webView stringByEvaluatingJavaScript:@"selectTextNode(h1.childNodes[0])"];
+
+    EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"getSelection().toString()"]);
+    [observer waitForActionSheetAfterBlock:^() {
+        [webView _simulateLongPressActionAtLocation:CGPointMake(200, 200)];
+    }];
+    EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"getSelection().toString()"]);
+}
+
+} // namespace TestWebKitAPI
+
+#endif // PLATFORM(IOS)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to