Move Lookup Code for better cross platform usage
[WebKit-https.git] / Source / WebKit / WebProcess / WebPage / ios / WebPageIOS.mm
index 2a947fd..6e5a6d1 100644 (file)
@@ -26,7 +26,7 @@
 #import "config.h"
 #import "WebPage.h"
 
-#if PLATFORM(IOS)
+#if PLATFORM(IOS_FAMILY)
 
 #import "AccessibilityIOS.h"
 #import "AssistedNodeInformation.h"
 #import "GestureTypes.h"
 #import "InteractionInformationAtPosition.h"
 #import "Logging.h"
+#import "NativeWebKeyboardEvent.h"
 #import "PluginView.h"
 #import "PrintInfo.h"
 #import "RemoteLayerTreeDrawingArea.h"
 #import "SandboxUtilities.h"
+#import "UIKitSPI.h"
 #import "UserData.h"
 #import "VisibleContentRectUpdateInfo.h"
 #import "WKAccessibilityWebPageObjectIOS.h"
 #import <WebCore/HTMLParserIdioms.h>
 #import <WebCore/HTMLSelectElement.h>
 #import <WebCore/HTMLTextAreaElement.h>
+#import <WebCore/HTMLTextFormControlElement.h>
 #import <WebCore/HistoryItem.h>
 #import <WebCore/HitTestResult.h>
+#import <WebCore/InputMode.h>
 #import <WebCore/KeyboardEvent.h>
 #import <WebCore/LibWebRTCProvider.h>
-#import <WebCore/MainFrame.h>
 #import <WebCore/MediaSessionManagerIOS.h>
 #import <WebCore/Node.h>
 #import <WebCore/NodeList.h>
 #import <wtf/MemoryPressureHandler.h>
 #import <wtf/SetForScope.h>
 #import <wtf/SoftLinking.h>
+#import <wtf/cocoa/Entitlements.h>
 #import <wtf/text/TextStream.h>
 
 #if ENABLE(MEDIA_STREAM)
@@ -123,9 +127,8 @@ SOFT_LINK_CLASS_OPTIONAL(Celestial, AVSystemController)
 SOFT_LINK_CONSTANT_MAY_FAIL(Celestial, AVSystemController_PIDToInheritApplicationStateFrom, NSString *)
 #endif
 
-using namespace WebCore;
-
 namespace WebKit {
+using namespace WebCore;
 
 const int blockSelectionStartWidth = 100;
 const int blockSelectionStartHeight = 100;
@@ -190,12 +193,16 @@ void WebPage::platformEditorState(Frame& frame, EditorState& result, IncludePost
         }
     }
 
-    // We only set the remaining EditorState entries if the layout is done. To compute these
-    // entries, we need the layout to be done and we don't want to trigger a synchronous
-    // layout as this would be bad for performance. If we have a composition, we send everything
-    // right away as the UIProcess needs the caretRects ASAP for marked text.
-    bool frameViewHasFinishedLayout = frame.view() && !frame.view()->needsLayout();
-    if (shouldIncludePostLayoutData == IncludePostLayoutDataHint::No && !frameViewHasFinishedLayout && !frame.editor().hasComposition()) {
+    // We only set the remaining EditorState entries if layout is done as a performance optimization
+    // to avoid the need to force a synchronous layout here to compute these entries. If we
+    // have a composition or are using a hardware keyboard then we send the full editor state
+    // immediately so that the UIProcess can update UI, including the position of the caret.
+    bool needsLayout = !frame.view() || frame.view()->needsLayout();
+    bool requiresPostLayoutData = frame.editor().hasComposition();
+#if !PLATFORM(IOSMAC)
+    requiresPostLayoutData |= [UIKeyboard isInHardwareKeyboardMode];
+#endif
+    if (shouldIncludePostLayoutData == IncludePostLayoutDataHint::No && needsLayout && !requiresPostLayoutData) {
         result.isMissingPostLayoutData = true;
         return;
     }
@@ -237,6 +244,7 @@ void WebPage::platformEditorState(Frame& frame, EditorState& result, IncludePost
         if (m_assistedNode && m_assistedNode->renderer()) {
             postLayoutData.selectionClipRect = view->contentsToRootView(m_assistedNode->renderer()->absoluteBoundingBoxRect());
             postLayoutData.caretColor = m_assistedNode->renderer()->style().caretColor();
+            postLayoutData.elementIsTransparent = m_assistedNode->renderer()->isTransparentRespectingParentFrames();
         }
         computeEditableRootHasContentAndPlainText(selection, postLayoutData);
     }
@@ -252,6 +260,11 @@ FloatSize WebPage::availableScreenSize() const
     return m_availableScreenSize;
 }
 
+FloatSize WebPage::overrideScreenSize() const
+{
+    return m_overrideScreenSize;
+}
+
 void WebPage::didReceiveMobileDocType(bool isMobileDoctype)
 {
     resetViewportDefaultConfiguration(m_mainFrame.get(), isMobileDoctype);
@@ -295,13 +308,15 @@ static FloatPoint relativeCenterAfterContentSizeChange(const FloatRect& original
 
 static inline FloatRect adjustExposedRectForNewScale(const FloatRect& exposedRect, double exposedRectScale, double newScale)
 {
-    double overscaledWidth = exposedRect.width();
-    double missingHorizonalMargin = exposedRect.width() * exposedRectScale / newScale - overscaledWidth;
+    if (exposedRectScale == newScale)
+        return exposedRect;
 
-    double overscaledHeight = exposedRect.height();
-    double missingVerticalMargin = exposedRect.height() * exposedRectScale / newScale - overscaledHeight;
+    float horizontalChange = exposedRect.width() * exposedRectScale / newScale - exposedRect.width();
+    float verticalChange = exposedRect.height() * exposedRectScale / newScale - exposedRect.height();
 
-    return FloatRect(exposedRect.x() - missingHorizonalMargin / 2, exposedRect.y() - missingVerticalMargin / 2, exposedRect.width() + missingHorizonalMargin, exposedRect.height() + missingVerticalMargin);
+    auto adjustedRect = exposedRect;
+    adjustedRect.inflate({ horizontalChange / 2, verticalChange / 2 });
+    return adjustedRect;
 }
 
 void WebPage::restorePageState(const HistoryItem& historyItem)
@@ -393,7 +408,7 @@ bool WebPage::handleEditingKeyboardEvent(KeyboardEvent* event)
 
 bool WebPage::parentProcessHasServiceWorkerEntitlement() const
 {
-    static bool hasEntitlement = connectedProcessHasEntitlement(WebProcess::singleton().parentProcessConnection()->xpcConnection(), "com.apple.developer.WebKit.ServiceWorkers");
+    static bool hasEntitlement = WTF::hasEntitlement(WebProcess::singleton().parentProcessConnection()->xpcConnection(), "com.apple.developer.WebKit.ServiceWorkers");
     return hasEntitlement;
 }
 
@@ -402,21 +417,6 @@ void WebPage::sendComplexTextInputToPlugin(uint64_t, const String&)
     notImplemented();
 }
 
-void WebPage::performDictionaryLookupAtLocation(const FloatPoint&)
-{
-    notImplemented();
-}
-
-void WebPage::performDictionaryLookupForSelection(Frame&, const VisibleSelection&, TextIndicatorPresentationTransition)
-{
-    notImplemented();
-}
-
-void WebPage::performDictionaryLookupForRange(Frame&, Range&, NSDictionary *, TextIndicatorPresentationTransition)
-{
-    notImplemented();
-}
-
 bool WebPage::performNonEditingBehaviorForSelector(const String&, WebCore::KeyboardEvent*)
 {
     notImplemented();
@@ -483,30 +483,6 @@ WKAccessibilityWebPageObject* WebPage::accessibilityRemoteObject()
     return 0;
 }
 
-bool WebPage::platformHasLocalDataForURL(const WebCore::URL&)
-{
-    notImplemented();
-    return false;
-}
-
-String WebPage::cachedSuggestedFilenameForURL(const URL&)
-{
-    notImplemented();
-    return String();
-}
-
-String WebPage::cachedResponseMIMETypeForURL(const URL&)
-{
-    notImplemented();
-    return String();
-}
-
-RefPtr<SharedBuffer> WebPage::cachedResponseDataForURL(const URL&)
-{
-    notImplemented();
-    return nullptr;
-}
-
 bool WebPage::platformCanHandleRequest(const WebCore::ResourceRequest&)
 {
     notImplemented();
@@ -712,7 +688,7 @@ void WebPage::sendTapHighlightForNodeIfNecessary(uint64_t requestID, Node* node)
 
     if (is<Element>(*node)) {
         ASSERT(m_page);
-        m_page->mainFrame().loader().client().prefetchDNS(downcast<Element>(*node).absoluteLinkURL().host());
+        m_page->mainFrame().loader().client().prefetchDNS(downcast<Element>(*node).absoluteLinkURL().host().toString());
     }
 
     if (is<HTMLAreaElement>(node)) {
@@ -767,6 +743,36 @@ void WebPage::handleTwoFingerTapAtPoint(const WebCore::IntPoint& point, uint64_t
         completeSyntheticClick(nodeRespondingToClick, adjustedPoint, WebCore::TwoFingerTap);
 }
 
+void WebPage::handleStylusSingleTapAtPoint(const WebCore::IntPoint& point, uint64_t requestID)
+{
+    auto& frame = m_page->focusController().focusedOrMainFrame();
+
+    auto pointInDocument = frame.view()->rootViewToContents(point);
+    HitTestResult hitTest = frame.eventHandler().hitTestResultAtPoint(pointInDocument, HitTestRequest::ReadOnly | HitTestRequest::Active);
+
+    Node* node = hitTest.innerNonSharedNode();
+    if (!node)
+        return;
+    auto renderer = node->renderer();
+    if (!renderer)
+        return;
+
+    if (renderer->isReplaced())
+        return;
+
+    VisiblePosition position = renderer->positionForPoint(hitTest.localPoint(), nullptr);
+    if (position.isNull())
+        position = firstPositionInOrBeforeNode(node);
+
+    if (position.isNull())
+        return;
+
+    auto range = Range::create(*frame.document(), position, position);
+    frame.selection().setSelectedRange(range.ptr(), position.affinity(), WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
+    frame.editor().insertEditableImage();
+    resetAssistedNodeForFrame(m_mainFrame.get());
+}
+
 void WebPage::potentialTapAtPosition(uint64_t requestID, const WebCore::FloatPoint& position)
 {
     m_potentialTapNode = m_page->mainFrame().nodeRespondingToClickEvents(position, m_potentialTapLocation, m_potentialTapSecurityOrigin.get());
@@ -1049,7 +1055,7 @@ RefPtr<Range> WebPage::rangeForWebSelectionAtPosition(const IntPoint& point, con
         return nullptr;
 
     RenderObject* renderer = bestChoice->renderer();
-    if (!renderer || renderer->style().userSelect() == SELECT_NONE)
+    if (!renderer || renderer->style().userSelect() == UserSelect::None)
         return nullptr;
 
     if (renderer->childrenInline() && (is<RenderBlock>(*renderer) && !downcast<RenderBlock>(*renderer).inlineContinuation()) && !renderer->isTable()) {
@@ -1071,364 +1077,6 @@ RefPtr<Range> WebPage::rangeForWebSelectionAtPosition(const IntPoint& point, con
     return range->collapsed() ? nullptr : range;
 }
 
-#if __IPHONE_OS_VERSION_MAX_ALLOWED < 120000
-static bool canShrinkToTextSelection(Range& range)
-{
-    if (range.startContainer().isTextNode() && range.endContainer().isTextNode())
-        return true;
-    return canShrinkToTextSelection(range.commonAncestorContainer());
-}
-static const int maxHitTests = 10;
-
-static inline float distanceBetweenRectsForPosition(IntRect& first, IntRect& second, SelectionHandlePosition handlePosition)
-{
-    switch (handlePosition) {
-    case SelectionHandlePosition::Top:
-        return abs(first.y() - second.y());
-    case SelectionHandlePosition::Right:
-        return abs(first.maxX() - second.maxX());
-    case SelectionHandlePosition::Bottom:
-        return abs(first.maxY() - second.maxY());
-    case SelectionHandlePosition::Left:
-        return abs(first.x() - second.x());
-    }
-}
-
-static inline bool rectsEssentiallyTheSame(IntRect& first, IntRect& second, float allowablePercentDifference)
-{
-    const float minMagnitudeRatio = 1.0 - allowablePercentDifference;
-    const float maxDisplacementRatio = allowablePercentDifference;
-    
-    float xOriginShiftRatio = abs(first.x() - second.x()) / std::min(first.width(), second.width());
-    float yOriginShiftRatio = abs(first.y() - second.y()) / std::min(first.height(), second.height());
-    
-    float widthRatio = std::min(first.width() / second.width(), second.width() / first.width());
-    float heightRatio = std::min(first.height() / second.height(), second.height() / first.height());
-    return ((widthRatio > minMagnitudeRatio && xOriginShiftRatio < maxDisplacementRatio) && (heightRatio > minMagnitudeRatio && yOriginShiftRatio < maxDisplacementRatio));
-}
-
-static inline RefPtr<Range> unionDOMRanges(Range* rangeA, Range* rangeB)
-{
-    if (!rangeB)
-        return rangeA;
-    if (!rangeA)
-        return rangeB;
-    
-    auto startToStartComparison = rangeA->compareBoundaryPoints(Range::START_TO_START, *rangeB);
-    if (startToStartComparison.hasException())
-        return nullptr;
-    
-    auto endToEndComparison = rangeA->compareBoundaryPoints(Range::END_TO_END, *rangeB);
-    if (endToEndComparison.hasException())
-        return nullptr;
-    
-    auto* start = startToStartComparison.releaseReturnValue() <= 0 ? rangeA : rangeB;
-    auto* end = endToEndComparison.releaseReturnValue() <= 0 ? rangeB : rangeA;
-    
-    return Range::create(rangeA->ownerDocument(), &start->startContainer(), start->startOffset(), &end->endContainer(), end->endOffset());
-}
-
-static inline IntPoint computeEdgeCenter(const IntRect& box, SelectionHandlePosition handlePosition)
-{
-    switch (handlePosition) {
-    case SelectionHandlePosition::Top:
-        return IntPoint(box.x() + box.width() / 2, box.y());
-    case SelectionHandlePosition::Right:
-        return IntPoint(box.maxX(), box.y() + box.height() / 2);
-    case SelectionHandlePosition::Bottom:
-        return IntPoint(box.x() + box.width() / 2, box.maxY());
-    case SelectionHandlePosition::Left:
-        return IntPoint(box.x(), box.y() + box.height() / 2);
-    }
-}
-
-Ref<Range> WebPage::expandedRangeFromHandle(Range& currentRange, SelectionHandlePosition handlePosition)
-{
-    IntRect currentBox = selectionBoxForRange(&currentRange);
-    IntPoint edgeCenter = computeEdgeCenter(currentBox, handlePosition);
-    static const float maxDistance = 1000;
-    const float multiple = powf(maxDistance, 1.0 / (maxHitTests - 1));
-    float distance = 1;
-    
-    RefPtr<Range> bestRange;
-    IntRect bestRect;
-    
-    while (distance < maxDistance) {
-        if (bestRange) {
-            if (distanceBetweenRectsForPosition(bestRect, currentBox, handlePosition) < distance) {
-                // Break early, we're unlikely to do any better.
-                break;
-            }
-        }
-        
-        IntPoint testPoint = edgeCenter;
-        switch (handlePosition) {
-        case SelectionHandlePosition::Top:
-            testPoint.move(0, -distance);
-            break;
-        case SelectionHandlePosition::Right:
-            testPoint.move(distance, 0);
-            break;
-        case SelectionHandlePosition::Bottom:
-            testPoint.move(0, distance);
-            break;
-        case SelectionHandlePosition::Left:
-            testPoint.move(-distance, 0);
-            break;
-        }
-        
-        distance = ceilf(distance * multiple);
-        
-        RefPtr<Range> newRange;
-        RefPtr<Range> rangeAtPosition = rangeForBlockAtPoint(testPoint);
-        if (!rangeAtPosition || &currentRange.ownerDocument() != &rangeAtPosition->ownerDocument())
-            continue;
-        
-        if (rangeAtPosition->contains(currentRange))
-            newRange = rangeAtPosition;
-        else if (currentRange.contains(*rangeAtPosition.get()))
-            newRange = &currentRange;
-        else
-            newRange = unionDOMRanges(&currentRange, rangeAtPosition.get());
-        
-        IntRect copyRect = selectionBoxForRange(newRange.get());
-        
-        // Is it different and bigger than the current?
-        bool isBetterChoice = !(rectsEssentiallyTheSame(copyRect, currentBox, .05));
-        if (isBetterChoice) {
-            switch (handlePosition) {
-            case SelectionHandlePosition::Top:
-            case SelectionHandlePosition::Bottom:
-                isBetterChoice = (copyRect.height() > currentBox.height());
-                break;
-            case SelectionHandlePosition::Right:
-            case SelectionHandlePosition::Left:
-                isBetterChoice = (copyRect.width() > currentBox.width());
-                break;
-            }
-            
-        }
-        
-        if (bestRange && isBetterChoice) {
-            // Furtherore, is it smaller than the best we've found so far?
-            switch (handlePosition) {
-            case SelectionHandlePosition::Top:
-            case SelectionHandlePosition::Bottom:
-                isBetterChoice = (copyRect.height() < bestRect.height());
-                break;
-            case SelectionHandlePosition::Right:
-            case SelectionHandlePosition::Left:
-                isBetterChoice = (copyRect.width() < bestRect.width());
-                break;
-            }
-        }
-        
-        if (isBetterChoice) {
-            bestRange = newRange;
-            bestRect = copyRect;
-        }
-    }
-    
-    if (bestRange)
-        return bestRange.releaseNonNull();
-    
-    return currentRange;
-}
-
-Ref<Range> WebPage::contractedRangeFromHandle(Range& currentRange, SelectionHandlePosition handlePosition, SelectionFlags& flags)
-{
-    // Shrinking with a base and extent will always give better results. If we only have a single element,
-    // see if we can break that down to a base and extent. Shrinking base and extent is comparatively straightforward.
-    // Shrinking down to another element is unlikely to move just one edge, but we can try that as a fallback.
-    
-    IntRect currentBox = selectionBoxForRange(&currentRange);
-    IntPoint edgeCenter = computeEdgeCenter(currentBox, handlePosition);
-    
-    float maxDistance;
-    
-    switch (handlePosition) {
-    case SelectionHandlePosition::Top:
-    case SelectionHandlePosition::Bottom:
-        maxDistance = currentBox.height();
-        break;
-    case SelectionHandlePosition::Right:
-    case SelectionHandlePosition::Left:
-        maxDistance = currentBox.width();
-        break;
-    }
-    
-    const float multiple = powf(maxDistance - 1, 1.0 / (maxHitTests - 1));
-    float distance = 1;
-    RefPtr<Range> bestRange;
-    IntRect bestRect;
-    
-    while (distance < maxDistance) {
-        if (bestRange) {
-            float shrankDistance;
-            switch (handlePosition) {
-            case SelectionHandlePosition::Top:
-            case SelectionHandlePosition::Bottom:
-                shrankDistance = abs(currentBox.height() - bestRect.height());
-                break;
-            case SelectionHandlePosition::Right:
-            case SelectionHandlePosition::Left:
-                shrankDistance = abs(currentBox.width() - bestRect.width());
-                break;
-            }
-            if (shrankDistance > distance) {
-                // Certainly not going to do any better than that.
-                break;
-            }
-        }
-        
-        IntPoint testPoint = edgeCenter;
-        switch (handlePosition) {
-        case SelectionHandlePosition::Top:
-            testPoint.move(0, distance);
-            break;
-        case SelectionHandlePosition::Right:
-            testPoint.move(-distance, 0);
-            break;
-        case SelectionHandlePosition::Bottom:
-            testPoint.move(0, -distance);
-            break;
-        case SelectionHandlePosition::Left:
-            testPoint.move(distance, 0);
-            break;
-        }
-        
-        distance *= multiple;
-        
-        RefPtr<Range> newRange = rangeForBlockAtPoint(testPoint);
-        if (!newRange || &newRange->ownerDocument() != &currentRange.ownerDocument())
-            continue;
-        
-        if (handlePosition == SelectionHandlePosition::Top || handlePosition == SelectionHandlePosition::Left)
-            newRange = Range::create(newRange->startContainer().document(), newRange->endPosition(), currentRange.endPosition());
-        else
-            newRange = Range::create(newRange->startContainer().document(), currentRange.startPosition(), newRange->startPosition());
-        
-        IntRect copyRect = selectionBoxForRange(newRange.get());
-        if (copyRect.isEmpty()) {
-            // If the new range is an empty rectangle, we try the block at the current point
-            // and see if that has a rectangle that is a better choice.
-            newRange = rangeForBlockAtPoint(testPoint);
-            copyRect = selectionBoxForRange(newRange.get());
-        }
-        bool isBetterChoice;
-        switch (handlePosition) {
-        case SelectionHandlePosition::Top:
-        case SelectionHandlePosition::Bottom:
-            isBetterChoice = (copyRect.height() < currentBox.height());
-            if (copyRect.height() == currentBox.height())
-                isBetterChoice = canShrinkToTextSelection(*newRange.get());
-            break;
-        case SelectionHandlePosition::Left:
-        case SelectionHandlePosition::Right:
-            isBetterChoice = (copyRect.width() > bestRect.width());
-            break;
-        }
-        
-        isBetterChoice = isBetterChoice && !areRangesEqual(newRange.get(), &currentRange);
-        if (bestRange && isBetterChoice) {
-            switch (handlePosition) {
-            case SelectionHandlePosition::Top:
-            case SelectionHandlePosition::Bottom:
-                isBetterChoice = (copyRect.height() > bestRect.height());
-                break;
-            case SelectionHandlePosition::Left:
-            case SelectionHandlePosition::Right:
-                isBetterChoice = (copyRect.width() > bestRect.width());
-                break;
-            }
-        }
-        if (isBetterChoice) {
-            bestRange = newRange;
-            bestRect = copyRect;
-        }
-        
-    }
-    
-    if (!bestRange)
-        bestRange = &currentRange;
-    
-    // If we can shrink down to text only, the only reason we wouldn't is that
-    // there are multiple sub-element blocks beneath us. If we didn't find
-    // multiple sub-element blocks, don't shrink to a sub-element block.
-    
-    if (canShrinkToTextSelection(*bestRange.get()))
-        flags = None;
-    
-    return bestRange.releaseNonNull();
-}
-
-void WebPage::computeExpandAndShrinkThresholdsForHandle(const IntPoint& point, SelectionHandlePosition handlePosition, float& growThreshold, float& shrinkThreshold)
-{
-    Frame& frame = m_page->focusController().focusedOrMainFrame();
-    RefPtr<Range> currentRange = m_currentBlockSelection ? m_currentBlockSelection.get() : frame.selection().selection().toNormalizedRange();
-    
-    if (!currentRange)
-        return;
-    
-    Ref<Range> expandedRange = expandedRangeFromHandle(*currentRange, handlePosition);
-    SelectionFlags flags;
-    RefPtr<Range> contractedRange = contractedRangeFromHandle(*currentRange, handlePosition, flags);
-    
-    IntRect currentBounds = selectionBoxForRange(currentRange.get());
-    IntRect expandedBounds = selectionBoxForRange(expandedRange.ptr());
-    IntRect contractedBounds = selectionBoxForRange(contractedRange.get());
-    
-    float current;
-    float expanded;
-    float contracted;
-    float maxThreshold;
-    float minThreshold;
-    
-    switch (handlePosition) {
-    case SelectionHandlePosition::Top: {
-        current = currentBounds.y();
-        expanded = expandedBounds.y();
-        contracted = contractedBounds.y();
-        maxThreshold = FLT_MIN;
-        minThreshold = FLT_MAX;
-        break;
-    }
-    case SelectionHandlePosition::Right: {
-        current = currentBounds.maxX();
-        expanded = expandedBounds.maxX();
-        contracted = contractedBounds.maxX();
-        maxThreshold = FLT_MAX;
-        minThreshold = FLT_MIN;
-        break;
-    }
-    case SelectionHandlePosition::Bottom: {
-        current = currentBounds.maxY();
-        expanded = expandedBounds.maxY();
-        contracted = contractedBounds.maxY();
-        maxThreshold = FLT_MAX;
-        minThreshold = FLT_MIN;
-        break;
-    }
-    case SelectionHandlePosition::Left: {
-        current = currentBounds.x();
-        expanded = expandedBounds.x();
-        contracted = contractedBounds.x();
-        maxThreshold = FLT_MIN;
-        minThreshold = FLT_MAX;
-        break;
-    }
-    }
-    
-    static const float fractionToGrow = 0.3;
-    
-    growThreshold = current + (expanded - current) * fractionToGrow;
-    shrinkThreshold = current + (contracted - current) * (1 - fractionToGrow);
-    if (areRangesEqual(expandedRange.ptr(), currentRange.get()))
-        growThreshold = maxThreshold;
-    
-}
-#endif
-
 void WebPage::selectWithGesture(const IntPoint& point, uint32_t granularity, uint32_t gestureType, uint32_t gestureState, bool isInteractingWithAssistedNode, CallbackID callbackID)
 {
     auto& frame = m_page->focusController().focusedOrMainFrame();
@@ -1495,7 +1143,31 @@ void WebPage::selectWithGesture(const IntPoint& point, uint32_t granularity, uin
         if (position.rootEditableElement())
             range = Range::create(*frame.document(), position, position);
         else
+#if !PLATFORM(IOSMAC)
             range = wordRangeFromPosition(position);
+#else
+            switch (wkGestureState) {
+            case GestureRecognizerState::Began:
+                m_startingGestureRange = Range::create(*frame.document(), position, position);
+                break;
+            case GestureRecognizerState::Changed:
+                if (m_startingGestureRange) {
+                    if (m_startingGestureRange->startPosition() < position)
+                        range = Range::create(*frame.document(), m_startingGestureRange->startPosition(), position);
+                    else
+                        range = Range::create(*frame.document(), position, m_startingGestureRange->startPosition());
+                }
+                break;
+            case GestureRecognizerState::Ended:
+            case GestureRecognizerState::Cancelled:
+                m_startingGestureRange = nullptr;
+                break;
+            case GestureRecognizerState::Failed:
+            case GestureRecognizerState::Possible:
+                ASSERT_NOT_REACHED();
+                break;
+            }
+#endif
         break;
 
     case GestureType::TapAndAHalf:
@@ -1561,36 +1233,56 @@ void WebPage::selectWithGesture(const IntPoint& point, uint32_t granularity, uin
         break;
     }
     if (range)
-        frame.selection().setSelectedRange(range.get(), position.affinity(), true, UserTriggered);
+        frame.selection().setSelectedRange(range.get(), position.affinity(), WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
 
     send(Messages::WebPageProxy::GestureCallback(point, gestureType, gestureState, static_cast<uint32_t>(flags), callbackID));
 }
 
-static RefPtr<Range> rangeForPosition(Frame* frame, const VisiblePosition& position, bool baseIsStart)
+static RefPtr<Range> rangeForPointInRootViewCoordinates(Frame& frame, const IntPoint& pointInRootViewCoordinates, bool baseIsStart)
 {
-    RefPtr<Range> range;
-    VisiblePosition result = position;
+    VisibleSelection existingSelection = frame.selection().selection();
+    VisiblePosition selectionStart = existingSelection.visibleStart();
+    VisiblePosition selectionEnd = existingSelection.visibleEnd();
 
-    if (baseIsStart) {
-        VisiblePosition selectionStart = frame->selection().selection().visibleStart();
-        bool wouldFlip = position <= selectionStart;
+    auto pointInDocument = frame.view()->rootViewToContents(pointInRootViewCoordinates);
 
-        if (wouldFlip)
+    if (baseIsStart) {
+        int startY = selectionStart.absoluteCaretBounds().center().y();
+        if (pointInDocument.y() < startY)
+            pointInDocument.setY(startY);
+    } else {
+        int endY = selectionEnd.absoluteCaretBounds().center().y();
+        if (pointInDocument.y() > endY)
+            pointInDocument.setY(endY);
+    }
+    
+    VisiblePosition result;
+    RefPtr<Range> range;
+    
+    HitTestResult hitTest = frame.eventHandler().hitTestResultAtPoint(pointInDocument, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::AllowChildFrameContent);
+    if (hitTest.targetNode())
+        result = frame.eventHandler().selectionExtentRespectingEditingBoundary(frame.selection().selection(), hitTest.localPoint(), hitTest.targetNode()).deepEquivalent();
+    else
+        result = frame.visiblePositionForPoint(pointInDocument).deepEquivalent();
+    
+    if (baseIsStart) {
+        if (comparePositions(result, selectionStart) <= 0)
             result = selectionStart.next();
-
+        else if (&selectionStart.deepEquivalent().anchorNode()->treeScope() != &hitTest.targetNode()->treeScope())
+            result = VisibleSelection::adjustPositionForEnd(result.deepEquivalent(), selectionStart.deepEquivalent().containerNode());
+        
         if (result.isNotNull())
-            range = Range::create(*frame->document(), selectionStart, result);
+            range = Range::create(*frame.document(), selectionStart, result);
     } else {
-        VisiblePosition selectionEnd = frame->selection().selection().visibleEnd();
-        bool wouldFlip = position >= selectionEnd;
-
-        if (wouldFlip)
+        if (comparePositions(selectionEnd, result) <= 0)
             result = selectionEnd.previous();
-
+        else if (&hitTest.targetNode()->treeScope() != &selectionEnd.deepEquivalent().anchorNode()->treeScope())
+            result = VisibleSelection::adjustPositionForStart(result.deepEquivalent(), selectionEnd.deepEquivalent().containerNode());
+        
         if (result.isNotNull())
-            range = Range::create(*frame->document(), result, selectionEnd);
+            range = Range::create(*frame.document(), result.deepEquivalent(), selectionEnd);
     }
-
+    
     return range;
 }
 
@@ -1643,91 +1335,9 @@ static RefPtr<Range> rangeAtWordBoundaryForPosition(Frame* frame, const VisibleP
 
     return (base < extent) ? Range::create(*frame->document(), base, extent) : Range::create(*frame->document(), extent, base);
 }
-    
-#if __IPHONE_OS_VERSION_MAX_ALLOWED < 120000
-
-RefPtr<Range> WebPage::rangeForBlockAtPoint(const IntPoint& point)
-{
-    HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint((point), HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowUserAgentShadowContent | HitTestRequest::IgnoreClipping);
-
-    Node* currentNode = result.innerNode();
-    RefPtr<Range> range;
-
-    if (currentNode->isTextNode()) {
-        range = enclosingTextUnitOfGranularity(m_page->focusController().focusedOrMainFrame().visiblePositionForPoint(point), ParagraphGranularity, DirectionForward);
-        if (range && !range->collapsed())
-            return range;
-    }
-
-    if (!currentNode->isElementNode())
-        currentNode = currentNode->parentElement();
-
-    if (!currentNode)
-        return nullptr;
-
-    range = Range::create(currentNode->document());
-    range->selectNodeContents(*currentNode);
-    return range;
-}
-    
-static inline bool shouldExpand(SelectionHandlePosition handlePosition, const IntRect& rect, const IntPoint& point)
-{
-    switch (handlePosition) {
-    case SelectionHandlePosition::Top:
-        return (point.y() < rect.y());
-    case SelectionHandlePosition::Left:
-        return (point.x() < rect.x());
-    case SelectionHandlePosition::Right:
-        return (point.x() > rect.maxX());
-    case SelectionHandlePosition::Bottom:
-        return (point.y() > rect.maxY());
-    }
-}
-
-RefPtr<WebCore::Range> WebPage::changeBlockSelection(const IntPoint& point, SelectionHandlePosition handlePosition, float& growThreshold, float& shrinkThreshold, SelectionFlags& flags)
-{
-    Frame& frame = m_page->focusController().focusedOrMainFrame();
-    RefPtr<Range> currentRange = m_currentBlockSelection ? m_currentBlockSelection.get() : frame.selection().selection().toNormalizedRange();
-    if (!currentRange)
-        return nullptr;
-    RefPtr<Range> newRange = shouldExpand(handlePosition, selectionBoxForRange(currentRange.get()), point) ? expandedRangeFromHandle(*currentRange, handlePosition) : contractedRangeFromHandle(*currentRange, handlePosition, flags);
-    
-    if (newRange) {
-        m_currentBlockSelection = newRange;
-        frame.selection().setSelectedRange(newRange.get(), VP_DEFAULT_AFFINITY, true, UserTriggered);
-    }
-    
-    computeExpandAndShrinkThresholdsForHandle(point, handlePosition, growThreshold, shrinkThreshold);
-    return newRange;
-}
-
-void WebPage::updateBlockSelectionWithTouch(const IntPoint& point, uint32_t touch, uint32_t handlePosition)
-{
-    Frame& frame = m_page->focusController().focusedOrMainFrame();
-    IntPoint adjustedPoint = frame.view()->rootViewToContents(point);
-    
-    float growThreshold = 0;
-    float shrinkThreshold = 0;
-    SelectionFlags flags = None;
-    
-    switch (static_cast<SelectionTouch>(touch)) {
-    case SelectionTouch::Started:
-        computeExpandAndShrinkThresholdsForHandle(adjustedPoint, static_cast<SelectionHandlePosition>(handlePosition), growThreshold, shrinkThreshold);
-        break;
-    case SelectionTouch::Ended:
-        break;
-    case SelectionTouch::Moved:
-        changeBlockSelection(adjustedPoint, static_cast<SelectionHandlePosition>(handlePosition), growThreshold, shrinkThreshold, flags);
-        break;
-    default:
-        return;
-    }
-    
-    send(Messages::WebPageProxy::DidUpdateBlockSelectionWithTouch(touch, static_cast<uint32_t>(flags), growThreshold, shrinkThreshold));
-}
-#endif
 
 void WebPage::clearSelection(){
+    m_startingGestureRange = nullptr;
     m_currentBlockSelection = nullptr;
     m_page->focusController().focusedOrMainFrame().selection().clear();
 }
@@ -1757,7 +1367,7 @@ void WebPage::updateSelectionWithTouches(const IntPoint& point, uint32_t touches
             if (result.isNotNull())
                 range = Range::create(*frame.document(), result, result);
         } else
-            range = rangeForPosition(&frame, position, baseIsStart);
+            range = rangeForPointInRootViewCoordinates(frame, point, baseIsStart);
         break;
 
     case SelectionTouch::EndedMovingForward:
@@ -1769,11 +1379,11 @@ void WebPage::updateSelectionWithTouches(const IntPoint& point, uint32_t touches
         break;
 
     case SelectionTouch::Moved:
-        range = rangeForPosition(&frame, position, baseIsStart);
+        range = rangeForPointInRootViewCoordinates(frame, point, baseIsStart);
         break;
     }
     if (range)
-        frame.selection().setSelectedRange(range.get(), position.affinity(), true, UserTriggered);
+        frame.selection().setSelectedRange(range.get(), position.affinity(), WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
 
     send(Messages::WebPageProxy::TouchesCallback(point, touches, flags, callbackID));
 }
@@ -1789,7 +1399,7 @@ void WebPage::selectWithTwoTouches(const WebCore::IntPoint& from, const WebCore:
             range = Range::create(*frame.document(), fromPosition, toPosition);
         else
             range = Range::create(*frame.document(), toPosition, fromPosition);
-        frame.selection().setSelectedRange(range.get(), fromPosition.affinity(), true, UserTriggered);
+        frame.selection().setSelectedRange(range.get(), fromPosition.affinity(), WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
     }
 
     // We can use the same callback for the gestures with one point.
@@ -1804,7 +1414,7 @@ void WebPage::extendSelection(uint32_t granularity)
         return;
 
     VisiblePosition position = frame.selection().selection().start();
-    frame.selection().setSelectedRange(wordRangeFromPosition(position).get(), position.affinity(), true, UserTriggered);
+    frame.selection().setSelectedRange(wordRangeFromPosition(position).get(), position.affinity(), WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
 }
 
 void WebPage::selectWordBackward()
@@ -1816,7 +1426,7 @@ void WebPage::selectWordBackward()
     VisiblePosition position = frame.selection().selection().start();
     VisiblePosition startPosition = positionOfNextBoundaryOfGranularity(position, WordGranularity, DirectionBackward);
     if (startPosition.isNotNull() && startPosition != position)
-        frame.selection().setSelectedRange(Range::create(*frame.document(), startPosition, position).ptr(), position.affinity(), true, UserTriggered);
+        frame.selection().setSelectedRange(Range::create(*frame.document(), startPosition, position).ptr(), position.affinity(), WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
 }
 
 void WebPage::moveSelectionByOffset(int32_t offset, CallbackID callbackID)
@@ -1834,7 +1444,7 @@ void WebPage::moveSelectionByOffset(int32_t offset, CallbackID callbackID)
             break;
     }
     if (position.isNotNull() && startPosition != position)
-        frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), position.affinity(), true, UserTriggered);
+        frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), position.affinity(), WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
     send(Messages::WebPageProxy::VoidCallback(callbackID));
 }
     
@@ -1954,7 +1564,7 @@ void WebPage::selectPositionAtPoint(const WebCore::IntPoint& point, bool isInter
     VisiblePosition position = visiblePositionInFocusedNodeForPoint(frame, point, isInteractingWithAssistedNode);
     
     if (position.isNotNull())
-        frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), position.affinity(), true, UserTriggered);
+        frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), position.affinity(), WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
     send(Messages::WebPageProxy::VoidCallback(callbackID));
 }
 
@@ -1966,7 +1576,7 @@ void WebPage::selectPositionAtBoundaryWithDirection(const WebCore::IntPoint& poi
     if (position.isNotNull()) {
         position = positionOfNextBoundaryOfGranularity(position, static_cast<WebCore::TextGranularity>(granularity), static_cast<SelectionDirection>(direction));
         if (position.isNotNull())
-            frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), UPSTREAM, true, UserTriggered);
+            frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), UPSTREAM, WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
     }
     send(Messages::WebPageProxy::VoidCallback(callbackID));
 }
@@ -1980,7 +1590,7 @@ void WebPage::moveSelectionAtBoundaryWithDirection(uint32_t granularity, uint32_
         VisiblePosition position = (isForward) ? frame.selection().selection().visibleEnd() : frame.selection().selection().visibleStart();
         position = positionOfNextBoundaryOfGranularity(position, static_cast<WebCore::TextGranularity>(granularity), static_cast<SelectionDirection>(direction));
         if (position.isNotNull())
-            frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), isForward? UPSTREAM : DOWNSTREAM, true, UserTriggered);
+            frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), isForward? UPSTREAM : DOWNSTREAM, WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
     }
     send(Messages::WebPageProxy::VoidCallback(callbackID));
 }
@@ -2037,7 +1647,7 @@ void WebPage::selectTextWithGranularityAtPoint(const WebCore::IntPoint& point, u
     }
 
     if (range)
-        frame.selection().setSelectedRange(range.get(), UPSTREAM, true, UserTriggered);
+        frame.selection().setSelectedRange(range.get(), UPSTREAM, WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
     m_initialSelection = range;
     send(Messages::WebPageProxy::VoidCallback(callbackID));
 }
@@ -2072,7 +1682,7 @@ void WebPage::updateSelectionWithExtentPointAndBoundary(const WebCore::IntPoint&
         range = Range::create(*frame.document(), selectionStart, selectionEnd);
     
     if (range)
-        frame.selection().setSelectedRange(range.get(), UPSTREAM, true, UserTriggered);
+        frame.selection().setSelectedRange(range.get(), UPSTREAM, WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
     
     send(Messages::WebPageProxy::UnsignedCallback(selectionStart == m_initialSelection->startPosition(), callbackID));
 }
@@ -2115,7 +1725,7 @@ void WebPage::updateSelectionWithExtentPoint(const WebCore::IntPoint& point, boo
         range = Range::create(*frame.document(), selectionStart, selectionEnd);
 
     if (range)
-        frame.selection().setSelectedRange(range.get(), UPSTREAM, true, UserTriggered);
+        frame.selection().setSelectedRange(range.get(), UPSTREAM, WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
 
     send(Messages::WebPageProxy::UnsignedCallback(m_selectionAnchor == Start, callbackID));
 }
@@ -2178,7 +1788,7 @@ void WebPage::replaceSelectedText(const String& oldText, const String& newText)
         return;
     
     frame.editor().setIgnoreSelectionChanges(true);
-    frame.selection().setSelectedRange(wordRange.get(), UPSTREAM, true);
+    frame.selection().setSelectedRange(wordRange.get(), UPSTREAM, WebCore::FrameSelection::ShouldCloseTyping::Yes);
     frame.editor().insertText(newText, 0);
     frame.editor().setIgnoreSelectionChanges(false);
 }
@@ -2205,7 +1815,7 @@ void WebPage::replaceDictatedText(const String& oldText, const String& newText)
 
     // We don't want to notify the client that the selection has changed until we are done inserting the new text.
     frame.editor().setIgnoreSelectionChanges(true);
-    frame.selection().setSelectedRange(range.get(), UPSTREAM, true);
+    frame.selection().setSelectedRange(range.get(), UPSTREAM, WebCore::FrameSelection::ShouldCloseTyping::Yes);
     frame.editor().insertText(newText, 0);
     frame.editor().setIgnoreSelectionChanges(false);
 }
@@ -2339,7 +1949,7 @@ void WebPage::syncApplyAutocorrection(const String& correction, const String& or
     if (range && range->collapsed())
         affinity = VisiblePosition(range->startPosition(), UPSTREAM).affinity();
     
-    frame.selection().setSelectedRange(range.get(), affinity, true);
+    frame.selection().setSelectedRange(range.get(), affinity, WebCore::FrameSelection::ShouldCloseTyping::Yes);
     if (correction.length())
         frame.editor().insertText(correction, 0, originalText.isEmpty() ? TextEventInputKeyboard : TextEventInputAutocompletion);
     else
@@ -2395,7 +2005,7 @@ static void computeAutocorrectionContext(Frame& frame, String& contextBefore, St
             if (currentPosition.isNotNull() && currentPosition != startPosition) {
                 contextBefore = plainTextReplacingNoBreakSpace(Range::create(*frame.document(), currentPosition, startPosition).ptr());
                 if (atBoundaryOfGranularity(currentPosition, ParagraphGranularity, DirectionBackward))
-                    contextBefore = ASCIILiteral("\n ") + contextBefore;
+                    contextBefore = makeString("\n "_s, contextBefore);
             }
         }
 
@@ -2446,6 +2056,10 @@ static inline bool isAssistableElement(Element& node)
     if (is<HTMLInputElement>(node)) {
         HTMLInputElement& inputElement = downcast<HTMLInputElement>(node);
         // FIXME: This laundry list of types is not a good way to factor this. Need a suitable function on HTMLInputElement itself.
+#if ENABLE(INPUT_TYPE_COLOR)
+        if (inputElement.isColorControl())
+            return true;
+#endif
         return inputElement.isTextField() || inputElement.isDateField() || inputElement.isDateTimeLocalField() || inputElement.isMonthField() || inputElement.isTimeField();
     }
     return node.isContentEditable();
@@ -2602,12 +2216,29 @@ void WebPage::getPositionInformation(const InteractionInformationRequest& reques
                 if (attachment.file())
                     info.url = URL::fileURLWithFileSystemPath(downcast<HTMLAttachmentElement>(*hitNode).file()->path());
             } else {
-                info.isSelectable = renderer->style().userSelect() != SELECT_NONE;
+                info.isSelectable = renderer->style().userSelect() != UserSelect::None;
                 if (info.isSelectable && !hitNode->isTextNode())
                     info.isSelectable = !isAssistableElement(*downcast<Element>(hitNode)) && !rectIsTooBigForSelection(info.bounds, *result.innerNodeFrame());
             }
+#if PLATFORM(IOSMAC)
+            bool isInsideFixedPosition;
+            VisiblePosition caretPosition(renderer->positionForPoint(request.point, nullptr));
+            info.caretRect = caretPosition.absoluteCaretBounds(&isInsideFixedPosition);
+#endif
+        }
+    }
+
+    // Prevent the callout bar from showing when tapping on the datalist button.
+#if ENABLE(DATALIST_ELEMENT)
+    if (is<HTMLInputElement>(*hitNode)) {
+        const HTMLInputElement& input = downcast<HTMLInputElement>(*hitNode);
+        if (input.list()) {
+            HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint(request.point, HitTestRequest::ReadOnly | HitTestRequest::Active);
+            if (result.innerNode() == input.dataListButtonElement())
+                info.preventTextInteraction = true;
         }
     }
+#endif
 
 #if ENABLE(DATA_INTERACTION)
     info.hasSelectionAtPosition = m_page->hasSelectionAtPosition(adjustedPoint);
@@ -2691,11 +2322,6 @@ static inline Element* nextAssistableElement(Node* startNode, Page& page, bool i
     return nextElement;
 }
 
-static inline bool hasAssistableElement(Node* startNode, Page& page, bool isForward)
-{
-    return nextAssistableElement(startNode, page, isForward);
-}
-
 void WebPage::focusNextAssistedNode(bool isForward, CallbackID callbackID)
 {
     Element* nextElement = nextAssistableElement(m_assistedNode.get(), *m_page, isForward);
@@ -2706,6 +2332,19 @@ void WebPage::focusNextAssistedNode(bool isForward, CallbackID callbackID)
     send(Messages::WebPageProxy::VoidCallback(callbackID));
 }
 
+static IntRect elementRectInRootViewCoordinates(const Node& node, const Frame& frame)
+{
+    auto* view = frame.view();
+    if (!view)
+        return { };
+
+    auto* renderer = node.renderer();
+    if (!renderer)
+        return { };
+
+    return view->contentsToRootView(renderer->absoluteBoundingBoxRect());
+}
+
 void WebPage::getAssistedNodeInformation(AssistedNodeInformation& information)
 {
     layoutIfNeeded();
@@ -2716,13 +2355,14 @@ void WebPage::getAssistedNodeInformation(AssistedNodeInformation& information)
 
     if (RenderObject* renderer = m_assistedNode->renderer()) {
         Frame& elementFrame = m_page->focusController().focusedOrMainFrame();
-        information.elementRect = elementFrame.view()->contentsToRootView(renderer->absoluteBoundingBoxRect());
+        information.elementRect = elementRectInRootViewCoordinates(*m_assistedNode, elementFrame);
         information.nodeFontSize = renderer->style().fontDescription().computedSize();
+        information.elementIsTransparent = renderer->isTransparentRespectingParentFrames();
 
         bool inFixed = false;
         renderer->localToContainerPoint(FloatPoint(), nullptr, UseTransforms, &inFixed);
         information.insideFixedPosition = inFixed;
-        information.isRTL = renderer->style().direction() == RTL;
+        information.isRTL = renderer->style().direction() == TextDirection::RTL;
 
         FrameView* frameView = elementFrame.view();
         if (inFixed && elementFrame.isMainFrame() && !frameView->frame().settings().visualViewportEnabled()) {
@@ -2746,8 +2386,16 @@ void WebPage::getAssistedNodeInformation(AssistedNodeInformation& information)
     information.maximumScaleFactorIgnoringAlwaysScalable = maximumPageScaleFactorIgnoringAlwaysScalable();
     information.allowsUserScaling = m_viewportConfiguration.allowsUserScaling();
     information.allowsUserScalingIgnoringAlwaysScalable = m_viewportConfiguration.allowsUserScalingIgnoringAlwaysScalable();
-    information.hasNextNode = hasAssistableElement(m_assistedNode.get(), *m_page, true);
-    information.hasPreviousNode = hasAssistableElement(m_assistedNode.get(), *m_page, false);
+    if (auto* nextElement = nextAssistableElement(m_assistedNode.get(), *m_page, true)) {
+        if (auto* frame = nextElement->document().frame())
+            information.nextNodeRect = elementRectInRootViewCoordinates(*nextElement, *frame);
+        information.hasNextNode = true;
+    }
+    if (auto* previousElement = nextAssistableElement(m_assistedNode.get(), *m_page, false)) {
+        if (auto* frame = previousElement->document().frame())
+            information.previousNodeRect = elementRectInRootViewCoordinates(*previousElement, *frame);
+        information.hasPreviousNode = true;
+    }
     information.assistedNodeIdentifier = m_currentAssistedNodeIdentifier;
 
     if (is<LabelableElement>(*m_assistedNode)) {
@@ -2766,6 +2414,12 @@ void WebPage::getAssistedNodeInformation(AssistedNodeInformation& information)
         }
     }
 
+    if (is<Element>(m_assistedNode.get())) {
+        auto& element = downcast<Element>(*m_assistedNode);
+        information.title = element.title();
+        information.ariaLabel = element.attributeWithoutSynchronization(HTMLNames::aria_labelAttr);
+    }
+
     if (is<HTMLSelectElement>(*m_assistedNode)) {
         HTMLSelectElement& element = downcast<HTMLSelectElement>(*m_assistedNode);
         information.elementType = InputType::Select;
@@ -2797,12 +2451,16 @@ void WebPage::getAssistedNodeInformation(AssistedNodeInformation& information)
         information.value = element.value();
         information.autofillFieldName = WebCore::toAutofillFieldName(element.autofillData().fieldName);
         information.placeholder = element.attributeWithoutSynchronization(HTMLNames::placeholderAttr);
+        information.inputMode = element.canonicalInputMode();
     } else if (is<HTMLInputElement>(*m_assistedNode)) {
         HTMLInputElement& element = downcast<HTMLInputElement>(*m_assistedNode);
         HTMLFormElement* form = element.form();
         if (form)
             information.formAction = form->getURLAttribute(WebCore::HTMLNames::actionAttr);
-        information.acceptsAutofilledLoginCredentials = !!WebCore::AutofillElements::computeAutofillElements(element);
+        if (auto autofillElements = WebCore::AutofillElements::computeAutofillElements(element)) {
+            information.acceptsAutofilledLoginCredentials = true;
+            information.isAutofillableUsernameField = autofillElements->username() == m_assistedNode;
+        }
         information.representingPageURL = element.document().urlForBindings();
         information.autocapitalizeType = element.autocapitalizeType();
         information.isAutocorrect = element.shouldAutocorrect();
@@ -2842,11 +2500,22 @@ void WebPage::getAssistedNodeInformation(AssistedNodeInformation& information)
                     information.elementType = InputType::Search;
             }
         }
+#if ENABLE(INPUT_TYPE_COLOR)
+        else if (element.isColorControl()) {
+            information.elementType = InputType::Color;
+#if ENABLE(DATALIST_ELEMENT)
+            information.suggestedColors = element.suggestedColors();
+#endif
+        }
+#endif
 
+#if ENABLE(DATALIST_ELEMENT)
+        information.hasSuggestions = !!element.list();
+#endif
+        information.inputMode = element.canonicalInputMode();
         information.isReadOnly = element.isReadOnly();
         information.value = element.value();
         information.valueAsNumber = element.valueAsNumber();
-        information.title = element.title();
         information.autofillFieldName = WebCore::toAutofillFieldName(element.autofillData().fieldName);
     } else if (m_assistedNode->hasEditableStyle()) {
         information.elementType = InputType::ContentEditable;
@@ -2854,6 +2523,7 @@ void WebPage::getAssistedNodeInformation(AssistedNodeInformation& information)
             auto& assistedElement = downcast<HTMLElement>(*m_assistedNode);
             information.isAutocorrect = assistedElement.shouldAutocorrect();
             information.autocapitalizeType = assistedElement.autocapitalizeType();
+            information.inputMode = assistedElement.canonicalInputMode();
         } else {
             information.isAutocorrect = true;
             information.autocapitalizeType = AutocapitalizeTypeDefault;
@@ -2864,17 +2534,29 @@ void WebPage::getAssistedNodeInformation(AssistedNodeInformation& information)
 
 void WebPage::autofillLoginCredentials(const String& username, const String& password)
 {
-    if (is<HTMLInputElement>(*m_assistedNode)) {
+    if (is<HTMLInputElement>(m_assistedNode.get())) {
         if (auto autofillElements = AutofillElements::computeAutofillElements(downcast<HTMLInputElement>(*m_assistedNode)))
             autofillElements->autofill(username, password);
     }
 }
 
-void WebPage::setViewportConfigurationMinimumLayoutSize(const FloatSize& size, const FloatSize& viewSize)
+// WebCore stores the page scale factor as float instead of double. When we get a scale from WebCore,
+// we need to ignore differences that are within a small rounding error on floats.
+static inline bool areEssentiallyEqualAsFloat(float a, float b)
 {
-    LOG_WITH_STREAM(VisibleRects, stream << "WebPage " << m_pageID << " setViewportConfigurationMinimumLayoutSize " << size << " viewSize " << viewSize);
-    if (m_viewportConfiguration.setMinimumLayoutSize(size, viewSize))
-        viewportConfigurationChanged();
+    return WTF::areEssentiallyEqual(a, b);
+}
+
+void WebPage::setViewportConfigurationViewLayoutSize(const FloatSize& size, double scaleFactor, double minimumEffectiveDeviceWidth)
+{
+    LOG_WITH_STREAM(VisibleRects, stream << "WebPage " << m_pageID << " setViewportConfigurationViewLayoutSize " << size << " scaleFactor " << scaleFactor << " minimumEffectiveDeviceWidth " << minimumEffectiveDeviceWidth);
+
+    ZoomToInitialScale shouldZoomToInitialScale = ZoomToInitialScale::No;
+    if (m_viewportConfiguration.layoutSizeScaleFactor() != scaleFactor && areEssentiallyEqualAsFloat(m_viewportConfiguration.initialScale(), pageScaleFactor()))
+        shouldZoomToInitialScale = ZoomToInitialScale::Yes;
+
+    if (m_viewportConfiguration.setViewLayoutSize(size, scaleFactor, minimumEffectiveDeviceWidth))
+        viewportConfigurationChanged(shouldZoomToInitialScale);
 }
 
 void WebPage::setMaximumUnobscuredSize(const FloatSize& maximumUnobscuredSize)
@@ -2891,11 +2573,10 @@ void WebPage::setDeviceOrientation(int32_t deviceOrientation)
     m_page->mainFrame().orientationChanged();
 }
 
-// WebCore stores the page scale factor as float instead of double. When we get a scale from WebCore,
-// we need to ignore differences that are within a small rounding error on floats.
-static inline bool areEssentiallyEqualAsFloat(float a, float b)
+void WebPage::setOverrideViewportArguments(const std::optional<WebCore::ViewportArguments>& arguments)
 {
-    return WTF::areEssentiallyEqual(a, b);
+    if (auto* document = m_page->mainFrame().document())
+        document->setOverrideViewportArguments(arguments);
 }
 
 void WebPage::resetTextAutosizing()
@@ -2908,12 +2589,12 @@ void WebPage::resetTextAutosizing()
     }
 }
 
-void WebPage::dynamicViewportSizeUpdate(const FloatSize& minimumLayoutSize, const FloatSize& viewSize, const WebCore::FloatSize& maximumUnobscuredSize, const FloatRect& targetExposedContentRect, const FloatRect& targetUnobscuredRect, const WebCore::FloatRect& targetUnobscuredRectInScrollViewCoordinates, const WebCore::FloatBoxExtent& targetUnobscuredSafeAreaInsets, double targetScale, int32_t deviceOrientation, uint64_t dynamicViewportSizeUpdateID)
+void WebPage::dynamicViewportSizeUpdate(const FloatSize& viewLayoutSize, const WebCore::FloatSize& maximumUnobscuredSize, const FloatRect& targetExposedContentRect, const FloatRect& targetUnobscuredRect, const WebCore::FloatRect& targetUnobscuredRectInScrollViewCoordinates, const WebCore::FloatBoxExtent& targetUnobscuredSafeAreaInsets, double targetScale, int32_t deviceOrientation, DynamicViewportSizeUpdateID dynamicViewportSizeUpdateID)
 {
     SetForScope<bool> dynamicSizeUpdateGuard(m_inDynamicSizeUpdate, true);
     // FIXME: this does not handle the cases where the content would change the content size or scroll position from JavaScript.
     // To handle those cases, we would need to redo this computation on every change until the next visible content rect update.
-    LOG_WITH_STREAM(VisibleRects, stream << "\nWebPage::dynamicViewportSizeUpdate - minimumLayoutSize " << minimumLayoutSize << " viewSize " << viewSize << " targetUnobscuredRect " << targetUnobscuredRect << " targetExposedContentRect " << targetExposedContentRect << " targetScale " << targetScale);
+    LOG_WITH_STREAM(VisibleRects, stream << "\nWebPage::dynamicViewportSizeUpdate - viewLayoutSize " << viewLayoutSize << " targetUnobscuredRect " << targetUnobscuredRect << " targetExposedContentRect " << targetExposedContentRect << " targetScale " << targetScale);
 
     FrameView& frameView = *m_page->mainFrame().view();
     IntSize oldContentSize = frameView.contentsSize();
@@ -2945,8 +2626,8 @@ void WebPage::dynamicViewportSizeUpdate(const FloatSize& minimumLayoutSize, cons
         }
     }
 
-    LOG_WITH_STREAM(VisibleRects, stream << "WebPage::dynamicViewportSizeUpdate setting minimum layout size to " << minimumLayoutSize);
-    m_viewportConfiguration.setMinimumLayoutSize(minimumLayoutSize, viewSize);
+    LOG_WITH_STREAM(VisibleRects, stream << "WebPage::dynamicViewportSizeUpdate setting view layout size to " << viewLayoutSize);
+    m_viewportConfiguration.setViewLayoutSize(viewLayoutSize);
     IntSize newLayoutSize = m_viewportConfiguration.layoutSize();
 
     if (setFixedLayoutSize(newLayoutSize))
@@ -3028,7 +2709,7 @@ void WebPage::dynamicViewportSizeUpdate(const FloatSize& minimumLayoutSize, cons
                 newExposedContentRect.setY(0);
             }
 
-            bool likelyResponsiveDesignViewport = newLayoutSize.width() == minimumLayoutSize.width() && areEssentiallyEqualAsFloat(scale, 1);
+            bool likelyResponsiveDesignViewport = newLayoutSize.width() == viewLayoutSize.width() && areEssentiallyEqualAsFloat(scale, 1);
             bool contentBleedsOutsideLayoutWidth = newContentSize.width() > newLayoutSize.width();
             bool originalScrollPositionWasOnTheLeftEdge = targetUnobscuredRect.x() <= 0;
             if (likelyResponsiveDesignViewport && contentBleedsOutsideLayoutWidth && originalScrollPositionWasOnTheLeftEdge) {
@@ -3068,9 +2749,11 @@ void WebPage::dynamicViewportSizeUpdate(const FloatSize& minimumLayoutSize, cons
 
     frameView.updateLayoutAndStyleIfNeededRecursive();
 
-    if (frameView.frame().settings().visualViewportEnabled()) {
+    auto& settings = frameView.frame().settings();
+    if (settings.visualViewportEnabled()) {
         LayoutRect documentRect = IntRect(frameView.scrollOrigin(), frameView.contentsSize());
-        LayoutRect layoutViewportRect = FrameView::computeUpdatedLayoutViewportRect(frameView.layoutViewportRect(), documentRect, LayoutSize(newUnobscuredContentRect.size()), LayoutRect(newUnobscuredContentRect), frameView.baseLayoutViewportSize(), frameView.minStableLayoutViewportOrigin(), frameView.maxStableLayoutViewportOrigin(), FrameView::LayoutViewportConstraint::ConstrainedToDocumentRect);
+        auto layoutViewportSize = FrameView::expandedLayoutViewportSize(frameView.baseLayoutViewportSize(), LayoutSize(documentRect.size()), settings.layoutViewportHeightExpansionFactor());
+        LayoutRect layoutViewportRect = FrameView::computeUpdatedLayoutViewportRect(frameView.layoutViewportRect(), documentRect, LayoutSize(newUnobscuredContentRect.size()), LayoutRect(newUnobscuredContentRect), layoutViewportSize, frameView.minStableLayoutViewportOrigin(), frameView.maxStableLayoutViewportOrigin(), FrameView::LayoutViewportConstraint::ConstrainedToDocumentRect);
         frameView.setLayoutViewportOverrideRect(layoutViewportRect);
     } else {
         IntRect fixedPositionLayoutRect = enclosingIntRect(frameView.viewportConstrainedObjectsRect());
@@ -3083,14 +2766,7 @@ void WebPage::dynamicViewportSizeUpdate(const FloatSize& minimumLayoutSize, cons
 
     m_drawingArea->scheduleCompositingLayerFlush();
 
-    send(Messages::WebPageProxy::DynamicViewportUpdateChangedTarget(pageScaleFactor(), frameView.scrollPosition(), dynamicViewportSizeUpdateID));
-}
-
-void WebPage::synchronizeDynamicViewportUpdate(double& newTargetScale, FloatPoint& newScrollPosition, uint64_t& nextValidLayerTreeTransactionID)
-{
-    newTargetScale = pageScaleFactor();
-    newScrollPosition = m_page->mainFrame().view()->scrollPosition();
-    nextValidLayerTreeTransactionID = downcast<RemoteLayerTreeDrawingArea>(*m_drawingArea).nextTransactionID();
+    m_pendingDynamicViewportSizeUpdateID = dynamicViewportSizeUpdateID;
 }
 
 void WebPage::resetViewportDefaultConfiguration(WebFrame* frame, bool hasMobileDocType)
@@ -3101,8 +2777,15 @@ void WebPage::resetViewportDefaultConfiguration(WebFrame* frame, bool hasMobileD
         return;
     }
 
+    auto parametersForStandardFrame = [&] {
+        if (m_page->settings().shouldIgnoreMetaViewport())
+            return ViewportConfiguration::nativeWebpageParameters();
+
+        return ViewportConfiguration::webpageParameters();
+    };
+
     if (!frame) {
-        m_viewportConfiguration.setDefaultConfiguration(ViewportConfiguration::webpageParameters());
+        m_viewportConfiguration.setDefaultConfiguration(parametersForStandardFrame());
         return;
     }
 
@@ -3117,17 +2800,17 @@ void WebPage::resetViewportDefaultConfiguration(WebFrame* frame, bool hasMobileD
     else if (document->isTextDocument())
         m_viewportConfiguration.setDefaultConfiguration(ViewportConfiguration::textDocumentParameters());
     else
-        m_viewportConfiguration.setDefaultConfiguration(ViewportConfiguration::webpageParameters());
+        m_viewportConfiguration.setDefaultConfiguration(parametersForStandardFrame());
 }
 
-void WebPage::viewportConfigurationChanged()
+void WebPage::viewportConfigurationChanged(ZoomToInitialScale zoomToInitialScale)
 {
     if (setFixedLayoutSize(m_viewportConfiguration.layoutSize()))
         resetTextAutosizing();
 
     double initialScale = m_viewportConfiguration.initialScale();
     double scale;
-    if (m_userHasChangedPageScaleFactor)
+    if (m_userHasChangedPageScaleFactor && zoomToInitialScale == ZoomToInitialScale::No)
         scale = std::max(std::min(pageScaleFactor(), m_viewportConfiguration.maximumScale()), m_viewportConfiguration.minimumScale());
     else
         scale = initialScale;
@@ -3141,7 +2824,7 @@ void WebPage::viewportConfigurationChanged()
     FrameView& frameView = *mainFrameView();
     IntPoint scrollPosition = frameView.scrollPosition();
     if (!m_hasReceivedVisibleContentRectsAfterDidCommitLoad) {
-        FloatSize minimumLayoutSizeInScrollViewCoordinates = m_viewportConfiguration.minimumLayoutSize();
+        FloatSize minimumLayoutSizeInScrollViewCoordinates = m_viewportConfiguration.viewLayoutSize();
         minimumLayoutSizeInScrollViewCoordinates.scale(1 / scale);
         IntSize minimumLayoutSizeInDocumentCoordinates = roundedIntSize(minimumLayoutSizeInScrollViewCoordinates);
         frameView.setUnobscuredContentSize(minimumLayoutSizeInDocumentCoordinates);
@@ -3163,19 +2846,20 @@ void WebPage::viewportConfigurationChanged()
 
 void WebPage::updateViewportSizeForCSSViewportUnits()
 {
-    FloatSize largestUnobscuredRect = m_maximumUnobscuredSize;
-    if (largestUnobscuredRect.isEmpty())
-        largestUnobscuredRect = m_viewportConfiguration.minimumLayoutSize();
+    FloatSize largestUnobscuredSize = m_maximumUnobscuredSize;
+    if (largestUnobscuredSize.isEmpty())
+        largestUnobscuredSize = m_viewportConfiguration.viewLayoutSize();
 
     FrameView& frameView = *mainFrameView();
-    largestUnobscuredRect.scale(1 / m_viewportConfiguration.initialScaleIgnoringContentSize());
-    frameView.setViewportSizeForCSSViewportUnits(roundedIntSize(largestUnobscuredRect));
+    largestUnobscuredSize.scale(1 / m_viewportConfiguration.initialScaleIgnoringContentSize());
+    frameView.setViewportSizeForCSSViewportUnits(roundedIntSize(largestUnobscuredSize));
 }
 
 void WebPage::applicationWillResignActive()
 {
     [[NSNotificationCenter defaultCenter] postNotificationName:WebUIApplicationWillResignActiveNotification object:nil];
-    m_page->applicationWillResignActive();
+    if (m_page)
+        m_page->applicationWillResignActive();
 }
 
 void WebPage::applicationDidEnterBackground(bool isSuspendedUnderLock)
@@ -3183,9 +2867,10 @@ void WebPage::applicationDidEnterBackground(bool isSuspendedUnderLock)
     [[NSNotificationCenter defaultCenter] postNotificationName:WebUIApplicationDidEnterBackgroundNotification object:nil userInfo:@{@"isSuspendedUnderLock": [NSNumber numberWithBool:isSuspendedUnderLock]}];
 
     m_isSuspendedUnderLock = isSuspendedUnderLock;
-    setLayerTreeStateIsFrozen(true);
+    freezeLayerTree(LayerTreeFreezeReason::BackgroundApplication);
 
-    m_page->applicationDidEnterBackground();
+    if (m_page)
+        m_page->applicationDidEnterBackground();
 }
 
 void WebPage::applicationDidFinishSnapshottingAfterEnteringBackground()
@@ -3197,17 +2882,19 @@ void WebPage::applicationWillEnterForeground(bool isSuspendedUnderLock)
 {
     m_isSuspendedUnderLock = false;
     cancelMarkLayersVolatile();
-    setLayerTreeStateIsFrozen(false);
+    unfreezeLayerTree(LayerTreeFreezeReason::BackgroundApplication);
 
     [[NSNotificationCenter defaultCenter] postNotificationName:WebUIApplicationWillEnterForegroundNotification object:nil userInfo:@{@"isSuspendedUnderLock": @(isSuspendedUnderLock)}];
 
-    m_page->applicationWillEnterForeground();
+    if (m_page)
+        m_page->applicationWillEnterForeground();
 }
 
 void WebPage::applicationDidBecomeActive()
 {
     [[NSNotificationCenter defaultCenter] postNotificationName:WebUIApplicationDidBecomeActiveNotification object:nil];
-    m_page->applicationDidBecomeActive();
+    if (m_page)
+        m_page->applicationDidBecomeActive();
 }
 
 static inline void adjustVelocityDataForBoundedScale(double& horizontalVelocity, double& verticalVelocity, double& scaleChangeRate, double exposedRectScale, double minimumScale, double maximumScale)
@@ -3221,19 +2908,10 @@ static inline void adjustVelocityDataForBoundedScale(double& horizontalVelocity,
         scaleChangeRate = 0;
 }
 
-static inline FloatRect adjustExposedRectForBoundedScale(const FloatRect& exposedRect, double exposedRectScale, double newScale)
-{
-    if (exposedRectScale < newScale)
-        return exposedRect;
-
-    return adjustExposedRectForNewScale(exposedRect, exposedRectScale, newScale);
-}
-
 std::optional<float> WebPage::scaleFromUIProcess(const VisibleContentRectUpdateInfo& visibleContentRectUpdateInfo) const
 {
-    auto transactionIDForLastScaleSentToUIProcess = downcast<RemoteLayerTreeDrawingArea>(*m_drawingArea).lastCommittedTransactionID();
     auto transactionIDForLastScaleFromUIProcess = visibleContentRectUpdateInfo.lastLayerTreeTransactionID();
-    if (transactionIDForLastScaleSentToUIProcess != transactionIDForLastScaleFromUIProcess)
+    if (m_lastTransactionIDWithScaleChange > transactionIDForLastScaleFromUIProcess)
         return std::nullopt;
 
     float scaleFromUIProcess = visibleContentRectUpdateInfo.scale();
@@ -3299,7 +2977,7 @@ void WebPage::updateVisibleContentRects(const VisibleContentRectUpdateInfo& visi
 
     float scaleToUse = scaleFromUIProcess.value_or(m_page->pageScaleFactor());
     FloatRect exposedContentRect = visibleContentRectUpdateInfo.exposedContentRect();
-    FloatRect adjustedExposedContentRect = adjustExposedRectForBoundedScale(exposedContentRect, visibleContentRectUpdateInfo.scale(), scaleToUse);
+    FloatRect adjustedExposedContentRect = adjustExposedRectForNewScale(exposedContentRect, visibleContentRectUpdateInfo.scale(), scaleToUse);
     m_drawingArea->setExposedContentRect(adjustedExposedContentRect);
 
     IntPoint scrollPosition = roundedIntPoint(visibleContentRectUpdateInfo.unobscuredContentRect().location());
@@ -3326,9 +3004,7 @@ void WebPage::updateVisibleContentRects(const VisibleContentRectUpdateInfo& visi
     if (scrollPosition != frameView.scrollPosition())
         m_dynamicSizeUpdateHistory.clear();
 
-    bool didUpdateForceHorizontalShrinkToFit = m_viewportConfiguration.setForceHorizontalShrinkToFit(visibleContentRectUpdateInfo.forceHorizontalShrinkToFit());
-    bool didUpdateCanIgnoreViewportScalingConstraints = m_viewportConfiguration.setCanIgnoreScalingConstraints(m_ignoreViewportScalingConstraints && visibleContentRectUpdateInfo.allowShrinkToFit());
-    if (didUpdateForceHorizontalShrinkToFit || didUpdateCanIgnoreViewportScalingConstraints)
+    if (m_viewportConfiguration.setCanIgnoreScalingConstraints(m_ignoreViewportScalingConstraints && visibleContentRectUpdateInfo.allowShrinkToFit()))
         viewportConfigurationChanged();
 
     frameView.setUnobscuredContentSize(visibleContentRectUpdateInfo.unobscuredContentRect().size());
@@ -3385,18 +3061,6 @@ void WebPage::willStartUserTriggeredZooming()
     m_userHasChangedPageScaleFactor = true;
 }
 
-#if ENABLE(WEBGL)
-WebCore::WebGLLoadPolicy WebPage::webGLPolicyForURL(WebFrame*, const URL&)
-{
-    return WebGLAllowCreation;
-}
-
-WebCore::WebGLLoadPolicy WebPage::resolveWebGLPolicyForURL(WebFrame*, const URL&)
-{
-    return WebGLAllowCreation;
-}
-#endif
-
 #if ENABLE(IOS_TOUCH_EVENTS)
 void WebPage::dispatchAsynchronousTouchEvents(const Vector<WebTouchEvent, 1>& queue)
 {
@@ -3406,10 +3070,10 @@ void WebPage::dispatchAsynchronousTouchEvents(const Vector<WebTouchEvent, 1>& qu
 }
 #endif
 
-void WebPage::computePagesForPrintingAndDrawToPDF(uint64_t frameID, const PrintInfo& printInfo, CallbackID callbackID, Ref<Messages::WebPage::ComputePagesForPrintingAndDrawToPDF::DelayedReply>&& reply)
+void WebPage::computePagesForPrintingAndDrawToPDF(uint64_t frameID, const PrintInfo& printInfo, CallbackID callbackID, Messages::WebPage::ComputePagesForPrintingAndDrawToPDF::DelayedReply&& reply)
 {
     if (printInfo.snapshotFirstPage) {
-        reply->send(1);
+        reply(1);
         IntSize snapshotSize { FloatSize { printInfo.availablePaperWidth, printInfo.availablePaperHeight } };
         IntRect snapshotRect { {0, 0}, snapshotSize };
         auto pdfData = pdfSnapshotAtSize(snapshotRect, snapshotSize, 0);
@@ -3424,7 +3088,7 @@ void WebPage::computePagesForPrintingAndDrawToPDF(uint64_t frameID, const PrintI
     ASSERT(pageRects.size() >= 1);
     std::size_t pageCount = pageRects.size();
     ASSERT(pageCount <= std::numeric_limits<uint32_t>::max());
-    reply->send(pageCount);
+    reply(pageCount);
 
     RetainPtr<CFMutableDataRef> pdfPageData;
     drawPagesToPDFImpl(frameID, printInfo, 0, pageCount, pdfPageData);
@@ -3444,6 +3108,12 @@ String WebPage::platformUserAgent(const URL&) const
     return String();
 }
 
+void WebPage::hardwareKeyboardAvailabilityChanged()
+{
+    if (auto* focusedFrame = m_page->focusController().focusedFrame())
+        focusedFrame->eventHandler().capsLockStateMayHaveChanged();
+}
+
 #if USE(QUICK_LOOK)
 void WebPage::didReceivePasswordForQuickLookDocument(const String& password)
 {
@@ -3451,6 +3121,15 @@ void WebPage::didReceivePasswordForQuickLookDocument(const String& password)
 }
 #endif
 
+bool WebPage::platformPrefersTextLegibilityBasedZoomScaling() const
+{
+#if PLATFORM(WATCHOS)
+    return true;
+#else
+    return false;
+#endif
+}
+
 #if ENABLE(MEDIA_STREAM)
 void WebPage::prepareToSendUserMediaPermissionRequest()
 {
@@ -3469,4 +3148,4 @@ void WebPage::prepareToSendUserMediaPermissionRequest()
 
 } // namespace WebKit
 
-#endif // PLATFORM(IOS)
+#endif // PLATFORM(IOS_FAMILY)