Implement tab-size with units
authorjh718.park@samsung.com <jh718.park@samsung.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 7 Jun 2019 08:27:25 +0000 (08:27 +0000)
committerjh718.park@samsung.com <jh718.park@samsung.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 7 Jun 2019 08:27:25 +0000 (08:27 +0000)
https://bugs.webkit.org/show_bug.cgi?id=179022

Reviewed by Simon Fraser.

This change is ported from Blink.
The committed revision is https://src.chromium.org/viewvc/blink?revision=189430&view=revision.

Additionally, this patch lets css "number" value be allowed as tab-size's property value,
not css "integer" value,
according to https://drafts.csswg.org/css-text-3/#tab-size-property.

LayoutTests/imported/w3c:

* web-platform-tests/css/css-text/inheritance-expected.txt:
* web-platform-tests/css/css-text/parsing/tab-size-valid-expected.txt:
* web-platform-tests/css/css-values/calc-numbers-expected.txt: Added.
* web-platform-tests/css/css-values/calc-numbers.html: Added.

Source/WebCore:

Tests: css3/tab-size.html
       imported/w3c/web-platform-tests/css/css-values/calc-numbers.html

* Headers.cmake:
* WebCore.xcodeproj/project.pbxproj:
* css/CSSComputedStyleDeclaration.cpp:
(WebCore::ComputedStyleExtractor::valueForPropertyInStyle):
* css/CSSProperties.json:
* css/StyleBuilderConverter.h:
(WebCore::StyleBuilderConverter::convertTabSize):
* css/parser/CSSPropertyParser.cpp:
(WebCore::consumeTabSize):
* layout/inlineformatting/text/TextUtil.cpp:
(WebCore::Layout::TextUtil::width):
* platform/graphics/FontCascade.h:
(WebCore::FontCascade::tabWidth const):
* platform/graphics/TabSize.h: Added.
(WebCore::TabSize::TabSize):
(WebCore::TabSize::isSpaces const):
(WebCore::TabSize::widthInPixels const):
(WebCore::TabSize::operator bool const):
(WebCore::operator==):
(WebCore::operator!=):
* platform/graphics/TextRun.cpp:
* platform/graphics/TextRun.h:
(WebCore::TextRun::tabSize const):
(WebCore::TextRun::setTabSize):
* rendering/SimpleLineLayoutTextFragmentIterator.cpp:
(WebCore::SimpleLineLayout::TextFragmentIterator::Style::Style):
* rendering/SimpleLineLayoutTextFragmentIterator.h:
* rendering/style/RenderStyle.h:
(WebCore::RenderStyle::tabSize const):
(WebCore::RenderStyle::setTabSize):
(WebCore::RenderStyle::initialTabSize):
* rendering/style/StyleRareInheritedData.cpp:
* rendering/style/StyleRareInheritedData.h:

LayoutTests:

* TestExpectations:
* css3/tab-size-expected.txt: Added.
* css3/tab-size.html: Added.
* fast/css/tab-size-expected.html:
* fast/css/tab-size.html:

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

28 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/css3/tab-size-expected.txt [new file with mode: 0644]
LayoutTests/css3/tab-size.html [new file with mode: 0644]
LayoutTests/fast/css/tab-size-expected.html
LayoutTests/fast/css/tab-size.html
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/css/css-text/inheritance-expected.txt
LayoutTests/imported/w3c/web-platform-tests/css/css-text/parsing/tab-size-valid-expected.txt
LayoutTests/imported/w3c/web-platform-tests/css/css-values/calc-numbers-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/css/css-values/calc-numbers.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/Headers.cmake
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/css/CSSComputedStyleDeclaration.cpp
Source/WebCore/css/CSSProperties.json
Source/WebCore/css/StyleBuilderConverter.h
Source/WebCore/css/parser/CSSPropertyParser.cpp
Source/WebCore/layout/inlineformatting/text/TextUtil.cpp
Source/WebCore/platform/graphics/FontCascade.h
Source/WebCore/platform/graphics/TabSize.h [new file with mode: 0644]
Source/WebCore/platform/graphics/TextRun.cpp
Source/WebCore/platform/graphics/TextRun.h
Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.cpp
Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.h
Source/WebCore/rendering/style/RenderStyle.h
Source/WebCore/rendering/style/StyleRareInheritedData.cpp
Source/WebCore/rendering/style/StyleRareInheritedData.h

index 8617212..e64ce5f 100644 (file)
@@ -1,3 +1,23 @@
+2019-06-07  Joonghun Park  <jh718.park@samsung.com>
+
+        Implement tab-size with units
+        https://bugs.webkit.org/show_bug.cgi?id=179022
+
+        Reviewed by Simon Fraser.
+
+        This change is ported from Blink.
+        The committed revision is https://src.chromium.org/viewvc/blink?revision=189430&view=revision.
+
+        Additionally, this patch lets css "number" value be allowed as tab-size's property value,
+        not css "integer" value,
+        according to https://drafts.csswg.org/css-text-3/#tab-size-property.
+
+        * TestExpectations:
+        * css3/tab-size-expected.txt: Added.
+        * css3/tab-size.html: Added.
+        * fast/css/tab-size-expected.html:
+        * fast/css/tab-size.html:
+
 2019-06-06  Youenn Fablet  <youenn@apple.com>
 
         Allow WebKitTestRunner to terminate network process after it finishes service worker file operations
index 893f2ad..2ad822b 100644 (file)
@@ -1821,8 +1821,6 @@ webkit.org/b/183258 imported/w3c/web-platform-tests/css/css-text/line-breaking/l
 webkit.org/b/183258 imported/w3c/web-platform-tests/css/css-text/line-breaking/line-breaking-011.html [ ImageOnlyFailure ]
 webkit.org/b/183258 imported/w3c/web-platform-tests/css/css-text/line-breaking/line-breaking-ic-002.html [ ImageOnlyFailure ]
 webkit.org/b/183258 imported/w3c/web-platform-tests/css/css-text/line-breaking/line-breaking-ic-003.html [ ImageOnlyFailure ]
-webkit.org/b/183258 imported/w3c/web-platform-tests/css/css-text/tab-size/tab-size-length-001.html [ ImageOnlyFailure ]
-webkit.org/b/183258 imported/w3c/web-platform-tests/css/css-text/tab-size/tab-size-length-002.html [ ImageOnlyFailure ]
 webkit.org/b/183258 imported/w3c/web-platform-tests/css/css-text/text-align/text-align-end-001.html [ ImageOnlyFailure ]
 webkit.org/b/183258 imported/w3c/web-platform-tests/css/css-text/text-align/text-align-end-002.html [ ImageOnlyFailure ]
 webkit.org/b/183258 imported/w3c/web-platform-tests/css/css-text/text-align/text-align-end-003.html [ ImageOnlyFailure ]
@@ -1917,7 +1915,6 @@ webkit.org/b/195275 imported/w3c/web-platform-tests/css/css-text/line-break/line
 webkit.org/b/195275 imported/w3c/web-platform-tests/css/css-text/line-break/line-break-loose-015.xht [ ImageOnlyFailure ]
 webkit.org/b/195275 imported/w3c/web-platform-tests/css/css-text/tab-size/tab-size-spacing-001.html [ ImageOnlyFailure ]
 webkit.org/b/195275 imported/w3c/web-platform-tests/css/css-text/tab-size/tab-min-rendered-width-1.html [ ImageOnlyFailure ]
-webkit.org/b/195275 imported/w3c/web-platform-tests/css/css-text/tab-size/tab-size-inheritance-001.html [ ImageOnlyFailure ]
 webkit.org/b/195275 imported/w3c/web-platform-tests/css/css-text/text-indent/text-indent-percentage-002.html [ ImageOnlyFailure ]
 webkit.org/b/195275 imported/w3c/web-platform-tests/css/css-text/text-indent/text-indent-percentage-004.html [ ImageOnlyFailure ]
 webkit.org/b/195275 imported/w3c/web-platform-tests/css/css-text/text-indent/text-indent-percentage-003.html [ ImageOnlyFailure ]
diff --git a/LayoutTests/css3/tab-size-expected.txt b/LayoutTests/css3/tab-size-expected.txt
new file mode 100644 (file)
index 0000000..8975e62
--- /dev/null
@@ -0,0 +1,27 @@
+Test tab-size measurements.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS pxTabLength is pxExpected
+PASS emTabLength is emExpected
+PASS intTabLength is intExpected
+PASS fractionTabLength is fractionExpected
+PASS pxTabLength is pxExpected
+PASS emTabLength is emExpected
+PASS intTabLength is intExpected
+PASS fractionTabLength is fractionExpected
+PASS successfullyParsed is true
+
+TEST COMPLETE
+       leading text, tab-size in px.
+       leading text, tab-size in em.
+       leading text, tab-size in spaces.
+       leading text, tab-size in fraction.
+leading text   trailing text, tab-size in px.
+leading text   trailing text, tab-size in em.
+leading text   trailing text, tab-size in spaces.
+leading text   trailing text, tab-size in fraction.
+Some spaces... '         ' ... for size reference.
+A space... ' ' ... for size reference.
+'leading text', for size reference.
diff --git a/LayoutTests/css3/tab-size.html b/LayoutTests/css3/tab-size.html
new file mode 100644 (file)
index 0000000..a57c598
--- /dev/null
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+body {
+  font-size: 13px;
+}
+.px-tab-size {
+  tab-size: 60px;
+}
+.em-tab-size {
+  tab-size: 7em;
+}
+.int-tab-size {
+  tab-size: 9;
+}
+.fractional-tab-size {
+  tab-size: 2.5;
+}
+    </style>
+    <script src="../resources/js-test.js"></script>
+  </head>
+  <body>
+    <div style="background-repeat: repeat-x;">
+    <div><pre id="leading-px" class="px-tab-size">&Tab;<span>leading text, tab-size in px.</span></pre></div>
+    <div><pre id="leading-em" class="em-tab-size">&Tab;<span>leading text, tab-size in em.</span></pre></div>
+    <div><pre id="leading-int" class="int-tab-size">&Tab;<span>leading text, tab-size in spaces.</span></pre></div>
+    <div><pre id="leading-fraction" class="fractional-tab-size">&Tab;<span>leading text, tab-size in fraction.</span></pre></div>
+    <div><pre id="trailing-px" class="px-tab-size"><span>leading text</span>&Tab;<span>trailing text, tab-size in px.</span></pre></div>
+    <div><pre id="trailing-em" class="em-tab-size"><span>leading text</span>&Tab;<span>trailing text, tab-size in em.</span></pre></div>
+    <div><pre id="trailing-int" class="int-tab-size"><span>leading text</span>&Tab;<span>trailing text, tab-size in spaces.</span></pre></div>
+    <div><pre id="trailing-fraction" class="fractional-tab-size"><span>leading text</span>&Tab;<span>trailing text, tab-size in fraction.</span></pre></div>
+    <div><pre>Some spaces... '<span id="space-size-reference">         </span>' ... for size reference.</pre></div>
+    <div><pre>A space... '<span id="one-space-size-reference"> </span>' ... for size reference.</pre></div>
+    <div><pre>'<span id="leading-text-size-reference">leading text</span>', for size reference.</pre></div>
+    <script>
+
+description('Test tab-size measurements.');
+
+// Tests with a tab character at the beginning of the line.
+
+var pxPre = document.getElementById('leading-px');
+var emPre = document.getElementById('leading-em');
+var intPre = document.getElementById('leading-int');
+var fractionPre = document.getElementById("leading-fraction");
+
+var pxLeadingSpan = pxPre.firstElementChild;
+var emLeadingSpan = emPre.firstElementChild;
+var intLeadingSpan = intPre.firstElementChild;
+var fractionLeadingspan = fractionPre.firstElementChild;
+
+var pxExpected = 60;  // tab size in px.
+var emExpected = 13 * 7;  // (font size) * (tab size in em)
+var intExpected = document.getElementById('space-size-reference').getBoundingClientRect().width;
+var fractionExpected = 2.5 * document.getElementById('one-space-size-reference').getBoundingClientRect().width;
+
+var pxTabLength = pxLeadingSpan.getBoundingClientRect().left - pxPre.getBoundingClientRect().left;
+var emTabLength = emLeadingSpan.getBoundingClientRect().left - emPre.getBoundingClientRect().left;
+var intTabLength = intLeadingSpan.getBoundingClientRect().left - intPre.getBoundingClientRect().left;
+var fractionTabLength = fractionLeadingspan.getBoundingClientRect().left - fractionPre.getBoundingClientRect().left;
+
+shouldBe("pxTabLength", "pxExpected", false, 0.02);
+shouldBe("emTabLength", "emExpected", false, 0.02);
+shouldBe("intTabLength", "intExpected", false, 0.02);
+shouldBe("fractionTabLength", "fractionExpected", false, 0.02);
+
+// Tests with a tab character after leading text.
+
+var leadingTextSize = document.getElementById('leading-text-size-reference').getBoundingClientRect().width;
+pxExpected = pxExpected - (leadingTextSize % pxExpected);
+emExpected = emExpected - (leadingTextSize % emExpected);
+intExpected = intExpected - (leadingTextSize % intExpected);
+fractionExpected = fractionExpected - (leadingTextSize % fractionExpected);
+
+pxPre = document.getElementById('trailing-px');
+emPre = document.getElementById('trailing-em');
+intPre = document.getElementById('trailing-int');
+fractionPre = document.getElementById("trailing-fraction");
+
+pxLeadingSpan = pxPre.firstElementChild;
+emLeadingSpan = emPre.firstElementChild;
+intLeadingSpan = intPre.firstElementChild;
+fractionLeadingspan = fractionPre.firstElementChild;
+
+pxTrailingSpan = pxPre.lastElementChild;
+emTrailingSpan = emPre.lastElementChild;
+intTrailingSpan = intPre.lastElementChild;
+fractionTrailingSpan = fractionPre.lastElementChild;
+
+pxTabLength = pxTrailingSpan.getBoundingClientRect().left - pxLeadingSpan.getBoundingClientRect().right;
+emTabLength = emTrailingSpan.getBoundingClientRect().left - emLeadingSpan.getBoundingClientRect().right;
+intTabLength = intTrailingSpan.getBoundingClientRect().left - intLeadingSpan.getBoundingClientRect().right;
+fractionTabLength = fractionTrailingSpan.getBoundingClientRect().left - fractionLeadingspan.getBoundingClientRect().right;
+
+shouldBe("pxTabLength", "pxExpected", false, 0.02);
+shouldBe("emTabLength", "emExpected", false, 0.02);
+shouldBe("intTabLength", "intExpected", false, 0.02);
+shouldBe("fractionTabLength", "fractionExpected", false, 0.02);
+    </script>
+  </body>
+</html>
index 2c7aa5c..d6ff02e 100644 (file)
@@ -29,14 +29,6 @@ pre { margin: 0.1em; }
 <pre>xx  xx  x</pre>
 <pre>xxxxxxxxx xx  x</pre>
 </div>
-<b>Tab size = 20px, should not assert, and fall back to 8.</b>
-<div>
-<pre>        x</pre>
-<pre>                x</pre>
-<pre>        x       x</pre>
-<pre>xx      xx      x</pre>
-<pre>xxxxxxxxx       xx      x</pre>
-</div>
 <b>Tab size becomes 2 dynamically.</b>
 <div>
 <pre>  x</pre>
index ac052ad..90aae07 100644 (file)
@@ -25,7 +25,6 @@ function test()
     setupBlock("Default tab size (8).", null);
     setupBlock("Tab size = -10, should fall back to the default.", "tab-size: -10;");
     setupBlock("Tab size = 2.", "tab-size: 2;");
-    setupBlock("Tab size = 20px, should not assert, and fall back to 8.", "tab-size: 20px;");
 
     var dynamicBlock = setupBlock("Tab size becomes 2 dynamically.", null);
 
index 9bee994..f1cb903 100644 (file)
@@ -1,3 +1,22 @@
+2019-06-07  Joonghun Park  <jh718.park@samsung.com>
+
+        Implement tab-size with units
+        https://bugs.webkit.org/show_bug.cgi?id=179022
+
+        Reviewed by Simon Fraser.
+
+        This change is ported from Blink.
+        The committed revision is https://src.chromium.org/viewvc/blink?revision=189430&view=revision.
+
+        Additionally, this patch lets css "number" value be allowed as tab-size's property value,
+        not css "integer" value,
+        according to https://drafts.csswg.org/css-text-3/#tab-size-property.
+
+        * web-platform-tests/css/css-text/inheritance-expected.txt:
+        * web-platform-tests/css/css-text/parsing/tab-size-valid-expected.txt:
+        * web-platform-tests/css/css-values/calc-numbers-expected.txt: Added.
+        * web-platform-tests/css/css-values/calc-numbers.html: Added.
+
 2019-06-05  Antoine Quint  <graouts@apple.com>
 
         [Pointer Events] Fire pointerout and pointerleave events after firing pointercancel
index 288b67c..1fff9fa 100644 (file)
@@ -10,7 +10,7 @@ PASS Property line-break inherits
 PASS Property overflow-wrap has initial value normal 
 FAIL Property overflow-wrap inherits assert_equals: expected "break-word" but got "normal"
 PASS Property tab-size has initial value 8 
-FAIL Property tab-size inherits assert_equals: expected "10px" but got "8"
+PASS Property tab-size inherits 
 PASS Property text-align-all has initial value start 
 PASS Property text-align-all inherits 
 PASS Property text-align-last has initial value auto 
index c5fdb60..13c0bf4 100644 (file)
@@ -1,7 +1,7 @@
 
 PASS e.style['tab-size'] = "0" should set the property value 
-FAIL e.style['tab-size'] = "2.5" should set the property value assert_not_equals: property should be set got disallowed value ""
-FAIL e.style['tab-size'] = "0px" should set the property value assert_not_equals: property should be set got disallowed value ""
-FAIL e.style['tab-size'] = "10px" should set the property value assert_not_equals: property should be set got disallowed value ""
-FAIL e.style['tab-size'] = "calc(2em + 3ex)" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['tab-size'] = "2.5" should set the property value 
+PASS e.style['tab-size'] = "0px" should set the property value 
+PASS e.style['tab-size'] = "10px" should set the property value 
+PASS e.style['tab-size'] = "calc(2em + 3ex)" should set the property value 
 
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-values/calc-numbers-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/css/css-values/calc-numbers-expected.txt
new file mode 100644 (file)
index 0000000..406c668
--- /dev/null
@@ -0,0 +1,13 @@
+
+PASS testing tab-size: calc(2 * 3) 
+FAIL testing tab-size: calc(2 * -4) assert_equals: calc(2 * -4) should compute to 0 expected "0" but got "12345"
+PASS testing opacity: calc(2 / 4) 
+PASS testing tab-size: calc(2 / 4) 
+FAIL testing opacity: calc(2 / 4) * 1px assert_equals: calc(2 / 4) * 1px should compute to 0.9 expected "0.9" but got "0.8999999761581421"
+PASS testing tab-size: calc(1 + 1px) 
+PASS testing tab-size: calc(1 + 100%) 
+PASS testing tab-size: calc(100%) 
+PASS testing tab-size: calc(10px) bla 
+PASS testing tab-size: calc(bla) 10px 
+PASS testing tab-size: calc(10px) 
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-values/calc-numbers.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-values/calc-numbers.html
new file mode 100644 (file)
index 0000000..995595b
--- /dev/null
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Values and Units Test: computed value of 'tab-size' and 'opacity' when specified with calc() function</title>
+
+  <!--
+
+  Original test is:
+
+https://chromium.googlesource.com/chromium/src/+/c825d655f6aaf73484f9d56e9012793f5b9668cc/third_party/WebKit/LayoutTests/css3/calc/calc-numbers.html
+
+  -->
+
+  <link rel="author" title="GĂ©rard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-color-3/#transparency">
+  <link rel="help" href="https://www.w3.org/TR/css-text-3/#tab-size-property">
+  <link rel="help" href="https://www.w3.org/TR/css3-values/#calc-computed-value">
+  <link rel="help" href="https://www.w3.org/TR/css3-values/#calc-range">
+
+  <meta name="flags" content="invalid">
+  <meta content="This test verifies how 11 calc() functions are computed for 'opacity' and 'tab-size'." name="assert">
+
+  <script src="/resources/testharness.js"></script>
+
+  <script src="/resources/testharnessreport.js"></script>
+
+  <div id="target"></div>
+
+  <script>
+  function startTesting()
+  {
+
+    function verifyComputedStyle(property_name, initial_value, specified_value, expected_value, description)
+    {
+
+    var elemTarget = document.getElementById("target");
+
+    test(function()
+      {
+
+      elemTarget.style.setProperty(property_name, initial_value);
+
+      /*
+      In exactly 6 out of the 11 sub-tests, the initial_value will
+      act as a fallback value because the specified value generates
+      an invalid value. Since we are running 11 consecutive tests
+      on the same element, then it is necessary to 'reset' its
+      property to an initial value.
+      */
+
+      elemTarget.style.setProperty(property_name, specified_value);
+
+      assert_equals(getComputedStyle(elemTarget)[property_name], expected_value, specified_value + ' should compute to ' + expected_value);
+
+      }, description);
+    }
+
+ /* verifyComputedStyle(property_name, initial_value, specified_value, expected_value, description) */
+
+    verifyComputedStyle("tab-size", "initial", "calc(2 * 3)", "6", "testing tab-size: calc(2 * 3)");
+
+    verifyComputedStyle("tab-size", "12345", "calc(2 * -4)", "0", "testing tab-size: calc(2 * -4)");
+    /*
+    an out-of-range value inside a calc() does not cause
+    the declaration to become invalid. The value resulting
+    from an expression must be clamped to the range
+    allowed in the target context.
+    https://www.w3.org/TR/css-values-3/#calc-range
+    */
+
+    verifyComputedStyle("opacity", "initial", "calc(2 / 4)", "0.5", "testing opacity: calc(2 / 4)");
+
+    verifyComputedStyle("tab-size", "12345", "calc(2 / 4)", "0.5", "testing tab-size: calc(2 / 4)");
+    /*
+    'tab-size' accepts <number> values.
+    */
+
+    verifyComputedStyle("opacity", "0.9", "calc(2 / 4) * 1px", "0.9", "testing opacity: calc(2 / 4) * 1px");
+
+    verifyComputedStyle("tab-size", "12345", "calc(1 + 1px)", "12345", "testing tab-size: calc(1 + 1px)");
+
+    verifyComputedStyle("tab-size", "12345", "calc(1 + 100%)", "12345", "testing tab-size: calc(1 + 100%)");
+
+    verifyComputedStyle("tab-size", "12345", "calc(100%)", "12345", "testing tab-size: calc(100%)");
+
+    verifyComputedStyle("tab-size", "12345", "calc(10px) bla", "12345", "testing tab-size: calc(10px) bla");
+
+    verifyComputedStyle("tab-size", "12345", "calc(bla) 10px", "12345", "testing tab-size: calc(bla) 10px");
+
+    verifyComputedStyle("tab-size", "initial", "calc(10px)", "10px", "testing tab-size: calc(10px)");
+
+ /* verifyComputedStyle(property_name, initial_value, specified_value, expected_value, description) */
+  }
+
+  startTesting();
+
+  </script>
index 176cced..630abb1 100644 (file)
@@ -1,3 +1,54 @@
+2019-06-07  Joonghun Park  <jh718.park@samsung.com>
+
+        Implement tab-size with units
+        https://bugs.webkit.org/show_bug.cgi?id=179022
+
+        Reviewed by Simon Fraser.
+
+        This change is ported from Blink.
+        The committed revision is https://src.chromium.org/viewvc/blink?revision=189430&view=revision.
+
+        Additionally, this patch lets css "number" value be allowed as tab-size's property value,
+        not css "integer" value,
+        according to https://drafts.csswg.org/css-text-3/#tab-size-property.
+
+        Tests: css3/tab-size.html
+               imported/w3c/web-platform-tests/css/css-values/calc-numbers.html
+
+        * Headers.cmake:
+        * WebCore.xcodeproj/project.pbxproj:
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::ComputedStyleExtractor::valueForPropertyInStyle):
+        * css/CSSProperties.json:
+        * css/StyleBuilderConverter.h:
+        (WebCore::StyleBuilderConverter::convertTabSize):
+        * css/parser/CSSPropertyParser.cpp:
+        (WebCore::consumeTabSize):
+        * layout/inlineformatting/text/TextUtil.cpp:
+        (WebCore::Layout::TextUtil::width):
+        * platform/graphics/FontCascade.h:
+        (WebCore::FontCascade::tabWidth const):
+        * platform/graphics/TabSize.h: Added.
+        (WebCore::TabSize::TabSize):
+        (WebCore::TabSize::isSpaces const):
+        (WebCore::TabSize::widthInPixels const):
+        (WebCore::TabSize::operator bool const):
+        (WebCore::operator==):
+        (WebCore::operator!=):
+        * platform/graphics/TextRun.cpp:
+        * platform/graphics/TextRun.h:
+        (WebCore::TextRun::tabSize const):
+        (WebCore::TextRun::setTabSize):
+        * rendering/SimpleLineLayoutTextFragmentIterator.cpp:
+        (WebCore::SimpleLineLayout::TextFragmentIterator::Style::Style):
+        * rendering/SimpleLineLayoutTextFragmentIterator.h:
+        * rendering/style/RenderStyle.h:
+        (WebCore::RenderStyle::tabSize const):
+        (WebCore::RenderStyle::setTabSize):
+        (WebCore::RenderStyle::initialTabSize):
+        * rendering/style/StyleRareInheritedData.cpp:
+        * rendering/style/StyleRareInheritedData.h:
+
 2019-06-07  Philippe Normand  <pnormand@igalia.com>
 
         [GStreamer] videorate issues with v4l2src
index f46e1be..66dc90f 100644 (file)
@@ -1086,6 +1086,7 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS
     platform/graphics/RemoteVideoSample.h
     platform/graphics/RoundedRect.h
     platform/graphics/StringTruncator.h
+    platform/graphics/TabSize.h
     platform/graphics/TextRun.h
     platform/graphics/TiledBacking.h
     platform/graphics/TrackPrivateBase.h
index f87491e..7b69a86 100644 (file)
                38F23AB31E8E83D000CE46F5 /* JSWebGPUComputeCommandEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 38F23AB01E8E83D000CE46F5 /* JSWebGPUComputeCommandEncoder.h */; };
                38F23AB51E8E83D000CE46F5 /* JSWebGPUComputePipelineState.h in Headers */ = {isa = PBXBuildFile; fileRef = 38F23AB21E8E83D000CE46F5 /* JSWebGPUComputePipelineState.h */; };
                3AC648B2129E146500C3EB25 /* EditingBoundary.h in Headers */ = {isa = PBXBuildFile; fileRef = 3AC648B1129E146500C3EB25 /* EditingBoundary.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               3BB6B81122A7D313003A2A69 /* TabSize.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BB6B80F22A7D311003A2A69 /* TabSize.h */; settings = {ATTRIBUTES = (Private, ); }; };
                3C244FEAA375AC633F88BE6F /* RenderLayerModelObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C244FE4A375AC633F88BE6F /* RenderLayerModelObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
                3F2B33EF165AF15600E3987C /* JSWebKitCSSViewportRule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F2B33EA165AF15500E3987C /* JSWebKitCSSViewportRule.h */; };
                3F42B31D1881191B00278AAC /* WebVideoFullscreenControllerAVKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F42B31B1881191B00278AAC /* WebVideoFullscreenControllerAVKit.h */; settings = {ATTRIBUTES = (Private, ); }; };
                38F23AB11E8E83D000CE46F5 /* JSWebGPUComputePipelineState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebGPUComputePipelineState.cpp; sourceTree = "<group>"; };
                38F23AB21E8E83D000CE46F5 /* JSWebGPUComputePipelineState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWebGPUComputePipelineState.h; sourceTree = "<group>"; };
                3AC648B1129E146500C3EB25 /* EditingBoundary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditingBoundary.h; sourceTree = "<group>"; };
+               3BB6B80F22A7D311003A2A69 /* TabSize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TabSize.h; sourceTree = "<group>"; };
                3C244FE4A375AC633F88BE6F /* RenderLayerModelObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderLayerModelObject.h; sourceTree = "<group>"; };
                3C244FE5A375AC633F88BE6F /* RenderLayerModelObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderLayerModelObject.cpp; sourceTree = "<group>"; };
                3F2B33E3165ABD3500E3987C /* WebKitCSSViewportRule.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebKitCSSViewportRule.idl; sourceTree = "<group>"; };
                                849F77750EFEC6200090849D /* StrokeStyleApplier.h */,
                                087558C313B4A57D00F49307 /* SurrogatePairAwareTextIterator.cpp */,
                                087558C413B4A57D00F49307 /* SurrogatePairAwareTextIterator.h */,
+                               3BB6B80F22A7D311003A2A69 /* TabSize.h */,
                                376DCCE013B4F966002EBEFC /* TextRun.cpp */,
                                A824B4640E2EF2EA0081A7B7 /* TextRun.h */,
                                CD1E7346167BC78E009A885D /* TextTrackRepresentation.cpp */,
                                0F03C0741884695E00A5F8CA /* SystemMemory.h in Headers */,
                                5D5975B319635F1100D00878 /* SystemVersion.h in Headers */,
                                A8CFF0510A154F09000A4234 /* TableLayout.h in Headers */,
+                               3BB6B81122A7D313003A2A69 /* TabSize.h in Headers */,
                                463EB6231B8789E00096ED51 /* TagCollection.h in Headers */,
                                F55B3DD61251F12D003EF269 /* TelephoneInputType.h in Headers */,
                                7CC564B818BABEA6001B9652 /* TelephoneNumberDetector.h in Headers */,
index d9ccb4b..5c5c338 100644 (file)
@@ -3026,7 +3026,7 @@ RefPtr<CSSValue> ComputedStyleExtractor::valueForPropertyInStyle(const RenderSty
                 return cssValuePool.createIdentifierValue(CSSValueAuto);
             return zoomAdjustedPixelValue(style.columnWidth(), style);
         case CSSPropertyTabSize:
-            return cssValuePool.createValue(style.tabSize(), CSSPrimitiveValue::CSS_NUMBER);
+            return cssValuePool.createValue(style.tabSize().widthInPixels(1.0), style.tabSize().isSpaces() ? CSSPrimitiveValue::CSS_NUMBER : CSSPrimitiveValue::CSS_PX);
         case CSSPropertyCursor: {
             RefPtr<CSSValueList> list;
             auto* cursors = style.cursors();
index 1536159..c2718a7 100644 (file)
         },
         "tab-size": {
             "inherited": true,
+            "codegen-properties": {
+                "converter": "TabSize"
+            },
             "specification": {
                 "category": "css-text",
-                "url": "https://www.w3.org/TR/css-text-3/#tab-size"
+                "url": "https://drafts.csswg.org/css-text-3/#tab-size-property"
             }
         },
         "text-align": {
index e5dd3fd..69af558 100644 (file)
@@ -53,6 +53,7 @@
 #include "Settings.h"
 #include "StyleResolver.h"
 #include "StyleScrollSnapPoints.h"
+#include "TabSize.h"
 #include "TouchAction.h"
 #include "TransformFunctions.h"
 #include <wtf/Optional.h>
@@ -66,6 +67,7 @@ public:
     static Length convertLengthOrAuto(const StyleResolver&, const CSSValue&);
     static Length convertLengthSizing(const StyleResolver&, const CSSValue&);
     static Length convertLengthMaxSizing(const StyleResolver&, const CSSValue&);
+    static TabSize convertTabSize(const StyleResolver&, const CSSValue&);
     template<typename T> static T convertComputedLength(StyleResolver&, const CSSValue&);
     template<typename T> static T convertLineWidth(StyleResolver&, const CSSValue&);
     static float convertSpacing(StyleResolver&, const CSSValue&);
@@ -255,6 +257,14 @@ inline Length StyleBuilderConverter::convertLengthMaxSizing(const StyleResolver&
     return convertLengthSizing(styleResolver, value);
 }
 
+inline TabSize StyleBuilderConverter::convertTabSize(const StyleResolver& styleResolver, const CSSValue& value)
+{
+    auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+    if (primitiveValue.isNumber())
+        return TabSize(primitiveValue.floatValue(), SpaceValueType);
+    return TabSize(primitiveValue.computeLength<float>(styleResolver.state().cssToLengthConversionData()), LengthValueType);
+}
+
 template<typename T>
 inline T StyleBuilderConverter::convertComputedLength(StyleResolver& styleResolver, const CSSValue& value)
 {
index 8407504..b7471dd 100644 (file)
@@ -1121,9 +1121,12 @@ static RefPtr<CSSValue> consumeWordSpacing(CSSParserTokenRange& range, CSSParser
     return consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow);
 }
     
-static RefPtr<CSSValue> consumeTabSize(CSSParserTokenRange& range, CSSParserMode)
+static RefPtr<CSSValue> consumeTabSize(CSSParserTokenRange& range, CSSParserMode cssParserMode)
 {
-    return consumeInteger(range, 0);
+    auto tabSize = consumeNumber(range, ValueRangeNonNegative);
+    if (tabSize)
+        return tabSize;
+    return consumeLength(range, cssParserMode, ValueRangeNonNegative);
 }
 
 #if ENABLE(TEXT_AUTOSIZING)
index efe74b5..bc6b590 100644 (file)
@@ -57,7 +57,7 @@ LayoutUnit TextUtil::width(const InlineBox& inlineBox, unsigned from, unsigned t
     if (measureWithEndSpace)
         ++to;
     LayoutUnit width;
-    auto tabWidth = style.collapseWhiteSpace() ? 0 : style.tabSize();
+    auto tabWidth = style.collapseWhiteSpace() ? TabSize(0) : style.tabSize();
 
     WebCore::TextRun run(StringView(text).substring(from, to - from), contentLogicalLeft);
     if (tabWidth)
index e766f33..22be5ea 100644 (file)
@@ -149,8 +149,8 @@ public:
 
     const FontMetrics& fontMetrics() const { return primaryFont().fontMetrics(); }
     float spaceWidth() const { return primaryFont().spaceWidth() + m_letterSpacing; }
-    float tabWidth(const Font&, unsigned tabSize, float position) const;
-    float tabWidth(unsigned tabSize, float position) const { return tabWidth(primaryFont(), tabSize, position); }
+    float tabWidth(const Font&, const TabSize&, float) const;
+    float tabWidth(const TabSize& tabSize, float position) const { return tabWidth(primaryFont(), tabSize, position); }
     bool hasValidAverageCharWidth() const;
     bool fastAverageCharWidthIfAvailable(float &width) const; // returns true on success
 
@@ -354,13 +354,13 @@ inline FontSelector* FontCascade::fontSelector() const
     return m_fonts ? m_fonts->fontSelector() : nullptr;
 }
 
-inline float FontCascade::tabWidth(const Font& font, unsigned tabSize, float position) const
+inline float FontCascade::tabWidth(const Font& font, const TabSize& tabSize, float position) const
 {
-    if (!tabSize)
+    float baseTabWidth = tabSize.widthInPixels(font.spaceWidth());
+    if (!baseTabWidth)
         return letterSpacing();
-    float tabWidth = tabSize * font.spaceWidth() + letterSpacing();
-    float tabDeltaWidth = tabWidth - fmodf(position, tabWidth);
-    return (tabDeltaWidth < font.spaceWidth() / 2) ? tabWidth : tabDeltaWidth;
+    float tabDeltaWidth = baseTabWidth - fmodf(position, baseTabWidth);
+    return (tabDeltaWidth < font.spaceWidth() / 2) ? baseTabWidth : tabDeltaWidth;
 }
 
 }
diff --git a/Source/WebCore/platform/graphics/TabSize.h b/Source/WebCore/platform/graphics/TabSize.h
new file mode 100644 (file)
index 0000000..fdd1c68
--- /dev/null
@@ -0,0 +1,72 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright (C) 2019 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * 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.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER 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
+
+namespace WebCore {
+
+enum TabSizeValueType {
+    LengthValueType,
+    SpaceValueType,
+};
+
+struct TabSize {
+    TabSize(float numOrLength, TabSizeValueType isSpaces = SpaceValueType)
+        : m_value(numOrLength)
+        , m_isSpaces(isSpaces)
+    {
+    }
+
+    bool isSpaces() const
+    {
+        return m_isSpaces;
+    }
+
+    float widthInPixels(float spaceWidth) const
+    {
+        return m_isSpaces ? m_value * spaceWidth : m_value;
+    }
+
+    operator bool() const { return m_value; }
+
+    float m_value;
+    bool m_isSpaces;
+};
+
+inline bool operator==(const TabSize& a, const TabSize& b)
+{
+    return (a.m_value == b.m_value) && (a.m_isSpaces == b.m_isSpaces);
+}
+
+inline bool operator!=(const TabSize& a, const TabSize& b)
+{
+    return !(a == b);
+}
+
+} // namespace WebCore
index f9c6586..63e6638 100644 (file)
@@ -30,7 +30,7 @@ namespace WebCore {
 
 struct ExpectedTextRunSize {
     String text;
-    unsigned integer1;
+    TabSize tabSize;
     float float1;
     float float2;
     float float3;
index 80d2817..5f1066c 100644 (file)
@@ -24,6 +24,7 @@
 #ifndef TextRun_h
 #define TextRun_h
 
+#include "TabSize.h"
 #include "TextFlags.h"
 #include "WritingMode.h"
 #include <wtf/text/StringView.h>
@@ -95,8 +96,8 @@ public:
     void setHorizontalGlyphStretch(float scale) { m_horizontalGlyphStretch = scale; }
 
     bool allowTabs() const { return m_allowTabs; }
-    unsigned tabSize() const { return m_tabSize; }
-    void setTabSize(bool, unsigned);
+    const TabSize& tabSize() const { return m_tabSize; }
+    void setTabSize(bool, const TabSize&);
 
     float xPos() const { return m_xpos; }
     void setXPos(float xPos) { m_xpos = xPos; }
@@ -118,7 +119,7 @@ public:
 private:
     String m_text;
 
-    unsigned m_tabSize;
+    TabSize m_tabSize;
 
     // m_xpos is the x position relative to the left start of the text line, not relative to the left
     // start of the containing block. In the case of right alignment or center alignment, left start of
@@ -136,7 +137,7 @@ private:
     unsigned m_disableSpacing : 1;
 };
 
-inline void TextRun::setTabSize(bool allow, unsigned size)
+inline void TextRun::setTabSize(bool allow, const TabSize& size)
 {
     m_allowTabs = allow;
     m_tabSize = size;
index b8e5d01..e445d56 100644 (file)
@@ -49,7 +49,7 @@ TextFragmentIterator::Style::Style(const RenderStyle& style)
     , breakNBSP(wrapLines && style.nbspMode() == NBSPMode::Space)
     , keepAllWordsForCJK(style.wordBreak() == WordBreak::KeepAll)
     , wordSpacing(font.wordSpacing())
-    , tabWidth(collapseWhitespace ? 0 : style.tabSize())
+    , tabWidth(collapseWhitespace ? TabSize(0) : style.tabSize())
     , shouldHyphenate(style.hyphens() == Hyphens::Auto && canHyphenate(style.locale()))
     , hyphenStringWidth(shouldHyphenate ? font.width(TextRun(String(style.hyphenString()))) : 0)
     , hyphenLimitBefore(style.hyphenationLimitBefore() < 0 ? 2 : style.hyphenationLimitBefore())
index 13dfdf4..9ecfd9d 100644 (file)
@@ -118,7 +118,7 @@ public:
         bool breakNBSP;
         bool keepAllWordsForCJK;
         float wordSpacing;
-        unsigned tabWidth;
+        TabSize tabWidth;
         bool shouldHyphenate;
         float hyphenStringWidth;
         unsigned hyphenLimitBefore;
index fcf069c..9dc0414 100644 (file)
@@ -661,7 +661,7 @@ public:
     TextCombine textCombine() const { return static_cast<TextCombine>(m_rareNonInheritedData->textCombine); }
     bool hasTextCombine() const { return textCombine() != TextCombine::None; }
 
-    unsigned tabSize() const { return m_rareInheritedData->tabSize; }
+    const TabSize& tabSize() const { return m_rareInheritedData->tabSize; }
 
     // End CSS3 Getters
 
@@ -1190,7 +1190,7 @@ public:
     void setBackdropFilter(const FilterOperations& ops) { SET_NESTED_VAR(m_rareNonInheritedData, backdropFilter, operations, ops); }
 #endif
 
-    void setTabSize(unsigned size) { SET_VAR(m_rareInheritedData, tabSize, size); }
+    void setTabSize(TabSize size) { SET_VAR(m_rareInheritedData, tabSize, size); }
 
     void setBreakBefore(BreakBetween breakBehavior) { SET_VAR(m_rareNonInheritedData, breakBefore, static_cast<unsigned>(breakBehavior)); }
     void setBreakAfter(BreakBetween breakBehavior) { SET_VAR(m_rareNonInheritedData, breakAfter, static_cast<unsigned>(breakBehavior)); }
@@ -1672,7 +1672,7 @@ public:
     static GridPosition initialGridItemRowStart() { return GridPosition(); }
     static GridPosition initialGridItemRowEnd() { return GridPosition(); }
 
-    static unsigned initialTabSize() { return 8; }
+    static TabSize initialTabSize() { return 8; }
 
     static const AtomicString& initialLineGrid() { return nullAtom(); }
     static LineSnap initialLineSnap() { return LineSnap::None; }
index 899873d..1f22a1a 100644 (file)
@@ -50,7 +50,7 @@ struct GreaterThanOrSameSizeAsStyleRareInheritedData : public RefCounted<Greater
     TextDecorationThickness thickness;
     unsigned bitfields[4];
     short pagedMediaShorts[2];
-    unsigned unsigneds[1];
+    TabSize tabSize;
     short hyphenationShorts[3];
 
 #if PLATFORM(IOS_FAMILY)
index a0332d8..e5c5943 100644 (file)
@@ -28,6 +28,7 @@
 #include "DataRef.h"
 #include "Length.h"
 #include "StyleCustomPropertyData.h"
+#include "TabSize.h"
 #include "TextDecorationThickness.h"
 #include "TextUnderlineOffset.h"
 #include <wtf/RefCounted.h>
@@ -172,7 +173,7 @@ public:
     DataRef<StyleFilterData> appleColorFilter;
 
     AtomicString lineGrid;
-    unsigned tabSize;
+    TabSize tabSize;
 
 #if ENABLE(TEXT_AUTOSIZING)
     TextSizeAdjustment textSizeAdjust;