Title: [271920] trunk
Revision
271920
Author
[email protected]
Date
2021-01-26 16:31:23 -0800 (Tue, 26 Jan 2021)

Log Message

Expose the value of `<meta name="theme-color" content="...">` as SPI
https://bugs.webkit.org/show_bug.cgi?id=220944
<rdar://problem/72198083>

Reviewed by Tim Horton.

Source/WebCore:

* html/HTMLMetaElement.h:
* html/HTMLMetaElement.cpp:
(WebCore::HTMLMetaElement::attributeChanged): Added.
(WebCore::HTMLMetaElement::parseAttribute):
(WebCore::HTMLMetaElement::removedFromAncestor): Added.
(WebCore::HTMLMetaElement::process):

* dom/Document.h:
(WebCore::Document::themeColor const): Added.
* dom/Document.cpp:
(WebCore::Document::processThemeColor): Added.
* page/Page.h:
* page/Page.cpp:
(WebCore::Page::themeColor const): Added.
* page/ChromeClient.h:
(WebCore::ChromeClient::themeColorChanged const): Added.
Save the `Color` to a variable so it can be accessed later during rendering so that updates
are kept in sync with other changes (e.g. modifying the CSS `background-color`).

* platform/graphics/cocoa/ColorCocoa.h:
* WebCore.xcodeproj/project.pbxproj:
Expose this file and export its functions so they can be used in WebKit.

Source/WebKit:

* WebProcess/WebPage/WebPage.h:
(WebKit::WebPage::themeColorChanged): Added.
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::willCommitLayerTree):
(WebKit::WebPage::didCommitLoad):
(WebKit::WebPage::flushPendingThemeColorChange): Added.
* WebProcess/WebCoreSupport/WebChromeClient.h:
* WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::themeColorChanged const):
* WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:
(WebKit::TiledCoreAnimationDrawingArea::updateRendering):
* UIProcess/WebPageProxy.messages.in:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::themeColorChanged): Added.
On macOS, keep a flag indicating whether the `themeColor` has changed. Use this flag when
updating rendering to send the `Color` to the UIProcess so that it's kept in sync with other
changes (e.g. modifying the CSS `background-color`).

* Shared/RemoteLayerTree/RemoteLayerTreeTransaction.h:
(WebKit::RemoteLayerTreeTransaction::themeColor const): Added.
(WebKit::RemoteLayerTreeTransaction::setThemeColor): Added.
* Shared/RemoteLayerTree/RemoteLayerTreeTransaction.mm:
(WebKit::RemoteLayerTreeTransaction::encode const):
(WebKit::RemoteLayerTreeTransaction::decode):
* UIProcess/ios/WebPageProxyIOS.mm:
(WebKit::WebPageProxy::didCommitLayerTree):
On iOS, include the `themeColor` in every `RemoteLayerTreeTransaction` so that it's kept in
sync with other changes (e.g. modifying the CSS `background-color`).

* UIProcess/PageClient.h:
(WebKit::PageClient::themeColorWillChange): Added.
(WebKit::PageClient::themeColorDidChange): Added.
* UIProcess/Cocoa/PageClientImplCocoa.h:
* UIProcess/Cocoa/PageClientImplCocoa.mm:
(WebKit::PageClientImplCocoa::themeColorWillChange): Added.
(WebKit::PageClientImplCocoa::themeColorDidChange): Added.
Add support for ObjC KVO of `-[WKWebView _themeColor]`.

* UIProcess/WebPageProxy.h:
(WebKit::WebPageProxy::themeColor const): Added.
* UIProcess/API/Cocoa/WKWebViewPrivate.h:
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _themeColor]): Added.

Tools:

* TestWebKitAPI/Tests/WebKitCocoa/HTMLMetaThemeColor.mm: Added.
(TEST.HTMLMetaThemeColor.OnLoad):
(TEST.HTMLMetaThemeColor.MultipleTags):
(-[WKWebViewThemeColorObserver initWithWebView:]):
(-[WKWebViewThemeColorObserver observeValueForKeyPath:ofObject:change:context:]):
(TEST.HTMLMetaThemeColor.KVO):

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (271919 => 271920)


--- trunk/Source/WebCore/ChangeLog	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebCore/ChangeLog	2021-01-27 00:31:23 UTC (rev 271920)
@@ -1,3 +1,34 @@
+2021-01-26  Devin Rousso  <[email protected]>
+
+        Expose the value of `<meta name="theme-color" content="...">` as SPI
+        https://bugs.webkit.org/show_bug.cgi?id=220944
+        <rdar://problem/72198083>
+
+        Reviewed by Tim Horton.
+
+        * html/HTMLMetaElement.h:
+        * html/HTMLMetaElement.cpp:
+        (WebCore::HTMLMetaElement::attributeChanged): Added.
+        (WebCore::HTMLMetaElement::parseAttribute):
+        (WebCore::HTMLMetaElement::removedFromAncestor): Added.
+        (WebCore::HTMLMetaElement::process):
+
+        * dom/Document.h:
+        (WebCore::Document::themeColor const): Added.
+        * dom/Document.cpp:
+        (WebCore::Document::processThemeColor): Added.
+        * page/Page.h:
+        * page/Page.cpp:
+        (WebCore::Page::themeColor const): Added.
+        * page/ChromeClient.h:
+        (WebCore::ChromeClient::themeColorChanged const): Added.
+        Save the `Color` to a variable so it can be accessed later during rendering so that updates
+        are kept in sync with other changes (e.g. modifying the CSS `background-color`).
+
+        * platform/graphics/cocoa/ColorCocoa.h:
+        * WebCore.xcodeproj/project.pbxproj:
+        Expose this file and export its functions so they can be used in WebKit.
+
 2021-01-26  Simon Fraser  <[email protected]>
 
         Make showRenderTree() dump FloatingObjects

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (271919 => 271920)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-01-27 00:31:23 UTC (rev 271920)
@@ -5271,7 +5271,7 @@
 		F48223131E386E240066FC79 /* AbstractPasteboard.h in Headers */ = {isa = PBXBuildFile; fileRef = F48223121E386E240066FC79 /* AbstractPasteboard.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F48D2A6C215623B400C6752B /* FontShadow.h in Headers */ = {isa = PBXBuildFile; fileRef = F48D2A6A215623B400C6752B /* FontShadow.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F48D2A7E2157182600C6752B /* FontAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = F48D2A712156DC0A00C6752B /* FontAttributes.h */; settings = {ATTRIBUTES = (Private, ); }; };
-		F48D2AA52159740D00C6752B /* ColorCocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = F48D2AA32159740D00C6752B /* ColorCocoa.h */; };
+		F48D2AA52159740D00C6752B /* ColorCocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = F48D2AA32159740D00C6752B /* ColorCocoa.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F49786881FF45FA500E060AB /* PasteboardItemInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = F49786871FF45FA500E060AB /* PasteboardItemInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F4B422C4220C0568009E1E7D /* DOMPasteAccess.h in Headers */ = {isa = PBXBuildFile; fileRef = F4B422C2220C0000009E1E7D /* DOMPasteAccess.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F4BFB9851E1DDF9B00862C24 /* DumpEditingHistory.js in Copy Scripts */ = {isa = PBXBuildFile; fileRef = F48389831E1DDF2B0076B7EA /* DumpEditingHistory.js */; };

Modified: trunk/Source/WebCore/dom/Document.cpp (271919 => 271920)


--- trunk/Source/WebCore/dom/Document.cpp	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebCore/dom/Document.cpp	2021-01-27 00:31:23 UTC (rev 271920)
@@ -33,6 +33,7 @@
 #include "BeforeUnloadEvent.h"
 #include "CDATASection.h"
 #include "CSSFontSelector.h"
+#include "CSSParser.h"
 #include "CSSStyleDeclaration.h"
 #include "CSSStyleSheet.h"
 #include "CachedCSSStyleSheet.h"
@@ -3797,6 +3798,20 @@
     }
 }
 
+void Document::processThemeColor(const String& themeColorString)
+{
+    auto themeColor = CSSParser::parseColor(themeColorString);
+    if (themeColor == m_themeColor)
+        return;
+
+    m_themeColor = WTFMove(themeColor);
+
+    scheduleRenderingUpdate({ });
+
+    if (auto* page = this->page())
+        page->chrome().client().themeColorChanged(m_themeColor);
+}
+
 #if ENABLE(DARK_MODE_CSS)
 static void processColorSchemeString(StringView colorScheme, const WTF::Function<void(StringView key)>& callback)
 {

Modified: trunk/Source/WebCore/dom/Document.h (271919 => 271920)


--- trunk/Source/WebCore/dom/Document.h	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebCore/dom/Document.h	2021-01-27 00:31:23 UTC (rev 271920)
@@ -739,6 +739,9 @@
 #if !LOG_DISABLED
     Seconds timeSinceDocumentCreation() const { return MonotonicTime::now() - m_documentCreationTime; };
 #endif
+
+    const Color& themeColor() const { return m_themeColor; }
+
     void setTextColor(const Color& color) { m_textColor = color; }
     const Color& textColor() const { return m_textColor; }
 
@@ -908,6 +911,7 @@
     void processDisabledAdaptations(const String& adaptations);
     void updateViewportArguments();
     void processReferrerPolicy(const String& policy, ReferrerPolicySource);
+    void processThemeColor(const String& themeColor);
 
 #if ENABLE(DARK_MODE_CSS)
     void processColorScheme(const String& colorScheme);
@@ -1776,6 +1780,7 @@
 
     std::unique_ptr<FormController> m_formController;
 
+    Color m_themeColor;
     Color m_textColor { Color::black };
     Color m_linkColor;
     Color m_visitedLinkColor;

Modified: trunk/Source/WebCore/html/HTMLMetaElement.cpp (271919 => 271920)


--- trunk/Source/WebCore/html/HTMLMetaElement.cpp	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebCore/html/HTMLMetaElement.cpp	2021-01-27 00:31:23 UTC (rev 271920)
@@ -52,6 +52,14 @@
     return adoptRef(*new HTMLMetaElement(tagName, document));
 }
 
+void HTMLMetaElement::attributeChanged(const QualifiedName& name, const AtomString& oldValue, const AtomString& newValue, AttributeModificationReason reason)
+{
+    HTMLElement::attributeChanged(name, oldValue, newValue, reason);
+
+    if (name == nameAttr && equalLettersIgnoringASCIICase(oldValue, "theme-color") && !equalLettersIgnoringASCIICase(newValue, "theme-color"))
+        document().processThemeColor(emptyString());
+}
+
 void HTMLMetaElement::parseAttribute(const QualifiedName& name, const AtomString& value)
 {
     if (name == http_equivAttr)
@@ -58,9 +66,9 @@
         process();
     else if (name == contentAttr)
         process();
-    else if (name == nameAttr) {
-        // Do nothing
-    } else
+    else if (name == nameAttr)
+        process();
+    else
         HTMLElement::parseAttribute(name, value);
 }
 
@@ -77,6 +85,14 @@
     process();
 }
 
+void HTMLMetaElement::removedFromAncestor(RemovalType removalType, ContainerNode& oldParentOfRemovedTree)
+{
+    HTMLElement::removedFromAncestor(removalType, oldParentOfRemovedTree);
+
+    if (!isConnected() && equalLettersIgnoringASCIICase(name(), "theme-color"))
+        oldParentOfRemovedTree.document().processThemeColor(emptyString());
+}
+
 void HTMLMetaElement::process()
 {
     // Changing a meta tag while it's not in the tree shouldn't have any effect on the document.
@@ -95,6 +111,8 @@
     else if (equalLettersIgnoringASCIICase(name(), "color-scheme") || equalLettersIgnoringASCIICase(name(), "supported-color-schemes"))
         document().processColorScheme(contentValue);
 #endif
+    else if (equalLettersIgnoringASCIICase(name(), "theme-color"))
+        document().processThemeColor(contentValue);
 #if PLATFORM(IOS_FAMILY)
     else if (equalLettersIgnoringASCIICase(name(), "format-detection"))
         document().processFormatDetection(contentValue);

Modified: trunk/Source/WebCore/html/HTMLMetaElement.h (271919 => 271920)


--- trunk/Source/WebCore/html/HTMLMetaElement.h	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebCore/html/HTMLMetaElement.h	2021-01-27 00:31:23 UTC (rev 271920)
@@ -39,9 +39,11 @@
 private:
     HTMLMetaElement(const QualifiedName&, Document&);
 
+    void attributeChanged(const QualifiedName&, const AtomString& oldValue, const AtomString& newValue, AttributeModificationReason = ModifiedDirectly) final;
     void parseAttribute(const QualifiedName&, const AtomString&) final;
     InsertedIntoAncestorResult insertedIntoAncestor(InsertionType, ContainerNode&) final;
     void didFinishInsertingNode();
+    void removedFromAncestor(RemovalType, ContainerNode&) final;
 
     void process();
 };

Modified: trunk/Source/WebCore/page/ChromeClient.h (271919 => 271920)


--- trunk/Source/WebCore/page/ChromeClient.h	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebCore/page/ChromeClient.h	2021-01-27 00:31:23 UTC (rev 271920)
@@ -226,6 +226,7 @@
 
     virtual Color underlayColor() const { return Color(); }
 
+    virtual void themeColorChanged(Color) const { }
     virtual void pageExtendedBackgroundColorDidChange(Color) const { }
 
     virtual void exceededDatabaseQuota(Frame&, const String& databaseName, DatabaseDetails) = 0;

Modified: trunk/Source/WebCore/page/Page.cpp (271919 => 271920)


--- trunk/Source/WebCore/page/Page.cpp	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebCore/page/Page.cpp	2021-01-27 00:31:23 UTC (rev 271920)
@@ -2430,6 +2430,15 @@
     m_requestedLayoutMilestones.remove(milestones);
 }
 
+Color Page::themeColor() const
+{
+    auto* document = mainFrame().document();
+    if (!document)
+        return { };
+
+    return document->themeColor();
+}
+
 Color Page::pageExtendedBackgroundColor() const
 {
     FrameView* frameView = mainFrame().view();

Modified: trunk/Source/WebCore/page/Page.h (271919 => 271920)


--- trunk/Source/WebCore/page/Page.h	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebCore/page/Page.h	2021-01-27 00:31:23 UTC (rev 271920)
@@ -610,6 +610,7 @@
     int headerHeight() const { return m_headerHeight; }
     int footerHeight() const { return m_footerHeight; }
 
+    WEBCORE_EXPORT Color themeColor() const;
     WEBCORE_EXPORT Color pageExtendedBackgroundColor() const;
 
     bool isCountingRelevantRepaintedObjects() const;

Modified: trunk/Source/WebCore/platform/graphics/cocoa/ColorCocoa.h (271919 => 271920)


--- trunk/Source/WebCore/platform/graphics/cocoa/ColorCocoa.h	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebCore/platform/graphics/cocoa/ColorCocoa.h	2021-01-27 00:31:23 UTC (rev 271920)
@@ -33,11 +33,11 @@
 class Color;
 
 #if USE(APPKIT)
-NSColor *platformColor(const Color&);
+WEBCORE_EXPORT NSColor *platformColor(const Color&);
 #endif
 
 #if PLATFORM(IOS_FAMILY)
-UIColor *platformColor(const Color&);
+WEBCORE_EXPORT UIColor *platformColor(const Color&);
 #endif
 
 } // namespace WebCore

Modified: trunk/Source/WebKit/ChangeLog (271919 => 271920)


--- trunk/Source/WebKit/ChangeLog	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebKit/ChangeLog	2021-01-27 00:31:23 UTC (rev 271920)
@@ -1,3 +1,55 @@
+2021-01-26  Devin Rousso  <[email protected]>
+
+        Expose the value of `<meta name="theme-color" content="...">` as SPI
+        https://bugs.webkit.org/show_bug.cgi?id=220944
+        <rdar://problem/72198083>
+
+        Reviewed by Tim Horton.
+
+        * WebProcess/WebPage/WebPage.h:
+        (WebKit::WebPage::themeColorChanged): Added.
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::willCommitLayerTree):
+        (WebKit::WebPage::didCommitLoad):
+        (WebKit::WebPage::flushPendingThemeColorChange): Added.
+        * WebProcess/WebCoreSupport/WebChromeClient.h:
+        * WebProcess/WebCoreSupport/WebChromeClient.cpp:
+        (WebKit::WebChromeClient::themeColorChanged const):
+        * WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:
+        (WebKit::TiledCoreAnimationDrawingArea::updateRendering):
+        * UIProcess/WebPageProxy.messages.in:
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::themeColorChanged): Added.
+        On macOS, keep a flag indicating whether the `themeColor` has changed. Use this flag when
+        updating rendering to send the `Color` to the UIProcess so that it's kept in sync with other
+        changes (e.g. modifying the CSS `background-color`).
+
+        * Shared/RemoteLayerTree/RemoteLayerTreeTransaction.h:
+        (WebKit::RemoteLayerTreeTransaction::themeColor const): Added.
+        (WebKit::RemoteLayerTreeTransaction::setThemeColor): Added.
+        * Shared/RemoteLayerTree/RemoteLayerTreeTransaction.mm:
+        (WebKit::RemoteLayerTreeTransaction::encode const):
+        (WebKit::RemoteLayerTreeTransaction::decode):
+        * UIProcess/ios/WebPageProxyIOS.mm:
+        (WebKit::WebPageProxy::didCommitLayerTree):
+        On iOS, include the `themeColor` in every `RemoteLayerTreeTransaction` so that it's kept in
+        sync with other changes (e.g. modifying the CSS `background-color`).
+
+        * UIProcess/PageClient.h:
+        (WebKit::PageClient::themeColorWillChange): Added.
+        (WebKit::PageClient::themeColorDidChange): Added.
+        * UIProcess/Cocoa/PageClientImplCocoa.h:
+        * UIProcess/Cocoa/PageClientImplCocoa.mm:
+        (WebKit::PageClientImplCocoa::themeColorWillChange): Added.
+        (WebKit::PageClientImplCocoa::themeColorDidChange): Added.
+        Add support for ObjC KVO of `-[WKWebView _themeColor]`.
+
+        * UIProcess/WebPageProxy.h:
+        (WebKit::WebPageProxy::themeColor const): Added.
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _themeColor]): Added.
+
 2021-01-26  Brent Fulgham  <[email protected]>
 
         IPC::Decoder constructor should mark the Decoder as invalid if header decoding fails 

Modified: trunk/Source/WebKit/Shared/RemoteLayerTree/RemoteLayerTreeTransaction.h (271919 => 271920)


--- trunk/Source/WebKit/Shared/RemoteLayerTree/RemoteLayerTreeTransaction.h	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebKit/Shared/RemoteLayerTree/RemoteLayerTreeTransaction.h	2021-01-27 00:31:23 UTC (rev 271920)
@@ -226,7 +226,10 @@
     
     WebCore::LayoutPoint maxStableLayoutViewportOrigin() const { return m_maxStableLayoutViewportOrigin; }
     void setMaxStableLayoutViewportOrigin(const WebCore::LayoutPoint& point) { m_maxStableLayoutViewportOrigin = point; };
-    
+
+    WebCore::Color themeColor() const { return m_themeColor; }
+    void setThemeColor(WebCore::Color color) { m_themeColor = color; }
+
     WebCore::Color pageExtendedBackgroundColor() const { return m_pageExtendedBackgroundColor; }
     void setPageExtendedBackgroundColor(WebCore::Color color) { m_pageExtendedBackgroundColor = color; }
 
@@ -307,6 +310,7 @@
     WebCore::LayoutPoint m_minStableLayoutViewportOrigin;
     WebCore::LayoutPoint m_maxStableLayoutViewportOrigin;
     WebCore::IntPoint m_scrollPosition;
+    WebCore::Color m_themeColor;
     WebCore::Color m_pageExtendedBackgroundColor;
     double m_pageScaleFactor { 1 };
     double m_minimumScaleFactor { 1 };

Modified: trunk/Source/WebKit/Shared/RemoteLayerTree/RemoteLayerTreeTransaction.mm (271919 => 271920)


--- trunk/Source/WebKit/Shared/RemoteLayerTree/RemoteLayerTreeTransaction.mm	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebKit/Shared/RemoteLayerTree/RemoteLayerTreeTransaction.mm	2021-01-27 00:31:23 UTC (rev 271920)
@@ -564,6 +564,7 @@
 
     encoder << m_scrollPosition;
 
+    encoder << m_themeColor;
     encoder << m_pageExtendedBackgroundColor;
     encoder << m_pageScaleFactor;
     encoder << m_minimumScaleFactor;
@@ -658,7 +659,10 @@
 
     if (!decoder.decode(result.m_scrollPosition))
         return false;
-    
+
+    if (!decoder.decode(result.m_themeColor))
+        return false;
+
     if (!decoder.decode(result.m_pageExtendedBackgroundColor))
         return false;
 

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm (271919 => 271920)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2021-01-27 00:31:23 UTC (rev 271920)
@@ -30,6 +30,7 @@
 #import "APIFrameTreeNode.h"
 #import "APIPageConfiguration.h"
 #import "APISerializedScriptValue.h"
+#import "CocoaColor.h"
 #import "CocoaImage.h"
 #import "CompletionHandlerCallChecker.h"
 #import "ContentAsStringIncludesChildFrames.h"
@@ -117,6 +118,7 @@
 #import "_WKVisitedLinkStoreInternal.h"
 #import "_WKWebsitePoliciesInternal.h"
 #import <WebCore/AttributedString.h>
+#import <WebCore/ColorCocoa.h>
 #import <WebCore/ColorSerialization.h>
 #import <WebCore/ElementContext.h>
 #import <WebCore/JSDOMBinding.h>
@@ -2786,6 +2788,14 @@
     _page->setCanUseCredentialStorage(canUseCredentialStorage);
 }
 
+- (CocoaColor *)_themeColor
+{
+    auto themeColor = _page->themeColor();
+    if (!themeColor.isValid())
+        return nil;
+    return WebCore::platformColor(themeColor);
+}
+
 - (id <_WKInputDelegate>)_inputDelegate
 {
     return _inputDelegate.getAutoreleased();

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h (271919 => 271920)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h	2021-01-27 00:31:23 UTC (rev 271920)
@@ -362,6 +362,21 @@
 - (void)_didEnableBrowserExtensions:(NSDictionary<NSString *, NSString *> *)extensionIDToNameMap WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 - (void)_didDisableBrowserExtensions:(NSSet<NSString *> *)extensionIDs WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 
+/*! @abstract The theme color of the active page.
+ @discussion This is the value of the most recently created or modified
+ @textblock
+    <meta name="theme-color" contents="...">
+ @/textblock
+ in the current page.
+ @link WKWebView @/link is key-value observing (KVO) compliant for this
+ property.
+ */
+#if TARGET_OS_IPHONE
+@property (nonatomic, readonly) UIColor *_themeColor WK_API_AVAILABLE(ios(WK_IOS_TBA));
+#else
+@property (nonatomic, readonly) NSColor *_themeColor WK_API_AVAILABLE(macos(WK_MAC_TBA));
+#endif
+
 @end
 
 #if TARGET_OS_IPHONE

Modified: trunk/Source/WebKit/UIProcess/Cocoa/PageClientImplCocoa.h (271919 => 271920)


--- trunk/Source/WebKit/UIProcess/Cocoa/PageClientImplCocoa.h	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebKit/UIProcess/Cocoa/PageClientImplCocoa.h	2021-01-27 00:31:23 UTC (rev 271920)
@@ -49,6 +49,8 @@
 
     void pageClosed() override;
 
+    void themeColorWillChange() final;
+    void themeColorDidChange() final;
     void isPlayingAudioWillChange() final;
     void isPlayingAudioDidChange() final;
 

Modified: trunk/Source/WebKit/UIProcess/Cocoa/PageClientImplCocoa.mm (271919 => 271920)


--- trunk/Source/WebKit/UIProcess/Cocoa/PageClientImplCocoa.mm	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebKit/UIProcess/Cocoa/PageClientImplCocoa.mm	2021-01-27 00:31:23 UTC (rev 271920)
@@ -44,6 +44,16 @@
 
 PageClientImplCocoa::~PageClientImplCocoa() = default;
 
+void PageClientImplCocoa::themeColorWillChange()
+{
+    [m_webView willChangeValueForKey:@"_themeColor"];
+}
+
+void PageClientImplCocoa::themeColorDidChange()
+{
+    [m_webView didChangeValueForKey:@"_themeColor"];
+}
+
 void PageClientImplCocoa::isPlayingAudioWillChange()
 {
     [m_webView willChangeValueForKey:NSStringFromSelector(@selector(_isPlayingAudio))];

Modified: trunk/Source/WebKit/UIProcess/PageClient.h (271919 => 271920)


--- trunk/Source/WebKit/UIProcess/PageClient.h	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebKit/UIProcess/PageClient.h	2021-01-27 00:31:23 UTC (rev 271920)
@@ -492,6 +492,8 @@
     virtual void didFailNavigation(API::Navigation*) = 0;
     virtual void didSameDocumentNavigationForMainFrame(SameDocumentNavigationType) = 0;
 
+    virtual void themeColorWillChange() { }
+    virtual void themeColorDidChange() { }
     virtual void didChangeBackgroundColor() = 0;
     virtual void isPlayingAudioWillChange() = 0;
     virtual void isPlayingAudioDidChange() = 0;

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (271919 => 271920)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2021-01-27 00:31:23 UTC (rev 271920)
@@ -8417,6 +8417,16 @@
     m_pageCount = pageCount;
 }
 
+void WebPageProxy::themeColorChanged(const Color& themeColor)
+{
+    if (m_themeColor == themeColor)
+        return;
+
+    pageClient().themeColorWillChange();
+    m_themeColor = themeColor;
+    pageClient().themeColorDidChange();
+}
+
 void WebPageProxy::pageExtendedBackgroundColorDidChange(const Color& backgroundColor)
 {
     m_pageExtendedBackgroundColor = backgroundColor;

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (271919 => 271920)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.h	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h	2021-01-27 00:31:23 UTC (rev 271920)
@@ -629,6 +629,9 @@
     float topContentInset() const { return m_topContentInset; }
     void setTopContentInset(float);
 
+    // Corresponds to the web content's `<meta name="theme-color" content="...">`.
+    WebCore::Color themeColor() const { return m_themeColor; }
+
     WebCore::Color underlayColor() const { return m_underlayColor; }
     void setUnderlayColor(const WebCore::Color&);
 
@@ -1996,6 +1999,7 @@
     void didChangeScrollbarsForMainFrame(bool hasHorizontalScrollbar, bool hasVerticalScrollbar);
     void didChangeScrollOffsetPinningForMainFrame(bool pinnedToLeftSide, bool pinnedToRightSide, bool pinnedToTopSide, bool pinnedToBottomSide);
     void didChangePageCount(unsigned);
+    void themeColorChanged(const WebCore::Color&);
     void pageExtendedBackgroundColorDidChange(const WebCore::Color&);
 #if ENABLE(NETSCAPE_PLUGIN_API)
     void didFailToInitializePlugin(const String& mimeType, const String& frameURLString, const String& pageURLString);
@@ -2541,6 +2545,7 @@
 
     LayerHostingMode m_layerHostingMode { LayerHostingMode::InProcess };
 
+    WebCore::Color m_themeColor;
     WebCore::Color m_underlayColor;
     WebCore::Color m_pageExtendedBackgroundColor;
 

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in (271919 => 271920)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in	2021-01-27 00:31:23 UTC (rev 271920)
@@ -77,6 +77,7 @@
     DidChangeScrollbarsForMainFrame(bool hasHorizontalScrollbar, bool hasVerticalScrollbar)
     DidChangeScrollOffsetPinningForMainFrame(bool pinnedToLeftSide, bool pinnedToRightSide, bool pinnedToTopSide, bool pinnedToBottomSide)
     DidChangePageCount(unsigned pageCount)
+    ThemeColorChanged(WebCore::Color themeColor)
     PageExtendedBackgroundColorDidChange(WebCore::Color backgroundColor)
 #if ENABLE(NETSCAPE_PLUGIN_API)
     DidFailToInitializePlugin(String mimeType, String frameURLString, String pageURLString)

Modified: trunk/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm (271919 => 271920)


--- trunk/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm	2021-01-27 00:31:23 UTC (rev 271920)
@@ -335,6 +335,7 @@
 
 void WebPageProxy::didCommitLayerTree(const WebKit::RemoteLayerTreeTransaction& layerTreeTransaction)
 {
+    themeColorChanged(layerTreeTransaction.themeColor());
     m_pageExtendedBackgroundColor = layerTreeTransaction.pageExtendedBackgroundColor();
 
     if (!m_hasReceivedLayerTreeTransactionAfterDidCommitLoad) {

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp (271919 => 271920)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp	2021-01-27 00:31:23 UTC (rev 271920)
@@ -1139,6 +1139,11 @@
     return m_page.underlayColor();
 }
 
+void WebChromeClient::themeColorChanged(Color /* themeColor */) const
+{
+    m_page.themeColorChanged();
+}
+
 void WebChromeClient::pageExtendedBackgroundColorDidChange(Color backgroundColor) const
 {
 #if PLATFORM(MAC)

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h (271919 => 271920)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h	2021-01-27 00:31:23 UTC (rev 271920)
@@ -328,6 +328,7 @@
 
     WebCore::Color underlayColor() const final;
 
+    void themeColorChanged(WebCore::Color) const final;
     void pageExtendedBackgroundColorDidChange(WebCore::Color) const final;
     
     void wheelEventHandlersChanged(bool) final;

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (271919 => 271920)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2021-01-27 00:31:23 UTC (rev 271920)
@@ -3908,6 +3908,7 @@
     layerTransaction.setScrollOrigin(frameView->scrollOrigin());
     layerTransaction.setPageScaleFactor(corePage()->pageScaleFactor());
     layerTransaction.setRenderTreeSize(corePage()->renderTreeSize());
+    layerTransaction.setThemeColor(corePage()->themeColor());
     layerTransaction.setPageExtendedBackgroundColor(corePage()->pageExtendedBackgroundColor());
 
     layerTransaction.setBaseLayoutViewportSize(frameView->baseLayoutViewportSize());
@@ -3937,6 +3938,8 @@
 
     layerTransaction.setScrollPosition(frameView->scrollPosition());
 
+    m_pendingThemeColorChange = false;
+
     if (m_hasPendingEditorStateUpdate) {
         layerTransaction.setEditorState(editorState());
         m_hasPendingEditorStateUpdate = false;
@@ -6127,6 +6130,8 @@
     m_loadCommitTime = WallTime::now();
 #endif
 
+    themeColorChanged();
+
     WebProcess::singleton().updateActivePages(m_processDisplayName);
 
     updateMainFrameScrollOffsetPinning();
@@ -6264,6 +6269,16 @@
 }
 #endif
 
+void WebPage::flushPendingThemeColorChange()
+{
+    if (!m_pendingThemeColorChange)
+        return;
+
+    m_pendingThemeColorChange = false;
+
+    send(Messages::WebPageProxy::ThemeColorChanged(m_page->themeColor()));
+}
+
 void WebPage::flushPendingEditorStateUpdate()
 {
     if (!m_hasPendingEditorStateUpdate)

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.h (271919 => 271920)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2021-01-27 00:31:23 UTC (rev 271920)
@@ -1215,6 +1215,9 @@
 
     static PluginView* pluginViewForFrame(WebCore::Frame*);
 
+    void themeColorChanged() { m_pendingThemeColorChange = true; }
+    void flushPendingThemeColorChange();
+
     void flushPendingEditorStateUpdate();
 
 #if ENABLE(RESOURCE_LOAD_STATISTICS)
@@ -2031,6 +2034,7 @@
     RefPtr<WebCore::Element> m_focusedElement;
     RefPtr<WebCore::Element> m_recentlyBlurredElement;
     bool m_hasPendingInputContextUpdateAfterBlurringAndRefocusingElement { false };
+    bool m_pendingThemeColorChange { false };
     bool m_hasPendingEditorStateUpdate { false };
 
 #if ENABLE(IOS_TOUCH_EVENTS)

Modified: trunk/Source/WebKit/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm (271919 => 271920)


--- trunk/Source/WebKit/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Source/WebKit/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm	2021-01-27 00:31:23 UTC (rev 271920)
@@ -446,6 +446,7 @@
         scaleViewToFitDocumentIfNeeded();
 
         m_webPage.updateRendering();
+        m_webPage.flushPendingThemeColorChange();
         m_webPage.flushPendingEditorStateUpdate();
         m_webPage.flushPendingIntrinsicContentSizeUpdate();
 

Modified: trunk/Tools/ChangeLog (271919 => 271920)


--- trunk/Tools/ChangeLog	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Tools/ChangeLog	2021-01-27 00:31:23 UTC (rev 271920)
@@ -1,3 +1,20 @@
+2021-01-26  Devin Rousso  <[email protected]>
+
+        Expose the value of `<meta name="theme-color" content="...">` as SPI
+        https://bugs.webkit.org/show_bug.cgi?id=220944
+        <rdar://problem/72198083>
+
+        Reviewed by Tim Horton.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/HTMLMetaThemeColor.mm: Added.
+        (TEST.HTMLMetaThemeColor.OnLoad):
+        (TEST.HTMLMetaThemeColor.MultipleTags):
+        (-[WKWebViewThemeColorObserver initWithWebView:]):
+        (-[WKWebViewThemeColorObserver observeValueForKeyPath:ofObject:change:context:]):
+        (TEST.HTMLMetaThemeColor.KVO):
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+
 2021-01-26  Lauro Moura  <[email protected]>
 
         [GLIB] API tests fail to report harness failures

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (271919 => 271920)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2021-01-27 00:11:09 UTC (rev 271919)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2021-01-27 00:31:23 UTC (rev 271920)
@@ -843,6 +843,7 @@
 		93F56DA91E5F919D003EDE84 /* WKWebViewSnapshot.mm in Sources */ = {isa = PBXBuildFile; fileRef = 93F56DA81E5F9181003EDE84 /* WKWebViewSnapshot.mm */; };
 		93F7E86F14DC8E5C00C84A99 /* NewFirstVisuallyNonEmptyLayoutFrames_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93F7E86E14DC8E5B00C84A99 /* NewFirstVisuallyNonEmptyLayoutFrames_Bundle.cpp */; };
 		950E4CC1252E75240071659F /* iOSStylusSupport.mm in Sources */ = {isa = PBXBuildFile; fileRef = 950E4CC0252E75230071659F /* iOSStylusSupport.mm */; };
+		95A524952581A10D00461FE9 /* HTMLMetaThemeColor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 95A524942581A10D00461FE9 /* HTMLMetaThemeColor.mm */; };
 		95B6B3B7251EBF2F00FC4382 /* MediaDocument.mm in Sources */ = {isa = PBXBuildFile; fileRef = 95B6B3B6251EBF2F00FC4382 /* MediaDocument.mm */; };
 		9984FACC1CFFAF60008D198C /* WKWebViewTextInput.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9984FACA1CFFAEEE008D198C /* WKWebViewTextInput.mm */; };
 		9984FACE1CFFB090008D198C /* editable-body.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9984FACD1CFFB038008D198C /* editable-body.html */; };
@@ -2484,6 +2485,7 @@
 		93F7E86B14DC8E4D00C84A99 /* NewFirstVisuallyNonEmptyLayoutFrames.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NewFirstVisuallyNonEmptyLayoutFrames.cpp; sourceTree = "<group>"; };
 		93F7E86E14DC8E5B00C84A99 /* NewFirstVisuallyNonEmptyLayoutFrames_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NewFirstVisuallyNonEmptyLayoutFrames_Bundle.cpp; sourceTree = "<group>"; };
 		950E4CC0252E75230071659F /* iOSStylusSupport.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = iOSStylusSupport.mm; sourceTree = "<group>"; };
+		95A524942581A10D00461FE9 /* HTMLMetaThemeColor.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = HTMLMetaThemeColor.mm; sourceTree = "<group>"; };
 		95B6B3B6251EBF2F00FC4382 /* MediaDocument.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MediaDocument.mm; sourceTree = "<group>"; };
 		9984FACA1CFFAEEE008D198C /* WKWebViewTextInput.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKWebViewTextInput.mm; sourceTree = "<group>"; };
 		9984FACD1CFFB038008D198C /* editable-body.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "editable-body.html"; sourceTree = "<group>"; };
@@ -3316,6 +3318,7 @@
 				07E1F6A01FFC3A080096C7EC /* GetDisplayMedia.mm */,
 				2DADF26221CB8F32003D3E3A /* GetResourceData.mm */,
 				465E2806255B2A690063A787 /* GPUProcess.mm */,
+				95A524942581A10D00461FE9 /* HTMLMetaThemeColor.mm */,
 				51AF23DE1EF1A3720072F281 /* IconLoadingDelegate.mm */,
 				EB230D3E245E726300C66AD1 /* IDBCheckpointWAL.mm */,
 				510477751D298E03009747EB /* IDBDeleteRecovery.mm */,
@@ -5300,6 +5303,7 @@
 				7CCE7EFA1A411AE600447C4C /* HitTestResultNodeHandle.cpp in Sources */,
 				7CCE7EC11A411A7E00447C4C /* HTMLCollectionNamedItem.mm in Sources */,
 				7CCE7EC21A411A7E00447C4C /* HTMLFormCollectionNamedItem.mm in Sources */,
+				95A524952581A10D00461FE9 /* HTMLMetaThemeColor.mm in Sources */,
 				7C83E0501D0A641800FEBCF3 /* HTMLParserIdioms.cpp in Sources */,
 				5CA1DEC81F71F70100E71BD3 /* HTTPHeaderField.cpp in Sources */,
 				46FA2FEE23846CA5000CCB0C /* HTTPHeaderMap.cpp in Sources */,

Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/HTMLMetaThemeColor.mm (0 => 271920)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/HTMLMetaThemeColor.mm	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/HTMLMetaThemeColor.mm	2021-01-27 00:31:23 UTC (rev 271920)
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2020 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 "CocoaColor.h"
+#import "TestCocoa.h"
+#import "TestWKWebView.h"
+#import <WebKit/WKWebViewPrivate.h>
+#import <wtf/RetainPtr.h>
+
+#define EXPECT_NSSTRING_EQ(expected, actual) \
+    EXPECT_TRUE([actual isKindOfClass:[NSString class]]); \
+    EXPECT_WK_STREQ(expected, (NSString *)actual);
+
+constexpr CGFloat redColorComponents[4] = { 1, 0, 0, 1 };
+constexpr CGFloat blueColorComponents[4] = { 0, 0, 1, 1 };
+
+TEST(HTMLMetaThemeColor, OnLoad)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
+    EXPECT_TRUE(![webView _themeColor]);
+
+    [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@"<meta name='theme-color' content='red'>"];
+
+    auto sRGBColorSpace = adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceSRGB));
+    auto redColor = adoptCF(CGColorCreate(sRGBColorSpace.get(), redColorComponents));
+    EXPECT_TRUE(CGColorEqualToColor([webView _themeColor].CGColor, redColor.get()));
+
+    [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@"<meta name='not-theme-color' content='red'>"];
+
+    EXPECT_TRUE(![webView _themeColor]);
+}
+
+TEST(HTMLMetaThemeColor, MultipleTags)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
+    EXPECT_TRUE(![webView _themeColor]);
+
+    [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@"<meta name='theme-color' content='red'><meta name='theme-color' content='blue'>"];
+
+    auto sRGBColorSpace = adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceSRGB));
+    auto blueColor = adoptCF(CGColorCreate(sRGBColorSpace.get(), blueColorComponents));
+    EXPECT_TRUE(CGColorEqualToColor([webView _themeColor].CGColor, blueColor.get()));
+}
+
+@interface WKWebViewThemeColorObserver : NSObject
+
+- (instancetype)initWithWebView:(WKWebView *)webView;
+
+@property (nonatomic, readonly) WKWebView *webView;
+@property (nonatomic, copy) NSString *state;
+
+@end
+
+@implementation WKWebViewThemeColorObserver
+
+- (instancetype)initWithWebView:(WKWebView *)webView
+{
+    if (!(self = [super init]))
+        return nil;
+
+    _state = @"before-init";
+
+    _webView = webView;
+    [_webView addObserver:self forKeyPath:@"_themeColor" options:NSKeyValueObservingOptionInitial context:nil];
+
+    return self;
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
+{
+    if ([_state isEqualToString:@"before-init"]) {
+        _state = @"after-init";
+        return;
+    }
+
+    if ([_state isEqualToString:@"before-load"]) {
+        _state = @"after-load";
+        return;
+    }
+
+    if ([_state isEqualToString:@"before-content-change"]) {
+        _state = @"after-content-change";
+        return;
+    }
+
+    if ([_state isEqualToString:@"before-name-change-not-theme-color"]) {
+        _state = @"after-name-change-not-theme-color";
+        return;
+    }
+
+    if ([_state isEqualToString:@"before-name-change-theme-color"]) {
+        _state = @"after-name-change-theme-color";
+        return;
+    }
+
+    if ([_state isEqualToString:@"before-node-removed"]) {
+        _state = @"after-node-removed";
+        return;
+    }
+
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+@end
+
+TEST(HTMLMetaThemeColor, KVO)
+{
+    auto sRGBColorSpace = adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceSRGB));
+    auto redColor = adoptCF(CGColorCreate(sRGBColorSpace.get(), redColorComponents));
+    auto blueColor = adoptCF(CGColorCreate(sRGBColorSpace.get(), blueColorComponents));
+
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
+    auto themeColorObserver = adoptNS([[WKWebViewThemeColorObserver alloc] initWithWebView:webView.get()]);
+    EXPECT_NSSTRING_EQ("after-init", [themeColorObserver state]);
+    EXPECT_TRUE(![webView _themeColor]);
+
+    [themeColorObserver setState:@"before-load"];
+    [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@"<meta name='theme-color' content='red'>"];
+    EXPECT_NSSTRING_EQ("after-load", [themeColorObserver state]);
+    EXPECT_TRUE(CGColorEqualToColor([webView _themeColor].CGColor, redColor.get()));
+
+    [themeColorObserver setState:@"before-content-change"];
+    [webView objectByEvaluatingJavaScript:@"document.querySelector('meta').setAttribute('content', 'blue')"];
+    [webView waitForNextPresentationUpdate];
+    EXPECT_NSSTRING_EQ("after-content-change", [themeColorObserver state]);
+    EXPECT_TRUE(CGColorEqualToColor([webView _themeColor].CGColor, blueColor.get()));
+
+    [themeColorObserver setState:@"before-name-change-not-theme-color"];
+    [webView objectByEvaluatingJavaScript:@"document.querySelector('meta').setAttribute('name', 'not-theme-color')"];
+    [webView waitForNextPresentationUpdate];
+    EXPECT_NSSTRING_EQ("after-name-change-not-theme-color", [themeColorObserver state]);
+    EXPECT_TRUE(![webView _themeColor]);
+
+    [themeColorObserver setState:@"before-name-change-theme-color"];
+    [webView objectByEvaluatingJavaScript:@"document.querySelector('meta').setAttribute('name', 'theme-color')"];
+    [webView waitForNextPresentationUpdate];
+    EXPECT_NSSTRING_EQ("after-name-change-theme-color", [themeColorObserver state]);
+    EXPECT_TRUE(CGColorEqualToColor([webView _themeColor].CGColor, blueColor.get()));
+
+    [themeColorObserver setState:@"before-node-removed"];
+    [webView objectByEvaluatingJavaScript:@"document.querySelector('meta').remove()"];
+    [webView waitForNextPresentationUpdate];
+    EXPECT_NSSTRING_EQ("after-node-removed", [themeColorObserver state]);
+    EXPECT_TRUE(![webView _themeColor]);
+}
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to