https://bugs.webkit.org/show_bug.cgi?id=180376
rdar://problem/
35837993
Patch by David Quesada <david_quesada@apple.com> on 2017-12-07
Reviewed by Geoffrey Garen.
Source/WebCore:
Tests: applicationmanifest/display-mode-subframe.html
applicationmanifest/display-mode.html
* Modules/applicationmanifest/ApplicationManifest.h:
(WebCore::ApplicationManifest::encode const):
(WebCore::ApplicationManifest::decode):
* Modules/applicationmanifest/ApplicationManifestParser.cpp:
(WebCore::ApplicationManifestParser::parseManifest):
(WebCore::ApplicationManifestParser::parseDisplay):
* Modules/applicationmanifest/ApplicationManifestParser.h:
Add a 'display' property to ApplicationManifest and have ApplicationManifestParser
populate it by parsing the 'display' property from the raw manifest.
* css/CSSValueKeywords.in:
* css/MediaFeatureNames.h:
* css/MediaQueryEvaluator.cpp:
(WebCore::displayModeEvaluate):
To evaluate whether a display-mode query matches, compare the parameter to the
display mode of the manifest applied to the main frame. If there is no manifest,
use the fallback display mode 'browser' - the spec mandates that display-mode
must be exposed even if there is no applied manifest.
* css/MediaQueryExpression.cpp:
(WebCore::featureWithValidIdent):
(WebCore::isFeatureValidWithoutValue):
Source/WebKit:
* UIProcess/API/Cocoa/_WKApplicationManifest.h:
* UIProcess/API/Cocoa/_WKApplicationManifest.mm:
(-[_WKApplicationManifest initWithCoder:]):
(-[_WKApplicationManifest encodeWithCoder:]):
(-[_WKApplicationManifest displayMode]):
Tools:
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebCore/ApplicationManifestParser.cpp:
(WebCore::operator<<):
(ApplicationManifestParserTest::testDisplay):
(TEST_F):
Add unit tests for the parsing of the 'display' manifest property.
* TestWebKitAPI/Tests/WebKitCocoa/ApplicationManifest.mm:
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/WebKitCocoa/display-mode.html: Added.
Update API tests to include _WKApplicationManifest.displayMode.
* WebKitTestRunner/TestController.cpp:
(WTR::parseStringTestHeaderValueAsRelativePath):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
* WebKitTestRunner/cocoa/TestControllerCocoa.mm:
(WTR::TestController::platformCreateWebView):
Teach WKTR to look for and apply an app manifest. A new <!--webkit-test-runner-->
directive 'applicationManifest' can specify a path (relative to the test file itself)
to a JSON app manifest to be applied to the web view before running the test.
LayoutTests:
* applicationmanifest/display-mode-expected.txt: Added.
* applicationmanifest/display-mode-subframe-expected.txt: Added.
* applicationmanifest/display-mode-subframe.html: Added.
* applicationmanifest/display-mode.html: Added.
* applicationmanifest/resources/display-mode-subframe-1.html: Added.
* applicationmanifest/resources/standalone.manifest: Added.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225639
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2017-12-07 David Quesada <david_quesada@apple.com>
+
+ [Web App Manifest] Support display-mode media feature
+ https://bugs.webkit.org/show_bug.cgi?id=180376
+ rdar://problem/35837993
+
+ Reviewed by Geoffrey Garen.
+
+ * applicationmanifest/display-mode-expected.txt: Added.
+ * applicationmanifest/display-mode-subframe-expected.txt: Added.
+ * applicationmanifest/display-mode-subframe.html: Added.
+ * applicationmanifest/display-mode.html: Added.
+ * applicationmanifest/resources/display-mode-subframe-1.html: Added.
+ * applicationmanifest/resources/standalone.manifest: Added.
+
2017-12-07 Jer Noble <jer.noble@apple.com>
Creating a second AVPlayerItemVideoOutput causes flakey failures
--- /dev/null
+(display-mode) (display-mode: standalone)
--- /dev/null
+(display-mode) (display-mode: browser)
--- /dev/null
+<script>
+if (window.testRunner)
+ testRunner.dumpAsText();
+</script>
+<style>
+div { display: none; }
+@media (display-mode) {
+ .display-mode-null { display: inline; }
+}
+@media (display-mode: browser) {
+ .display-mode-browser { display: inline; }
+}
+@media (display-mode: minimal-ui) {
+ .display-mode-minimal-ui { display: inline; }
+}
+@media (display-mode: standalone) {
+ .display-mode-standalone { display: inline; }
+}
+@media (display-mode: fullscreen) {
+ .display-mode-fullscreen { display: inline; }
+}
+@media (display-mode: invalid-value) {
+ .display-mode-invalid-value { display: inline; }
+}
+</style>
+<div class="display-mode-null">(display-mode)</div>
+<div class="display-mode-browser">(display-mode: browser)</div>
+<div class="display-mode-minimal-ui">(display-mode: minimal-ui)</div>
+<div class="display-mode-standalone">(display-mode: standalone)</div>
+<div class="display-mode-fullscreen">(display-mode: fullscreen)</div>
+<div class="display-mode-invalid-value">(display-mode: invalid-value)</div>
\ No newline at end of file
--- /dev/null
+
+
+--------
+Frame: '<!--framePath //<!--frame0-->-->'
+--------
+(display-mode) (display-mode: standalone)
--- /dev/null
+<!-- webkit-test-runner [ applicationManifest=resources/standalone.manifest ] -->
+<script>
+if (window.testRunner)
+ testRunner.dumpChildFramesAsText();
+</script>
+<iframe src="resources/display-mode-subframe-1.html"></iframe>
\ No newline at end of file
--- /dev/null
+<!-- webkit-test-runner [ applicationManifest=resources/standalone.manifest ] -->
+<script>
+if (window.testRunner)
+ testRunner.dumpAsText();
+</script>
+<style>
+div { display: none; }
+@media (display-mode) {
+ .display-mode-null { display: inline; }
+}
+@media (display-mode: browser) {
+ .display-mode-browser { display: inline; }
+}
+@media (display-mode: minimal-ui) {
+ .display-mode-minimal-ui { display: inline; }
+}
+@media (display-mode: standalone) {
+ .display-mode-standalone { display: inline; }
+}
+@media (display-mode: fullscreen) {
+ .display-mode-fullscreen { display: inline; }
+}
+@media (display-mode: invalid-value) {
+ .display-mode-invalid-value { display: inline; }
+}
+</style>
+<div class="display-mode-null">(display-mode)</div>
+<div class="display-mode-browser">(display-mode: browser)</div>
+<div class="display-mode-minimal-ui">(display-mode: minimal-ui)</div>
+<div class="display-mode-standalone">(display-mode: standalone)</div>
+<div class="display-mode-fullscreen">(display-mode: fullscreen)</div>
+<div class="display-mode-invalid-value">(display-mode: invalid-value)</div>
\ No newline at end of file
--- /dev/null
+<style>
+div { display: none; }
+@media (display-mode) {
+ .display-mode-null { display: inline; }
+}
+@media (display-mode: browser) {
+ .display-mode-browser { display: inline; }
+}
+@media (display-mode: minimal-ui) {
+ .display-mode-minimal-ui { display: inline; }
+}
+@media (display-mode: standalone) {
+ .display-mode-standalone { display: inline; }
+}
+@media (display-mode: fullscreen) {
+ .display-mode-fullscreen { display: inline; }
+}
+@media (display-mode: invalid-value) {
+ .display-mode-invalid-value { display: inline; }
+}
+</style>
+<div class="display-mode-null">(display-mode)</div>
+<div class="display-mode-browser">(display-mode: browser)</div>
+<div class="display-mode-minimal-ui">(display-mode: minimal-ui)</div>
+<div class="display-mode-standalone">(display-mode: standalone)</div>
+<div class="display-mode-fullscreen">(display-mode: fullscreen)</div>
+<div class="display-mode-invalid-value">(display-mode: invalid-value)</div>
\ No newline at end of file
--- /dev/null
+{
+ "display": "standalone"
+}
\ No newline at end of file
+2017-12-07 David Quesada <david_quesada@apple.com>
+
+ [Web App Manifest] Support display-mode media feature
+ https://bugs.webkit.org/show_bug.cgi?id=180376
+ rdar://problem/35837993
+
+ Reviewed by Geoffrey Garen.
+
+ Tests: applicationmanifest/display-mode-subframe.html
+ applicationmanifest/display-mode.html
+
+ * Modules/applicationmanifest/ApplicationManifest.h:
+ (WebCore::ApplicationManifest::encode const):
+ (WebCore::ApplicationManifest::decode):
+ * Modules/applicationmanifest/ApplicationManifestParser.cpp:
+ (WebCore::ApplicationManifestParser::parseManifest):
+ (WebCore::ApplicationManifestParser::parseDisplay):
+ * Modules/applicationmanifest/ApplicationManifestParser.h:
+ Add a 'display' property to ApplicationManifest and have ApplicationManifestParser
+ populate it by parsing the 'display' property from the raw manifest.
+
+ * css/CSSValueKeywords.in:
+ * css/MediaFeatureNames.h:
+ * css/MediaQueryEvaluator.cpp:
+ (WebCore::displayModeEvaluate):
+ To evaluate whether a display-mode query matches, compare the parameter to the
+ display mode of the manifest applied to the main frame. If there is no manifest,
+ use the fallback display mode 'browser' - the spec mandates that display-mode
+ must be exposed even if there is no applied manifest.
+ * css/MediaQueryExpression.cpp:
+ (WebCore::featureWithValidIdent):
+ (WebCore::isFeatureValidWithoutValue):
+
2017-12-07 Jer Noble <jer.noble@apple.com>
Creating a second AVPlayerItemVideoOutput causes flakey failures
#if ENABLE(APPLICATION_MANIFEST)
#include "URL.h"
+#include <wtf/EnumTraits.h>
#include <wtf/Optional.h>
namespace WebCore {
struct ApplicationManifest {
+ enum class Display {
+ Browser,
+ MinimalUI,
+ Standalone,
+ Fullscreen,
+ };
+
String name;
String shortName;
String description;
URL scope;
+ Display display;
URL startURL;
template<class Encoder> void encode(Encoder&) const;
template<class Encoder>
void ApplicationManifest::encode(Encoder& encoder) const
{
- encoder << name << shortName << description << scope << startURL;
+ encoder << name << shortName << description << scope << display << startURL;
}
template<class Decoder>
return std::nullopt;
if (!decoder.decode(result.scope))
return std::nullopt;
+ if (!decoder.decodeEnum(result.display))
+ return std::nullopt;
if (!decoder.decode(result.startURL))
return std::nullopt;
} // namespace WebCore
+namespace WTF {
+
+template<> struct EnumTraits<WebCore::ApplicationManifest::Display> {
+ using values = EnumValues<
+ WebCore::ApplicationManifest::Display,
+ WebCore::ApplicationManifest::Display::Browser,
+ WebCore::ApplicationManifest::Display::MinimalUI,
+ WebCore::ApplicationManifest::Display::Standalone,
+ WebCore::ApplicationManifest::Display::Fullscreen
+ >;
+};
+
+} // namespace WTF;
+
#endif // ENABLE(APPLICATION_MANIFEST)
ApplicationManifest parsedManifest;
parsedManifest.startURL = parseStartURL(*manifest, documentURL);
+ parsedManifest.display = parseDisplay(*manifest);
parsedManifest.name = parseName(*manifest);
parsedManifest.description = parseDescription(*manifest);
parsedManifest.shortName = parseShortName(*manifest);
return startURL;
}
+ApplicationManifest::Display ApplicationManifestParser::parseDisplay(const JSON::Object& manifest)
+{
+ RefPtr<JSON::Value> value;
+ if (!manifest.getValue(ASCIILiteral("display"), value))
+ return ApplicationManifest::Display::Browser;
+
+ String stringValue;
+ if (!value->asString(stringValue)) {
+ logManifestPropertyNotAString(ASCIILiteral("display"));
+ return ApplicationManifest::Display::Browser;
+ }
+
+ stringValue = stringValue.stripWhiteSpace().convertToASCIILowercase();
+
+ if (stringValue == "fullscreen")
+ return ApplicationManifest::Display::Fullscreen;
+ if (stringValue == "standalone")
+ return ApplicationManifest::Display::Standalone;
+ if (stringValue == "minimal-ui")
+ return ApplicationManifest::Display::MinimalUI;
+ if (stringValue == "browser")
+ return ApplicationManifest::Display::Browser;
+
+ logDeveloperWarning(ASCIILiteral("\"") + stringValue + ASCIILiteral("\" is not a valid display mode."));
+ return ApplicationManifest::Display::Browser;
+}
+
String ApplicationManifestParser::parseName(const JSON::Object& manifest)
{
return parseGenericString(manifest, ASCIILiteral("name"));
ApplicationManifest parseManifest(const String&, const URL&, const URL&);
URL parseStartURL(const JSON::Object&, const URL&);
+ ApplicationManifest::Display parseDisplay(const JSON::Object&);
String parseName(const JSON::Object&);
String parseDescription(const JSON::Object&);
String parseShortName(const JSON::Object&);
swap
fallback
optional
+
+#if defined(ENABLE_APPLICATION_MANIFEST) && ENABLE_APPLICATION_MANIFEST
+fullscreen
+standalone
+minimal-ui
+browser
+#endif
#include <wtf/NeverDestroyed.h>
#include <wtf/text/AtomicString.h>
-#define CSS_MEDIAQUERY_VIEW_MODE(macro)
+#if ENABLE(APPLICATION_MANIFEST)
+#define CSS_MEDIAQUERY_DISPLAY_MODE(macro) macro(displayMode, "display-mode")
+#else
+#define CSS_MEDIAQUERY_DISPLAY_MODE(macro)
+#endif
#define CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(macro) \
macro(animation, "-webkit-animation") \
macro(transition, "-webkit-transition") \
macro(videoPlayableInline, "-webkit-video-playable-inline") \
macro(width, "width") \
- CSS_MEDIAQUERY_VIEW_MODE(macro)
+ CSS_MEDIAQUERY_DISPLAY_MODE(macro) \
// end of macro
return downcast<CSSPrimitiveValue>(*value).valueID() == (userPrefersReducedMotion ? CSSValueReduce : CSSValueNoPreference);
}
+#if ENABLE(APPLICATION_MANIFEST)
+static bool displayModeEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix)
+{
+ if (!value)
+ return true;
+
+ auto keyword = downcast<CSSPrimitiveValue>(*value).valueID();
+
+ auto manifest = frame.mainFrame().applicationManifest();
+ if (!manifest)
+ return keyword == CSSValueBrowser;
+
+ switch (manifest->display) {
+ case ApplicationManifest::Display::Fullscreen:
+ return keyword == CSSValueFullscreen;
+ case ApplicationManifest::Display::Standalone:
+ return keyword == CSSValueStandalone;
+ case ApplicationManifest::Display::MinimalUI:
+ return keyword == CSSValueMinimalUi;
+ case ApplicationManifest::Display::Browser:
+ return keyword == CSSValueBrowser;
+ }
+
+ return false;
+}
+#endif // ENABLE(APPLICATION_MANIFEST)
+
// Use this function instead of calling add directly to avoid inlining.
static void add(MediaQueryFunctionMap& map, AtomicStringImpl* key, MediaQueryFunction value)
{
|| mediaFeature == MediaFeatureNames::hover
|| mediaFeature == MediaFeatureNames::invertedColors
|| mediaFeature == MediaFeatureNames::pointer
+#if ENABLE(APPLICATION_MANIFEST)
+ || mediaFeature == MediaFeatureNames::displayMode
+#endif
|| mediaFeature == MediaFeatureNames::prefersReducedMotion;
}
|| mediaFeature == MediaFeatureNames::prefersReducedMotion
|| mediaFeature == MediaFeatureNames::devicePixelRatio
|| mediaFeature == MediaFeatureNames::resolution
+#if ENABLE(APPLICATION_MANIFEST)
+ || mediaFeature == MediaFeatureNames::displayMode
+#endif
|| mediaFeature == MediaFeatureNames::videoPlayableInline;
}
+2017-12-07 David Quesada <david_quesada@apple.com>
+
+ [Web App Manifest] Support display-mode media feature
+ https://bugs.webkit.org/show_bug.cgi?id=180376
+ rdar://problem/35837993
+
+ Reviewed by Geoffrey Garen.
+
+ * UIProcess/API/Cocoa/_WKApplicationManifest.h:
+ * UIProcess/API/Cocoa/_WKApplicationManifest.mm:
+ (-[_WKApplicationManifest initWithCoder:]):
+ (-[_WKApplicationManifest encodeWithCoder:]):
+ (-[_WKApplicationManifest displayMode]):
+
2017-12-07 Chris Dumez <cdumez@apple.com>
Unreviewed build fix after r225622.
NS_ASSUME_NONNULL_BEGIN
+typedef NS_ENUM(NSInteger, _WKApplicationManifestDisplayMode) {
+ _WKApplicationManifestDisplayModeBrowser,
+ _WKApplicationManifestDisplayModeMinimalUI,
+ _WKApplicationManifestDisplayModeStandalone,
+ _WKApplicationManifestDisplayModeFullScreen,
+} WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+
WK_CLASS_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA))
@interface _WKApplicationManifest : NSObject <NSCoding>
@property (nonatomic, readonly, nullable, copy) NSString *applicationDescription;
@property (nonatomic, readonly, nullable, copy) NSURL *scope;
@property (nonatomic, readonly, copy) NSURL *startURL;
+@property (nonatomic, readonly) _WKApplicationManifestDisplayMode displayMode;
-+ (_WKApplicationManifest *)applicationManifestFromJSON:(NSString *)json manifestURL:(NSURL *)manifestURL documentURL:(nullable NSURL *)documentURL;
++ (_WKApplicationManifest *)applicationManifestFromJSON:(NSString *)json manifestURL:(nullable NSURL *)manifestURL documentURL:(nullable NSURL *)documentURL;
@end
NSString *shortName = [aDecoder decodeObjectForKey:@"short_name"];
NSString *description = [aDecoder decodeObjectForKey:@"description"];
NSURL *scopeURL = [aDecoder decodeObjectForKey:@"scope"];
+ NSInteger display = [aDecoder decodeIntegerForKey:@"display"];
NSURL *startURL = [aDecoder decodeObjectForKey:@"start_url"];
WebCore::ApplicationManifest coreApplicationManifest {
WTF::String(shortName),
WTF::String(description),
WebCore::URL(scopeURL),
+ static_cast<WebCore::ApplicationManifest::Display>(display),
WebCore::URL(startURL)
};
[aCoder encodeObject:self.shortName forKey:@"short_name"];
[aCoder encodeObject:self.applicationDescription forKey:@"description"];
[aCoder encodeObject:self.scope forKey:@"scope"];
+ [aCoder encodeInteger:static_cast<NSInteger>(_applicationManifest->applicationManifest().display) forKey:@"display"];
[aCoder encodeObject:self.startURL forKey:@"start_url"];
}
return _applicationManifest->applicationManifest().startURL;
}
+- (_WKApplicationManifestDisplayMode)displayMode
+{
+ switch (_applicationManifest->applicationManifest().display) {
+ case WebCore::ApplicationManifest::Display::Browser:
+ return _WKApplicationManifestDisplayModeBrowser;
+ case WebCore::ApplicationManifest::Display::MinimalUI:
+ return _WKApplicationManifestDisplayModeMinimalUI;
+ case WebCore::ApplicationManifest::Display::Standalone:
+ return _WKApplicationManifestDisplayModeStandalone;
+ case WebCore::ApplicationManifest::Display::Fullscreen:
+ return _WKApplicationManifestDisplayModeFullScreen;
+ }
+
+ ASSERT_NOT_REACHED();
+}
+
#else // ENABLE(APPLICATION_MANIFEST)
+ (_WKApplicationManifest *)applicationManifestFromJSON:(NSString *)json manifestURL:(NSURL *)manifestURL documentURL:(NSURL *)documentURL
return nil;
}
+- (_WKApplicationManifestDisplayMode)displayMode
+{
+ return _WKApplicationManifestDisplayModeBrowser;
+}
+
#endif // ENABLE(APPLICATION_MANIFEST)
@end
+2017-12-07 David Quesada <david_quesada@apple.com>
+
+ [Web App Manifest] Support display-mode media feature
+ https://bugs.webkit.org/show_bug.cgi?id=180376
+ rdar://problem/35837993
+
+ Reviewed by Geoffrey Garen.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebCore/ApplicationManifestParser.cpp:
+ (WebCore::operator<<):
+ (ApplicationManifestParserTest::testDisplay):
+ (TEST_F):
+ Add unit tests for the parsing of the 'display' manifest property.
+
+ * TestWebKitAPI/Tests/WebKitCocoa/ApplicationManifest.mm:
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/Tests/WebKitCocoa/display-mode.html: Added.
+ Update API tests to include _WKApplicationManifest.displayMode.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::parseStringTestHeaderValueAsRelativePath):
+ (WTR::updateTestOptionsFromTestHeader):
+ * WebKitTestRunner/TestOptions.h:
+ (WTR::TestOptions::hasSameInitializationOptions const):
+ * WebKitTestRunner/cocoa/TestControllerCocoa.mm:
+ (WTR::TestController::platformCreateWebView):
+ Teach WKTR to look for and apply an app manifest. A new <!--webkit-test-runner-->
+ directive 'applicationManifest' can specify a path (relative to the test file itself)
+ to a JSON app manifest to be applied to the web view before running the test.
+
2017-12-07 Eric Carlson <eric.carlson@apple.com>
Add WebRTC watchlist rule, update MediaStream rule
6354F4D11F7C3AB500D89DF3 /* ApplicationManifestParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6354F4D01F7C3AB500D89DF3 /* ApplicationManifestParser.cpp */; };
6356FB221EC4E0BA0044BF18 /* VisibleContentRect.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6356FB211EC4E0BA0044BF18 /* VisibleContentRect.mm */; };
636353A71E98665D0009F8AF /* GeolocationGetCurrentPositionResult.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 636353A61E9861940009F8AF /* GeolocationGetCurrentPositionResult.html */; };
+ 63A61B8B1FAD251100F06885 /* display-mode.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 63A61B8A1FAD204D00F06885 /* display-mode.html */; };
63F668221F97F7F90032EE51 /* ApplicationManifest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 63F668201F97C3AA0032EE51 /* ApplicationManifest.mm */; };
6BFD294C1D5E6C1D008EC968 /* HashCountedSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A38D7E51C752D5F004F157D /* HashCountedSet.cpp */; };
751B05D61F8EAC410028A09E /* DatabaseTrackerTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 751B05D51F8EAC1A0028A09E /* DatabaseTrackerTest.mm */; };
F4512E131F60C44600BB369E /* DataTransferItem-getAsEntry.html in Copy Resources */,
C07E6CB213FD73930038B22B /* devicePixelRatio.html in Copy Resources */,
0799C34B1EBA3301003B7532 /* disableGetUserMedia.html in Copy Resources */,
+ 63A61B8B1FAD251100F06885 /* display-mode.html in Copy Resources */,
F41AB9A21EF4696B0083FA08 /* div-and-large-image.html in Copy Resources */,
37E1064C1697681800B78BD0 /* DOMHTMLTableCellElementCellAbove.html in Copy Resources */,
37DC6791140D7D7600ABCCDB /* DOMRangeOfString.html in Copy Resources */,
6354F4D01F7C3AB500D89DF3 /* ApplicationManifestParser.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ApplicationManifestParser.cpp; sourceTree = "<group>"; };
6356FB211EC4E0BA0044BF18 /* VisibleContentRect.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = VisibleContentRect.mm; sourceTree = "<group>"; };
636353A61E9861940009F8AF /* GeolocationGetCurrentPositionResult.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = GeolocationGetCurrentPositionResult.html; sourceTree = "<group>"; };
+ 63A61B8A1FAD204D00F06885 /* display-mode.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "display-mode.html"; sourceTree = "<group>"; };
63F668201F97C3AA0032EE51 /* ApplicationManifest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ApplicationManifest.mm; sourceTree = "<group>"; };
751B05D51F8EAC1A0028A09E /* DatabaseTrackerTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = DatabaseTrackerTest.mm; sourceTree = "<group>"; };
754CEC801F6722DC00D0039A /* AutoFillAvailable.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = AutoFillAvailable.mm; sourceTree = "<group>"; };
F486B1CF1F6794FF00F34BDD /* DataTransfer-setDragImage.html */,
F4512E121F60C43400BB369E /* DataTransferItem-getAsEntry.html */,
0799C34A1EBA32F4003B7532 /* disableGetUserMedia.html */,
+ 63A61B8A1FAD204D00F06885 /* display-mode.html */,
F41AB99E1EF4692C0083FA08 /* div-and-large-image.html */,
837A35F01D9A1E6400663C57 /* DownloadRequestBlobURL.html */,
5714ECB81CA8B58800051AC8 /* DownloadRequestOriginalURL.html */,
using namespace WTF;
using namespace WebCore;
+namespace WebCore {
+static inline std::ostream& operator<<(std::ostream& os, const ApplicationManifest::Display& display)
+{
+ switch (display) {
+ case ApplicationManifest::Display::Browser:
+ return os << "ApplicationManifest::Display::Browser";
+ case ApplicationManifest::Display::MinimalUI:
+ return os << "ApplicationManifest::Display::MinimalUI";
+ case ApplicationManifest::Display::Standalone:
+ return os << "ApplicationManifest::Display::Standalone";
+ case ApplicationManifest::Display::Fullscreen:
+ return os << "ApplicationManifest::Display::Fullscreen";
+ }
+}
+} // namespace WebCore
+
class ApplicationManifestParserTest : public testing::Test {
public:
URL m_manifestURL;
EXPECT_STREQ(expectedValue.string().utf8().data(), value.string().utf8().data());
}
+ void testDisplay(const String& rawJSON, ApplicationManifest::Display expectedValue)
+ {
+ auto manifest = parseTopLevelProperty("display", rawJSON);
+ auto value = manifest.display;
+ EXPECT_EQ(expectedValue, value);
+ }
+
void testName(const String& rawJSON, const String& expectedValue)
{
auto manifest = parseTopLevelProperty("name", rawJSON);
testStartURL("\"../page2\"", "https://example.com/page2");
}
+TEST_F(ApplicationManifestParserTest, Display)
+{
+ testDisplay("123", ApplicationManifest::Display::Browser);
+ testDisplay("null", ApplicationManifest::Display::Browser);
+ testDisplay("true", ApplicationManifest::Display::Browser);
+ testDisplay("{ }", ApplicationManifest::Display::Browser);
+ testDisplay("[ ]", ApplicationManifest::Display::Browser);
+ testDisplay("\"\"", ApplicationManifest::Display::Browser);
+ testDisplay("\"garbage string\"", ApplicationManifest::Display::Browser);
+
+ testDisplay("\"browser\"", ApplicationManifest::Display::Browser);
+ testDisplay("\"standalone\"", ApplicationManifest::Display::Standalone);
+ testDisplay("\"minimal-ui\"", ApplicationManifest::Display::MinimalUI);
+ testDisplay("\"fullscreen\"", ApplicationManifest::Display::Fullscreen);
+
+ testDisplay("[\"\\tMINIMAL-ui\\t\"]", ApplicationManifest::Display::MinimalUI);
+}
+
TEST_F(ApplicationManifestParserTest, Name)
{
testName("123", String());
#import "Test.h"
#import "TestNavigationDelegate.h"
#import "TestWKWebView.h"
+#import <WebKit/WKWebViewConfigurationPrivate.h>
#import <WebKit/WKWebViewPrivate.h>
#import <WebKit/_WKApplicationManifest.h>
TEST(WebKit, ApplicationManifestCoding)
{
- auto jsonString = @"{ \"name\": \"TestName\", \"short_name\": \"TestShortName\", \"description\": \"TestDescription\", \"scope\": \"https://test.com/app\", \"start_url\": \"https://test.com/app/index.html\" }";
+ auto jsonString = @"{ \"name\": \"TestName\", \"short_name\": \"TestShortName\", \"description\": \"TestDescription\", \"scope\": \"https://test.com/app\", \"start_url\": \"https://test.com/app/index.html\", \"display\": \"minimal-ui\" }";
RetainPtr<_WKApplicationManifest> manifest { [_WKApplicationManifest applicationManifestFromJSON:jsonString manifestURL:[NSURL URLWithString:@"https://test.com/manifest.json"] documentURL:[NSURL URLWithString:@"https://test.com/"]] };
manifest = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:manifest.get()]];
EXPECT_STREQ("TestDescription", manifest.get().applicationDescription.UTF8String);
EXPECT_STREQ("https://test.com/app", manifest.get().scope.absoluteString.UTF8String);
EXPECT_STREQ("https://test.com/app/index.html", manifest.get().startURL.absoluteString.UTF8String);
+ EXPECT_EQ(_WKApplicationManifestDisplayModeMinimalUI, manifest.get().displayMode);
}
TEST(WebKit, ApplicationManifestBasic)
Util::run(&done);
}
+TEST(WebKit, ApplicationManifestDisplayMode)
+{
+ static bool done;
+ NSDictionary *displayModesAndExpectedContent = @{
+ @"": @"(display-mode) (display-mode: browser)",
+ @"browser": @"(display-mode) (display-mode: browser)",
+ @"minimal-ui": @"(display-mode) (display-mode: minimal-ui)",
+ @"standalone": @"(display-mode) (display-mode: standalone)",
+ @"fullscreen": @"(display-mode) (display-mode: fullscreen)",
+ };
+
+ NSURL *baseURL = [[[NSBundle mainBundle] bundleURL] URLByAppendingPathComponent:@"TestWebKitAPI.resources"];
+ [displayModesAndExpectedContent enumerateKeysAndObjectsUsingBlock:^(NSString *displayMode, NSString *expectedPageContent, BOOL* stop) {
+ @autoreleasepool {
+ NSString *m2 = displayMode.length ? [NSString stringWithFormat:@"{\"display\": \"%@\"}", displayMode] : @"{}";
+ RetainPtr<_WKApplicationManifest> manifest = [_WKApplicationManifest applicationManifestFromJSON:m2 manifestURL:[baseURL URLByAppendingPathComponent:@"manifest.json"] documentURL:baseURL];
+ auto config = adoptNS([[WKWebViewConfiguration alloc] init]);
+ config.get()._applicationManifest = manifest.get();
+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:config.get()]);
+ [webView synchronouslyLoadTestPageNamed:@"display-mode"];
+
+ done = false;
+ [webView _getContentsAsStringWithCompletionHandler:^(NSString *contents, NSError *error) {
+ done = true;
+ EXPECT_STREQ(expectedPageContent.UTF8String, contents.UTF8String);
+ }];
+ Util::run(&done);
+ [webView removeFromSuperview];
+ }
+ }];
+}
+
} // namespace TestWebKitAPI
#endif // WK_API_ENABLED && ENABLE(APPLICATION_MANIFEST)
--- /dev/null
+<style>
+div { display: none; }
+@media (display-mode) {
+ .display-mode-null { display: inline; }
+}
+@media (display-mode: browser) {
+ .display-mode-browser { display: inline; }
+}
+@media (display-mode: minimal-ui) {
+ .display-mode-minimal-ui { display: inline; }
+}
+@media (display-mode: standalone) {
+ .display-mode-standalone { display: inline; }
+}
+@media (display-mode: fullscreen) {
+ .display-mode-fullscreen { display: inline; }
+}
+@media (display-mode: invalid-value) {
+ .display-mode-invalid-value { display: inline; }
+}
+</style>
+<div class="display-mode-null">(display-mode)</div>
+<div class="display-mode-browser">(display-mode: browser)</div>
+<div class="display-mode-minimal-ui">(display-mode: minimal-ui)</div>
+<div class="display-mode-standalone">(display-mode: standalone)</div>
+<div class="display-mode-fullscreen">(display-mode: fullscreen)</div>
+<div class="display-mode-invalid-value">(display-mode: invalid-value)</div>
return false;
}
+static std::string parseStringTestHeaderValueAsRelativePath(const std::string& value, const std::string& pathOrURL)
+{
+ WKRetainPtr<WKURLRef> baseURL(AdoptWK, createTestURL(pathOrURL.c_str()));
+ WKRetainPtr<WKURLRef> relativeURL(AdoptWK, WKURLCreateWithBaseURL(baseURL.get(), value.c_str()));
+ return toSTD(adoptWK(WKURLCopyPath(relativeURL.get())));
+}
+
static void updateTestOptionsFromTestHeader(TestOptions& testOptions, const std::string& pathOrURL, const std::string& absolutePath)
{
std::string filename = absolutePath;
testOptions.enableInspectorAdditions = parseBooleanTestHeaderValue(value);
if (key == "dumpJSConsoleLogInStdErr")
testOptions.dumpJSConsoleLogInStdErr = parseBooleanTestHeaderValue(value);
+ if (key == "applicationManifest")
+ testOptions.applicationManifest = parseStringTestHeaderValueAsRelativePath(value, pathOrURL);
pairStart = pairEnd + 1;
}
}
float deviceScaleFactor { 1 };
Vector<String> overrideLanguages;
+ std::string applicationManifest;
TestOptions(const std::string& pathOrURL);
|| enableCredentialManagement != options.enableCredentialManagement
|| enableIsSecureContextAttribute != options.enableIsSecureContextAttribute
|| enableInspectorAdditions != options.enableInspectorAdditions
- || dumpJSConsoleLogInStdErr != options.dumpJSConsoleLogInStdErr)
+ || dumpJSConsoleLogInStdErr != options.dumpJSConsoleLogInStdErr
+ || applicationManifest != options.applicationManifest)
return false;
return true;
#import <WebKit/WKWebsiteDataRecordPrivate.h>
#import <WebKit/WKWebsiteDataStorePrivate.h>
#import <WebKit/WKWebsiteDataStoreRef.h>
+#import <WebKit/_WKApplicationManifest.h>
#import <WebKit/_WKProcessPoolConfiguration.h>
#import <WebKit/_WKUserContentExtensionStore.h>
#import <WebKit/_WKUserContentExtensionStorePrivate.h>
if (options.enableAttachmentElement)
[copiedConfiguration _setAttachmentElementEnabled: YES];
+ if (options.applicationManifest.length()) {
+ auto manifestPath = [NSString stringWithUTF8String:options.applicationManifest.c_str()];
+ NSString *text = [NSString stringWithContentsOfFile:manifestPath usedEncoding:nullptr error:nullptr];
+ [copiedConfiguration _setApplicationManifest:[_WKApplicationManifest applicationManifestFromJSON:text manifestURL:nil documentURL:nil]];
+ }
+
m_mainWebView = std::make_unique<PlatformWebView>(copiedConfiguration.get(), options);
#else
m_mainWebView = std::make_unique<PlatformWebView>(globalWebViewConfiguration, options);