[Cocoa] REGRESSION (r245672): Contenteditable with optical sizing freezes Safari
https://bugs.webkit.org/show_bug.cgi?id=202262

Reviewed by Tim Horton.

Source/WebKit:

r250640 didn't go far enough. We need to apply the same fix everywhere [NSFontDescriptor fontDescriptorWithFontAttributes:] is called.

* Shared/Cocoa/ArgumentCodersCocoa.mm:
(IPC::decodeFontInternal):
* Shared/Cocoa/CoreTextHelpers.h: Added.
* Shared/Cocoa/CoreTextHelpers.mm: Added.
(fontDescriptorWithFontAttributes):
* SourcesCocoa.txt:
* UIProcess/Cocoa/WebViewImpl.mm:
(WebKit::WebViewImpl::updateFontManagerIfNeeded):
* UIProcess/mac/WebPopupMenuProxyMac.mm:
(WebKit::WebPopupMenuProxyMac::showPopupMenu):
* WebKit.xcodeproj/project.pbxproj:

LayoutTests:

* fast/forms/contenteditable-font-optical-size-expected.txt: Added.
* fast/forms/contenteditable-font-optical-size.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@251086 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 790234e..27e08bc 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,13 @@
+2019-10-14  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [Cocoa] REGRESSION (r245672): Contenteditable with optical sizing freezes Safari
+        https://bugs.webkit.org/show_bug.cgi?id=202262
+
+        Reviewed by Tim Horton.
+
+        * fast/forms/contenteditable-font-optical-size-expected.txt: Added.
+        * fast/forms/contenteditable-font-optical-size.html: Added.
+
 2019-10-14  Russell Epstein  <russell_e@apple.com>
 
         Unreviewed, rolling out r251081.
diff --git a/LayoutTests/fast/forms/contenteditable-font-optical-size-expected.txt b/LayoutTests/fast/forms/contenteditable-font-optical-size-expected.txt
new file mode 100644
index 0000000..aee2599
--- /dev/null
+++ b/LayoutTests/fast/forms/contenteditable-font-optical-size-expected.txt
@@ -0,0 +1,9 @@
+This test makes sure that contenteditable with optical size doesn't hang the browser. The test passes if there is no hang when typing occurs in the contenteditable element.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Lorem ipsumabcde
diff --git a/LayoutTests/fast/forms/contenteditable-font-optical-size.html b/LayoutTests/fast/forms/contenteditable-font-optical-size.html
new file mode 100644
index 0000000..74234aa
--- /dev/null
+++ b/LayoutTests/fast/forms/contenteditable-font-optical-size.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+div{
+    text-rendering: optimizeLegibility;
+    font-family: -apple-system, sans-serif;
+}
+</style>
+<script src="../../resources/js-test-pre.js"></script>
+<script src="../../resources/ui-helper.js"></script>
+</head>
+<body>
+<div id="target" contenteditable="true">Lorem ipsum</div>
+<script>
+window.jsTestIsAsync = true;
+description("This test makes sure that contenteditable with optical size doesn't hang the browser. The test passes if there is no hang when typing occurs in the contenteditable element.");
+let target = document.getElementById("target");
+function handleFocus() {
+    if (window.testRunner) {
+        // For some reason, "await" doesn't seem to work...
+        UIHelper.ensurePresentationUpdate().then(function() {
+            UIHelper.keyDown("a").then(function() {
+                UIHelper.keyDown("b").then(function() {
+                    UIHelper.keyDown("c").then(function() {
+                        UIHelper.keyDown("d").then(function() {
+                            UIHelper.keyDown("e").then(function() {
+                                UIHelper.ensurePresentationUpdate().then(function() {
+                                    finishJSTest();
+                                });
+                            });
+                        });
+                    });
+                });
+            });
+        });
+    }
+}
+target.addEventListener("focus", handleFocus, { once: true });
+if (window.testRunner)
+    UIHelper.activateFormControl(target);
+else
+    target.focus();
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog
index 6c0c6d2..0008582 100644
--- a/Source/WebKit/ChangeLog
+++ b/Source/WebKit/ChangeLog
@@ -1,3 +1,24 @@
+2019-10-14  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [Cocoa] REGRESSION (r245672): Contenteditable with optical sizing freezes Safari
+        https://bugs.webkit.org/show_bug.cgi?id=202262
+
+        Reviewed by Tim Horton.
+
+        r250640 didn't go far enough. We need to apply the same fix everywhere [NSFontDescriptor fontDescriptorWithFontAttributes:] is called.
+
+        * Shared/Cocoa/ArgumentCodersCocoa.mm:
+        (IPC::decodeFontInternal):
+        * Shared/Cocoa/CoreTextHelpers.h: Added.
+        * Shared/Cocoa/CoreTextHelpers.mm: Added.
+        (fontDescriptorWithFontAttributes):
+        * SourcesCocoa.txt:
+        * UIProcess/Cocoa/WebViewImpl.mm:
+        (WebKit::WebViewImpl::updateFontManagerIfNeeded):
+        * UIProcess/mac/WebPopupMenuProxyMac.mm:
+        (WebKit::WebPopupMenuProxyMac::showPopupMenu):
+        * WebKit.xcodeproj/project.pbxproj:
+
 2019-10-14  Truitt Savell  <tsavell@apple.com>
 
         Unreviewed, rolling out r251045.
diff --git a/Source/WebKit/Shared/Cocoa/ArgumentCodersCocoa.mm b/Source/WebKit/Shared/Cocoa/ArgumentCodersCocoa.mm
index a1cd863..534a5ba 100644
--- a/Source/WebKit/Shared/Cocoa/ArgumentCodersCocoa.mm
+++ b/Source/WebKit/Shared/Cocoa/ArgumentCodersCocoa.mm
@@ -29,9 +29,11 @@
 #if PLATFORM(COCOA)
 
 #import "ArgumentCodersCF.h"
+#import "CoreTextHelpers.h"
 #import <CoreText/CTFont.h>
 #import <CoreText/CTFontDescriptor.h>
 #import <pal/spi/cocoa/NSKeyedArchiverSPI.h>
+#import <wtf/BlockObjCExceptions.h>
 #import <wtf/HashSet.h>
 
 #if USE(APPKIT)
@@ -328,8 +330,14 @@
     if (!decode(decoder, fontAttributes))
         return WTF::nullopt;
 
-    PlatformFontDescriptor *fontDescriptor = [PlatformFontDescriptor fontDescriptorWithFontAttributes:fontAttributes.get()];
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+    PlatformFontDescriptor *fontDescriptor = WebKit::fontDescriptorWithFontAttributes(fontAttributes.get());
     return { [PlatformFont fontWithDescriptor:fontDescriptor size:0] };
+
+    END_BLOCK_OBJC_EXCEPTIONS
+
+    return { };
 }
 
 #pragma mark - NSNumber
diff --git a/Source/WebKit/Shared/Cocoa/CoreTextHelpers.h b/Source/WebKit/Shared/Cocoa/CoreTextHelpers.h
new file mode 100644
index 0000000..89e4f45
--- /dev/null
+++ b/Source/WebKit/Shared/Cocoa/CoreTextHelpers.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018-2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if USE(APPKIT)
+#import <AppKit/AppKit.h>
+#else
+#import <UIKit/UIKit.h>
+#endif
+
+#import <wtf/RetainPtr.h>
+
+namespace WebKit {
+
+#if USE(APPKIT)
+using PlatformFontDescriptor = NSFontDescriptor;
+#else
+using PlatformFontDescriptor = UIFontDescriptor;
+#endif
+
+PlatformFontDescriptor *fontDescriptorWithFontAttributes(NSDictionary *attributes);
+
+}
diff --git a/Source/WebKit/Shared/Cocoa/CoreTextHelpers.mm b/Source/WebKit/Shared/Cocoa/CoreTextHelpers.mm
new file mode 100644
index 0000000..363d954
--- /dev/null
+++ b/Source/WebKit/Shared/Cocoa/CoreTextHelpers.mm
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "CoreTextHelpers.h"
+
+#import <pal/spi/cocoa/CoreTextSPI.h>
+#import <wtf/BlockObjCExceptions.h>
+
+namespace WebKit {
+
+PlatformFontDescriptor *fontDescriptorWithFontAttributes(NSDictionary *attributes)
+{
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+#if HAVE(NSFONT_WITH_OPTICAL_SIZING_BUG)
+    auto mutableDictionary = adoptNS([attributes mutableCopy]);
+    if (id opticalSizeAttribute = [mutableDictionary objectForKey:(__bridge NSString *)kCTFontOpticalSizeAttribute]) {
+        if ([opticalSizeAttribute isKindOfClass:[NSString class]]) {
+            [mutableDictionary removeObjectForKey:(__bridge NSString *)kCTFontOpticalSizeAttribute];
+            if (NSNumber *size = [mutableDictionary objectForKey:(__bridge NSString *)kCTFontSizeAttribute])
+                [mutableDictionary setObject:size forKey:(__bridge NSString *)kCTFontOpticalSizeAttribute];
+        }
+    }
+    return [PlatformFontDescriptor fontDescriptorWithFontAttributes:mutableDictionary.get()];
+#else
+    return [PlatformFontDescriptor fontDescriptorWithFontAttributes:attributes];
+#endif
+
+    END_BLOCK_OBJC_EXCEPTIONS
+
+    return nil;
+}
+
+}
diff --git a/Source/WebKit/Shared/ios/WebAutocorrectionData.mm b/Source/WebKit/Shared/ios/WebAutocorrectionData.mm
index 5a7e57a..5324f63 100644
--- a/Source/WebKit/Shared/ios/WebAutocorrectionData.mm
+++ b/Source/WebKit/Shared/ios/WebAutocorrectionData.mm
@@ -32,6 +32,7 @@
 #import "Decoder.h"
 #import "Encoder.h"
 #import "WebCoreArgumentCoders.h"
+#import <UIKit/UIKit.h>
 #import <WebCore/FloatRect.h>
 
 namespace WebKit {
diff --git a/Source/WebKit/SourcesCocoa.txt b/Source/WebKit/SourcesCocoa.txt
index b3f1222..327ea4e 100644
--- a/Source/WebKit/SourcesCocoa.txt
+++ b/Source/WebKit/SourcesCocoa.txt
@@ -142,6 +142,7 @@
 Shared/Cocoa/ArgumentCodersCocoa.mm
 Shared/Cocoa/AuxiliaryProcessCocoa.mm
 Shared/Cocoa/CompletionHandlerCallChecker.mm
+Shared/Cocoa/CoreTextHelpers.mm
 Shared/Cocoa/DataDetectionResult.mm
 Shared/Cocoa/InsertTextOptions.cpp
 Shared/Cocoa/LoadParametersCocoa.mm
diff --git a/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm b/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm
index 1262717..e275b3c 100644
--- a/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm
+++ b/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm
@@ -34,6 +34,7 @@
 #import "AppKitSPI.h"
 #import "AttributedString.h"
 #import "ColorSpaceData.h"
+#import "CoreTextHelpers.h"
 #import "FontInfo.h"
 #import "FullscreenClient.h"
 #import "GenericCallback.h"
@@ -117,6 +118,7 @@
 #import <pal/spi/mac/NSViewSPI.h>
 #import <pal/spi/mac/NSWindowSPI.h>
 #import <sys/stat.h>
+#import <wtf/BlockObjCExceptions.h>
 #import <wtf/FileSystem.h>
 #import <wtf/NeverDestroyed.h>
 #import <wtf/ProcessPrivilege.h>
@@ -1119,7 +1121,7 @@
     default:
         ASSERT_NOT_REACHED();
     }
-    
+
     return nsTextAlignment;
 }
 
@@ -1599,9 +1601,9 @@
         m_page->clearSelection();
 
     m_page->activityStateDidChange(WebCore::ActivityState::IsFocused);
-    
+
     m_inResignFirstResponder = false;
-    
+
     return true;
 }
 
@@ -1748,7 +1750,7 @@
         if (WebCore::AXObjectCache::accessibilityEnabled())
             accessibilityPosition = [[weakThis->m_view accessibilityAttributeValue:NSAccessibilityPositionAttribute] pointValue];
             ALLOW_DEPRECATED_DECLARATIONS_END
-        
+
         weakThis->m_page->windowAndViewFramesChanged(viewFrameInWindowCoordinates, accessibilityPosition);
     });
 }
@@ -2321,7 +2323,7 @@
 
     ColorSpaceData colorSpaceData;
     colorSpaceData.cgColorSpace = [m_colorSpace CGColorSpace];
-    
+
     return colorSpaceData;
 }
 
@@ -2568,7 +2570,7 @@
         // The input source changed; discard any entered text.
         [[WKTextInputWindowController sharedTextInputWindowController] unmarkText];
     }
-    
+
     // This will force the current input context to be updated to its correct value.
     [NSApp updateWindows];
 }
@@ -2818,18 +2820,18 @@
 {
     if (_shareSheet)
         [_shareSheet dismiss];
-    
+
     ASSERT([view respondsToSelector:@selector(shareSheetDidDismiss:)]);
     _shareSheet = adoptNS([[WKShareSheet alloc] initWithView:view]);
     [_shareSheet setDelegate:view];
-    
+
     [_shareSheet presentWithParameters:data inRect:WTF::nullopt completionHandler:WTFMove(completionHandler)];
 }
-    
+
 void WebViewImpl::shareSheetDidDismiss(WKShareSheet *shareSheet)
 {
     ASSERT(_shareSheet == shareSheet);
-    
+
     [_shareSheet setDelegate:nil];
     _shareSheet = nil;
 }
@@ -2853,11 +2855,13 @@
         if (error != CallbackBase::Error::None)
             return;
 
+        BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
         NSDictionary *attributeDictionary = (__bridge NSDictionary *)fontInfo.fontAttributeDictionary.get();
         if (!attributeDictionary)
             return;
 
-        NSFontDescriptor *descriptor = [NSFontDescriptor fontDescriptorWithFontAttributes:attributeDictionary];
+        PlatformFontDescriptor *descriptor = fontDescriptorWithFontAttributes(attributeDictionary);
         if (!descriptor)
             return;
 
@@ -2866,6 +2870,8 @@
             return;
 
         [NSFontManager.sharedFontManager setSelectedFont:font isMultiple:selectionHasMultipleFonts];
+
+        END_BLOCK_OBJC_EXCEPTIONS
     });
 }
 
@@ -3238,7 +3244,7 @@
 {
     if (static_cast<bool>(flag) == TextChecker::state().isAutomaticTextReplacementEnabled)
         return;
-    
+
     TextChecker::setAutomaticTextReplacementEnabled(flag);
     m_page->process().updateTextCheckerState();
 }
@@ -3661,14 +3667,14 @@
             return NSAccessibilityUnignoredAncestor([m_view superview]);
             if ([attribute isEqualToString:NSAccessibilityEnabledAttribute])
                 return @YES;
-    
+
     if ([attribute isEqualToString:@"AXConvertRelativeFrame"]) {
         if ([parameter isKindOfClass:[NSValue class]]) {
             NSRect rect = [(NSValue *)parameter rectValue];
             return [NSValue valueWithRect:m_pageClient->rootViewToScreen(WebCore::IntRect(rect))];
         }
     }
-    
+
     return [m_view _web_superAccessibilityAttributeValue:attribute];
 }
 
@@ -3780,7 +3786,7 @@
 {
     if (!oldToolTip.isNull())
         sendToolTipMouseExited();
-    
+
     if (!newToolTip.isEmpty()) {
         // See radar 3500217 for why we remove all tooltips rather than just the single one we created.
         [m_view removeAllToolTips];
@@ -3971,7 +3977,7 @@
     SandboxExtension::HandleArray sandboxExtensionForUpload;
 
     if (![types containsObject:PasteboardTypes::WebArchivePboardType] && [types containsObject:WebCore::legacyFilesPromisePasteboardType()]) {
-        
+
         // FIXME: legacyFilesPromisePasteboardType() contains UTIs, not path names. Also, it's not
         // guaranteed that the count of UTIs equals the count of files, since some clients only write
         // unique UTIs.
@@ -4025,9 +4031,9 @@
             delete dragData;
             return false;
         }
-        
+
         Vector<String> fileNames;
-        
+
         for (NSString *file in files)
             fileNames.append(file);
         m_page->createSandboxExtensionsIfNeeded(fileNames, sandboxExtensionHandle, sandboxExtensionForUpload);
@@ -4248,14 +4254,14 @@
     // "Fix" the filename of the path.
     NSString *filename = filenameByFixingIllegalCharacters([path lastPathComponent]);
     path = [[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:filename];
-    
+
     if (fileExists(path)) {
         // Don't overwrite existing file by appending "-n", "-n.ext" or "-n.ext.ext" to the filename.
         NSString *extensions = nil;
         NSString *pathWithoutExtensions;
         NSString *lastPathComponent = [path lastPathComponent];
         NSRange periodRange = [lastPathComponent rangeOfString:@"."];
-        
+
         if (periodRange.location == NSNotFound) {
             pathWithoutExtensions = path;
         } else {
@@ -4263,7 +4269,7 @@
             lastPathComponent = [lastPathComponent substringToIndex:periodRange.location];
             pathWithoutExtensions = [[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:lastPathComponent];
         }
-        
+
         for (unsigned i = 1; ; i++) {
             NSString *pathWithAppendedNumber = [NSString stringWithFormat:@"%@-%d", pathWithoutExtensions, i];
             path = [extensions length] ? [pathWithAppendedNumber stringByAppendingPathExtension:extensions] : pathWithAppendedNumber;
@@ -4271,7 +4277,7 @@
                 break;
         }
     }
-    
+
     return path;
 }
 
@@ -4279,20 +4285,20 @@
 {
     RetainPtr<NSFileWrapper> wrapper;
     RetainPtr<NSData> data;
-    
+
     if (m_promisedImage) {
         data = m_promisedImage->data()->createNSData();
         wrapper = adoptNS([[NSFileWrapper alloc] initRegularFileWithContents:data.get()]);
     } else
         wrapper = adoptNS([[NSFileWrapper alloc] initWithURL:[NSURL URLWithString:m_promisedURL] options:NSFileWrapperReadingImmediate error:nil]);
-    
+
     if (wrapper)
         [wrapper setPreferredFilename:m_promisedFilename];
     else {
         LOG_ERROR("Failed to create image file.");
         return nil;
     }
-    
+
     // FIXME: Report an error if we fail to create a file.
     NSString *path = [[dropDestination path] stringByAppendingPathComponent:[wrapper preferredFilename]];
     path = pathWithUniqueFilenameForPath(path);
@@ -4301,7 +4307,7 @@
 
     if (!m_promisedURL.isEmpty())
         FileSystem::setMetadataURL(String(path), m_promisedURL);
-    
+
     return [NSArray arrayWithObject:[path lastPathComponent]];
 }
 
@@ -4498,7 +4504,7 @@
     bool handledEvent = gestureController.handleScrollWheelEvent(event);
 
     gestureController.setShouldIgnorePinnedState(wasIgnoringPinnedState);
-    
+
     return handledEvent;
 }
 
@@ -4641,7 +4647,7 @@
     m_keyDownEventBeingResent = event;
     [NSApp _setCurrentEvent:event];
     [NSApp sendEvent:event];
-    
+
     m_keyDownEventBeingResent = nullptr;
 }
 
@@ -4686,7 +4692,7 @@
             }
             result.append(WebCore::CompositionUnderline(range.location, NSMaxRange(range), compositionUnderlineColor, color, style.intValue > 1));
         }
-        
+
         i = range.location + range.length;
     }
 
@@ -5106,7 +5112,7 @@
         });
         return YES;
     }
-    
+
     return [m_view _web_superPerformKeyEquivalent:event];
 }
 
@@ -5316,7 +5322,7 @@
 {
     NSRect eventScreenPosition = [[m_view window] convertRectToScreen:NSMakeRect(event.locationInWindow.x, event.locationInWindow.y, 0, 0)];
     NSInteger eventWindowNumber = [NSWindow windowNumberAtPoint:eventScreenPosition.origin belowWindowWithWindowNumber:0];
-        
+
     return [m_view window].windowNumber != eventWindowNumber;
 }
 
@@ -5356,7 +5362,7 @@
         return false;
     return m_gestureController->completeSimulatedSwipeInDirectionForTesting(ViewGestureController::SwipeDirection::Back);
 }
-    
+
 void WebViewImpl::setUseSystemAppearance(bool useSystemAppearance)
 {
     m_page->setUseSystemAppearance(useSystemAppearance);
diff --git a/Source/WebKit/UIProcess/mac/WebPopupMenuProxyMac.mm b/Source/WebKit/UIProcess/mac/WebPopupMenuProxyMac.mm
index fd65734..03b3980 100644
--- a/Source/WebKit/UIProcess/mac/WebPopupMenuProxyMac.mm
+++ b/Source/WebKit/UIProcess/mac/WebPopupMenuProxyMac.mm
@@ -28,12 +28,12 @@
 
 #if USE(APPKIT)
 
+#import "CoreTextHelpers.h"
 #import "NativeWebMouseEvent.h"
 #import "PageClientImplMac.h"
 #import "PlatformPopupMenuData.h"
 #import "StringUtilities.h"
 #import "WebPopupItem.h"
-#import <pal/spi/cocoa/CoreTextSPI.h>
 #import <pal/system/mac/PopupMenu.h>
 #import <wtf/BlockObjCExceptions.h>
 #import <wtf/ProcessPrivilege.h>
@@ -106,17 +106,7 @@
     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
     if (data.fontInfo.fontAttributeDictionary) {
-        RetainPtr<NSMutableDictionary> mutableDictionary = adoptNS([(__bridge NSDictionary *)data.fontInfo.fontAttributeDictionary.get() mutableCopy]);
-#if HAVE(NSFONT_WITH_OPTICAL_SIZING_BUG)
-        if (id opticalSizeAttribute = [mutableDictionary objectForKey:(__bridge NSString *)kCTFontOpticalSizeAttribute]) {
-            if ([opticalSizeAttribute isKindOfClass:[NSString class]]) {
-                [mutableDictionary removeObjectForKey:(__bridge NSString *)kCTFontOpticalSizeAttribute];
-                if (NSNumber *size = [mutableDictionary objectForKey:(__bridge NSString *)kCTFontSizeAttribute])
-                    [mutableDictionary setObject:size forKey:(__bridge NSString *)kCTFontOpticalSizeAttribute];
-            }
-        }
-#endif
-        NSFontDescriptor *fontDescriptor = [NSFontDescriptor fontDescriptorWithFontAttributes:mutableDictionary.get()];
+        PlatformFontDescriptor *fontDescriptor = fontDescriptorWithFontAttributes(static_cast<NSDictionary *>(data.fontInfo.fontAttributeDictionary.get()));
         font = [NSFont fontWithDescriptor:fontDescriptor size:((pageScaleFactor != 1) ? [fontDescriptor pointSize] * pageScaleFactor : 0)];
     } else
         font = [NSFont menuFontOfSize:0];
diff --git a/Source/WebKit/WebKit.xcodeproj/project.pbxproj b/Source/WebKit/WebKit.xcodeproj/project.pbxproj
index da21741..f2bb573 100644
--- a/Source/WebKit/WebKit.xcodeproj/project.pbxproj
+++ b/Source/WebKit/WebKit.xcodeproj/project.pbxproj
@@ -2474,6 +2474,8 @@
 		1C20935E22318CB000026A39 /* NSAttributedString.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSAttributedString.h; sourceTree = "<group>"; };
 		1C20935F22318CB000026A39 /* NSAttributedString.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = NSAttributedString.mm; sourceTree = "<group>"; };
 		1C2184012233872800BAC700 /* NSAttributedStringPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSAttributedStringPrivate.h; sourceTree = "<group>"; };
+		1C739E852347BCF600C621EC /* CoreTextHelpers.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CoreTextHelpers.mm; sourceTree = "<group>"; };
+		1C739E872347BD0F00C621EC /* CoreTextHelpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CoreTextHelpers.h; sourceTree = "<group>"; };
 		1C77C1951288A872006A742F /* WebInspectorProxy.messages.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebInspectorProxy.messages.in; sourceTree = "<group>"; };
 		1C891D6219B124FF00BA79DD /* WebInspectorUI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebInspectorUI.cpp; sourceTree = "<group>"; };
 		1C891D6319B124FF00BA79DD /* WebInspectorUI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebInspectorUI.h; sourceTree = "<group>"; };
@@ -6518,6 +6520,8 @@
 				1A698F171E4910220064E881 /* AuxiliaryProcessCocoa.mm */,
 				37BEC4DF19491486008B4286 /* CompletionHandlerCallChecker.h */,
 				37BEC4DE19491486008B4286 /* CompletionHandlerCallChecker.mm */,
+				1C739E872347BD0F00C621EC /* CoreTextHelpers.h */,
+				1C739E852347BCF600C621EC /* CoreTextHelpers.mm */,
 				C55F916C1C595E440029E92D /* DataDetectionResult.h */,
 				C55F916D1C595E440029E92D /* DataDetectionResult.mm */,
 				CE550E132283744400D28791 /* InsertTextOptions.cpp */,