/* * 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 "TestCocoa.h" #import "TestWKWebView.h" #import #import #import #import #import #define EXPECT_NSSTRING_EQ(expected, actual) \ EXPECT_TRUE([actual isKindOfClass:[NSString class]]); \ EXPECT_WK_STREQ(expected, (NSString *)actual); TEST(WKWebViewThemeColor, MetaElementValidNameAndColor) { auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]); EXPECT_TRUE(![webView themeColor]); [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@""]; auto sRGBColorSpace = adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceSRGB)); auto redColor = adoptCF(CGColorCreate(sRGBColorSpace.get(), redColorComponents)); EXPECT_TRUE(CGColorEqualToColor([webView themeColor].CGColor, redColor.get())); } TEST(WKWebViewThemeColor, MetaElementValidNameAndColorAndMedia) { auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]); EXPECT_TRUE(![webView themeColor]); [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@""]; auto sRGBColorSpace = adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceSRGB)); auto redColor = adoptCF(CGColorCreate(sRGBColorSpace.get(), redColorComponents)); EXPECT_TRUE(CGColorEqualToColor([webView themeColor].CGColor, redColor.get())); } TEST(WKWebViewThemeColor, MetaElementInvalidName) { auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]); EXPECT_TRUE(![webView themeColor]); [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@""]; auto sRGBColorSpace = adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceSRGB)); auto redColor = adoptCF(CGColorCreate(sRGBColorSpace.get(), redColorComponents)); EXPECT_TRUE(CGColorEqualToColor([webView themeColor].CGColor, redColor.get())); } TEST(WKWebViewThemeColor, MetaElementInvalidColor) { auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]); EXPECT_TRUE(![webView themeColor]); [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@""]; auto sRGBColorSpace = adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceSRGB)); auto redColor = adoptCF(CGColorCreate(sRGBColorSpace.get(), redColorComponents)); EXPECT_TRUE(CGColorEqualToColor([webView themeColor].CGColor, redColor.get())); } TEST(WKWebViewThemeColor, MetaElementInvalidMedia) { auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]); EXPECT_TRUE(![webView themeColor]); [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@""]; auto sRGBColorSpace = adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceSRGB)); auto redColor = adoptCF(CGColorCreate(sRGBColorSpace.get(), redColorComponents)); EXPECT_TRUE(CGColorEqualToColor([webView themeColor].CGColor, redColor.get())); } TEST(WKWebViewThemeColor, MetaElementMultipleValid) { auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]); EXPECT_TRUE(![webView themeColor]); [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@"
"]; auto sRGBColorSpace = adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceSRGB)); auto redColor = adoptCF(CGColorCreate(sRGBColorSpace.get(), redColorComponents)); EXPECT_TRUE(CGColorEqualToColor([webView themeColor].CGColor, redColor.get())); } TEST(WKWebViewThemeColor, MetaElementValidSubframe) { auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]); EXPECT_TRUE(![webView themeColor]); [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@""]; auto sRGBColorSpace = adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceSRGB)); auto redColor = adoptCF(CGColorCreate(sRGBColorSpace.get(), redColorComponents)); EXPECT_TRUE(CGColorEqualToColor([webView themeColor].CGColor, redColor.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-invalid"]) { _state = @"after-content-change-invalid"; return; } if ([_state isEqualToString:@"before-content-change-valid"]) { _state = @"after-content-change-valid"; 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-invalid-media-added"]) { _state = @"after-invalid-media-added"; return; } if ([_state isEqualToString:@"before-media-changed-valid"]) { _state = @"after-media-changed-valid"; return; } if ([_state isEqualToString:@"before-media-state-changed"]) { _state = @"after-media-state-changed"; return; } if ([_state isEqualToString:@"before-node-inserted"]) { _state = @"after-node-inserted"; return; } if ([_state isEqualToString:@"before-node-removed"]) { _state = @"after-node-removed"; return; } RELEASE_ASSERT_NOT_REACHED(); } @end TEST(WKWebViewThemeColor, 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:@""]; EXPECT_NSSTRING_EQ("after-load", [themeColorObserver state]); EXPECT_TRUE(CGColorEqualToColor([webView themeColor].CGColor, redColor.get())); [themeColorObserver setState:@"before-content-change-invalid"]; [webView objectByEvaluatingJavaScript:@"document.querySelector('meta').setAttribute('content', 'invalid')"]; [webView waitForNextPresentationUpdate]; EXPECT_NSSTRING_EQ("after-content-change-invalid", [themeColorObserver state]); EXPECT_TRUE(![webView themeColor]); [themeColorObserver setState:@"before-content-change-valid"]; [webView objectByEvaluatingJavaScript:@"document.querySelector('meta').setAttribute('content', 'blue')"]; [webView waitForNextPresentationUpdate]; EXPECT_NSSTRING_EQ("after-content-change-valid", [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-invalid-media-added"]; [webView objectByEvaluatingJavaScript:@"document.querySelector('meta').setAttribute('media', 'invalid')"]; [webView waitForNextPresentationUpdate]; EXPECT_NSSTRING_EQ("after-invalid-media-added", [themeColorObserver state]); EXPECT_TRUE(![webView themeColor]); [themeColorObserver setState:@"before-media-changed-valid"]; [webView objectByEvaluatingJavaScript:@"document.querySelector('meta').setAttribute('media', 'screen')"]; [webView waitForNextPresentationUpdate]; EXPECT_NSSTRING_EQ("after-media-changed-valid", [themeColorObserver state]); EXPECT_TRUE(CGColorEqualToColor([webView themeColor].CGColor, blueColor.get())); [themeColorObserver setState:@"before-media-state-changed"]; [webView setMediaType:@"print"]; [webView waitForNextPresentationUpdate]; EXPECT_NSSTRING_EQ("after-media-state-changed", [themeColorObserver state]); EXPECT_TRUE(![webView themeColor]); [themeColorObserver setState:@"before-node-inserted"]; [webView objectByEvaluatingJavaScript:@"document.querySelector('meta').insertAdjacentHTML('beforebegin', \"\")"]; [webView waitForNextPresentationUpdate]; EXPECT_NSSTRING_EQ("after-node-inserted", [themeColorObserver state]); EXPECT_TRUE(CGColorEqualToColor([webView themeColor].CGColor, redColor.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]); } #if ENABLE(APPLICATION_MANIFEST) TEST(WKWebViewThemeColor, ApplicationManifest) { auto sRGBColorSpace = adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceSRGB)); auto redColor = adoptCF(CGColorCreate(sRGBColorSpace.get(), redColorComponents)); auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]); EXPECT_TRUE(![webView themeColor]); NSDictionary *manifestObject = @{ @"name": @"Test", @"theme_color": @"red" }; [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:[NSString stringWithFormat:@"", [[NSJSONSerialization dataWithJSONObject:manifestObject options:0 error:nil] base64EncodedStringWithOptions:0]]]; static bool didGetApplicationManifest = false; [webView _getApplicationManifestWithCompletionHandler:[&] (_WKApplicationManifest *manifest) { EXPECT_TRUE(CGColorEqualToColor(manifest.themeColor.CGColor, redColor.get())); didGetApplicationManifest = true; }]; TestWebKitAPI::Util::run(&didGetApplicationManifest); [webView waitForNextPresentationUpdate]; EXPECT_TRUE(CGColorEqualToColor([webView themeColor].CGColor, redColor.get())); } TEST(WKWebViewThemeColor, MetaElementOverridesApplicationManifest) { auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]); EXPECT_TRUE(![webView themeColor]); NSDictionary *manifestObject = @{ @"name": @"Test", @"theme_color": @"blue" }; [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:[NSString stringWithFormat:@"", [[NSJSONSerialization dataWithJSONObject:manifestObject options:0 error:nil] base64EncodedStringWithOptions:0]]]; auto sRGBColorSpace = adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceSRGB)); auto redColor = adoptCF(CGColorCreate(sRGBColorSpace.get(), redColorComponents)); EXPECT_TRUE(CGColorEqualToColor([webView themeColor].CGColor, redColor.get())); } #endif // ENABLE(APPLICATION_MANIFEST)