Skip to content
Permalink
Browse files
font shorthand should reset more longhands
https://bugs.webkit.org/show_bug.cgi?id=246912
rdar://101486558

Reviewed by Tim Nguyen.

https://drafts.csswg.org/css-fonts/#font-prop
"All subproperties of the font property are first reset to their initial values"

There are multiple things done here:
1) Add more longhands to font shorthand for all "subproperties of font property" listed.
2) Change style building code to reset them to initial values.
3) Change computed style code to make an empty font shorthand when any of these have non-initial values.
4) Use CSSPrimitiveValue for font-style keywords without angles, rather than CSSFontStyleValue.
5) Renamed CSSFontStyleValue to CSSFontStyleWithAngleValue.

The change (4) simplifies some code. The legacy CSS object model doesn't otherwise represent a
simple keyword as a CSSValue subclass. In an earlier version of this work, the rest of the
changes depended on this, but at this point it's just a separate improvement.

* LayoutTests/fast/css/font-shorthand-expected.txt: Updated since many more properties are set
to initial by the font shorthand now.

* LayoutTests/fast/css/font-systemFontID-parsing-expected.txt: Updated since the test is changed,
but also to expect a wrong result due to a bug we haven't fixed: "font: caption" does not serialize.
* LayoutTests/fast/css/font-systemFontID-parsing.html: Updated to match what's specified, where
font-family and other font subproperties do not reflect system fonts, which can only be specified
with the font shorthand (which makes it not quite a shorthand).

* LayoutTests/fast/inspector-support/style-expected.txt: Updated since many more properties are set
to initial by the font shorthand now.

* LayoutTests/fast/text/font-stretch-parse-expected.txt: Updated.
* LayoutTests/fast/text/font-stretch-parse.html: Updated to expect font shorthand to serialize
as empty string when font-stretch is set to a value font shorthand can't express.

* LayoutTests/fast/text/font-style-parse-expected.txt: Updated.
* LayoutTests/fast/text/font-style-parse.html: Updated to expect font shorthand to serialize
as empty string when font-stretch is set to a value font shorthand can't express. Also took
out "window." so test is slightly less wordy.

* LayoutTests/imported/w3c/web-platform-tests/css/css-fonts/font-palette-vs-shorthand-expected.txt:
Expect all PASS instead of FAIL.

* LayoutTests/imported/w3c/web-platform-tests/css/css-fonts/system-fonts-serialization.tentative-expected.txt:
Expect a different failure; this test expects all subproperties of font to serialize as the
empty string when the font property is set to a system font. This change doesn't do that for
all of them, so the test doesn't pass yet, but it fails later.

* LayoutTests/imported/w3c/web-platform-tests/css/cssom/font-shorthand-serialization-expected.txt:
Updated since the font shorthand now affects so many more font subproperties. The test is still
failing because we haven't added the font shorthand to the StyleProperties::asTextInternal function,
and this will need to remain until we revise editing code to not depend on current behavior.

* LayoutTests/platform/win/fast/css/font-shorthand-expected.txt: Added. This is different because
PLATFORM(WIN) doesn't yet support variation fonts.
* LayoutTests/platform/win/fast/inspector-support/style-expected.txt: Added. Ditto.

* LayoutTests/svg/css/getComputedStyle-basic-expected.txt: Updated since font-style is now a
CSSPrimitiveValue instead of a CSSFontStyleValue, web-exposed in the legacy CSS object model.

* Source/WebCore/Sources.txt: Renamed to CSSFontStyleWithAngleValue.
* Source/WebCore/WebCore.xcodeproj/project.pbxproj: Ditto.

* Source/WebCore/css/CSSFontFace.cpp:
(WebCore::calculateItalicRange): Instead of explicitly checking for CSSFontStyleValue, just call
BuilderConverter::convertFontStyleFromValue on anything other than a CSSFontStyleRangeValue. This
makes this function work with CSSPrimitiveValue, and it's nicer for encapsulation since this
already needs to know about the CSSFontStyleRangeValue class.

* Source/WebCore/css/CSSFontFaceSet.cpp: Removed include of CSSFontStyleValue.h.

* Source/WebCore/css/CSSFontStyleWithAngleValue.cpp: Renamed from Source/WebCore/css/CSSFontStyleValue.cpp.
(WebCore::CSSFontStyleValue::CSSFontStyleValue): Moved out of header.
Also only take a single primitive value for oblique angle.
(WebCore::CSSFontStyleValue::create): Ditto.
(WebCore::CSSFontStyleValue::customCSSText const): Updated since this class is now only used for
oblique with an angle. Also use makeString instead of StringBuilder.
(WebCore::CSSFontStyleValue::equals const): Updated since class is now only used for oblique
with an angle.
* Source/WebCore/css/CSSFontStyleWithAngleValue.h: Renamed from Source/WebCore/css/CSSFontStyleValue.h.
Changed this to a class that just stores oblique with a non-optional angle since we now use
CSSPrimitiveValue directly for keywords without angles. Also removed isItalicOrOblique function,
since this is an editing heuristic that should have been using italicThreshold, not italicValue
anyway. Moved logic into editing code. For coding style reasons, added an obliqueAngle getter
and made data members private.

* Source/WebCore/css/CSSFontValue.cpp: Updated include for CSSFontStyleWithAngleValue change.
* Source/WebCore/css/CSSFontValue.h: Changed style member to CSSValue since it can now be
either a CSSPrimitiveValue or a CSSFontStyleValue.

* Source/WebCore/css/CSSProperties.json: Added all new longhands for all subproperties of
the font shorthand. Used an order that seems logical. Strangely, the order of longhands
is web-exposed so should probably be standardized and tested.

* Source/WebCore/css/CSSValue.cpp: Updated for CSSFontStyleWithAngleValue change.
* Source/WebCore/css/CSSValue.h: Ditto.

* Source/WebCore/css/ComputedStyleExtractor.cpp:
(WebCore::fontStyle): Changed return type to CSSValue since this can return a primitive value.
Revised to only return a CSSFontStyleValue when an angle is specified.
(WebCore::fontShorthandValueForSelectionProperties): Deleted. Merged into new fontShorthandValue.
(WebCore::fontShorthandValue): Added. Implements rule for when to compute as empty, when any
longhand property is not expressible by shorthand. This separates those rules from actual
code that builds serializable value, which can now be more straightforward.
(WebCore::ComputedStyleExtractor::valueForPropertyInStyle): Call fontShorthandValue for CSSPropertFont.

* Source/WebCore/css/StyleProperties.cpp:
(WebCore::StyleProperties::fontValue const): Added a FIXME because while there are no tests
covering it, there may need to be some additional work here to make sure that font is serialized
as empty string in specified style in case where font subproperties other than the ones checked
here are set.
(WebCore::StyleProperties::getPropertyCSSValue const): Added code to return nullptr for system
font shorthands. A better solution is likely to use a different CSSValue class for these, but
that will require changes in many other places.
(WebCore::StyleProperties::asTextInternal const): Added more font subproperty longhands and
revise the comment to make it more clear that we do indeed want to support the font shorthand
once we make it so the editing code no longer relies on it.

* Source/WebCore/css/makeprop.pl: Support properties that are not enabled, but are shorthands
for a longhand that is enabled. The example of this right now is font-optical-sizing.

* Source/WebCore/css/parser/CSSPropertyParser.cpp:
(WebCore::CSSPropertyParser::consumeSystemFont): Deleted. Merged into consumeFont.
(WebCore::CSSPropertyParser::consumeFont): Rearranged this function so all parsing comes first,
then all properties are added in a single block at the end. Added some local lambdas so that code
is shorter and much easier to read. Made this single function handle system fonts too so more code
can be shared, including all the new font subproperties.
(WebCore::CSSPropertyParser::parseShorthand): Updated to remove call to consumeSystemFont.

* Source/WebCore/css/parser/CSSPropertyParser.h: Removed consumeSystemFont.

* Source/WebCore/css/parser/CSSPropertyParserWorkerSafe.cpp:
(WebCore::CSSPropertyParserHelpersWorkerSafe::consumeFontStyle): Changed return type to CSSValue
since this can return a primitive value. Revised to only return a CSSFontStyleWithAngleValue when
an angle is specified.

* Source/WebCore/css/parser/CSSPropertyParserWorkerSafe.h: Updated return type of consumeFontStyle.

* Source/WebCore/editing/EditingStyle.cpp:
(WebCore::identifierForStyleProperty): Moved italic threshold logic out of CSSFontStyleValue
into this function, where it can be alongside similar bold threshold logic. Rearranged the code
a bit to be tighter, and added a comment.
(WebCore::StyleChange::extractTextStyles): Removed check for CSSValueOblique because
identifierForStyleProperty can never return CSSValueOblique. That was true before these changes
and remains true.

* Source/WebCore/style/StyleBuilderConverter.h:
(WebCore::Style::BuilderConverter::convertFontStretchFromValue): Updated to handle system
font keyword. Turns out the correct code path was already there and only an assertion needed
to be changed.
(WebCore::Style::BuilderConverter::convertFontStyleFromValue): Updated to handle keywords
specified as CSSPrimitiveValue.

* Source/WebCore/style/StyleBuilderCustom.h:
(WebCore::Style::applyFontStyle): Added. Helper so we don't copy the entire FontDescription
if we aren't changing it.
(WebCore::Style::BuilderCustom::applyInitialFontStyle): Use applyFontStyle.
(WebCore::Style::BuilderCustom::applyValueFontStyle): Ditto.
(WebCore::Style::BuilderCustom::applyValueFontStyle): Updated to handle keywords specified as
CSSPrimitiveValue, retaining support for system font shorthands. Use applyFontStyle.

* Tools/Scripts/do-webcore-rename: Used this for renaming.

Canonical link: https://commits.webkit.org/256349@main
  • Loading branch information
darinadler committed Nov 5, 2022
1 parent 6115b38 commit 9de002d111c74dfffa39582a67d6af89b9abf21c
Show file tree
Hide file tree
Showing 36 changed files with 759 additions and 399 deletions.

Large diffs are not rendered by default.

@@ -3,8 +3,10 @@ Tests 'font' CSS property parsing with system font values.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".


PASS testDivInvalid.style.getPropertyCSSValue('font') is null
FAIL testDivValid.style.getPropertyCSSValue('font') should be caption (of type string). Was null (of type object).
PASS testDivInvalid.style.getPropertyCSSValue('font-family') is null
PASS testDivValid.style.getPropertyCSSValue('font-family') is not null
PASS testDivValid.style.getPropertyCSSValue('font-family') is null
PASS successfullyParsed is true

TEST COMPLETE
@@ -6,9 +6,10 @@
<div id="testDivValid" style="font: caption"></div>
<script>
description("Tests 'font' CSS property parsing with system font values.");

shouldBeNull("testDivInvalid.style.getPropertyCSSValue('font')");
shouldBeEqualToString("testDivValid.style.getPropertyCSSValue('font')", "caption");
shouldBeNull("testDivInvalid.style.getPropertyCSSValue('font-family')");
shouldNotBe("testDivValid.style.getPropertyCSSValue('font-family')", "null");
shouldBeNull("testDivValid.style.getPropertyCSSValue('font-family')");
</script>
<script src="../../resources/js-test-post.js"></script>
</body>
@@ -14,11 +14,22 @@ margin-right: 1em (original property was margin and property was implicitly set.
margin-bottom: 1em (original property was margin and property was implicitly set.)
margin-left: 1em (original property was margin and property was implicitly set.)
color: white
font-style: normal (original property was font and property was implicitly set.)
font-variant-caps: normal (original property was font and property was implicitly set.)
font-weight: normal (original property was font and property was implicitly set.)
font-stretch: normal (original property was font and property was implicitly set.)
font-style: initial (original property was font and property was implicitly set.)
font-variant-caps: initial (original property was font and property was implicitly set.)
font-weight: initial (original property was font and property was implicitly set.)
font-stretch: initial (original property was font and property was implicitly set.)
font-size: 24px (original property was font)
line-height: normal (original property was font and property was implicitly set.)
line-height: initial (original property was font and property was implicitly set.)
font-family: "Lucida Grande" (original property was font)
font-size-adjust: initial (original property was font and property was implicitly set.)
font-kerning: initial (original property was font and property was implicitly set.)
font-variant-alternates: initial (original property was font and property was implicitly set.)
font-variant-ligatures: initial (original property was font and property was implicitly set.)
font-variant-numeric: initial (original property was font and property was implicitly set.)
font-variant-east-asian: initial (original property was font and property was implicitly set.)
font-variant-position: initial (original property was font and property was implicitly set.)
font-feature-settings: initial (original property was font and property was implicitly set.)
font-optical-sizing: initial (original property was font and property was implicitly set.)
font-variation-settings: initial (original property was font and property was implicitly set.)
font-palette: initial (original property was font and property was implicitly set.)

@@ -20,7 +20,7 @@ PASS getComputedStyle(document.getElementById('test19')).fontStretch is "100%"
PASS getComputedStyle(document.getElementById('test20')).fontStretch is "150%"
PASS getComputedStyle(document.getElementById('test21')).fontStretch is "7%"
PASS getComputedStyle(document.getElementById('test1')).font is "16px / 18px Times"
PASS getComputedStyle(document.getElementById('test2')).font is "16px / 18px Times"
PASS getComputedStyle(document.getElementById('test2')).font is ""
PASS getComputedStyle(document.getElementById('test3')).font is "16px / 18px Times"
PASS getComputedStyle(document.getElementById('test4')).font is "ultra-condensed 16px / 18px Times"
PASS getComputedStyle(document.getElementById('test5')).font is "extra-condensed 16px / 18px Times"
@@ -39,7 +39,7 @@ PASS getComputedStyle(document.getElementById('test17')).font is "100 extra-cond
PASS getComputedStyle(document.getElementById('test18')).font is "100 48px / 49px \"Helvetica Neue\""
PASS getComputedStyle(document.getElementById('test19')).font is "100 48px / 49px \"Helvetica Neue\""
PASS getComputedStyle(document.getElementById('test20')).font is "italic small-caps 100 extra-expanded 48px / 49px \"Helvetica Neue\""
PASS getComputedStyle(document.getElementById('test21')).font is "16px / 18px Times"
PASS getComputedStyle(document.getElementById('test21')).font is ""
PASS document.getElementById('test1').style.font is ""
PASS document.getElementById('test16').style.font is "100 extra-condensed 48px / 49px \"Helvetica Neue\""
PASS document.getElementById('test17').style.font is "100 extra-condensed 48px / 49px \"Helvetica Neue\""
@@ -51,7 +51,7 @@
shouldBeEqualToString("getComputedStyle(document.getElementById('test21')).fontStretch", "7%");

shouldBeEqualToString("getComputedStyle(document.getElementById('test1')).font", "16px / 18px Times");
shouldBeEqualToString("getComputedStyle(document.getElementById('test2')).font", "16px / 18px Times");
shouldBeEqualToString("getComputedStyle(document.getElementById('test2')).font", "");
shouldBeEqualToString("getComputedStyle(document.getElementById('test3')).font", "16px / 18px Times");
shouldBeEqualToString("getComputedStyle(document.getElementById('test4')).font", "ultra-condensed 16px / 18px Times");
shouldBeEqualToString("getComputedStyle(document.getElementById('test5')).font", "extra-condensed 16px / 18px Times");
@@ -70,7 +70,7 @@
shouldBeEqualToString("getComputedStyle(document.getElementById('test18')).font", `100 48px / 49px "Helvetica Neue"`);
shouldBeEqualToString("getComputedStyle(document.getElementById('test19')).font", `100 48px / 49px "Helvetica Neue"`);
shouldBeEqualToString("getComputedStyle(document.getElementById('test20')).font", `italic small-caps 100 extra-expanded 48px / 49px "Helvetica Neue"`);
shouldBeEqualToString("getComputedStyle(document.getElementById('test21')).font", "16px / 18px Times");
shouldBeEqualToString("getComputedStyle(document.getElementById('test21')).font", "");

shouldBeEqualToString("document.getElementById('test1').style.font", "");
shouldBeEqualToString("document.getElementById('test16').style.font", `100 extra-condensed 48px / 49px "Helvetica Neue"`);
@@ -1,47 +1,47 @@
PASS window.getComputedStyle(document.getElementById('test1')).fontStyle is "normal"
PASS window.getComputedStyle(document.getElementById('test2')).fontStyle is "oblique 1deg"
PASS window.getComputedStyle(document.getElementById('test3')).fontStyle is "oblique 18deg"
PASS window.getComputedStyle(document.getElementById('test4')).fontStyle is "oblique 16deg"
PASS window.getComputedStyle(document.getElementById('test5')).fontStyle is "oblique 14.25deg"
PASS window.getComputedStyle(document.getElementById('test6')).fontStyle is "normal"
PASS window.getComputedStyle(document.getElementById('test7')).fontStyle is "normal"
PASS window.getComputedStyle(document.getElementById('test8')).fontStyle is "italic"
PASS window.getComputedStyle(document.getElementById('test9')).fontStyle is "oblique"
PASS window.getComputedStyle(document.getElementById('test10')).fontStyle is "normal"
PASS window.getComputedStyle(document.getElementById('test11')).fontStyle is "normal"
PASS window.getComputedStyle(document.getElementById('test12')).fontStyle is "normal"
PASS window.getComputedStyle(document.getElementById('test13')).fontStyle is "normal"
PASS window.getComputedStyle(document.getElementById('test14')).fontStyle is "oblique 15.25deg"
PASS window.getComputedStyle(document.getElementById('test15')).fontStyle is "italic"
PASS window.getComputedStyle(document.getElementById('test16')).fontStyle is "italic"
PASS window.getComputedStyle(document.getElementById('test17')).fontStyle is "normal"
PASS window.getComputedStyle(document.getElementById('test18')).fontStyle is "italic"
PASS window.getComputedStyle(document.getElementById('test19')).fontStyle is "italic"
PASS window.getComputedStyle(document.getElementById('test20')).fontStyle is "normal"
PASS window.getComputedStyle(document.getElementById('test21')).fontStyle is "oblique 14deg"
PASS window.getComputedStyle(document.getElementById('test22')).fontStyle is "oblique"
PASS window.getComputedStyle(document.getElementById('test1')).font is "16px / 18px Times"
PASS window.getComputedStyle(document.getElementById('test2')).font is "16px / 18px Times"
PASS window.getComputedStyle(document.getElementById('test3')).font is "16px / 18px Times"
PASS window.getComputedStyle(document.getElementById('test4')).font is "16px / 18px Times"
PASS window.getComputedStyle(document.getElementById('test5')).font is "16px / 18px Times"
PASS window.getComputedStyle(document.getElementById('test6')).font is "16px / 18px Times"
PASS window.getComputedStyle(document.getElementById('test7')).font is "16px / 18px Times"
PASS window.getComputedStyle(document.getElementById('test8')).font is "italic 16px / 18px Times"
PASS window.getComputedStyle(document.getElementById('test9')).font is "oblique 16px / 18px Times"
PASS window.getComputedStyle(document.getElementById('test10')).font is "16px / 18px Times"
PASS window.getComputedStyle(document.getElementById('test11')).font is "16px / 18px Times"
PASS window.getComputedStyle(document.getElementById('test12')).font is "16px / 18px Times"
PASS window.getComputedStyle(document.getElementById('test13')).font is "16px / 18px Times"
PASS window.getComputedStyle(document.getElementById('test14')).font is "16px / 18px Times"
PASS window.getComputedStyle(document.getElementById('test15')).font is "italic 100 48px / 49px \"Helvetica Neue\""
PASS window.getComputedStyle(document.getElementById('test16')).font is "italic 100 48px / 49px \"Helvetica Neue\""
PASS window.getComputedStyle(document.getElementById('test17')).font is "100 48px / 49px \"Helvetica Neue\""
PASS window.getComputedStyle(document.getElementById('test18')).font is "italic 48px / 49px \"Helvetica Neue\""
PASS window.getComputedStyle(document.getElementById('test19')).font is "italic small-caps 100 extra-expanded 48px / 49px \"Helvetica Neue\""
PASS window.getComputedStyle(document.getElementById('test20')).font is "16px / 18px Times"
PASS window.getComputedStyle(document.getElementById('test21')).font is "48px / 49px \"Helvetica Neue\""
PASS window.getComputedStyle(document.getElementById('test22')).font is "oblique 16px / 18px Times"
PASS getComputedStyle(document.getElementById('test1')).fontStyle is "normal"
PASS getComputedStyle(document.getElementById('test2')).fontStyle is "oblique 1deg"
PASS getComputedStyle(document.getElementById('test3')).fontStyle is "oblique 18deg"
PASS getComputedStyle(document.getElementById('test4')).fontStyle is "oblique 16deg"
PASS getComputedStyle(document.getElementById('test5')).fontStyle is "oblique 14.25deg"
PASS getComputedStyle(document.getElementById('test6')).fontStyle is "normal"
PASS getComputedStyle(document.getElementById('test7')).fontStyle is "normal"
PASS getComputedStyle(document.getElementById('test8')).fontStyle is "italic"
PASS getComputedStyle(document.getElementById('test9')).fontStyle is "oblique"
PASS getComputedStyle(document.getElementById('test10')).fontStyle is "normal"
PASS getComputedStyle(document.getElementById('test11')).fontStyle is "normal"
PASS getComputedStyle(document.getElementById('test12')).fontStyle is "normal"
PASS getComputedStyle(document.getElementById('test13')).fontStyle is "normal"
PASS getComputedStyle(document.getElementById('test14')).fontStyle is "oblique 15.25deg"
PASS getComputedStyle(document.getElementById('test15')).fontStyle is "italic"
PASS getComputedStyle(document.getElementById('test16')).fontStyle is "italic"
PASS getComputedStyle(document.getElementById('test17')).fontStyle is "normal"
PASS getComputedStyle(document.getElementById('test18')).fontStyle is "italic"
PASS getComputedStyle(document.getElementById('test19')).fontStyle is "italic"
PASS getComputedStyle(document.getElementById('test20')).fontStyle is "normal"
PASS getComputedStyle(document.getElementById('test21')).fontStyle is "oblique 14deg"
PASS getComputedStyle(document.getElementById('test22')).fontStyle is "oblique"
PASS getComputedStyle(document.getElementById('test1')).font is "16px / 18px Times"
PASS getComputedStyle(document.getElementById('test2')).font is ""
PASS getComputedStyle(document.getElementById('test3')).font is ""
PASS getComputedStyle(document.getElementById('test4')).font is ""
PASS getComputedStyle(document.getElementById('test5')).font is ""
PASS getComputedStyle(document.getElementById('test6')).font is "16px / 18px Times"
PASS getComputedStyle(document.getElementById('test7')).font is "16px / 18px Times"
PASS getComputedStyle(document.getElementById('test8')).font is "italic 16px / 18px Times"
PASS getComputedStyle(document.getElementById('test9')).font is "oblique 16px / 18px Times"
PASS getComputedStyle(document.getElementById('test10')).font is "16px / 18px Times"
PASS getComputedStyle(document.getElementById('test11')).font is "16px / 18px Times"
PASS getComputedStyle(document.getElementById('test12')).font is "16px / 18px Times"
PASS getComputedStyle(document.getElementById('test13')).font is "16px / 18px Times"
PASS getComputedStyle(document.getElementById('test14')).font is ""
PASS getComputedStyle(document.getElementById('test15')).font is "italic 100 48px / 49px \"Helvetica Neue\""
PASS getComputedStyle(document.getElementById('test16')).font is "italic 100 48px / 49px \"Helvetica Neue\""
PASS getComputedStyle(document.getElementById('test17')).font is "100 48px / 49px \"Helvetica Neue\""
PASS getComputedStyle(document.getElementById('test18')).font is "italic 48px / 49px \"Helvetica Neue\""
PASS getComputedStyle(document.getElementById('test19')).font is "italic small-caps 100 extra-expanded 48px / 49px \"Helvetica Neue\""
PASS getComputedStyle(document.getElementById('test20')).font is "16px / 18px Times"
PASS getComputedStyle(document.getElementById('test21')).font is ""
PASS getComputedStyle(document.getElementById('test22')).font is "oblique 16px / 18px Times"
PASS document.getElementById('test1').style.font is ""
PASS document.getElementById('test15').style.font is "italic 100 48px / 49px \"Helvetica Neue\""
PASS document.getElementById('test16').style.font is "italic 100 48px / 49px \"Helvetica Neue\""

0 comments on commit 9de002d

Please sign in to comment.