Move Lookup Code for better cross platform usage
[WebKit-https.git] / Source / WebKit / WebProcess / WebPage / ios / WebPageIOS.mm
index 8b5d37c..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/MediaSessionManagerIOS.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)
@@ -122,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;
@@ -189,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;
     }
@@ -236,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);
     }
@@ -399,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;
 }
 
@@ -408,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();
@@ -749,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());
@@ -1119,7 +1143,7 @@ void WebPage::selectWithGesture(const IntPoint& point, uint32_t granularity, uin
         if (position.rootEditableElement())
             range = Range::create(*frame.document(), position, position);
         else
-#if !ENABLE(MINIMAL_SIMULATOR)
+#if !PLATFORM(IOSMAC)
             range = wordRangeFromPosition(position);
 #else
             switch (wkGestureState) {
@@ -1209,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;
 }
 
@@ -1323,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:
@@ -1335,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));
 }
@@ -1355,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.
@@ -1370,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()
@@ -1382,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)
@@ -1400,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));
 }
     
@@ -1520,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));
 }
 
@@ -1532,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));
 }
@@ -1546,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));
 }
@@ -1603,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));
 }
@@ -1638,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));
 }
@@ -1681,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));
 }
@@ -1744,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);
 }
@@ -1771,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);
 }
@@ -1905,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
@@ -1961,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);
             }
         }
 
@@ -2012,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();
@@ -2172,9 +2220,26 @@ void WebPage::getPositionInformation(const InteractionInformationRequest& reques
                 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);
 #endif
@@ -2292,11 +2357,12 @@ void WebPage::getAssistedNodeInformation(AssistedNodeInformation& information)
         Frame& elementFrame = m_page->focusController().focusedOrMainFrame();
         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()) {
@@ -2385,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();
@@ -2430,7 +2500,19 @@ 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();
@@ -2441,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;
@@ -2451,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::setViewportConfigurationViewLayoutSize(const FloatSize& size)
+// 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 << " setViewportConfigurationViewLayoutSize " << size);
-    if (m_viewportConfiguration.setViewLayoutSize(size))
-        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)
@@ -2478,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()
@@ -2683,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;
     }
 
@@ -2699,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;
@@ -2757,7 +2858,8 @@ void WebPage::updateViewportSizeForCSSViewportUnits()
 void WebPage::applicationWillResignActive()
 {
     [[NSNotificationCenter defaultCenter] postNotificationName:WebUIApplicationWillResignActiveNotification object:nil];
-    m_page->applicationWillResignActive();
+    if (m_page)
+        m_page->applicationWillResignActive();
 }
 
 void WebPage::applicationDidEnterBackground(bool isSuspendedUnderLock)
@@ -2765,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()
@@ -2779,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)
@@ -2805,9 +2910,8 @@ static inline void adjustVelocityDataForBoundedScale(double& horizontalVelocity,
 
 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();
@@ -2957,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)
 {
@@ -3016,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)
 {
@@ -3050,4 +3148,4 @@ void WebPage::prepareToSendUserMediaPermissionRequest()
 
 } // namespace WebKit
 
-#endif // PLATFORM(IOS)
+#endif // PLATFORM(IOS_FAMILY)