Expose obscured insets to web content (as "safe area insets")
authortimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 21 Apr 2017 07:34:18 +0000 (07:34 +0000)
committertimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 21 Apr 2017 07:34:18 +0000 (07:34 +0000)
https://bugs.webkit.org/show_bug.cgi?id=171013
<rdar://problem/31564652>

Reviewed by Wenson Hsieh and Dave Hyatt.

Tests: fast/css/variables/constants/invalid-constant-name-fallback.html
       fast/css/variables/constants/ios/safe-area-inset-set.html
       fast/css/variables/constants/safe-area-inset-cannot-override.html
       fast/css/variables/constants/safe-area-inset-zero.html

* CMakeLists.txt:
* WebCore.xcodeproj/project.pbxproj:
* css/CSSValueKeywords.in:
* css/CSSVariableData.cpp:
(WebCore::CSSVariableData::checkVariablesForCyclesWithRange):
(WebCore::CSSVariableData::resolveTokenRange):
* css/parser/CSSVariableParser.cpp:
(WebCore::isValidConstantName):
(WebCore::classifyBlock):
(WebCore::isValidConstantReference):
Add a constant() function, which takes both custom properties and
arbitrary idents which are looked up in ConstantPropertyMap, allowing
fallback from the arbitrary, UA-defined idents to custom properties.

* dom/ConstantPropertyMap.cpp: Added.
(WebCore::ConstantPropertyMap::ConstantPropertyMap):
(WebCore::ConstantPropertyMap::values):
(WebCore::ConstantPropertyMap::nameForProperty):
(WebCore::ConstantPropertyMap::setValueForProperty):
(WebCore::ConstantPropertyMap::buildValues):
(WebCore::variableDataForSafeAreaInset):
(WebCore::ConstantPropertyMap::didChangeObscuredInsets):
* dom/ConstantPropertyMap.h: Added.
Keep a mapping of UA-defined "constants", which can be looked up
from CSS via the aforementioned function. For now, this mapping
includes only safe-area-inset-{top, right, bottom, left}, which
expose the obscured insets (now that they can be painted into via
the viewport parameter clip-to-safe-area-inset=no).

* dom/Document.cpp:
(WebCore::Document::Document):
(WebCore::Document::didChangeObscuredInsets):
* dom/Document.h:
(WebCore::Document::constantProperties):
* page/Page.cpp:
(WebCore::Page::setObscuredInsets):
* page/Page.h:
(WebCore::Page::setObscuredInsets): Deleted.
Make setObscuredInsets and related storage not iOS-specific, though
nothing from the other platforms yet calls this code.

* style/StyleResolveForDocument.cpp:
(WebCore::Style::resolveForDocument):
Grab the constant properties from ConstantPropertyMap and plop them into
the CustomPropertyValueMap. Constant properties aren't allowed to start
with --, and variable properties must, so there is no opportunity here
for exposing things to var() (or allowing custom properties to override
UA-defined constant properties).

* TestExpectations:
* fast/css/variables/constants/invalid-constant-name-fallback-expected.html: Added.
* fast/css/variables/constants/invalid-constant-name-fallback.html: Added.
* fast/css/variables/constants/ios/safe-area-inset-set-expected.html: Added.
* fast/css/variables/constants/ios/safe-area-inset-set.html: Added.
* fast/css/variables/constants/safe-area-inset-cannot-override-expected.html: Added.
* fast/css/variables/constants/safe-area-inset-cannot-override.html: Added.
* fast/css/variables/constants/safe-area-inset-zero-expected.html: Added.
* fast/css/variables/constants/safe-area-inset-zero.html: Added.
* platform/ios-wk2/TestExpectations:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@215607 268f45cc-cd09-0410-ab3c-d52691b4dbfc

24 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/fast/css/variables/constants/invalid-constant-name-fallback-expected.html [new file with mode: 0644]
LayoutTests/fast/css/variables/constants/invalid-constant-name-fallback.html [new file with mode: 0644]
LayoutTests/fast/css/variables/constants/ios/safe-area-inset-set-expected.html [new file with mode: 0644]
LayoutTests/fast/css/variables/constants/ios/safe-area-inset-set.html [new file with mode: 0644]
LayoutTests/fast/css/variables/constants/safe-area-inset-cannot-override-expected.html [new file with mode: 0644]
LayoutTests/fast/css/variables/constants/safe-area-inset-cannot-override.html [new file with mode: 0644]
LayoutTests/fast/css/variables/constants/safe-area-inset-zero-expected.html [new file with mode: 0644]
LayoutTests/fast/css/variables/constants/safe-area-inset-zero.html [new file with mode: 0644]
LayoutTests/platform/ios-wk2/TestExpectations
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/css/CSSValueKeywords.in
Source/WebCore/css/CSSVariableData.cpp
Source/WebCore/css/parser/CSSVariableParser.cpp
Source/WebCore/dom/ConstantPropertyMap.cpp [new file with mode: 0644]
Source/WebCore/dom/ConstantPropertyMap.h [new file with mode: 0644]
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/page/Page.cpp
Source/WebCore/page/Page.h
Source/WebCore/style/StyleResolveForDocument.cpp

index 1893656..9ea787b 100644 (file)
@@ -1,3 +1,22 @@
+2017-04-21  Timothy Horton  <timothy_horton@apple.com>
+
+        Expose obscured insets to web content (as "safe area insets")
+        https://bugs.webkit.org/show_bug.cgi?id=171013
+        <rdar://problem/31564652>
+
+        Reviewed by Wenson Hsieh and Dave Hyatt.
+
+        * TestExpectations:
+        * fast/css/variables/constants/invalid-constant-name-fallback-expected.html: Added.
+        * fast/css/variables/constants/invalid-constant-name-fallback.html: Added.
+        * fast/css/variables/constants/ios/safe-area-inset-set-expected.html: Added.
+        * fast/css/variables/constants/ios/safe-area-inset-set.html: Added.
+        * fast/css/variables/constants/safe-area-inset-cannot-override-expected.html: Added.
+        * fast/css/variables/constants/safe-area-inset-cannot-override.html: Added.
+        * fast/css/variables/constants/safe-area-inset-zero-expected.html: Added.
+        * fast/css/variables/constants/safe-area-inset-zero.html: Added.
+        * platform/ios-wk2/TestExpectations:
+
 2017-04-20  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r215597.
index ca5c77e..c2c6bf7 100644 (file)
@@ -34,6 +34,7 @@ media/mac [ Skip ]
 media/ios [ Skip ]
 media/controls/ipad [ Skip ]
 fast/text-autosizing [ Skip ]
+fast/css/variables/constants/ios [ Skip ]
 
 # window.showModalDialog is only tested in DumpRenderTree on Mac.
 editing/execCommand/show-modal-dialog-during-execCommand.html [ Skip ]
diff --git a/LayoutTests/fast/css/variables/constants/invalid-constant-name-fallback-expected.html b/LayoutTests/fast/css/variables/constants/invalid-constant-name-fallback-expected.html
new file mode 100644 (file)
index 0000000..5cb46a9
--- /dev/null
@@ -0,0 +1,14 @@
+<style>
+div {
+    position: absolute;
+    left: 100px;
+    top: 100px;
+    width: 100px;
+    height: 100px;
+    background-color: green;
+}
+</style>
+<body>
+<div></div>
+<p>The box should be at 100, 100.</p>
+
diff --git a/LayoutTests/fast/css/variables/constants/invalid-constant-name-fallback.html b/LayoutTests/fast/css/variables/constants/invalid-constant-name-fallback.html
new file mode 100644 (file)
index 0000000..c05c652
--- /dev/null
@@ -0,0 +1,17 @@
+<style>
+div {
+    position: absolute;
+    width: 100px;
+    height: 100px;
+    background-color: green;
+
+    --valid-fallback: 100px;
+
+    top: constant(some-unknown-name, var(--valid-fallback));
+    left: constant(--some-invalid-name, var(--valid-fallback));
+}
+</style>
+<body>
+<div></div>
+<p>The box should be at 100, 100.</p>
+
diff --git a/LayoutTests/fast/css/variables/constants/ios/safe-area-inset-set-expected.html b/LayoutTests/fast/css/variables/constants/ios/safe-area-inset-set-expected.html
new file mode 100644 (file)
index 0000000..1f0c1e3
--- /dev/null
@@ -0,0 +1,24 @@
+<style>
+#a {
+    position: absolute;
+    left: 100px;
+    top: 200px;
+    width: 100px;
+    height: 100px;
+    background-color: green;
+}
+
+#b {
+    position: absolute;
+    left: 300px;
+    top: 250px;
+    width: 100px;
+    height: 100px;
+    background-color: blue;
+}
+</style>
+<body>
+<div id="a"></div>
+<div id="b"></div>
+<p>The boxes should be at 100, 200 and 300, 250.</p>
+
diff --git a/LayoutTests/fast/css/variables/constants/ios/safe-area-inset-set.html b/LayoutTests/fast/css/variables/constants/ios/safe-area-inset-set.html
new file mode 100644 (file)
index 0000000..d7daa54
--- /dev/null
@@ -0,0 +1,43 @@
+<style>
+#a {
+    position: absolute;
+    left: constant(safe-area-inset-right);
+    top: constant(safe-area-inset-top);
+    width: 100px;
+    height: 100px;
+    background-color: green;
+}
+
+#b {
+    position: absolute;
+    left: constant(safe-area-inset-bottom);
+    top: constant(safe-area-inset-left);
+    width: 100px;
+    height: 100px;
+    background-color: blue;
+}
+</style>
+<script>
+function getUIScript()
+{
+    return `
+    (function() {
+        uiController.setObscuredInsets(200, 100, 300, 250);
+        uiController.doAfterVisibleContentRectUpdate(function () {
+            uiController.uiScriptComplete();
+        });
+    })();`
+}
+
+if (window.testRunner) {
+    testRunner.waitUntilDone();
+    testRunner.runUIScript(getUIScript(), function(result) {
+        testRunner.notifyDone();
+    });
+}
+</script>
+<body>
+<div id="a"></div>
+<div id="b"></div>
+<p>The boxes should be at 100, 200 and 300, 250.</p>
+
diff --git a/LayoutTests/fast/css/variables/constants/safe-area-inset-cannot-override-expected.html b/LayoutTests/fast/css/variables/constants/safe-area-inset-cannot-override-expected.html
new file mode 100644 (file)
index 0000000..fb05184
--- /dev/null
@@ -0,0 +1,24 @@
+<style>
+#a {
+    position: absolute;
+    left: 0px;
+    top: 0px;
+    width: 100px;
+    height: 100px;
+    background-color: green;
+}
+
+#b {
+    position: absolute;
+    left: 0px;
+    top: 0px;
+    width: 100px;
+    height: 100px;
+    background-color: blue;
+}
+</style>
+<body>
+<div id="a"></div>
+<div id="b"></div>
+<p>The boxes should both be at 0, 0.</p>
+
diff --git a/LayoutTests/fast/css/variables/constants/safe-area-inset-cannot-override.html b/LayoutTests/fast/css/variables/constants/safe-area-inset-cannot-override.html
new file mode 100644 (file)
index 0000000..90df46c
--- /dev/null
@@ -0,0 +1,33 @@
+<style>
+html {
+    --safe-area-inset-bottom: 50px;
+    safe-area-inset-left: 50px;
+}
+
+#a {
+    position: absolute;
+    --safe-area-inset-right: 100px;
+    safe-area-inset-top: 100px;
+    left: constant(safe-area-inset-right);
+    top: constant(safe-area-inset-top);
+    width: 100px;
+    height: 100px;
+    background-color: green;
+}
+
+#b {
+    position: absolute;
+    --safe-area-inset-bottom: 200px;
+    safe-area-inset-left: 200px;
+    left: constant(safe-area-inset-bottom);
+    top: constant(safe-area-inset-left);
+    width: 100px;
+    height: 100px;
+    background-color: blue;
+}
+</style>
+<body>
+<div id="a"></div>
+<div id="b"></div>
+<p>The boxes should both be at 0, 0.</p>
+
diff --git a/LayoutTests/fast/css/variables/constants/safe-area-inset-zero-expected.html b/LayoutTests/fast/css/variables/constants/safe-area-inset-zero-expected.html
new file mode 100644 (file)
index 0000000..058d492
--- /dev/null
@@ -0,0 +1,14 @@
+<style>
+div {
+    position: absolute;
+    left: 0px;
+    top: 0px;
+    width: 100px;
+    height: 100px;
+    background-color: green;
+}
+</style>
+<body>
+<div></div>
+<p>The box should be at 0, 0.</p>
+
diff --git a/LayoutTests/fast/css/variables/constants/safe-area-inset-zero.html b/LayoutTests/fast/css/variables/constants/safe-area-inset-zero.html
new file mode 100644 (file)
index 0000000..7dda03e
--- /dev/null
@@ -0,0 +1,17 @@
+<style>
+div {
+    position: absolute;
+    left: 100px;
+    top: 100px;
+    width: 100px;
+    height: 100px;
+    background-color: green;
+
+    top: constant(safe-area-inset-top);
+    left: constant(safe-area-inset-left);
+}
+</style>
+<body>
+<div></div>
+<p>The box should be at 0, 0.</p>
+
index eb879a2..be17657 100644 (file)
@@ -14,6 +14,7 @@ fast/visual-viewport/ios/ [ Pass ]
 scrollingcoordinator/ios [ Pass ]
 tiled-drawing/ios [ Pass ]
 editing/selection/character-granularity-rect.html [ Pass ]
+fast/css/variables/constants/ios [ Pass ]
 
 fast/media/mq-inverted-colors-live-update.html [ Pass ]
 fast/media/mq-inverted-colors-live-update-in-subframes.html [ Pass ]
index 7d8219a..45f12cb 100644 (file)
@@ -1453,6 +1453,7 @@ set(WebCore_SOURCES
     dom/Comment.cpp
     dom/ComposedTreeIterator.cpp
     dom/CompositionEvent.cpp
+    dom/ConstantPropertyMap.cpp
     dom/ContainerNode.cpp
     dom/ContainerNodeAlgorithms.cpp
     dom/ContextDestructionObserver.cpp
index 98d3abd..42504d0 100644 (file)
@@ -1,3 +1,65 @@
+2017-04-21  Timothy Horton  <timothy_horton@apple.com>
+
+        Expose obscured insets to web content (as "safe area insets")
+        https://bugs.webkit.org/show_bug.cgi?id=171013
+        <rdar://problem/31564652>
+
+        Reviewed by Wenson Hsieh and Dave Hyatt.
+
+        Tests: fast/css/variables/constants/invalid-constant-name-fallback.html
+               fast/css/variables/constants/ios/safe-area-inset-set.html
+               fast/css/variables/constants/safe-area-inset-cannot-override.html
+               fast/css/variables/constants/safe-area-inset-zero.html
+
+        * CMakeLists.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * css/CSSValueKeywords.in:
+        * css/CSSVariableData.cpp:
+        (WebCore::CSSVariableData::checkVariablesForCyclesWithRange):
+        (WebCore::CSSVariableData::resolveTokenRange):
+        * css/parser/CSSVariableParser.cpp:
+        (WebCore::isValidConstantName):
+        (WebCore::classifyBlock):
+        (WebCore::isValidConstantReference):
+        Add a constant() function, which takes both custom properties and
+        arbitrary idents which are looked up in ConstantPropertyMap, allowing
+        fallback from the arbitrary, UA-defined idents to custom properties.
+
+        * dom/ConstantPropertyMap.cpp: Added.
+        (WebCore::ConstantPropertyMap::ConstantPropertyMap):
+        (WebCore::ConstantPropertyMap::values):
+        (WebCore::ConstantPropertyMap::nameForProperty):
+        (WebCore::ConstantPropertyMap::setValueForProperty):
+        (WebCore::ConstantPropertyMap::buildValues):
+        (WebCore::variableDataForSafeAreaInset):
+        (WebCore::ConstantPropertyMap::didChangeObscuredInsets):
+        * dom/ConstantPropertyMap.h: Added.
+        Keep a mapping of UA-defined "constants", which can be looked up
+        from CSS via the aforementioned function. For now, this mapping
+        includes only safe-area-inset-{top, right, bottom, left}, which
+        expose the obscured insets (now that they can be painted into via
+        the viewport parameter clip-to-safe-area-inset=no).
+
+        * dom/Document.cpp:
+        (WebCore::Document::Document):
+        (WebCore::Document::didChangeObscuredInsets):
+        * dom/Document.h:
+        (WebCore::Document::constantProperties):
+        * page/Page.cpp:
+        (WebCore::Page::setObscuredInsets):
+        * page/Page.h:
+        (WebCore::Page::setObscuredInsets): Deleted.
+        Make setObscuredInsets and related storage not iOS-specific, though
+        nothing from the other platforms yet calls this code.
+
+        * style/StyleResolveForDocument.cpp:
+        (WebCore::Style::resolveForDocument):
+        Grab the constant properties from ConstantPropertyMap and plop them into
+        the CustomPropertyValueMap. Constant properties aren't allowed to start
+        with --, and variable properties must, so there is no opportunity here
+        for exposing things to var() (or allowing custom properties to override
+        UA-defined constant properties).
+
 2017-04-20  Konstantin Tokarev  <annulen@yandex.ru>
 
         [cmake] Define FORWARDING_HEADERS_DIR in WebKitFS and use it everywhere
index 4157483..45c3ecd 100644 (file)
                2D9BF7471DBFDC49007A7D99 /* MediaKeyMessageEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2D9BF72F1DBFDC0F007A7D99 /* MediaKeyMessageEvent.cpp */; };
                2D9BF74A1DBFDDFF007A7D99 /* JSMediaKeySessionCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2D9BF7481DBFDDF8007A7D99 /* JSMediaKeySessionCustom.cpp */; };
                2D9F0E1314FF1CBF00BA0FF7 /* linearSRGB.icc in Resources */ = {isa = PBXBuildFile; fileRef = 2D9F0E1214FF1CBF00BA0FF7 /* linearSRGB.icc */; };
+               2DAF343C1EA7E0F100382CD3 /* ConstantPropertyMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2DAF343A1EA7E0F100382CD3 /* ConstantPropertyMap.cpp */; };
+               2DAF343D1EA7E0F100382CD3 /* ConstantPropertyMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DAF343B1EA7E0F100382CD3 /* ConstantPropertyMap.h */; };
                2DB9C4AA1B3231F40070F27F /* NSEventSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DB9C4A91B3231F40070F27F /* NSEventSPI.h */; settings = {ATTRIBUTES = (Private, ); }; };
                2DC4CF791D2DD98900ECCC94 /* DataDetectorsUISPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DC4CF781D2DD98900ECCC94 /* DataDetectorsUISPI.h */; settings = {ATTRIBUTES = (Private, ); }; };
                2DCB837919F99BBA00A7FBE4 /* NSSharingServicePickerSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DCB837719F99BBA00A7FBE4 /* NSSharingServicePickerSPI.h */; settings = {ATTRIBUTES = (Private, ); }; };
                2D9F0E1214FF1CBF00BA0FF7 /* linearSRGB.icc */ = {isa = PBXFileReference; lastKnownFileType = file; path = linearSRGB.icc; sourceTree = "<group>"; };
                2DAAE32C19DCAF6000E002D2 /* MockPageOverlayClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MockPageOverlayClient.cpp; sourceTree = "<group>"; };
                2DAAE32D19DCAF6000E002D2 /* MockPageOverlayClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockPageOverlayClient.h; sourceTree = "<group>"; };
+               2DAF343A1EA7E0F100382CD3 /* ConstantPropertyMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConstantPropertyMap.cpp; sourceTree = "<group>"; };
+               2DAF343B1EA7E0F100382CD3 /* ConstantPropertyMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstantPropertyMap.h; sourceTree = "<group>"; };
                2DB9C4A91B3231F40070F27F /* NSEventSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSEventSPI.h; sourceTree = "<group>"; };
                2DC4CF781D2DD98900ECCC94 /* DataDetectorsUISPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataDetectorsUISPI.h; sourceTree = "<group>"; };
                2DCB837719F99BBA00A7FBE4 /* NSSharingServicePickerSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSSharingServicePickerSPI.h; sourceTree = "<group>"; };
                                79F2F59E1091939A000D87CB /* CompositionEvent.cpp */,
                                79F2F59F1091939A000D87CB /* CompositionEvent.h */,
                                79F2F5A01091939A000D87CB /* CompositionEvent.idl */,
+                               2DAF343A1EA7E0F100382CD3 /* ConstantPropertyMap.cpp */,
+                               2DAF343B1EA7E0F100382CD3 /* ConstantPropertyMap.h */,
                                A81872140977D3C0005826D9 /* ContainerNode.cpp */,
                                A81872110977D3C0005826D9 /* ContainerNode.h */,
                                A7A78CD41532BA62006C21E4 /* ContainerNodeAlgorithms.cpp */,
                                7C77C3D71DEF850A00A50BFA /* BlobLineEndings.h in Headers */,
                                E1C94AF9191303F000D5A893 /* BlobPart.h in Headers */,
                                7C77C3D11DEE472400A50BFA /* BlobPropertyBag.h in Headers */,
+                               2DAF343D1EA7E0F100382CD3 /* ConstantPropertyMap.h in Headers */,
                                2EDEF1F5121B0EFC00726DB2 /* BlobRegistry.h in Headers */,
                                2EDEF1F7121B0EFC00726DB2 /* BlobRegistryImpl.h in Headers */,
                                2EB4BCD3121F03E300EC4885 /* BlobResourceHandle.h in Headers */,
                                E1E6EEA40B628DA8005F2F70 /* JSHTMLSelectElement.cpp in Sources */,
                                BC17F9660B64EBB8004A65CB /* JSHTMLSelectElementCustom.cpp in Sources */,
                                9B69D3B81B99100700E3512B /* JSHTMLSlotElement.cpp in Sources */,
+                               2DAF343C1EA7E0F100382CD3 /* ConstantPropertyMap.cpp in Sources */,
                                E446143B0CD689CC00FADA75 /* JSHTMLSourceElement.cpp in Sources */,
                                9752D38D1413104B003305BD /* JSHTMLSpanElement.cpp in Sources */,
                                A80E7B0F0A19D606007FB8C5 /* JSHTMLStyleElement.cpp in Sources */,
index ebc6da2..f615186 100644 (file)
@@ -844,6 +844,11 @@ var
 -internal-variable-value
 
 //
+// UA Constants
+//
+constant
+
+//
 // CSS_PROP_BREAK_BEFORE/AFTER/INSIDE
 //
 avoid-column
index 4dcebf0..751e0b3 100644 (file)
@@ -101,7 +101,7 @@ bool CSSVariableData::checkVariablesForCycles(const AtomicString& name, CustomPr
 bool CSSVariableData::checkVariablesForCyclesWithRange(CSSParserTokenRange range, CustomPropertyValueMap& customProperties, HashSet<AtomicString>& seenProperties, HashSet<AtomicString>& invalidProperties) const
 {
     while (!range.atEnd()) {
-        if (range.peek().functionId() == CSSValueVar) {
+        if (range.peek().functionId() == CSSValueVar || range.peek().functionId() == CSSValueConstant) {
             CSSParserTokenRange block = range.consumeBlock();
             
             block.consumeWhitespace();
@@ -171,7 +171,7 @@ bool CSSVariableData::resolveTokenRange(const CustomPropertyValueMap& customProp
 {
     bool success = true;
     while (!range.atEnd()) {
-        if (range.peek().functionId() == CSSValueVar)
+        if (range.peek().functionId() == CSSValueVar || range.peek().functionId() == CSSValueConstant)
             success &= resolveVariableReference(customProperties, range.consumeBlock(), result);
         else
             result.append(range.consume());
index 6acda4f..b104198 100644 (file)
@@ -49,7 +49,13 @@ bool CSSVariableParser::isValidVariableName(const String& string)
     return string.length() >= 2 && string[0] == '-' && string[1] == '-';
 }
 
+static bool isValidConstantName(const CSSParserToken& token)
+{
+    return token.type() == IdentToken;
+}
+
 bool isValidVariableReference(CSSParserTokenRange, bool& hasAtApplyRule);
+bool isValidConstantReference(CSSParserTokenRange, bool& hasAtApplyRule);
 
 static bool classifyBlock(CSSParserTokenRange range, bool& hasReferences, bool& hasAtApplyRule, bool isTopLevelBlock = true)
 {
@@ -63,6 +69,12 @@ static bool classifyBlock(CSSParserTokenRange range, bool& hasReferences, bool&
                 hasReferences = true;
                 continue;
             }
+            if (token.functionId() == CSSValueConstant) {
+                if (!isValidConstantReference(block, hasAtApplyRule))
+                    return false; // Bail if any references are invalid
+                hasReferences = true;
+                continue;
+            }
             if (!classifyBlock(block, hasReferences, hasAtApplyRule, false))
                 return false;
             continue;
@@ -122,6 +134,23 @@ bool isValidVariableReference(CSSParserTokenRange range, bool& hasAtApplyRule)
     return classifyBlock(range, hasReferences, hasAtApplyRule);
 }
 
+bool isValidConstantReference(CSSParserTokenRange range, bool& hasAtApplyRule)
+{
+    range.consumeWhitespace();
+    if (!isValidConstantName(range.consumeIncludingWhitespace()))
+        return false;
+    if (range.atEnd())
+        return true;
+
+    if (range.consume().type() != CommaToken)
+        return false;
+    if (range.atEnd())
+        return false;
+
+    bool hasReferences = false;
+    return classifyBlock(range, hasReferences, hasAtApplyRule);
+}
+
 static CSSValueID classifyVariableRange(CSSParserTokenRange range, bool& hasReferences, bool& hasAtApplyRule)
 {
     hasReferences = false;
diff --git a/Source/WebCore/dom/ConstantPropertyMap.cpp b/Source/WebCore/dom/ConstantPropertyMap.cpp
new file mode 100644 (file)
index 0000000..fa8c72b
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2017 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. ``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
+ * 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. 
+ *
+ */
+
+#include "config.h"
+#include "ConstantPropertyMap.h"
+
+#include "CSSCustomPropertyValue.h"
+#include "CSSParserTokenRange.h"
+#include "CSSVariableData.h"
+#include "Document.h"
+#include "Page.h"
+#include <wtf/NeverDestroyed.h>
+
+namespace WebCore {
+
+ConstantPropertyMap::ConstantPropertyMap(Document& document)
+    : m_document(document)
+{
+}
+
+const ConstantPropertyMap::Values& ConstantPropertyMap::values() const
+{
+    if (!m_values)
+        const_cast<ConstantPropertyMap&>(*this).buildValues();
+    return *m_values;
+}
+
+const AtomicString& ConstantPropertyMap::nameForProperty(ConstantProperty property) const
+{
+    static NeverDestroyed<AtomicString> safeAreaInsetTopName("safe-area-inset-top", AtomicString::ConstructFromLiteral);
+    static NeverDestroyed<AtomicString> safeAreaInsetRightName("safe-area-inset-right", AtomicString::ConstructFromLiteral);
+    static NeverDestroyed<AtomicString> safeAreaInsetBottomName("safe-area-inset-bottom", AtomicString::ConstructFromLiteral);
+    static NeverDestroyed<AtomicString> safeAreaInsetLeftName("safe-area-inset-left", AtomicString::ConstructFromLiteral);
+
+    switch (property) {
+    case ConstantProperty::SafeAreaInsetTop:
+        return safeAreaInsetTopName;
+    case ConstantProperty::SafeAreaInsetRight:
+        return safeAreaInsetRightName;
+    case ConstantProperty::SafeAreaInsetBottom:
+        return safeAreaInsetBottomName;
+    case ConstantProperty::SafeAreaInsetLeft:
+        return safeAreaInsetLeftName;
+    }
+
+    return nullAtom;
+}
+
+void ConstantPropertyMap::setValueForProperty(ConstantProperty property, Ref<CSSVariableData>&& data)
+{
+    if (!m_values)
+        buildValues();
+
+    auto& name = nameForProperty(property);
+    m_values->set(name, CSSCustomPropertyValue::createWithVariableData(name, WTFMove(data)));
+}
+
+void ConstantPropertyMap::buildValues()
+{
+    m_values = Values { };
+
+    updateConstantsForObscuredInsets();
+}
+
+static Ref<CSSVariableData> variableDataForPositivePixelLength(float lengthInPx)
+{
+    ASSERT(lengthInPx >= 0);
+
+    CSSParserToken token(NumberToken, lengthInPx, NumberValueType, NoSign);
+    token.convertToDimensionWithUnit("px");
+
+    Vector<CSSParserToken> tokens { token };
+    CSSParserTokenRange tokenRange(tokens);
+    return CSSVariableData::create(tokenRange, false);
+}
+
+void ConstantPropertyMap::updateConstantsForObscuredInsets()
+{
+    FloatBoxExtent obscuredInsets = m_document.page() ? m_document.page()->obscuredInsets() : FloatBoxExtent();
+    setValueForProperty(ConstantProperty::SafeAreaInsetTop, variableDataForPositivePixelLength(obscuredInsets.top()));
+    setValueForProperty(ConstantProperty::SafeAreaInsetRight, variableDataForPositivePixelLength(obscuredInsets.right()));
+    setValueForProperty(ConstantProperty::SafeAreaInsetBottom, variableDataForPositivePixelLength(obscuredInsets.bottom()));
+    setValueForProperty(ConstantProperty::SafeAreaInsetLeft, variableDataForPositivePixelLength(obscuredInsets.left()));
+}
+
+void ConstantPropertyMap::didChangeObscuredInsets()
+{
+    updateConstantsForObscuredInsets();
+    m_document.invalidateMatchedPropertiesCacheAndForceStyleRecalc();
+}
+
+}
diff --git a/Source/WebCore/dom/ConstantPropertyMap.h b/Source/WebCore/dom/ConstantPropertyMap.h
new file mode 100644 (file)
index 0000000..cc530b3
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 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. ``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
+ * 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
+
+#include <wtf/HashMap.h>
+#include <wtf/Ref.h>
+#include <wtf/text/AtomicString.h>
+#include <wtf/text/AtomicStringHash.h>
+
+namespace WebCore {
+
+class CSSCustomPropertyValue;
+class CSSVariableData;
+class Document;
+
+enum class ConstantProperty {
+    SafeAreaInsetTop,
+    SafeAreaInsetRight,
+    SafeAreaInsetBottom,
+    SafeAreaInsetLeft,
+};
+
+class ConstantPropertyMap {
+public:
+    explicit ConstantPropertyMap(Document&);
+
+    typedef HashMap<AtomicString, Ref<CSSCustomPropertyValue>> Values;
+    const Values& values() const;
+
+    void didChangeObscuredInsets();
+
+private:
+    void buildValues();
+
+    const AtomicString& nameForProperty(ConstantProperty) const;
+    void setValueForProperty(ConstantProperty, Ref<CSSVariableData>&&);
+
+    void updateConstantsForObscuredInsets();
+
+    std::optional<Values> m_values;
+
+    Document& m_document;
+};
+
+} // namespace WebCore
index 0fc6e7a..fb6bd68 100644 (file)
@@ -43,6 +43,7 @@
 #include "Comment.h"
 #include "CommonVM.h"
 #include "CompositionEvent.h"
+#include "ConstantPropertyMap.h"
 #include "ContentSecurityPolicy.h"
 #include "CookieJar.h"
 #include "CustomElementReactionQueue.h"
@@ -452,6 +453,7 @@ Document::Document(Frame* frame, const URL& url, unsigned documentClasses, unsig
     , m_scriptRunner(std::make_unique<ScriptRunner>(*this))
     , m_moduleLoader(std::make_unique<ScriptModuleLoader>(*this))
     , m_xmlVersion(ASCIILiteral("1.0"))
+    , m_constantPropertyMap(std::make_unique<ConstantPropertyMap>(*this))
     , m_documentClasses(documentClasses)
     , m_eventQueue(*this)
     , m_weakFactory(this)
@@ -2050,6 +2052,11 @@ StyleResolver& Document::userAgentShadowTreeStyleResolver()
 
 void Document::fontsNeedUpdate(FontSelector&)
 {
+    invalidateMatchedPropertiesCacheAndForceStyleRecalc();
+}
+
+void Document::invalidateMatchedPropertiesCacheAndForceStyleRecalc()
+{
     if (auto* resolver = styleScope().resolverIfExists())
         resolver->invalidateMatchedPropertiesCache();
     if (pageCacheState() != NotInPageCache || !renderView())
index 411648f..4828318 100644 (file)
@@ -73,6 +73,7 @@ namespace WebCore {
 class AXObjectCache;
 class Attr;
 class CDATASection;
+class CSSCustomPropertyValue;
 class CSSFontSelector;
 class CSSStyleDeclaration;
 class CSSStyleSheet;
@@ -83,6 +84,7 @@ class CachedScript;
 class CanvasRenderingContext;
 class CharacterData;
 class Comment;
+class ConstantPropertyMap;
 class DOMImplementation;
 class DOMNamedFlowCollection;
 class DOMSelection;
@@ -1206,6 +1208,8 @@ public:
 
     DocumentSharedObjectPool* sharedObjectPool() { return m_sharedObjectPool.get(); }
 
+    void invalidateMatchedPropertiesCacheAndForceStyleRecalc();
+
     void didRemoveAllPendingStylesheet();
     void didClearStyleResolver();
 
@@ -1299,6 +1303,8 @@ public:
     void attachToCachedFrame(CachedFrameBase&);
     void detachFromCachedFrame(CachedFrameBase&);
 
+    ConstantPropertyMap& constantProperties() const { return *m_constantPropertyMap; }
+
 protected:
     enum ConstructionFlags { Synthesized = 1, NonRenderedPlaceholder = 1 << 1 };
     Document(Frame*, const URL&, unsigned = DefaultDocumentClass, unsigned constructionFlags = 0);
@@ -1535,6 +1541,8 @@ private:
 
     DocumentOrderedMap m_imagesByUsemap;
 
+    std::unique_ptr<ConstantPropertyMap> m_constantPropertyMap;
+
     std::unique_ptr<SelectorQueryCache> m_selectorQueryCache;
 
     DocumentClassFlags m_documentClasses;
index 4a31fcb..7dd5880 100644 (file)
@@ -29,6 +29,7 @@
 #include "Chrome.h"
 #include "ChromeClient.h"
 #include "ClientRectList.h"
+#include "ConstantPropertyMap.h"
 #include "ContextMenuClient.h"
 #include "ContextMenuController.h"
 #include "DatabaseProvider.h"
@@ -2289,6 +2290,20 @@ void Page::accessibilitySettingsDidChange()
         LOG(Layout, "hasMediaQueriesAffectedByAccessibilitySettingsChange, enqueueing style recalc");
 }
 
+void Page::setObscuredInsets(const FloatBoxExtent& insets)
+{
+    if (m_obscuredInsets == insets)
+        return;
+
+    m_obscuredInsets = insets;
+
+    for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
+        if (!frame->document())
+            continue;
+        frame->document()->constantProperties().didChangeObscuredInsets();
+    }
+}
+
 #if ENABLE(DATA_INTERACTION)
 
 bool Page::hasSelectionAtPosition(const FloatPoint& position) const
index 43e0b80..8ca09a5 100644 (file)
@@ -329,10 +329,10 @@ public:
     float topContentInset() const { return m_topContentInset; }
     WEBCORE_EXPORT void setTopContentInset(float);
 
-#if PLATFORM(IOS)
     const FloatBoxExtent& obscuredInsets() const { return m_obscuredInsets; }
-    void setObscuredInsets(FloatBoxExtent insets) { m_obscuredInsets = insets; }
-    
+    WEBCORE_EXPORT void setObscuredInsets(const FloatBoxExtent&);
+
+#if PLATFORM(IOS)
     bool enclosedInScrollableAncestorView() const { return m_enclosedInScrollableAncestorView; }
     void setEnclosedInScrollableAncestorView(bool f) { m_enclosedInScrollableAncestorView = f; }
 #endif
@@ -686,10 +686,9 @@ private:
     float m_viewScaleFactor { 1 };
 
     float m_topContentInset;
+    FloatBoxExtent m_obscuredInsets;
 
 #if PLATFORM(IOS)
-    // This is only used for history scroll position restoration.
-    FloatBoxExtent m_obscuredInsets;
     bool m_enclosedInScrollableAncestorView { false };
 #endif
 
index 1d5ac76..6899e1d 100644 (file)
@@ -30,6 +30,7 @@
 #include "StyleResolveForDocument.h"
 
 #include "CSSFontSelector.h"
+#include "ConstantPropertyMap.h"
 #include "Document.h"
 #include "Frame.h"
 #include "FrameView.h"
@@ -124,6 +125,9 @@ RenderStyle resolveForDocument(const Document& document)
 
     documentStyle.fontCascade().update(&const_cast<Document&>(document).fontSelector());
 
+    for (auto& it : document.constantProperties().values())
+        documentStyle.setCustomPropertyValue(it.key, makeRef(it.value.get()));
+
     return documentStyle;
 }