[Cocoa] [Font Features] Implement font-variant-*
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 Sep 2015 00:40:53 +0000 (00:40 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 Sep 2015 00:40:53 +0000 (00:40 +0000)
https://bugs.webkit.org/show_bug.cgi?id=148413

Reviewed by Darin Adler.

Source/WebCore:

This patch is the first pass of implementing of the font-variant-* properties. Specifically,
these properties are:
font-variant-ligatures
font-variant-position
font-variant-caps
font-variant-numeric
font-variant-alternates
font-variant-east-asian

These new properties are held inside FontDescription as bit fields. At font creation time,
we consult with the FontDescription to figure out which variants are specified. We then
convert those variants to font features, and resolve these font features with the additional
features specified by font-feature-settings (as the spec requires). This patch also makes
our caches sensitive to these new properties of FontDescription so we don't look up cached,
stale fonts.

The implementation has some caveats, however. They are listed here:
1. These new properties need to interact correctly with @font-face declarations. In
particular, only certain properties of the FontDescription should be considered when
detecting if a @font-face declaration applies to a particular element. This discrimination
does not happen correctly. In addition, any feature-specific CSS properties inside the
@font-face declaration need to be consulted at a particular point during the feature
resolve. This does not currently occur.
2. One of the properties, font-variant-alternates, has a few values which require custom
CSS functions, which makes modeling the properties as bit fields tricky. These extra values
need to be implemented. This patch implements all the values which do not require extra CSS
features.
3. These new properties have a shorthand, font-variant, which is designed to be backward-
compatible with CSS 2.1's concept of font-variant. In particular, CSS 2.1 allows you to use
"normal" and "small-caps" with font-variant. Both of these values are values of the new
property font-variant-caps. However, our existing implementation of small-caps does not
use font features when they exist; instead, it simply draws text at a smaller font size and
uses (effectively) text-transform to force capital letters. This implementation needs to be
unified with the new font-variant-caps property so that we can expand font-variant to be
a shorthand for the new properties.
4. font-variant-position and font-variant-caps should provide appropriate synthesis if no
matching font-feature exists.
5. FontCascade::typesettingFeatures() is now no-longer accurate. Fixing this would be large
enough to warrant its own patch.
6. These properties are not tested with TrueType fonts.

Tests: css3/font-variant-all-webfont.html
       css3/font-variant-parsing.html

* css/CSSComputedStyleDeclaration.cpp: Reconstruct StyleProperties from a RenderStyle.
(WebCore::appendLigaturesValue):
(WebCore::fontVariantLigaturesPropertyValue):
(WebCore::fontVariantPositionPropertyValue):
(WebCore::fontVariantCapsPropertyValue):
(WebCore::fontVariantNumericPropertyValue):
(WebCore::fontVariantAlternatesPropertyValue):
(WebCore::fontVariantEastAsianPropertyValue):
(WebCore::ComputedStyleExtractor::propertyValue):
* css/CSSFontFeatureValue.cpp: Update to FontFeatureTag instead of WTF::String.
(WebCore::CSSFontFeatureValue::CSSFontFeatureValue):
(WebCore::CSSFontFeatureValue::customCSSText):
* css/CSSFontFeatureValue.h: Ditto.
(WebCore::CSSFontFeatureValue::create):
(WebCore::CSSFontFeatureValue::tag):
* css/CSSParser.cpp: Parse the new properties according to the CSS3 fonts spec.
(WebCore::isValidKeywordPropertyAndValue):
(WebCore::isKeywordPropertyID):
(WebCore::CSSParser::parseValue):
(WebCore::CSSParser::parseFontFeatureTag):
(WebCore::CSSParser::parseFontVariantLigatures):
(WebCore::CSSParser::parseFontVariantNumeric):
(WebCore::CSSParser::parseFontVariantEastAsian):
* css/CSSParser.h:
* css/CSSPrimitiveValueMappings.h: For the three properties which are simple keyword value
properties, implement casting operators to automatically convert between RenderStyle
objects and CSS property objects.
(WebCore::CSSPrimitiveValue::CSSPrimitiveValue):
(WebCore::CSSPrimitiveValue::operator FontVariantPosition):
(WebCore::CSSPrimitiveValue::operator FontVariantCaps):
(WebCore::CSSPrimitiveValue::operator FontVariantAlternates):
* css/CSSPropertyNames.in: New properties.
* css/CSSValueKeywords.in: New values.
* css/StyleBuilderConverter.h:
(WebCore::StyleBuilderConverter::convertFontFeatureSettings): Update to not use
RefPtrs.
* css/StyleBuilderCustom.h: Properties which are not simple keyword value properties are
decomposed into multiple members of FontDescription. These properties exist to convert
between these aggregate members and the CSS properties.
(WebCore::StyleBuilderCustom::applyInheritFontVariantLigatures):
(WebCore::StyleBuilderCustom::applyInitialFontVariantLigatures):
(WebCore::StyleBuilderCustom::applyValueFontVariantLigatures):
(WebCore::StyleBuilderCustom::applyInheritFontVariantNumeric):
(WebCore::StyleBuilderCustom::applyInitialFontVariantNumeric):
(WebCore::StyleBuilderCustom::applyValueFontVariantNumeric):
(WebCore::StyleBuilderCustom::applyInheritFontVariantEastAsian):
(WebCore::StyleBuilderCustom::applyInitialFontVariantEastAsian):
(WebCore::StyleBuilderCustom::applyValueFontVariantEastAsian):
(WebCore::StyleBuilderCustom::applyInitialWebkitFontVariantLigatures): Deleted.
(WebCore::StyleBuilderCustom::applyInheritWebkitFontVariantLigatures): Deleted.
(WebCore::StyleBuilderCustom::applyValueWebkitFontVariantLigatures): Deleted.
* editing/cocoa/HTMLConverter.mm:
(HTMLConverter::computedAttributesForElement): Unprefix font-variant-ligatures.
* platform/graphics/FontCache.h: Update cache to be sensitive to new state in
FontDescription.
(WebCore::FontDescriptionKey::FontDescriptionKey):
(WebCore::FontDescriptionKey::operator==):
(WebCore::FontDescriptionKey::computeHash):
(WebCore::FontDescriptionKey::makeFlagsKey):
(WebCore::FontDescriptionKey::makeFlagKey): Deleted.
* platform/graphics/FontCascade.cpp:
(WebCore::FontCascade::codePath): These new variants should trigger the complex text
codepath.
* platform/graphics/FontCascade.h:
(WebCore::FontCascade::computeTypesettingFeatures): Update to use new state enum.
* platform/graphics/FontDescription.cpp: Add state to hold new property values.
(WebCore::FontDescription::FontDescription):
(WebCore::FontCascadeDescription::FontCascadeDescription): Deleted.
* platform/graphics/FontDescription.h: Add state to hold new property values.
(WebCore::FontDescription::featureSettings):
(WebCore::FontDescription::variantCommonLigatures):
(WebCore::FontDescription::variantDiscretionaryLigatures):
(WebCore::FontDescription::variantHistoricalLigatures):
(WebCore::FontDescription::variantContextualAlternates):
(WebCore::FontDescription::variantPosition):
(WebCore::FontDescription::variantCaps):
(WebCore::FontDescription::variantNumericFigure):
(WebCore::FontDescription::variantNumericSpacing):
(WebCore::FontDescription::variantNumericFraction):
(WebCore::FontDescription::variantNumericOrdinal):
(WebCore::FontDescription::variantNumericSlashedZero):
(WebCore::FontDescription::variantAlternates):
(WebCore::FontDescription::variantEastAsianVariant):
(WebCore::FontDescription::variantEastAsianWidth):
(WebCore::FontDescription::variantEastAsianRuby):
(WebCore::FontDescription::variantSettings):
(WebCore::FontDescription::setFeatureSettings):
(WebCore::FontDescription::setVariantCommonLigatures):
(WebCore::FontDescription::setVariantDiscretionaryLigatures):
(WebCore::FontDescription::setVariantHistoricalLigatures):
(WebCore::FontDescription::setVariantContextualAlternates):
(WebCore::FontDescription::setVariantPosition):
(WebCore::FontDescription::setVariantCaps):
(WebCore::FontDescription::setVariantNumericFigure):
(WebCore::FontDescription::setVariantNumericSpacing):
(WebCore::FontDescription::setVariantNumericFraction):
(WebCore::FontDescription::setVariantNumericOrdinal):
(WebCore::FontDescription::setVariantNumericSlashedZero):
(WebCore::FontDescription::setVariantAlternates):
(WebCore::FontDescription::setVariantEastAsianVariant):
(WebCore::FontDescription::setVariantEastAsianWidth):
(WebCore::FontDescription::setVariantEastAsianRuby):
(WebCore::FontDescription::operator==):
(WebCore::FontCascadeDescription::initialVariantPosition):
(WebCore::FontCascadeDescription::initialVariantCaps):
(WebCore::FontCascadeDescription::initialVariantAlternates):
(WebCore::FontCascadeDescription::commonLigaturesState): Deleted.
(WebCore::FontCascadeDescription::discretionaryLigaturesState): Deleted.
(WebCore::FontCascadeDescription::historicalLigaturesState): Deleted.
(WebCore::FontCascadeDescription::setCommonLigaturesState): Deleted.
(WebCore::FontCascadeDescription::setDiscretionaryLigaturesState): Deleted.
(WebCore::FontCascadeDescription::setHistoricalLigaturesState): Deleted.
(WebCore::FontCascadeDescription::operator==): Deleted.
* platform/graphics/FontFeatureSettings.cpp: Update to use FontFeatureTag instead of
WTF::String.
(WebCore::FontFeature::FontFeature):
(WebCore::FontFeature::operator==):
(WebCore::FontFeature::operator<):
(WebCore::FontFeatureSettings::hash):
(WebCore::FontFeatureSettings::create): Deleted.
* platform/graphics/FontFeatureSettings.h: Update to use FontFeatureTag instead of
WTF::String.
(WebCore::fontFeatureTag):
(WebCore::FontFeatureTagHash::hash):
(WebCore::FontFeatureTagHash::equal):
(WebCore::FontFeatureTagHashTraits::constructDeletedValue):
(WebCore::FontFeatureTagHashTraits::isDeletedValue):
(WebCore::FontFeature::tag):
(WebCore::FontFeatureSettings::operator==):
(WebCore::FontFeatureSettings::begin):
(WebCore::FontFeatureSettings::end):
(WebCore::FontFeatureSettings::FontFeatureSettings): Deleted.
* platform/graphics/cocoa/FontCacheCoreText.cpp: Ditto. Also, when computing font
features, consult with the state inside FontDescription.
(WebCore::tagEquals):
(WebCore::appendTrueTypeFeature):
(WebCore::appendOpenTypeFeature):
(WebCore::computeFeatureSettingsFromVariants):
(WebCore::preparePlatformFont):
(WebCore::platformFontLookupWithFamily):
(WebCore::fontWithFamily):
(WebCore::FontCache::createFontPlatformData):
(WebCore::FontCache::systemFallbackForCharacters):
* platform/graphics/harfbuzz/HarfBuzzShaper.cpp: Update to use references instead of
pointers.
(WebCore::HarfBuzzShaper::setFontFeatures):
* platform/graphics/mac/FontCacheMac.mm:
(WebCore::platformFontWithFamily): Ditto.
* platform/graphics/mac/FontCustomPlatformData.cpp:
(WebCore::FontCustomPlatformData::fontPlatformData): Be sensitive to new state inside FontDescription.
* platform/text/TextFlags.h:
(WebCore::FontVariantSettings::isAllNormal): New state enums.
* rendering/RenderThemeIOS.mm:
(WebCore::RenderThemeIOS::updateCachedSystemFontDescription): Be sensitive to new state inside
FontDescription.
* rendering/line/BreakingContext.h:

Tools:

Update test font to use "lnum" feature.

* FontWithFeatures/FontWithFeatures/FontCreator.cpp:
(Generator::appendGSUBTable):

LayoutTests:

Updating tests because font-variant-ligatures is being unprefixed.

Also, update css3/resources/FontWithFeatures.otf to support "lnum" feature.

* css3/font-feature-settings-rendering-2-expected.html:
* css3/font-feature-settings-rendering-2.html:
* css3/font-variant-all-webfont-expected.html: Added.
* css3/font-variant-all-webfont.html: Added.
* css3/font-variant-parsing-expected.txt: Added.
* css3/font-variant-parsing.html: Added.
* css3/resources/FontWithFeatures.otf:
* fast/css/getComputedStyle/computed-style-expected.txt:
* fast/css/getComputedStyle/computed-style-font-family-expected.txt:
* fast/css/getComputedStyle/computed-style-without-renderer-expected.txt:
* fast/css/getComputedStyle/resources/property-names.js:
* fast/css/parsing-font-variant-ligatures.html:
* fast/text/font-variant-ligatures.html:
* platform/mac/TestExpectations:
* svg/css/getComputedStyle-basic-expected.txt:

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

44 files changed:
LayoutTests/ChangeLog
LayoutTests/css3/font-feature-settings-rendering-2-expected.html
LayoutTests/css3/font-feature-settings-rendering-2.html
LayoutTests/css3/font-variant-all-webfont-expected.html [new file with mode: 0644]
LayoutTests/css3/font-variant-all-webfont.html [new file with mode: 0644]
LayoutTests/css3/font-variant-parsing-expected.txt [new file with mode: 0644]
LayoutTests/css3/font-variant-parsing.html [new file with mode: 0644]
LayoutTests/css3/resources/FontWithFeatures.otf
LayoutTests/fast/css/getComputedStyle/computed-style-expected.txt
LayoutTests/fast/css/getComputedStyle/computed-style-font-family-expected.txt
LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-expected.txt
LayoutTests/fast/css/getComputedStyle/resources/property-names.js
LayoutTests/fast/css/parsing-font-variant-ligatures.html
LayoutTests/fast/text/font-variant-ligatures.html
LayoutTests/platform/mac/TestExpectations
LayoutTests/svg/css/getComputedStyle-basic-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/css/CSSComputedStyleDeclaration.cpp
Source/WebCore/css/CSSFontFeatureValue.cpp
Source/WebCore/css/CSSFontFeatureValue.h
Source/WebCore/css/CSSParser.cpp
Source/WebCore/css/CSSParser.h
Source/WebCore/css/CSSPrimitiveValueMappings.h
Source/WebCore/css/CSSPropertyNames.in
Source/WebCore/css/CSSValueKeywords.in
Source/WebCore/css/StyleBuilderConverter.h
Source/WebCore/css/StyleBuilderCustom.h
Source/WebCore/editing/cocoa/HTMLConverter.mm
Source/WebCore/platform/graphics/FontCache.h
Source/WebCore/platform/graphics/FontCascade.cpp
Source/WebCore/platform/graphics/FontCascade.h
Source/WebCore/platform/graphics/FontDescription.cpp
Source/WebCore/platform/graphics/FontDescription.h
Source/WebCore/platform/graphics/FontFeatureSettings.cpp
Source/WebCore/platform/graphics/FontFeatureSettings.h
Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp
Source/WebCore/platform/graphics/harfbuzz/HarfBuzzShaper.cpp
Source/WebCore/platform/graphics/mac/FontCacheMac.mm
Source/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
Source/WebCore/platform/text/TextFlags.h
Source/WebCore/rendering/RenderThemeIOS.mm
Source/WebCore/rendering/line/BreakingContext.h
Tools/ChangeLog
Tools/FontWithFeatures/FontWithFeatures/FontCreator.cpp

index 1e4bdbc..bd6bc9b 100644 (file)
@@ -1,3 +1,30 @@
+2015-09-23  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [Cocoa] [Font Features] Implement font-variant-*
+        https://bugs.webkit.org/show_bug.cgi?id=148413
+
+        Reviewed by Darin Adler.
+
+        Updating tests because font-variant-ligatures is being unprefixed.
+
+        Also, update css3/resources/FontWithFeatures.otf to support "lnum" feature.
+
+        * css3/font-feature-settings-rendering-2-expected.html:
+        * css3/font-feature-settings-rendering-2.html:
+        * css3/font-variant-all-webfont-expected.html: Added.
+        * css3/font-variant-all-webfont.html: Added.
+        * css3/font-variant-parsing-expected.txt: Added.
+        * css3/font-variant-parsing.html: Added.
+        * css3/resources/FontWithFeatures.otf:
+        * fast/css/getComputedStyle/computed-style-expected.txt:
+        * fast/css/getComputedStyle/computed-style-font-family-expected.txt:
+        * fast/css/getComputedStyle/computed-style-without-renderer-expected.txt:
+        * fast/css/getComputedStyle/resources/property-names.js:
+        * fast/css/parsing-font-variant-ligatures.html:
+        * fast/text/font-variant-ligatures.html:
+        * platform/mac/TestExpectations:
+        * svg/css/getComputedStyle-basic-expected.txt:
+
 2015-09-23  Chris Dumez  <cdumez@apple.com>
 
         Unreviewed, roll out r190085 as it seems to cause crashes in JSC
index 2822c05..a002260 100644 (file)
@@ -41,6 +41,7 @@ marks and X below.
 <span style="font-family: FontFeaturesTest;">BA</span>
 <span style="font-family: FontFeaturesTest;">BA</span>
 <span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
 </div>
 </body>
 </html>
index f552425..34d0a2c 100644 (file)
@@ -38,23 +38,24 @@ addElement("pcap", "L");
 addElement("c2pc", "M");
 addElement("unic", "N");
 addElement("titl", "O");
-addElement("onum", "P");
-addElement("pnum", "Q");
-addElement("tnum", "R");
-addElement("frac", "S");
-//addElement("afrc", "T");
-addElement("ordn", "U");
-addElement("zero", "V");
-addElement("hist", "W");
-addElement("jp78", "X");
-addElement("jp83", "Y");
-addElement("jp90", "Z");
-addElement("jp04", "a");
-addElement("smpl", "b");
-addElement("trad", "c");
-addElement("fwid", "d");
-addElement("pwid", "e");
-addElement("ruby", "f");
+addElement("lnum", "P");
+addElement("onum", "Q");
+addElement("pnum", "R");
+addElement("tnum", "S");
+addElement("frac", "T");
+//addElement("afrc", "U");
+addElement("ordn", "V");
+addElement("zero", "W");
+addElement("hist", "X");
+addElement("jp78", "Y");
+addElement("jp83", "Z");
+addElement("jp90", "a");
+addElement("jp04", "b");
+addElement("smpl", "c");
+addElement("trad", "d");
+addElement("fwid", "e");
+addElement("pwid", "f");
+addElement("ruby", "g");
 </script>
 </body>
 </html>
diff --git a/LayoutTests/css3/font-variant-all-webfont-expected.html b/LayoutTests/css3/font-variant-all-webfont-expected.html
new file mode 100644 (file)
index 0000000..34aaa64
--- /dev/null
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+@font-face {
+    font-family: "FontFeaturesTest";
+    src: url("resources/FontWithFeatures.otf") format("opentype");
+}
+</style>
+</head>
+<body>
+<p>This test is a dump-render-tree test which makes sure that the following properties are appropriately applied:</p>
+<ul>
+<li>-webkit-font-variant-ligatures</li>
+<li>-webkit-font-variant-position</li>
+<li>-webkit-font-variant-caps</li>
+<li>-webkit-font-variant-numeric</li>
+<li>-webkit-font-variant-alternates</li>
+<li>-webkit-font-variant-east-asian</li>
+</ul>
+The test passes if there is a particular sequence of checks and x characters below. Note that some x characters are expected.
+<div id="insertionpoint"><span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">B</span>
+<span style="font-family: FontFeaturesTest;">B</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">B</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">B</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">B</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+<span style="font-family: FontFeaturesTest;">A</span>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/css3/font-variant-all-webfont.html b/LayoutTests/css3/font-variant-all-webfont.html
new file mode 100644 (file)
index 0000000..9b980eb
--- /dev/null
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+@font-face {
+    font-family: "FontFeaturesTest";
+    src: url("resources/FontWithFeatures.otf") format("opentype");
+}
+</style>
+</head>
+<body>
+<p>This test is a dump-render-tree test which makes sure that the following properties are appropriately applied:</p>
+<ul>
+<li>-webkit-font-variant-ligatures</li>
+<li>-webkit-font-variant-position</li>
+<li>-webkit-font-variant-caps</li>
+<li>-webkit-font-variant-numeric</li>
+<li>-webkit-font-variant-alternates</li>
+<li>-webkit-font-variant-east-asian</li>
+</ul>
+The test passes if there is a particular sequence of checks and x characters below. Note that some x characters are expected.
+<div id="insertionpoint"></div>
+<script>
+var insertionpoint = document.getElementById("insertionpoint");
+function addElement(property, value, text) {
+    var element = document.createElement("span");
+    element.textContent = text;
+    element.setAttribute("style", "font-family: FontFeaturesTest; " + property + ": " + value + ";");
+    insertionpoint.appendChild(element);
+    insertionpoint.appendChild(document.createTextNode(" "));
+}
+addElement("font-variant-ligatures", "common-ligatures", "C");
+addElement("font-variant-ligatures", "common-ligatures", "D");
+addElement("font-variant-ligatures", "no-common-ligatures", "C");
+addElement("font-variant-ligatures", "no-common-ligatures", "D");
+addElement("font-variant-ligatures", "discretionary-ligatures", "E");
+addElement("font-variant-ligatures", "no-discretionary-ligatures", "E");
+addElement("font-variant-ligatures", "historical-ligatures", "F");
+addElement("font-variant-ligatures", "no-historical-ligatures", "F");
+addElement("font-variant-ligatures", "contextual", "G");
+addElement("font-variant-ligatures", "no-contextual", "G");
+addElement("font-variant-position", "sub", "H");
+addElement("font-variant-position", "super", "I");
+addElement("font-variant-caps", "small-caps", "J");
+addElement("font-variant-caps", "all-small-caps", "K");
+addElement("font-variant-caps", "petite-caps", "L");
+addElement("font-variant-caps", "all-petite-caps", "M");
+addElement("font-variant-caps", "unicase", "N");
+addElement("font-variant-caps", "titling-caps", "O");
+addElement("font-variant-numeric", "lining-nums", "P");
+addElement("font-variant-numeric", "oldstyle-nums", "Q");
+addElement("font-variant-numeric", "proportional-nums", "R");
+addElement("font-variant-numeric", "tabular-nums", "S");
+addElement("font-variant-numeric", "diagonal-fractions", "T");
+//addElement("font-variant-numeric", "stacked-fractions", "U");
+addElement("font-variant-numeric", "ordinal", "V");
+addElement("font-variant-numeric", "slashed-zero", "W");
+addElement("font-variant-alternates", "historical-forms", "X");
+addElement("font-variant-east-asian", "jis78", "Y");
+addElement("font-variant-east-asian", "jis83", "Z");
+addElement("font-variant-east-asian", "jis90", "a");
+addElement("font-variant-east-asian", "jis04", "b");
+addElement("font-variant-east-asian", "simplified", "c");
+addElement("font-variant-east-asian", "traditional", "d");
+addElement("font-variant-east-asian", "full-width", "e");
+addElement("font-variant-east-asian", "proportional-width", "f");
+addElement("font-variant-east-asian", "ruby", "g");
+</script>
+</body>
+</html>
diff --git a/LayoutTests/css3/font-variant-parsing-expected.txt b/LayoutTests/css3/font-variant-parsing-expected.txt
new file mode 100644 (file)
index 0000000..b774d8a
--- /dev/null
@@ -0,0 +1,87 @@
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-ligatures').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-ligatures').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-ligatures').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-ligatures').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-ligatures').cssText is "common-ligatures"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-ligatures').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-ligatures').cssText is "no-common-ligatures"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-ligatures').cssText is "discretionary-ligatures"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-ligatures').cssText is "no-discretionary-ligatures"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-ligatures').cssText is "historical-ligatures"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-ligatures').cssText is "no-historical-ligatures"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-ligatures').cssText is "contextual"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-ligatures').cssText is "no-contextual"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-ligatures').cssText is "common-ligatures no-contextual"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-ligatures').cssText is "common-ligatures no-contextual"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-ligatures').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-ligatures').cssText is "none"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-ligatures').cssText is "none"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-position').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-position').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-position').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-position').cssText is "sub"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-position').cssText is "super"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-position').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-caps').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-caps').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-caps').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-caps').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-caps').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-caps').cssText is "small-caps"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-caps').cssText is "all-small-caps"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-caps').cssText is "petite-caps"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-caps').cssText is "all-petite-caps"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-caps').cssText is "unicase"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-caps').cssText is "titling-caps"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-caps').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-caps').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "lining-nums"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "oldstyle-nums"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "proportional-nums"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "tabular-nums"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "diagonal-fractions"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "stacked-fractions"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "ordinal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "slashed-zero"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "lining-nums slashed-zero"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "lining-nums proportional-nums"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "lining-nums diagonal-fractions"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-numeric').cssText is "ordinal slashed-zero"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-alternates').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-alternates').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-alternates').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-alternates').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-alternates').cssText is "historical-forms"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-alternates').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "jis78"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "jis83"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "jis90"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "jis04"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "simplified"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "traditional"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "full-width"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "proportional-width"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "ruby"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "normal"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "traditional full-width"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "jis04 proportional-width"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "jis04 proportional-width ruby"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "jis83 ruby"
+PASS window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('font-variant-east-asian').cssText is "normal"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/css3/font-variant-parsing.html b/LayoutTests/css3/font-variant-parsing.html
new file mode 100644 (file)
index 0000000..9fcd818
--- /dev/null
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+function runTest(property, propertyText, expectedText) {
+    var element = document.createElement("span");
+    element.setAttribute("id", "testElement");
+    if (property != "")
+        element.setAttribute("style", property + ": " + propertyText + ";");
+    document.body.appendChild(element);
+    shouldBeEqualToString("window.getComputedStyle(document.getElementById('testElement')).getPropertyCSSValue('" + property + "').cssText", expectedText);
+    document.body.removeChild(element);
+}
+
+runTest("font-variant-ligatures", "", "normal");
+runTest("font-variant-ligatures", "normal", "normal");
+runTest("font-variant-ligatures", "normal common-ligatures", "normal");
+runTest("font-variant-ligatures", "notavalidvalue", "normal");
+runTest("font-variant-ligatures", "common-ligatures", "common-ligatures");
+runTest("font-variant-ligatures", "common-ligatures common-ligatures", "normal");
+runTest("font-variant-ligatures", "no-common-ligatures", "no-common-ligatures");
+runTest("font-variant-ligatures", "discretionary-ligatures", "discretionary-ligatures");
+runTest("font-variant-ligatures", "no-discretionary-ligatures", "no-discretionary-ligatures");
+runTest("font-variant-ligatures", "historical-ligatures", "historical-ligatures");
+runTest("font-variant-ligatures", "no-historical-ligatures", "no-historical-ligatures");
+runTest("font-variant-ligatures", "contextual", "contextual");
+runTest("font-variant-ligatures", "no-contextual", "no-contextual");
+runTest("font-variant-ligatures", "common-ligatures no-contextual", "common-ligatures no-contextual");
+runTest("font-variant-ligatures", "no-contextual common-ligatures", "common-ligatures no-contextual");
+runTest("font-variant-ligatures", "no-contextual common-ligatures notavalidvalue", "normal");
+runTest("font-variant-ligatures", "none", "none");
+runTest("font-variant-ligatures", "no-common-ligatures no-discretionary-ligatures no-historical-ligatures no-contextual", "none");
+
+runTest("font-variant-position", "", "normal");
+runTest("font-variant-position", "normal", "normal");
+runTest("font-variant-position", "notavalidvalue", "normal");
+runTest("font-variant-position", "sub", "sub");
+runTest("font-variant-position", "super", "super");
+runTest("font-variant-position", "sub super", "normal");
+
+runTest("font-variant-caps", "", "normal");
+runTest("font-variant-caps", "normal", "normal");
+runTest("font-variant-caps", "notavalidvalue", "normal");
+runTest("font-variant-caps", "normal notavalidvalue", "normal");
+runTest("font-variant-caps", "normal small-caps", "normal");
+runTest("font-variant-caps", "small-caps", "small-caps");
+runTest("font-variant-caps", "all-small-caps", "all-small-caps");
+runTest("font-variant-caps", "petite-caps", "petite-caps");
+runTest("font-variant-caps", "all-petite-caps", "all-petite-caps");
+runTest("font-variant-caps", "unicase", "unicase");
+runTest("font-variant-caps", "titling-caps", "titling-caps");
+runTest("font-variant-caps", "unicase titling-caps", "normal");
+runTest("font-variant-caps", "small-caps all-small-caps", "normal");
+
+runTest("font-variant-numeric", "", "normal");
+runTest("font-variant-numeric", "normal", "normal");
+runTest("font-variant-numeric", "notavalidvalue", "normal");
+runTest("font-variant-numeric", "normal notavalidvalue", "normal");
+runTest("font-variant-numeric", "normal lining-nums", "normal");
+runTest("font-variant-numeric", "lining-nums", "lining-nums");
+runTest("font-variant-numeric", "oldstyle-nums", "oldstyle-nums");
+runTest("font-variant-numeric", "proportional-nums", "proportional-nums");
+runTest("font-variant-numeric", "tabular-nums", "tabular-nums");
+runTest("font-variant-numeric", "diagonal-fractions", "diagonal-fractions");
+runTest("font-variant-numeric", "stacked-fractions", "stacked-fractions");
+runTest("font-variant-numeric", "ordinal", "ordinal");
+runTest("font-variant-numeric", "slashed-zero", "slashed-zero");
+runTest("font-variant-numeric", "lining-nums slashed-zero", "lining-nums slashed-zero");
+runTest("font-variant-numeric", "lining-nums oldstyle-nums", "normal");
+runTest("font-variant-numeric", "proportional-nums tabular-nums", "normal");
+runTest("font-variant-numeric", "diagonal-fractions stacked-fractions", "normal");
+runTest("font-variant-numeric", "lining-nums proportional-nums", "lining-nums proportional-nums");
+runTest("font-variant-numeric", "lining-nums diagonal-fractions", "lining-nums diagonal-fractions");
+runTest("font-variant-numeric", "ordinal slashed-zero", "ordinal slashed-zero");
+
+runTest("font-variant-alternates", "", "normal");
+runTest("font-variant-alternates", "normal", "normal");
+runTest("font-variant-alternates", "notavalidvalue", "normal");
+runTest("font-variant-alternates", "normal notavalidvalue", "normal");
+runTest("font-variant-alternates", "historical-forms", "historical-forms");
+runTest("font-variant-alternates", "normal historical-forms", "normal");
+
+runTest("font-variant-east-asian", "", "normal");
+runTest("font-variant-east-asian", "normal", "normal");
+runTest("font-variant-east-asian", "notavalidvalue", "normal");
+runTest("font-variant-east-asian", "normal notavalidvalue", "normal");
+runTest("font-variant-east-asian", "jis78", "jis78");
+runTest("font-variant-east-asian", "jis83", "jis83");
+runTest("font-variant-east-asian", "jis90", "jis90");
+runTest("font-variant-east-asian", "jis04", "jis04");
+runTest("font-variant-east-asian", "simplified", "simplified");
+runTest("font-variant-east-asian", "traditional", "traditional");
+runTest("font-variant-east-asian", "full-width", "full-width");
+runTest("font-variant-east-asian", "proportional-width", "proportional-width");
+runTest("font-variant-east-asian", "ruby", "ruby");
+runTest("font-variant-east-asian", "jis78 jis83", "normal");
+runTest("font-variant-east-asian", "jis90 traditional", "normal");
+runTest("font-variant-east-asian", "full-width traditional", "traditional full-width");
+runTest("font-variant-east-asian", "jis04 proportional-width", "jis04 proportional-width");
+runTest("font-variant-east-asian", "jis04 proportional-width ruby", "jis04 proportional-width ruby");
+runTest("font-variant-east-asian", "jis83 ruby", "jis83 ruby");
+runTest("font-variant-east-asian", "full-width proportional-width", "normal");
+</script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
index e0bf4d5..a404a42 100644 (file)
Binary files a/LayoutTests/css3/resources/FontWithFeatures.otf and b/LayoutTests/css3/resources/FontWithFeatures.otf differ
index e181a74..ac233c0 100644 (file)
@@ -159,7 +159,12 @@ justify-self: start;
 justify-items: start;
 -webkit-font-kerning: auto;
 -webkit-font-smoothing: auto;
--webkit-font-variant-ligatures: normal;
+font-variant-ligatures: normal;
+font-variant-position: normal;
+font-variant-caps: normal;
+font-variant-numeric: normal;
+font-variant-alternates: normal;
+font-variant-east-asian: normal;
 -webkit-grid-auto-columns: auto;
 -webkit-grid-auto-flow: row;
 -webkit-grid-auto-rows: auto;
index 7580fa7..3e759e5 100644 (file)
@@ -6,4 +6,10 @@ font-style: normal;
 font-synthesis: style weight;
 font-variant: normal;
 font-weight: normal;
+font-variant-ligatures: normal;
+font-variant-position: normal;
+font-variant-caps: normal;
+font-variant-numeric: normal;
+font-variant-alternates: normal;
+font-variant-east-asian: normal;
 
index b92628c..ab39550 100644 (file)
@@ -158,7 +158,12 @@ justify-self: auto
 justify-items: auto
 -webkit-font-kerning: auto
 -webkit-font-smoothing: auto
--webkit-font-variant-ligatures: normal
+font-variant-ligatures: normal
+font-variant-position: normal
+font-variant-caps: normal
+font-variant-numeric: normal
+font-variant-alternates: normal
+font-variant-east-asian: normal
 -webkit-grid-auto-columns: auto
 -webkit-grid-auto-flow: row
 -webkit-grid-auto-rows: auto
index 93f5425..0c72bc7 100644 (file)
@@ -48,7 +48,6 @@ var propertiesToTest = {
     "flex-wrap": true,
     "-webkit-font-kerning": true,
     "-webkit-font-smoothing": true,
-    "-webkit-font-variant-ligatures": true,
     "-webkit-grid-auto-columns": true,
     "-webkit-grid-auto-flow": true,
     "-webkit-grid-auto-rows": true,
@@ -184,6 +183,12 @@ var propertiesToTest = {
     "font-style": true,
     "font-synthesis": true,
     "font-variant": true,
+    "font-variant-ligatures": true,
+    "font-variant-position": true,
+    "font-variant-caps": true,
+    "font-variant-numeric": true,
+    "font-variant-alternates": true,
+    "font-variant-east-asian": true,
     "font-weight": true,
     "glyph-orientation-horizontal": true,
     "glyph-orientation-vertical": true,
index ac6b70f..1facab5 100644 (file)
     function test(value, expectedCSSText, expectedComputedCSSText)
     {
         var element = document.createElement("div");
-        element.style.setProperty("-webkit-font-variant-ligatures", value);
-        var cssText = element.style.webkitFontVariantLigatures;
+        element.style.setProperty("font-variant-ligatures", value);
+        var cssText = element.style.fontVariantLigatures;
         document.body.appendChild(element);
-        var computedCSSText = getComputedStyle(element).webkitFontVariantLigatures;
+        var computedCSSText = getComputedStyle(element).fontVariantLigatures;
         document.body.removeChild(element);
         if (cssText === expectedCSSText && computedCSSText == expectedComputedCSSText)
             log("PASS: '" + value + "' parsed as '" + expectedCSSText + "' and computed to '" + computedCSSText + "'");
index 7f4a74b..d5ad02f 100644 (file)
@@ -1,7 +1,7 @@
 <style>
-    .common-ligatures-disabled { -webkit-font-variant-ligatures: no-common-ligatures; }
-    .common-ligatures-enabled { -webkit-font-variant-ligatures: common-ligatures; }
-    .common-ligatures-normal { -webkit-font-variant-ligatures: normal; }
+    .common-ligatures-disabled { font-variant-ligatures: no-common-ligatures; }
+    .common-ligatures-enabled { font-variant-ligatures: common-ligatures; }
+    .common-ligatures-normal { font-variant-ligatures: normal; }
 </style>
 <body style="font-size: 36px;">
     <div>
index ed87d1e..d7fa149 100644 (file)
@@ -262,6 +262,8 @@ fast/css/draggable-region-parser.html
 css3/font-feature-settings-rendering.html
 
 webkit.org/b/149246 [ Mavericks ] css3/font-feature-settings-rendering-2.html
+webkit.org/b/149246 [ Mavericks ] css3/font-variant-all-webfont.html
+webkit.org/b/149246 [ Mavericks ] css3/font-variant-parsing.html
 
 # This feature is disabled on Mavericks.
 [ Mavericks ] http/tests/navigation/page-cache-pending-image-load.html [ Skip ]
index c6a007c..9d87827 100644 (file)
@@ -316,8 +316,18 @@ rect: style.getPropertyValue(-webkit-font-kerning) : auto
 rect: style.getPropertyCSSValue(-webkit-font-kerning) : [object CSSPrimitiveValue]
 rect: style.getPropertyValue(-webkit-font-smoothing) : auto
 rect: style.getPropertyCSSValue(-webkit-font-smoothing) : [object CSSPrimitiveValue]
-rect: style.getPropertyValue(-webkit-font-variant-ligatures) : normal
-rect: style.getPropertyCSSValue(-webkit-font-variant-ligatures) : [object CSSPrimitiveValue]
+rect: style.getPropertyValue(font-variant-ligatures) : normal
+rect: style.getPropertyCSSValue(font-variant-ligatures) : [object CSSPrimitiveValue]
+rect: style.getPropertyValue(font-variant-position) : normal
+rect: style.getPropertyCSSValue(font-variant-position) : [object CSSPrimitiveValue]
+rect: style.getPropertyValue(font-variant-caps) : normal
+rect: style.getPropertyCSSValue(font-variant-caps) : [object CSSPrimitiveValue]
+rect: style.getPropertyValue(font-variant-numeric) : normal
+rect: style.getPropertyCSSValue(font-variant-numeric) : [object CSSPrimitiveValue]
+rect: style.getPropertyValue(font-variant-alternates) : normal
+rect: style.getPropertyCSSValue(font-variant-alternates) : [object CSSPrimitiveValue]
+rect: style.getPropertyValue(font-variant-east-asian) : normal
+rect: style.getPropertyCSSValue(font-variant-east-asian) : [object CSSPrimitiveValue]
 rect: style.getPropertyValue(-webkit-grid-auto-columns) : auto
 rect: style.getPropertyCSSValue(-webkit-grid-auto-columns) : [object CSSPrimitiveValue]
 rect: style.getPropertyValue(-webkit-grid-auto-flow) : row
@@ -840,8 +850,18 @@ g: style.getPropertyValue(-webkit-font-kerning) : auto
 g: style.getPropertyCSSValue(-webkit-font-kerning) : [object CSSPrimitiveValue]
 g: style.getPropertyValue(-webkit-font-smoothing) : auto
 g: style.getPropertyCSSValue(-webkit-font-smoothing) : [object CSSPrimitiveValue]
-g: style.getPropertyValue(-webkit-font-variant-ligatures) : normal
-g: style.getPropertyCSSValue(-webkit-font-variant-ligatures) : [object CSSPrimitiveValue]
+g: style.getPropertyValue(font-variant-ligatures) : normal
+g: style.getPropertyCSSValue(font-variant-ligatures) : [object CSSPrimitiveValue]
+g: style.getPropertyValue(font-variant-position) : normal
+g: style.getPropertyCSSValue(font-variant-position) : [object CSSPrimitiveValue]
+g: style.getPropertyValue(font-variant-caps) : normal
+g: style.getPropertyCSSValue(font-variant-caps) : [object CSSPrimitiveValue]
+g: style.getPropertyValue(font-variant-numeric) : normal
+g: style.getPropertyCSSValue(font-variant-numeric) : [object CSSPrimitiveValue]
+g: style.getPropertyValue(font-variant-alternates) : normal
+g: style.getPropertyCSSValue(font-variant-alternates) : [object CSSPrimitiveValue]
+g: style.getPropertyValue(font-variant-east-asian) : normal
+g: style.getPropertyCSSValue(font-variant-east-asian) : [object CSSPrimitiveValue]
 g: style.getPropertyValue(-webkit-grid-auto-columns) : auto
 g: style.getPropertyCSSValue(-webkit-grid-auto-columns) : [object CSSPrimitiveValue]
 g: style.getPropertyValue(-webkit-grid-auto-flow) : row
index 6fae535..0d007fd 100644 (file)
@@ -1,3 +1,211 @@
+2015-09-23  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [Cocoa] [Font Features] Implement font-variant-*
+        https://bugs.webkit.org/show_bug.cgi?id=148413
+
+        Reviewed by Darin Adler.
+
+        This patch is the first pass of implementing of the font-variant-* properties. Specifically,
+        these properties are:
+        font-variant-ligatures
+        font-variant-position
+        font-variant-caps
+        font-variant-numeric
+        font-variant-alternates
+        font-variant-east-asian
+
+        These new properties are held inside FontDescription as bit fields. At font creation time,
+        we consult with the FontDescription to figure out which variants are specified. We then
+        convert those variants to font features, and resolve these font features with the additional
+        features specified by font-feature-settings (as the spec requires). This patch also makes
+        our caches sensitive to these new properties of FontDescription so we don't look up cached,
+        stale fonts.
+
+        The implementation has some caveats, however. They are listed here:
+        1. These new properties need to interact correctly with @font-face declarations. In
+        particular, only certain properties of the FontDescription should be considered when
+        detecting if a @font-face declaration applies to a particular element. This discrimination
+        does not happen correctly. In addition, any feature-specific CSS properties inside the
+        @font-face declaration need to be consulted at a particular point during the feature
+        resolve. This does not currently occur.
+        2. One of the properties, font-variant-alternates, has a few values which require custom
+        CSS functions, which makes modeling the properties as bit fields tricky. These extra values
+        need to be implemented. This patch implements all the values which do not require extra CSS
+        features.
+        3. These new properties have a shorthand, font-variant, which is designed to be backward-
+        compatible with CSS 2.1's concept of font-variant. In particular, CSS 2.1 allows you to use
+        "normal" and "small-caps" with font-variant. Both of these values are values of the new
+        property font-variant-caps. However, our existing implementation of small-caps does not
+        use font features when they exist; instead, it simply draws text at a smaller font size and
+        uses (effectively) text-transform to force capital letters. This implementation needs to be
+        unified with the new font-variant-caps property so that we can expand font-variant to be
+        a shorthand for the new properties.
+        4. font-variant-position and font-variant-caps should provide appropriate synthesis if no
+        matching font-feature exists.
+        5. FontCascade::typesettingFeatures() is now no-longer accurate. Fixing this would be large
+        enough to warrant its own patch.
+        6. These properties are not tested with TrueType fonts.
+
+        Tests: css3/font-variant-all-webfont.html
+               css3/font-variant-parsing.html
+
+        * css/CSSComputedStyleDeclaration.cpp: Reconstruct StyleProperties from a RenderStyle.
+        (WebCore::appendLigaturesValue):
+        (WebCore::fontVariantLigaturesPropertyValue):
+        (WebCore::fontVariantPositionPropertyValue):
+        (WebCore::fontVariantCapsPropertyValue):
+        (WebCore::fontVariantNumericPropertyValue):
+        (WebCore::fontVariantAlternatesPropertyValue):
+        (WebCore::fontVariantEastAsianPropertyValue):
+        (WebCore::ComputedStyleExtractor::propertyValue):
+        * css/CSSFontFeatureValue.cpp: Update to FontFeatureTag instead of WTF::String.
+        (WebCore::CSSFontFeatureValue::CSSFontFeatureValue):
+        (WebCore::CSSFontFeatureValue::customCSSText):
+        * css/CSSFontFeatureValue.h: Ditto.
+        (WebCore::CSSFontFeatureValue::create):
+        (WebCore::CSSFontFeatureValue::tag):
+        * css/CSSParser.cpp: Parse the new properties according to the CSS3 fonts spec.
+        (WebCore::isValidKeywordPropertyAndValue):
+        (WebCore::isKeywordPropertyID):
+        (WebCore::CSSParser::parseValue):
+        (WebCore::CSSParser::parseFontFeatureTag):
+        (WebCore::CSSParser::parseFontVariantLigatures):
+        (WebCore::CSSParser::parseFontVariantNumeric):
+        (WebCore::CSSParser::parseFontVariantEastAsian):
+        * css/CSSParser.h:
+        * css/CSSPrimitiveValueMappings.h: For the three properties which are simple keyword value
+        properties, implement casting operators to automatically convert between RenderStyle
+        objects and CSS property objects.
+        (WebCore::CSSPrimitiveValue::CSSPrimitiveValue):
+        (WebCore::CSSPrimitiveValue::operator FontVariantPosition):
+        (WebCore::CSSPrimitiveValue::operator FontVariantCaps):
+        (WebCore::CSSPrimitiveValue::operator FontVariantAlternates):
+        * css/CSSPropertyNames.in: New properties.
+        * css/CSSValueKeywords.in: New values.
+        * css/StyleBuilderConverter.h:
+        (WebCore::StyleBuilderConverter::convertFontFeatureSettings): Update to not use
+        RefPtrs.
+        * css/StyleBuilderCustom.h: Properties which are not simple keyword value properties are
+        decomposed into multiple members of FontDescription. These properties exist to convert
+        between these aggregate members and the CSS properties.
+        (WebCore::StyleBuilderCustom::applyInheritFontVariantLigatures):
+        (WebCore::StyleBuilderCustom::applyInitialFontVariantLigatures):
+        (WebCore::StyleBuilderCustom::applyValueFontVariantLigatures):
+        (WebCore::StyleBuilderCustom::applyInheritFontVariantNumeric):
+        (WebCore::StyleBuilderCustom::applyInitialFontVariantNumeric):
+        (WebCore::StyleBuilderCustom::applyValueFontVariantNumeric):
+        (WebCore::StyleBuilderCustom::applyInheritFontVariantEastAsian):
+        (WebCore::StyleBuilderCustom::applyInitialFontVariantEastAsian):
+        (WebCore::StyleBuilderCustom::applyValueFontVariantEastAsian):
+        (WebCore::StyleBuilderCustom::applyInitialWebkitFontVariantLigatures): Deleted.
+        (WebCore::StyleBuilderCustom::applyInheritWebkitFontVariantLigatures): Deleted.
+        (WebCore::StyleBuilderCustom::applyValueWebkitFontVariantLigatures): Deleted.
+        * editing/cocoa/HTMLConverter.mm:
+        (HTMLConverter::computedAttributesForElement): Unprefix font-variant-ligatures.
+        * platform/graphics/FontCache.h: Update cache to be sensitive to new state in
+        FontDescription.
+        (WebCore::FontDescriptionKey::FontDescriptionKey):
+        (WebCore::FontDescriptionKey::operator==):
+        (WebCore::FontDescriptionKey::computeHash):
+        (WebCore::FontDescriptionKey::makeFlagsKey):
+        (WebCore::FontDescriptionKey::makeFlagKey): Deleted.
+        * platform/graphics/FontCascade.cpp:
+        (WebCore::FontCascade::codePath): These new variants should trigger the complex text
+        codepath.
+        * platform/graphics/FontCascade.h:
+        (WebCore::FontCascade::computeTypesettingFeatures): Update to use new state enum.
+        * platform/graphics/FontDescription.cpp: Add state to hold new property values.
+        (WebCore::FontDescription::FontDescription):
+        (WebCore::FontCascadeDescription::FontCascadeDescription): Deleted.
+        * platform/graphics/FontDescription.h: Add state to hold new property values.
+        (WebCore::FontDescription::featureSettings):
+        (WebCore::FontDescription::variantCommonLigatures):
+        (WebCore::FontDescription::variantDiscretionaryLigatures):
+        (WebCore::FontDescription::variantHistoricalLigatures):
+        (WebCore::FontDescription::variantContextualAlternates):
+        (WebCore::FontDescription::variantPosition):
+        (WebCore::FontDescription::variantCaps):
+        (WebCore::FontDescription::variantNumericFigure):
+        (WebCore::FontDescription::variantNumericSpacing):
+        (WebCore::FontDescription::variantNumericFraction):
+        (WebCore::FontDescription::variantNumericOrdinal):
+        (WebCore::FontDescription::variantNumericSlashedZero):
+        (WebCore::FontDescription::variantAlternates):
+        (WebCore::FontDescription::variantEastAsianVariant):
+        (WebCore::FontDescription::variantEastAsianWidth):
+        (WebCore::FontDescription::variantEastAsianRuby):
+        (WebCore::FontDescription::variantSettings):
+        (WebCore::FontDescription::setFeatureSettings):
+        (WebCore::FontDescription::setVariantCommonLigatures):
+        (WebCore::FontDescription::setVariantDiscretionaryLigatures):
+        (WebCore::FontDescription::setVariantHistoricalLigatures):
+        (WebCore::FontDescription::setVariantContextualAlternates):
+        (WebCore::FontDescription::setVariantPosition):
+        (WebCore::FontDescription::setVariantCaps):
+        (WebCore::FontDescription::setVariantNumericFigure):
+        (WebCore::FontDescription::setVariantNumericSpacing):
+        (WebCore::FontDescription::setVariantNumericFraction):
+        (WebCore::FontDescription::setVariantNumericOrdinal):
+        (WebCore::FontDescription::setVariantNumericSlashedZero):
+        (WebCore::FontDescription::setVariantAlternates):
+        (WebCore::FontDescription::setVariantEastAsianVariant):
+        (WebCore::FontDescription::setVariantEastAsianWidth):
+        (WebCore::FontDescription::setVariantEastAsianRuby):
+        (WebCore::FontDescription::operator==):
+        (WebCore::FontCascadeDescription::initialVariantPosition):
+        (WebCore::FontCascadeDescription::initialVariantCaps):
+        (WebCore::FontCascadeDescription::initialVariantAlternates):
+        (WebCore::FontCascadeDescription::commonLigaturesState): Deleted.
+        (WebCore::FontCascadeDescription::discretionaryLigaturesState): Deleted.
+        (WebCore::FontCascadeDescription::historicalLigaturesState): Deleted.
+        (WebCore::FontCascadeDescription::setCommonLigaturesState): Deleted.
+        (WebCore::FontCascadeDescription::setDiscretionaryLigaturesState): Deleted.
+        (WebCore::FontCascadeDescription::setHistoricalLigaturesState): Deleted.
+        (WebCore::FontCascadeDescription::operator==): Deleted.
+        * platform/graphics/FontFeatureSettings.cpp: Update to use FontFeatureTag instead of
+        WTF::String.
+        (WebCore::FontFeature::FontFeature):
+        (WebCore::FontFeature::operator==):
+        (WebCore::FontFeature::operator<):
+        (WebCore::FontFeatureSettings::hash):
+        (WebCore::FontFeatureSettings::create): Deleted.
+        * platform/graphics/FontFeatureSettings.h: Update to use FontFeatureTag instead of
+        WTF::String.
+        (WebCore::fontFeatureTag):
+        (WebCore::FontFeatureTagHash::hash):
+        (WebCore::FontFeatureTagHash::equal):
+        (WebCore::FontFeatureTagHashTraits::constructDeletedValue):
+        (WebCore::FontFeatureTagHashTraits::isDeletedValue):
+        (WebCore::FontFeature::tag):
+        (WebCore::FontFeatureSettings::operator==):
+        (WebCore::FontFeatureSettings::begin):
+        (WebCore::FontFeatureSettings::end):
+        (WebCore::FontFeatureSettings::FontFeatureSettings): Deleted.
+        * platform/graphics/cocoa/FontCacheCoreText.cpp: Ditto. Also, when computing font
+        features, consult with the state inside FontDescription.
+        (WebCore::tagEquals):
+        (WebCore::appendTrueTypeFeature):
+        (WebCore::appendOpenTypeFeature):
+        (WebCore::computeFeatureSettingsFromVariants):
+        (WebCore::preparePlatformFont):
+        (WebCore::platformFontLookupWithFamily):
+        (WebCore::fontWithFamily):
+        (WebCore::FontCache::createFontPlatformData):
+        (WebCore::FontCache::systemFallbackForCharacters):
+        * platform/graphics/harfbuzz/HarfBuzzShaper.cpp: Update to use references instead of
+        pointers.
+        (WebCore::HarfBuzzShaper::setFontFeatures):
+        * platform/graphics/mac/FontCacheMac.mm:
+        (WebCore::platformFontWithFamily): Ditto.
+        * platform/graphics/mac/FontCustomPlatformData.cpp:
+        (WebCore::FontCustomPlatformData::fontPlatformData): Be sensitive to new state inside FontDescription.
+        * platform/text/TextFlags.h:
+        (WebCore::FontVariantSettings::isAllNormal): New state enums.
+        * rendering/RenderThemeIOS.mm:
+        (WebCore::RenderThemeIOS::updateCachedSystemFontDescription): Be sensitive to new state inside
+        FontDescription.
+        * rendering/line/BreakingContext.h:
+
 2015-09-23  Chris Dumez  <cdumez@apple.com>
 
         Unreviewed, roll out r190085 as it seems to cause crashes in JSC
index c527b5a..5577e7b 100644 (file)
@@ -319,7 +319,12 @@ static const CSSPropertyID computedProperties[] = {
 #endif
     CSSPropertyWebkitFontKerning,
     CSSPropertyWebkitFontSmoothing,
-    CSSPropertyWebkitFontVariantLigatures,
+    CSSPropertyFontVariantLigatures,
+    CSSPropertyFontVariantPosition,
+    CSSPropertyFontVariantCaps,
+    CSSPropertyFontVariantNumeric,
+    CSSPropertyFontVariantAlternates,
+    CSSPropertyFontVariantEastAsian,
 #if ENABLE(CSS_GRID_LAYOUT)
     CSSPropertyWebkitGridAutoColumns,
     CSSPropertyWebkitGridAutoFlow,
@@ -1197,6 +1202,192 @@ static Ref<CSSValue> getWillChangePropertyValue(const WillChangeData* willChange
     return WTF::move(list);
 }
 
+static inline void appendLigaturesValue(CSSValueList& list, FontVariantLigatures value, CSSValueID yesValue, CSSValueID noValue)
+{
+    switch (value) {
+    case FontVariantLigatures::Normal:
+        return;
+    case FontVariantLigatures::No:
+        list.append(CSSValuePool::singleton().createIdentifierValue(noValue));
+        return;
+    case FontVariantLigatures::Yes:
+        list.append(CSSValuePool::singleton().createIdentifierValue(yesValue));
+        return;
+    }
+    ASSERT_NOT_REACHED();
+}
+
+static Ref<CSSValue> fontVariantLigaturesPropertyValue(FontVariantLigatures common, FontVariantLigatures discretionary, FontVariantLigatures historical, FontVariantLigatures contextualAlternates)
+{
+    auto& cssValuePool = CSSValuePool::singleton();
+    if (common == FontVariantLigatures::No && discretionary == FontVariantLigatures::No && historical == FontVariantLigatures::No && contextualAlternates == FontVariantLigatures::No)
+        return cssValuePool.createIdentifierValue(CSSValueNone);
+    if (common == FontVariantLigatures::Normal && discretionary == FontVariantLigatures::Normal && historical == FontVariantLigatures::Normal && contextualAlternates == FontVariantLigatures::Normal)
+        return cssValuePool.createIdentifierValue(CSSValueNormal);
+
+    auto valueList = CSSValueList::createSpaceSeparated();
+    appendLigaturesValue(valueList, common, CSSValueCommonLigatures, CSSValueNoCommonLigatures);
+    appendLigaturesValue(valueList, discretionary, CSSValueDiscretionaryLigatures, CSSValueNoDiscretionaryLigatures);
+    appendLigaturesValue(valueList, historical, CSSValueHistoricalLigatures, CSSValueNoHistoricalLigatures);
+    appendLigaturesValue(valueList, contextualAlternates, CSSValueContextual, CSSValueNoContextual);
+    return WTF::move(valueList);
+}
+
+static Ref<CSSValue> fontVariantPositionPropertyValue(FontVariantPosition position)
+{
+    auto& cssValuePool = CSSValuePool::singleton();
+    CSSValueID valueID = CSSValueNormal;
+    switch (position) {
+    case FontVariantPosition::Normal:
+        break;
+    case FontVariantPosition::Subscript:
+        valueID = CSSValueSub;
+        break;
+    case FontVariantPosition::Superscript:
+        valueID = CSSValueSuper;
+        break;
+    }
+    return cssValuePool.createIdentifierValue(valueID);
+}
+
+static Ref<CSSValue> fontVariantCapsPropertyValue(FontVariantCaps caps)
+{
+    auto& cssValuePool = CSSValuePool::singleton();
+    CSSValueID valueID = CSSValueNormal;
+    switch (caps) {
+    case FontVariantCaps::Normal:
+        break;
+    case FontVariantCaps::Small:
+        valueID = CSSValueSmallCaps;
+        break;
+    case FontVariantCaps::AllSmall:
+        valueID = CSSValueAllSmallCaps;
+        break;
+    case FontVariantCaps::Petite:
+        valueID = CSSValuePetiteCaps;
+        break;
+    case FontVariantCaps::AllPetite:
+        valueID = CSSValueAllPetiteCaps;
+        break;
+    case FontVariantCaps::Unicase:
+        valueID = CSSValueUnicase;
+        break;
+    case FontVariantCaps::Titling:
+        valueID = CSSValueTitlingCaps;
+        break;
+    }
+    return cssValuePool.createIdentifierValue(valueID);
+}
+
+static Ref<CSSValue> fontVariantNumericPropertyValue(FontVariantNumericFigure figure, FontVariantNumericSpacing spacing, FontVariantNumericFraction fraction, FontVariantNumericOrdinal ordinal, FontVariantNumericSlashedZero slashedZero)
+{
+    auto& cssValuePool = CSSValuePool::singleton();
+    if (figure == FontVariantNumericFigure::Normal && spacing == FontVariantNumericSpacing::Normal && fraction == FontVariantNumericFraction::Normal && ordinal == FontVariantNumericOrdinal::Normal && slashedZero == FontVariantNumericSlashedZero::Normal)
+        return cssValuePool.createIdentifierValue(CSSValueNormal);
+
+    auto valueList = CSSValueList::createSpaceSeparated();
+    switch (figure) {
+    case FontVariantNumericFigure::Normal:
+        break;
+    case FontVariantNumericFigure::LiningNumbers:
+        valueList->append(cssValuePool.createIdentifierValue(CSSValueLiningNums));
+        break;
+    case FontVariantNumericFigure::OldStyleNumbers:
+        valueList->append(cssValuePool.createIdentifierValue(CSSValueOldstyleNums));
+        break;
+    }
+
+    switch (spacing) {
+    case FontVariantNumericSpacing::Normal:
+        break;
+    case FontVariantNumericSpacing::ProportionalNumbers:
+        valueList->append(cssValuePool.createIdentifierValue(CSSValueProportionalNums));
+        break;
+    case FontVariantNumericSpacing::TabularNumbers:
+        valueList->append(cssValuePool.createIdentifierValue(CSSValueTabularNums));
+        break;
+    }
+
+    switch (fraction) {
+    case FontVariantNumericFraction::Normal:
+        break;
+    case FontVariantNumericFraction::DiagonalFractions:
+        valueList->append(cssValuePool.createIdentifierValue(CSSValueDiagonalFractions));
+        break;
+    case FontVariantNumericFraction::StackedFractions:
+        valueList->append(cssValuePool.createIdentifierValue(CSSValueStackedFractions));
+        break;
+    }
+
+    if (ordinal == FontVariantNumericOrdinal::Yes)
+        valueList->append(cssValuePool.createIdentifierValue(CSSValueOrdinal));
+    if (slashedZero == FontVariantNumericSlashedZero::Yes)
+        valueList->append(cssValuePool.createIdentifierValue(CSSValueSlashedZero));
+
+    return WTF::move(valueList);
+}
+
+static Ref<CSSValue> fontVariantAlternatesPropertyValue(FontVariantAlternates alternates)
+{
+    auto& cssValuePool = CSSValuePool::singleton();
+    CSSValueID valueID = CSSValueNormal;
+    switch (alternates) {
+    case FontVariantAlternates::Normal:
+        break;
+    case FontVariantAlternates::HistoricalForms:
+        valueID = CSSValueHistoricalForms;
+        break;
+    }
+    return cssValuePool.createIdentifierValue(valueID);
+}
+
+static Ref<CSSValue> fontVariantEastAsianPropertyValue(FontVariantEastAsianVariant variant, FontVariantEastAsianWidth width, FontVariantEastAsianRuby ruby)
+{
+    auto& cssValuePool = CSSValuePool::singleton();
+    if (variant == FontVariantEastAsianVariant::Normal && width == FontVariantEastAsianWidth::Normal && ruby == FontVariantEastAsianRuby::Normal)
+        return cssValuePool.createIdentifierValue(CSSValueNormal);
+
+    auto valueList = CSSValueList::createSpaceSeparated();
+    switch (variant) {
+    case FontVariantEastAsianVariant::Normal:
+        break;
+    case FontVariantEastAsianVariant::Jis78:
+        valueList->append(cssValuePool.createIdentifierValue(CSSValueJis78));
+        break;
+    case FontVariantEastAsianVariant::Jis83:
+        valueList->append(cssValuePool.createIdentifierValue(CSSValueJis83));
+        break;
+    case FontVariantEastAsianVariant::Jis90:
+        valueList->append(cssValuePool.createIdentifierValue(CSSValueJis90));
+        break;
+    case FontVariantEastAsianVariant::Jis04:
+        valueList->append(cssValuePool.createIdentifierValue(CSSValueJis04));
+        break;
+    case FontVariantEastAsianVariant::Simplified:
+        valueList->append(cssValuePool.createIdentifierValue(CSSValueSimplified));
+        break;
+    case FontVariantEastAsianVariant::Traditional:
+        valueList->append(cssValuePool.createIdentifierValue(CSSValueTraditional));
+        break;
+    }
+
+    switch (width) {
+    case FontVariantEastAsianWidth::Normal:
+        break;
+    case FontVariantEastAsianWidth::FullWidth:
+        valueList->append(cssValuePool.createIdentifierValue(CSSValueFullWidth));
+        break;
+    case FontVariantEastAsianWidth::ProportionalWidth:
+        valueList->append(cssValuePool.createIdentifierValue(CSSValueProportionalWidth));
+        break;
+    }
+
+    if (ruby == FontVariantEastAsianRuby::Yes)
+        valueList->append(cssValuePool.createIdentifierValue(CSSValueRuby));
+
+    return WTF::move(valueList);
+}
+
 static Ref<CSSValueList> getDelayValue(const AnimationList* animList)
 {
     auto& cssValuePool = CSSValuePool::singleton();
@@ -2320,14 +2511,12 @@ RefPtr<CSSValue> ComputedStyleExtractor::propertyValue(CSSPropertyID propertyID,
         case CSSPropertyFontSynthesis:
             return fontSynthesisFromStyle(*style);
         case CSSPropertyWebkitFontFeatureSettings: {
-            const FontFeatureSettings* featureSettings = style->fontDescription().featureSettings();
-            if (!featureSettings || !featureSettings->size())
+            const FontFeatureSettings& featureSettings = style->fontDescription().featureSettings();
+            if (!featureSettings.size())
                 return cssValuePool.createIdentifierValue(CSSValueNormal);
             RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
-            for (unsigned i = 0; i < featureSettings->size(); ++i) {
-                const FontFeature& feature = featureSettings->at(i);
-                list->append(CSSFontFeatureValue::create(feature.tag(), feature.value()));
-            }
+            for (auto& feature : featureSettings)
+                list->append(CSSFontFeatureValue::create(FontFeatureTag(feature.tag()), feature.value()));
             return list;
         }
 #if ENABLE(CSS_GRID_LAYOUT)
@@ -2723,23 +2912,18 @@ RefPtr<CSSValue> ComputedStyleExtractor::propertyValue(CSSPropertyID propertyID,
             return cssValuePool.createValue(style->fontDescription().kerning());
         case CSSPropertyWebkitFontSmoothing:
             return cssValuePool.createValue(style->fontDescription().fontSmoothing());
-        case CSSPropertyWebkitFontVariantLigatures: {
-            auto commonLigaturesState = style->fontDescription().commonLigaturesState();
-            auto discretionaryLigaturesState = style->fontDescription().discretionaryLigaturesState();
-            auto historicalLigaturesState = style->fontDescription().historicalLigaturesState();
-            if (commonLigaturesState == FontCascadeDescription::NormalLigaturesState && discretionaryLigaturesState == FontCascadeDescription::NormalLigaturesState
-                && historicalLigaturesState == FontCascadeDescription::NormalLigaturesState)
-                return cssValuePool.createIdentifierValue(CSSValueNormal);
-
-            RefPtr<CSSValueList> valueList = CSSValueList::createSpaceSeparated();
-            if (commonLigaturesState != FontCascadeDescription::NormalLigaturesState)
-                valueList->append(cssValuePool.createIdentifierValue(commonLigaturesState == FontCascadeDescription::DisabledLigaturesState ? CSSValueNoCommonLigatures : CSSValueCommonLigatures));
-            if (discretionaryLigaturesState != FontCascadeDescription::NormalLigaturesState)
-                valueList->append(cssValuePool.createIdentifierValue(discretionaryLigaturesState == FontCascadeDescription::DisabledLigaturesState ? CSSValueNoDiscretionaryLigatures : CSSValueDiscretionaryLigatures));
-            if (historicalLigaturesState != FontCascadeDescription::NormalLigaturesState)
-                valueList->append(cssValuePool.createIdentifierValue(historicalLigaturesState == FontCascadeDescription::DisabledLigaturesState ? CSSValueNoHistoricalLigatures : CSSValueHistoricalLigatures));
-            return valueList;
-        }
+        case CSSPropertyFontVariantLigatures:
+            return fontVariantLigaturesPropertyValue(style->fontDescription().variantCommonLigatures(), style->fontDescription().variantDiscretionaryLigatures(), style->fontDescription().variantHistoricalLigatures(), style->fontDescription().variantContextualAlternates());
+        case CSSPropertyFontVariantPosition:
+            return fontVariantPositionPropertyValue(style->fontDescription().variantPosition());
+        case CSSPropertyFontVariantCaps:
+            return fontVariantCapsPropertyValue(style->fontDescription().variantCaps());
+        case CSSPropertyFontVariantNumeric:
+            return fontVariantNumericPropertyValue(style->fontDescription().variantNumericFigure(), style->fontDescription().variantNumericSpacing(), style->fontDescription().variantNumericFraction(), style->fontDescription().variantNumericOrdinal(), style->fontDescription().variantNumericSlashedZero());
+        case CSSPropertyFontVariantAlternates:
+            return fontVariantAlternatesPropertyValue(style->fontDescription().variantAlternates());
+        case CSSPropertyFontVariantEastAsian:
+            return fontVariantEastAsianPropertyValue(style->fontDescription().variantEastAsianVariant(), style->fontDescription().variantEastAsianWidth(), style->fontDescription().variantEastAsianRuby());
         case CSSPropertyZIndex:
             if (style->hasAutoZIndex())
                 return cssValuePool.createIdentifierValue(CSSValueAuto);
index 5543dbe..3d88c58 100644 (file)
@@ -32,9 +32,9 @@
 
 namespace WebCore {
 
-CSSFontFeatureValue::CSSFontFeatureValue(const String& tag, int value)
+CSSFontFeatureValue::CSSFontFeatureValue(FontFeatureTag&& tag, int value)
     : CSSValue(FontFeatureClass)
-    , m_tag(tag)
+    , m_tag(WTF::move(tag))
     , m_value(value)
 {
 }
@@ -43,7 +43,8 @@ String CSSFontFeatureValue::customCSSText() const
 {
     StringBuilder builder;
     builder.append('\'');
-    builder.append(m_tag);
+    for (char c : m_tag)
+        builder.append(c);
     builder.appendLiteral("' ");
     builder.appendNumber(m_value);
     return builder.toString();
index 214cb3b..c97c1b8 100644 (file)
 #define CSSFontFeatureValue_h
 
 #include "CSSValue.h"
-#include <wtf/text/WTFString.h>
+#include "FontFeatureSettings.h"
 
 namespace WebCore {
 
 class CSSFontFeatureValue : public CSSValue {
 public:
-    static Ref<CSSFontFeatureValue> create(const String& tag, int value)
+    static Ref<CSSFontFeatureValue> create(FontFeatureTag&& tag, int value)
     {
-        return adoptRef(*new CSSFontFeatureValue(tag, value));
+        return adoptRef(*new CSSFontFeatureValue(WTF::move(tag), value));
     }
 
-    const String& tag() const { return m_tag; }
+    const FontFeatureTag& tag() const { return m_tag; }
     int value() const { return m_value; }
     String customCSSText() const;
 
     bool equals(const CSSFontFeatureValue&) const;
 
 private:
-    CSSFontFeatureValue(const String&, int);
+    CSSFontFeatureValue(FontFeatureTag&&, int);
 
-    String m_tag;
+    FontFeatureTag m_tag;
     const int m_value;
 };
 
index 636d07f..89178fb 100644 (file)
@@ -1036,6 +1036,18 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int
             return true;
         break;
 #endif
+    case CSSPropertyFontVariantPosition: // normal | sub | super
+        if (valueID == CSSValueNormal || valueID == CSSValueSub || valueID == CSSValueSuper)
+            return true;
+        break;
+    case CSSPropertyFontVariantCaps: // normal | small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps
+        if (valueID == CSSValueNormal || valueID == CSSValueSmallCaps || valueID == CSSValueAllSmallCaps || valueID == CSSValuePetiteCaps || valueID == CSSValueAllPetiteCaps || valueID == CSSValueUnicase || valueID == CSSValueTitlingCaps)
+            return true;
+        break;
+    case CSSPropertyFontVariantAlternates: // We only support the normal and historical-forms values.
+        if (valueID == CSSValueNormal || valueID == CSSValueHistoricalForms)
+            return true;
+        break;
     default:
         ASSERT_NOT_REACHED();
         return false;
@@ -1162,6 +1174,9 @@ static inline bool isKeywordPropertyID(CSSPropertyID propertyId)
 #if ENABLE(CSS_TRAILING_WORD)
     case CSSPropertyAppleTrailingWord:
 #endif
+    case CSSPropertyFontVariantPosition:
+    case CSSPropertyFontVariantCaps:
+    case CSSPropertyFontVariantAlternates:
         return true;
     default:
         return false;
@@ -3015,13 +3030,25 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important)
         else
             return parseFontFeatureSettings(important);
         break;
-
-    case CSSPropertyWebkitFontVariantLigatures:
-        if (id == CSSValueNormal)
+    case CSSPropertyFontVariantLigatures:
+        if (id == CSSValueNormal || id == CSSValueNone)
             validPrimitive = true;
         else
             return parseFontVariantLigatures(important);
         break;
+    case CSSPropertyFontVariantNumeric:
+        if (id == CSSValueNormal)
+            validPrimitive = true;
+        else
+            return parseFontVariantNumeric(important);
+        break;
+    case CSSPropertyFontVariantEastAsian:
+        if (id == CSSValueNormal)
+            validPrimitive = true;
+        else
+            return parseFontVariantEastAsian(important);
+        break;
+
     case CSSPropertyWebkitClipPath:
         parsedValue = parseClipPath();
         break;
@@ -10382,23 +10409,21 @@ bool CSSParser::parseLineBoxContain(bool important)
 
 bool CSSParser::parseFontFeatureTag(CSSValueList& settings)
 {
-    // Feature tag name consists of 4-letter characters.
-    static const unsigned tagNameLength = 4;
-
     CSSParserValue* value = m_valueList->current();
     // Feature tag name comes first
     if (value->unit != CSSPrimitiveValue::CSS_STRING)
         return false;
-    if (value->string.length() != tagNameLength)
+    FontFeatureTag tag;
+    if (value->string.length() != tag.size())
         return false;
-    for (unsigned i = 0; i < tagNameLength; ++i) {
+    for (unsigned i = 0; i < tag.size(); ++i) {
         // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification.
         UChar character = value->string[i];
         if (character < 0x20 || character > 0x7E)
             return false;
+        tag[i] = toASCIILower(character);
     }
 
-    String tag = String(value->string).convertToASCIILowercase();
     int tagValue = 1;
     // Feature tag values could follow: <integer> | on | off
     value = m_valueList->next();
@@ -10413,7 +10438,7 @@ bool CSSParser::parseFontFeatureTag(CSSValueList& settings)
             m_valueList->next();
         }
     }
-    settings.append(CSSFontFeatureValue::create(tag, tagValue));
+    settings.append(CSSFontFeatureValue::create(WTF::move(tag), tagValue));
     return true;
 }
 
@@ -10445,10 +10470,11 @@ bool CSSParser::parseFontFeatureSettings(bool important)
 
 bool CSSParser::parseFontVariantLigatures(bool important)
 {
-    RefPtr<CSSValueList> ligatureValues = CSSValueList::createSpaceSeparated();
-    bool sawCommonLigaturesValue = false;
-    bool sawDiscretionaryLigaturesValue = false;
-    bool sawHistoricalLigaturesValue = false;
+    auto values = CSSValueList::createSpaceSeparated();
+    bool sawCommonValue = false;
+    bool sawDiscretionaryValue = false;
+    bool sawHistoricalValue = false;
+    bool sawContextualValue = false;
 
     for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
         if (value->unit != CSSPrimitiveValue::CSS_IDENT)
@@ -10457,34 +10483,148 @@ bool CSSParser::parseFontVariantLigatures(bool important)
         switch (value->id) {
         case CSSValueNoCommonLigatures:
         case CSSValueCommonLigatures:
-            if (sawCommonLigaturesValue)
+            if (sawCommonValue)
                 return false;
-            sawCommonLigaturesValue = true;
-            ligatureValues->append(CSSValuePool::singleton().createIdentifierValue(value->id));
+            sawCommonValue = true;
+            values->append(CSSValuePool::singleton().createIdentifierValue(value->id));
             break;
         case CSSValueNoDiscretionaryLigatures:
         case CSSValueDiscretionaryLigatures:
-            if (sawDiscretionaryLigaturesValue)
+            if (sawDiscretionaryValue)
                 return false;
-            sawDiscretionaryLigaturesValue = true;
-            ligatureValues->append(CSSValuePool::singleton().createIdentifierValue(value->id));
+            sawDiscretionaryValue = true;
+            values->append(CSSValuePool::singleton().createIdentifierValue(value->id));
             break;
         case CSSValueNoHistoricalLigatures:
         case CSSValueHistoricalLigatures:
-            if (sawHistoricalLigaturesValue)
+            if (sawHistoricalValue)
                 return false;
-            sawHistoricalLigaturesValue = true;
-            ligatureValues->append(CSSValuePool::singleton().createIdentifierValue(value->id));
+            sawHistoricalValue = true;
+            values->append(CSSValuePool::singleton().createIdentifierValue(value->id));
+            break;
+        case CSSValueContextual:
+        case CSSValueNoContextual:
+            if (sawContextualValue)
+                return false;
+            sawContextualValue = true;
+            values->append(CSSValuePool::singleton().createIdentifierValue(value->id));
             break;
         default:
             return false;
         }
     }
 
-    if (!ligatureValues->length())
+    if (!values->length())
+        return false;
+
+    addProperty(CSSPropertyFontVariantLigatures, WTF::move(values), important);
+    return true;
+}
+
+bool CSSParser::parseFontVariantNumeric(bool important)
+{
+    auto values = CSSValueList::createSpaceSeparated();
+    bool sawFigureValue = false;
+    bool sawSpacingValue = false;
+    bool sawFractionValue = false;
+    bool sawOrdinal = false;
+    bool sawSlashedZero = false;
+
+    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
+        if (value->unit != CSSPrimitiveValue::CSS_IDENT)
+            return false;
+
+        switch (value->id) {
+        case CSSValueLiningNums:
+        case CSSValueOldstyleNums:
+            if (sawFigureValue)
+                return false;
+            sawFigureValue = true;
+            values->append(CSSValuePool::singleton().createIdentifierValue(value->id));
+            break;
+        case CSSValueProportionalNums:
+        case CSSValueTabularNums:
+            if (sawSpacingValue)
+                return false;
+            sawSpacingValue = true;
+            values->append(CSSValuePool::singleton().createIdentifierValue(value->id));
+            break;
+        case CSSValueDiagonalFractions:
+        case CSSValueStackedFractions:
+            if (sawFractionValue)
+                return false;
+            sawFractionValue = true;
+            values->append(CSSValuePool::singleton().createIdentifierValue(value->id));
+            break;
+        case CSSValueOrdinal:
+            if (sawOrdinal)
+                return false;
+            sawOrdinal = true;
+            values->append(CSSValuePool::singleton().createIdentifierValue(value->id));
+            break;
+        case CSSValueSlashedZero:
+            if (sawSlashedZero)
+                return false;
+            sawSlashedZero = true;
+            values->append(CSSValuePool::singleton().createIdentifierValue(value->id));
+            break;
+        default:
+            return false;
+        }
+    }
+
+    if (!values->length())
+        return false;
+
+    addProperty(CSSPropertyFontVariantNumeric, WTF::move(values), important);
+    return true;
+}
+
+bool CSSParser::parseFontVariantEastAsian(bool important)
+{
+    auto values = CSSValueList::createSpaceSeparated();
+    bool sawVariantValue = false;
+    bool sawWidthValue = false;
+    bool sawRuby = false;
+
+    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
+        if (value->unit != CSSPrimitiveValue::CSS_IDENT)
+            return false;
+
+        switch (value->id) {
+        case CSSValueJis78:
+        case CSSValueJis83:
+        case CSSValueJis90:
+        case CSSValueJis04:
+        case CSSValueSimplified:
+        case CSSValueTraditional:
+            if (sawVariantValue)
+                return false;
+            sawVariantValue = true;
+            values->append(CSSValuePool::singleton().createIdentifierValue(value->id));
+            break;
+        case CSSValueFullWidth:
+        case CSSValueProportionalWidth:
+            if (sawWidthValue)
+                return false;
+            sawWidthValue = true;
+            values->append(CSSValuePool::singleton().createIdentifierValue(value->id));
+            break;
+        case CSSValueRuby:
+            sawRuby = true;
+            break;
+        default:
+            return false;
+        }
+    }
+
+    if (sawRuby)
+        values->append(CSSValuePool::singleton().createIdentifierValue(CSSValueRuby));
+
+    if (!values->length())
         return false;
 
-    addProperty(CSSPropertyWebkitFontVariantLigatures, ligatureValues.release(), important);
+    addProperty(CSSPropertyFontVariantEastAsian, WTF::move(values), important);
     return true;
 }
 
index 92c1b3e..660b438 100644 (file)
@@ -344,6 +344,8 @@ public:
     bool parseRegionThread(CSSPropertyID, bool important);
 
     bool parseFontVariantLigatures(bool important);
+    bool parseFontVariantNumeric(bool important);
+    bool parseFontVariantEastAsian(bool important);
 
     bool parseWillChange(bool important);
 
index 0620e1b..ee2f0d8 100644 (file)
@@ -5322,6 +5322,131 @@ template<> inline CSSPrimitiveValue::operator TrailingWord() const
 }
 #endif
 
+template<> inline CSSPrimitiveValue::CSSPrimitiveValue(FontVariantPosition position)
+    : CSSValue(PrimitiveClass)
+{
+    m_primitiveUnitType = CSS_VALUE_ID;
+    switch (position) {
+    case FontVariantPosition::Normal:
+        m_value.valueID = CSSValueNormal;
+        break;
+    case FontVariantPosition::Subscript:
+        m_value.valueID = CSSValueSub;
+        break;
+    case FontVariantPosition::Superscript:
+        m_value.valueID = CSSValueSuper;
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
+template<> inline CSSPrimitiveValue::operator FontVariantPosition() const
+{
+    ASSERT(isValueID());
+    switch (m_value.valueID) {
+    case CSSValueNormal:
+        return FontVariantPosition::Normal;
+    case CSSValueSub:
+        return FontVariantPosition::Subscript;
+    case CSSValueSuper:
+        return FontVariantPosition::Superscript;
+    default:
+        break;
+    }
+    ASSERT_NOT_REACHED();
+    return FontVariantPosition::Normal;
+}
+
+template<> inline CSSPrimitiveValue::CSSPrimitiveValue(FontVariantCaps caps)
+    : CSSValue(PrimitiveClass)
+{
+    m_primitiveUnitType = CSS_VALUE_ID;
+    switch (caps) {
+    case FontVariantCaps::Normal:
+        m_value.valueID = CSSValueNormal;
+        break;
+    case FontVariantCaps::Small:
+        m_value.valueID = CSSValueSmallCaps;
+        break;
+    case FontVariantCaps::AllSmall:
+        m_value.valueID = CSSValueAllSmallCaps;
+        break;
+    case FontVariantCaps::Petite:
+        m_value.valueID = CSSValuePetiteCaps;
+        break;
+    case FontVariantCaps::AllPetite:
+        m_value.valueID = CSSValueAllPetiteCaps;
+        break;
+    case FontVariantCaps::Unicase:
+        m_value.valueID = CSSValueUnicase;
+        break;
+    case FontVariantCaps::Titling:
+        m_value.valueID = CSSValueTitlingCaps;
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
+template<> inline CSSPrimitiveValue::operator FontVariantCaps() const
+{
+    ASSERT(isValueID());
+    switch (m_value.valueID) {
+    case CSSValueNormal:
+        return FontVariantCaps::Normal;
+    case CSSValueSmallCaps:
+        return FontVariantCaps::Small;
+    case CSSValueAllSmallCaps:
+        return FontVariantCaps::AllSmall;
+    case CSSValuePetiteCaps:
+        return FontVariantCaps::Petite;
+    case CSSValueAllPetiteCaps:
+        return FontVariantCaps::AllPetite;
+    case CSSValueUnicase:
+        return FontVariantCaps::Unicase;
+    case CSSValueTitlingCaps:
+        return FontVariantCaps::Titling;
+    default:
+        break;
+    }
+    ASSERT_NOT_REACHED();
+    return FontVariantCaps::Normal;
+}
+
+template<> inline CSSPrimitiveValue::CSSPrimitiveValue(FontVariantAlternates alternates)
+    : CSSValue(PrimitiveClass)
+{
+    m_primitiveUnitType = CSS_VALUE_ID;
+    switch (alternates) {
+    case FontVariantAlternates::Normal:
+        m_value.valueID = CSSValueNormal;
+        break;
+    case FontVariantAlternates::HistoricalForms:
+        m_value.valueID = CSSValueHistoricalForms;
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
+template<> inline CSSPrimitiveValue::operator FontVariantAlternates() const
+{
+    ASSERT(isValueID());
+    switch (m_value.valueID) {
+    case CSSValueNormal:
+        return FontVariantAlternates::Normal;
+    case CSSValueHistoricalForms:
+        return FontVariantAlternates::HistoricalForms;
+    default:
+        break;
+    }
+    ASSERT_NOT_REACHED();
+    return FontVariantAlternates::Normal;
+}
 }
 
 #endif
index c63b104..e861043 100644 (file)
@@ -108,7 +108,12 @@ text-rendering [Inherited, FontProperty, NameForMethods=TextRenderingMode]
 -webkit-font-feature-settings [Inherited, FontProperty, Custom=Initial|Inherit, Converter=FontFeatureSettings, NameForMethods=FeatureSettings]
 -webkit-font-kerning [Inherited, FontProperty, NameForMethods=Kerning]
 -webkit-font-smoothing [Inherited, FontProperty]
--webkit-font-variant-ligatures [Inherited, Custom=All]
+font-variant-ligatures [Inherited, FontProperty, NameForMethods=VariantLigatures, Custom=All]
+font-variant-position [Inherited, FontProperty, NameForMethods=VariantPosition]
+font-variant-caps [Inherited, FontProperty, NameForMethods=VariantCaps]
+font-variant-numeric [Inherited, FontProperty, NameForMethods=VariantNumeric, Custom=All]
+font-variant-alternates [Inherited, FontProperty, NameForMethods=VariantAlternates]
+font-variant-east-asian [Inherited, FontProperty, NameForMethods=VariantEastAsian, Custom=All]
 -webkit-locale [Inherited, FontProperty, Custom=Value]
 -webkit-text-orientation [Inherited, Custom=Value]
 -epub-text-orientation = -webkit-text-orientation
index b17d9e1..2690753 100644 (file)
@@ -67,15 +67,53 @@ all
 //normal
 small-caps
 
-// -webkit-font-variant-ligatures:
+// font-variant-ligatures:
 //
-// normal
 common-ligatures
 no-common-ligatures
 discretionary-ligatures
 no-discretionary-ligatures
 historical-ligatures
 no-historical-ligatures
+contextual
+no-contextual
+
+// font-variant-caps
+//
+// FIXME: Unify this with plain font-variant
+// small-caps
+all-small-caps
+petite-caps
+all-petite-caps
+unicase
+titling-caps
+
+// font-variant-numeric
+//
+lining-nums
+oldstyle-nums
+proportional-nums
+tabular-nums
+diagonal-fractions
+stacked-fractions
+ordinal
+slashed-zero
+
+// font-variant-alternates
+//
+historical-forms
+
+// font-variant-east-asian
+//
+jis78
+jis83
+jis90
+jis04
+simplified
+traditional
+full-width
+proportional-width
+ruby
 
 //
 // CSS_PROP_FONT_WEIGHT:
index eb03fb0..9508a54 100644 (file)
@@ -112,7 +112,7 @@ public:
 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
     static bool convertOverflowScrolling(StyleResolver&, CSSValue&);
 #endif
-    static RefPtr<FontFeatureSettings> convertFontFeatureSettings(StyleResolver&, CSSValue&);
+    static FontFeatureSettings convertFontFeatureSettings(StyleResolver&, CSSValue&);
     static SVGLength convertSVGLength(StyleResolver&, CSSValue&);
     static Vector<SVGLength> convertSVGLengthVector(StyleResolver&, CSSValue&);
     static Vector<SVGLength> convertStrokeDashArray(StyleResolver&, CSSValue&);
@@ -1004,19 +1004,19 @@ inline Optional<FilterOperations> StyleBuilderConverter::convertFilterOperations
     return Nullopt;
 }
 
-inline RefPtr<FontFeatureSettings> StyleBuilderConverter::convertFontFeatureSettings(StyleResolver&, CSSValue& value)
+inline FontFeatureSettings StyleBuilderConverter::convertFontFeatureSettings(StyleResolver&, CSSValue& value)
 {
     if (is<CSSPrimitiveValue>(value)) {
         ASSERT(downcast<CSSPrimitiveValue>(value).getValueID() == CSSValueNormal);
-        return nullptr;
+        return { };
     }
 
-    RefPtr<FontFeatureSettings> settings = FontFeatureSettings::create();
+    FontFeatureSettings settings;
     for (auto& item : downcast<CSSValueList>(value)) {
         auto& feature = downcast<CSSFontFeatureValue>(item.get());
-        settings->insert(FontFeature(feature.tag(), feature.value()));
+        settings.insert(FontFeature(feature.tag(), feature.value()));
     }
-    return WTF::move(settings);
+    return settings;
 }
 
 #if PLATFORM(IOS)
index 6db76d1..241b33c 100644 (file)
@@ -89,7 +89,9 @@ public:
     DECLARE_PROPERTY_CUSTOM_HANDLERS(TextShadow);
     DECLARE_PROPERTY_CUSTOM_HANDLERS(WebkitAspectRatio);
     DECLARE_PROPERTY_CUSTOM_HANDLERS(WebkitBoxShadow);
-    DECLARE_PROPERTY_CUSTOM_HANDLERS(WebkitFontVariantLigatures);
+    DECLARE_PROPERTY_CUSTOM_HANDLERS(FontVariantLigatures);
+    DECLARE_PROPERTY_CUSTOM_HANDLERS(FontVariantNumeric);
+    DECLARE_PROPERTY_CUSTOM_HANDLERS(FontVariantEastAsian);
 #if ENABLE(CSS_GRID_LAYOUT)
     DECLARE_PROPERTY_CUSTOM_HANDLERS(WebkitGridTemplateAreas);
     DECLARE_PROPERTY_CUSTOM_HANDLERS(WebkitGridTemplateColumns);
@@ -1388,55 +1390,216 @@ inline void StyleBuilderCustom::applyValueContent(StyleResolver& styleResolver,
         styleResolver.style()->clearContent();
 }
 
-inline void StyleBuilderCustom::applyInitialWebkitFontVariantLigatures(StyleResolver& styleResolver)
+inline void StyleBuilderCustom::applyInheritFontVariantLigatures(StyleResolver& styleResolver)
 {
     auto fontDescription = styleResolver.fontDescription();
-
-    fontDescription.setCommonLigaturesState(FontCascadeDescription::NormalLigaturesState);
-    fontDescription.setDiscretionaryLigaturesState(FontCascadeDescription::NormalLigaturesState);
-    fontDescription.setHistoricalLigaturesState(FontCascadeDescription::NormalLigaturesState);
-
+    fontDescription.setVariantCommonLigatures(styleResolver.parentFontDescription().variantCommonLigatures());
+    fontDescription.setVariantDiscretionaryLigatures(styleResolver.parentFontDescription().variantDiscretionaryLigatures());
+    fontDescription.setVariantHistoricalLigatures(styleResolver.parentFontDescription().variantHistoricalLigatures());
+    fontDescription.setVariantContextualAlternates(styleResolver.parentFontDescription().variantContextualAlternates());
     styleResolver.setFontDescription(fontDescription);
 }
 
-inline void StyleBuilderCustom::applyInheritWebkitFontVariantLigatures(StyleResolver& styleResolver)
+inline void StyleBuilderCustom::applyInitialFontVariantLigatures(StyleResolver& styleResolver)
 {
-    const auto& parentFontDescription = styleResolver.parentFontDescription();
     auto fontDescription = styleResolver.fontDescription();
-
-    fontDescription.setCommonLigaturesState(parentFontDescription.commonLigaturesState());
-    fontDescription.setDiscretionaryLigaturesState(parentFontDescription.discretionaryLigaturesState());
-    fontDescription.setHistoricalLigaturesState(parentFontDescription.historicalLigaturesState());
-
+    fontDescription.setVariantCommonLigatures(FontVariantLigatures::Normal);
+    fontDescription.setVariantDiscretionaryLigatures(FontVariantLigatures::Normal);
+    fontDescription.setVariantHistoricalLigatures(FontVariantLigatures::Normal);
+    fontDescription.setVariantContextualAlternates(FontVariantLigatures::Normal);
     styleResolver.setFontDescription(fontDescription);
 }
 
-inline void StyleBuilderCustom::applyValueWebkitFontVariantLigatures(StyleResolver& styleResolver, CSSValue& value)
+inline void StyleBuilderCustom::applyValueFontVariantLigatures(StyleResolver& styleResolver, CSSValue& value)
 {
-    auto commonLigaturesState = FontCascadeDescription::NormalLigaturesState;
-    auto discretionaryLigaturesState = FontCascadeDescription::NormalLigaturesState;
-    auto historicalLigaturesState = FontCascadeDescription::NormalLigaturesState;
+    FontVariantLigatures common = FontVariantLigatures::Normal;
+    FontVariantLigatures discretionary = FontVariantLigatures::Normal;
+    FontVariantLigatures historical = FontVariantLigatures::Normal;
+    FontVariantLigatures contextualAlternates = FontVariantLigatures::Normal;
 
     if (is<CSSValueList>(value)) {
         for (auto& item : downcast<CSSValueList>(value)) {
             switch (downcast<CSSPrimitiveValue>(item.get()).getValueID()) {
             case CSSValueNoCommonLigatures:
-                commonLigaturesState = FontCascadeDescription::DisabledLigaturesState;
+                common = FontVariantLigatures::No;
                 break;
             case CSSValueCommonLigatures:
-                commonLigaturesState = FontCascadeDescription::EnabledLigaturesState;
+                common = FontVariantLigatures::Yes;
                 break;
             case CSSValueNoDiscretionaryLigatures:
-                discretionaryLigaturesState = FontCascadeDescription::DisabledLigaturesState;
+                discretionary = FontVariantLigatures::No;
                 break;
             case CSSValueDiscretionaryLigatures:
-                discretionaryLigaturesState = FontCascadeDescription::EnabledLigaturesState;
+                discretionary = FontVariantLigatures::Yes;
                 break;
             case CSSValueNoHistoricalLigatures:
-                historicalLigaturesState = FontCascadeDescription::DisabledLigaturesState;
+                historical = FontVariantLigatures::No;
                 break;
             case CSSValueHistoricalLigatures:
-                historicalLigaturesState = FontCascadeDescription::EnabledLigaturesState;
+                historical = FontVariantLigatures::Yes;
+                break;
+            case CSSValueContextual:
+                contextualAlternates = FontVariantLigatures::Yes;
+                break;
+            case CSSValueNoContextual:
+                contextualAlternates = FontVariantLigatures::No;
+                break;
+            default:
+                ASSERT_NOT_REACHED();
+                break;
+            }
+        }
+    } else {
+        switch (downcast<CSSPrimitiveValue>(value).getValueID()) {
+        case CSSValueNormal:
+            break;
+        case CSSValueNone:
+            common = FontVariantLigatures::No;
+            discretionary = FontVariantLigatures::No;
+            historical = FontVariantLigatures::No;
+            contextualAlternates = FontVariantLigatures::No;
+            break;
+        default:
+            ASSERT_NOT_REACHED();
+            break;
+        }
+    }
+
+    auto fontDescription = styleResolver.fontDescription();
+    fontDescription.setVariantCommonLigatures(common);
+    fontDescription.setVariantDiscretionaryLigatures(discretionary);
+    fontDescription.setVariantHistoricalLigatures(historical);
+    fontDescription.setVariantContextualAlternates(contextualAlternates);
+    styleResolver.setFontDescription(fontDescription);
+}
+
+inline void StyleBuilderCustom::applyInheritFontVariantNumeric(StyleResolver& styleResolver)
+{
+    auto fontDescription = styleResolver.fontDescription();
+    fontDescription.setVariantNumericFigure(styleResolver.parentFontDescription().variantNumericFigure());
+    fontDescription.setVariantNumericSpacing(styleResolver.parentFontDescription().variantNumericSpacing());
+    fontDescription.setVariantNumericFraction(styleResolver.parentFontDescription().variantNumericFraction());
+    fontDescription.setVariantNumericOrdinal(styleResolver.parentFontDescription().variantNumericOrdinal());
+    fontDescription.setVariantNumericSlashedZero(styleResolver.parentFontDescription().variantNumericSlashedZero());
+    styleResolver.setFontDescription(fontDescription);
+}
+
+inline void StyleBuilderCustom::applyInitialFontVariantNumeric(StyleResolver& styleResolver)
+{
+    auto fontDescription = styleResolver.fontDescription();
+    fontDescription.setVariantNumericFigure(FontVariantNumericFigure::Normal);
+    fontDescription.setVariantNumericSpacing(FontVariantNumericSpacing::Normal);
+    fontDescription.setVariantNumericFraction(FontVariantNumericFraction::Normal);
+    fontDescription.setVariantNumericOrdinal(FontVariantNumericOrdinal::Normal);
+    fontDescription.setVariantNumericSlashedZero(FontVariantNumericSlashedZero::Normal);
+    styleResolver.setFontDescription(fontDescription);
+}
+
+inline void StyleBuilderCustom::applyValueFontVariantNumeric(StyleResolver& styleResolver, CSSValue& value)
+{
+    FontVariantNumericFigure figure = FontVariantNumericFigure::Normal;
+    FontVariantNumericSpacing spacing = FontVariantNumericSpacing::Normal;
+    FontVariantNumericFraction fraction = FontVariantNumericFraction::Normal;
+    FontVariantNumericOrdinal ordinal = FontVariantNumericOrdinal::Normal;
+    FontVariantNumericSlashedZero slashedZero = FontVariantNumericSlashedZero::Normal;
+
+    if (is<CSSValueList>(value)) {
+        for (auto& item : downcast<CSSValueList>(value)) {
+            switch (downcast<CSSPrimitiveValue>(item.get()).getValueID()) {
+            case CSSValueLiningNums:
+                figure = FontVariantNumericFigure::LiningNumbers;
+                break;
+            case CSSValueOldstyleNums:
+                figure = FontVariantNumericFigure::OldStyleNumbers;
+                break;
+            case CSSValueProportionalNums:
+                spacing = FontVariantNumericSpacing::ProportionalNumbers;
+                break;
+            case CSSValueTabularNums:
+                spacing = FontVariantNumericSpacing::TabularNumbers;
+                break;
+            case CSSValueDiagonalFractions:
+                fraction = FontVariantNumericFraction::DiagonalFractions;
+                break;
+            case CSSValueStackedFractions:
+                fraction = FontVariantNumericFraction::StackedFractions;
+                break;
+            case CSSValueOrdinal:
+                ordinal = FontVariantNumericOrdinal::Yes;
+                break;
+            case CSSValueSlashedZero:
+                slashedZero = FontVariantNumericSlashedZero::Yes;
+                break;
+            default:
+                ASSERT_NOT_REACHED();
+                break;
+            }
+        }
+    } else
+        ASSERT(downcast<CSSPrimitiveValue>(value).getValueID() == CSSValueNormal);
+
+    auto fontDescription = styleResolver.fontDescription();
+    fontDescription.setVariantNumericFigure(figure);
+    fontDescription.setVariantNumericSpacing(spacing);
+    fontDescription.setVariantNumericFraction(fraction);
+    fontDescription.setVariantNumericOrdinal(ordinal);
+    fontDescription.setVariantNumericSlashedZero(slashedZero);
+    styleResolver.setFontDescription(fontDescription);
+}
+
+inline void StyleBuilderCustom::applyInheritFontVariantEastAsian(StyleResolver& styleResolver)
+{
+    auto fontDescription = styleResolver.fontDescription();
+    fontDescription.setVariantEastAsianVariant(styleResolver.parentFontDescription().variantEastAsianVariant());
+    fontDescription.setVariantEastAsianWidth(styleResolver.parentFontDescription().variantEastAsianWidth());
+    fontDescription.setVariantEastAsianRuby(styleResolver.parentFontDescription().variantEastAsianRuby());
+    styleResolver.setFontDescription(fontDescription);
+}
+
+inline void StyleBuilderCustom::applyInitialFontVariantEastAsian(StyleResolver& styleResolver)
+{
+    auto fontDescription = styleResolver.fontDescription();
+    fontDescription.setVariantEastAsianVariant(FontVariantEastAsianVariant::Normal);
+    fontDescription.setVariantEastAsianWidth(FontVariantEastAsianWidth::Normal);
+    fontDescription.setVariantEastAsianRuby(FontVariantEastAsianRuby::Normal);
+    styleResolver.setFontDescription(fontDescription);
+}
+
+inline void StyleBuilderCustom::applyValueFontVariantEastAsian(StyleResolver& styleResolver, CSSValue& value)
+{
+    FontVariantEastAsianVariant variant = FontVariantEastAsianVariant::Normal;
+    FontVariantEastAsianWidth width = FontVariantEastAsianWidth::Normal;
+    FontVariantEastAsianRuby ruby = FontVariantEastAsianRuby::Normal;
+
+    if (is<CSSValueList>(value)) {
+        for (auto& item : downcast<CSSValueList>(value)) {
+            switch (downcast<CSSPrimitiveValue>(item.get()).getValueID()) {
+            case CSSValueJis78:
+                variant = FontVariantEastAsianVariant::Jis78;
+                break;
+            case CSSValueJis83:
+                variant = FontVariantEastAsianVariant::Jis83;
+                break;
+            case CSSValueJis90:
+                variant = FontVariantEastAsianVariant::Jis90;
+                break;
+            case CSSValueJis04:
+                variant = FontVariantEastAsianVariant::Jis04;
+                break;
+            case CSSValueSimplified:
+                variant = FontVariantEastAsianVariant::Simplified;
+                break;
+            case CSSValueTraditional:
+                variant = FontVariantEastAsianVariant::Traditional;
+                break;
+            case CSSValueFullWidth:
+                width = FontVariantEastAsianWidth::FullWidth;
+                break;
+            case CSSValueProportionalWidth:
+                width = FontVariantEastAsianWidth::ProportionalWidth;
+                break;
+            case CSSValueRuby:
+                ruby = FontVariantEastAsianRuby::Yes;
                 break;
             default:
                 ASSERT_NOT_REACHED();
@@ -1447,9 +1610,9 @@ inline void StyleBuilderCustom::applyValueWebkitFontVariantLigatures(StyleResolv
         ASSERT(downcast<CSSPrimitiveValue>(value).getValueID() == CSSValueNormal);
 
     auto fontDescription = styleResolver.fontDescription();
-    fontDescription.setCommonLigaturesState(commonLigaturesState);
-    fontDescription.setDiscretionaryLigaturesState(discretionaryLigaturesState);
-    fontDescription.setHistoricalLigaturesState(historicalLigaturesState);
+    fontDescription.setVariantEastAsianVariant(variant);
+    fontDescription.setVariantEastAsianWidth(width);
+    fontDescription.setVariantEastAsianRuby(ruby);
     styleResolver.setFontDescription(fontDescription);
 }
 
index 7f6c6cd..a9926e9 100644 (file)
@@ -1156,7 +1156,7 @@ NSDictionary *HTMLConverter::computedAttributesForElement(Element& element)
         }
     }
 
-    String fontLigatures = _caches->propertyValueForNode(element, CSSPropertyWebkitFontVariantLigatures);
+    String fontLigatures = _caches->propertyValueForNode(element, CSSPropertyFontVariantLigatures);
     if (fontLigatures.length()) {
         if (fontLigatures.contains("normal"))
             ;   // default: whatever the system decides to do
index 8bcb730..9473ab1 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "FontDescription.h"
 #include "Timer.h"
+#include <array>
 #include <limits.h>
 #include <wtf/Forward.h>
 #include <wtf/PassRefPtr.h>
@@ -73,7 +74,7 @@ struct FontDescriptionKey {
     FontDescriptionKey(const FontDescription& description)
         : m_size(description.computedPixelSize())
         , m_weight(description.weight())
-        , m_flags(makeFlagKey(description))
+        , m_flags(makeFlagsKey(description))
         , m_locale(description.locale())
         , m_featureSettings(description.featureSettings())
     { }
@@ -85,7 +86,7 @@ struct FontDescriptionKey {
     bool operator==(const FontDescriptionKey& other) const
     {
         return m_size == other.m_size && m_weight == other.m_weight && m_flags == other.m_flags && m_locale == other.m_locale
-            && ((m_featureSettings == other.m_featureSettings) || (m_featureSettings && other.m_featureSettings && m_featureSettings.get() == other.m_featureSettings.get()));
+            && m_featureSettings == other.m_featureSettings;
     }
 
     bool operator!=(const FontDescriptionKey& other) const
@@ -97,15 +98,21 @@ struct FontDescriptionKey {
 
     inline unsigned computeHash() const
     {
-        unsigned toHash[] = {m_size, m_weight, m_flags, m_locale.isNull() ? 0 : m_locale.impl()->existingHash(), m_featureSettings ? m_featureSettings->hash() : 0};
-        return StringHasher::hashMemory(toHash, sizeof(toHash));
+        IntegerHasher hasher;
+        hasher.add(m_size);
+        hasher.add(m_weight);
+        for (unsigned flagItem : m_flags)
+            hasher.add(flagItem);
+        hasher.add(m_locale.isNull() ? 0 : m_locale.impl()->existingHash());
+        hasher.add(m_featureSettings.hash());
+        return hasher.hash();
     }
 
 private:
-    static unsigned makeFlagKey(const FontDescription& description)
+    static std::array<unsigned, 2> makeFlagsKey(const FontDescription& description)
     {
         static_assert(USCRIPT_CODE_LIMIT < 0x1000, "Script code must fit in an unsigned along with the other flags");
-        return static_cast<unsigned>(description.script()) << 11
+        unsigned first = static_cast<unsigned>(description.script()) << 11
             | static_cast<unsigned>(description.textRenderingMode()) << 9
             | static_cast<unsigned>(description.smallCaps()) << 8
             | static_cast<unsigned>(description.fontSynthesis()) << 6
@@ -114,15 +121,31 @@ private:
             | static_cast<unsigned>(description.orientation()) << 2
             | static_cast<unsigned>(description.italic()) << 1
             | static_cast<unsigned>(description.renderingMode());
+        unsigned second = static_cast<unsigned>(description.variantEastAsianRuby()) << 27
+            | static_cast<unsigned>(description.variantEastAsianWidth()) << 25
+            | static_cast<unsigned>(description.variantEastAsianVariant()) << 22
+            | static_cast<unsigned>(description.variantAlternates()) << 21
+            | static_cast<unsigned>(description.variantNumericSlashedZero()) << 20
+            | static_cast<unsigned>(description.variantNumericOrdinal()) << 19
+            | static_cast<unsigned>(description.variantNumericFraction()) << 17
+            | static_cast<unsigned>(description.variantNumericSpacing()) << 15
+            | static_cast<unsigned>(description.variantNumericFigure()) << 13
+            | static_cast<unsigned>(description.variantCaps()) << 10
+            | static_cast<unsigned>(description.variantPosition()) << 8
+            | static_cast<unsigned>(description.variantContextualAlternates()) << 6
+            | static_cast<unsigned>(description.variantHistoricalLigatures()) << 4
+            | static_cast<unsigned>(description.variantDiscretionaryLigatures()) << 2
+            | static_cast<unsigned>(description.variantCommonLigatures());
+        return {{ first, second }};
     }
 
     static const unsigned cHashTableDeletedSize = 0xFFFFFFFFU;
 
     unsigned m_size { 0 };
     unsigned m_weight { 0 };
-    unsigned m_flags { 0 };
+    std::array<unsigned, 2> m_flags {{ 0, 0 }};
     AtomicString m_locale;
-    RefPtr<FontFeatureSettings> m_featureSettings;
+    FontFeatureSettings m_featureSettings;
 };
 
 struct FontDescriptionKeyHash {
@@ -234,14 +257,14 @@ struct SynthesisPair {
     bool needsSyntheticOblique;
 };
 
-RetainPtr<CTFontRef> preparePlatformFont(CTFontRef, TextRenderingMode, const FontFeatureSettings*);
+RetainPtr<CTFontRef> preparePlatformFont(CTFontRef, TextRenderingMode, const FontFeatureSettings&, const FontVariantSettings&);
 FontWeight fontWeightFromCoreText(CGFloat weight);
 uint16_t toCoreTextFontWeight(FontWeight);
 bool isFontWeightBold(FontWeight);
 void platformInvalidateFontCache();
 SynthesisPair computeNecessarySynthesis(CTFontRef, const FontDescription&, bool isPlatformFont = false);
 RetainPtr<CTFontRef> platformFontWithFamilySpecialCase(const AtomicString& family, FontWeight, CTFontSymbolicTraits, float size);
-RetainPtr<CTFontRef> platformFontWithFamily(const AtomicString& family, CTFontSymbolicTraits, FontWeight, const FontFeatureSettings*, TextRenderingMode, float size);
+RetainPtr<CTFontRef> platformFontWithFamily(const AtomicString& family, CTFontSymbolicTraits, FontWeight, TextRenderingMode, float size);
 RetainPtr<CTFontRef> platformLookupFallbackFont(CTFontRef, FontWeight, const AtomicString& locale, const UChar* characters, unsigned length);
 bool requiresCustomFallbackFont(UChar32 character);
 
index 0c60cc4..465facf 100644 (file)
@@ -600,7 +600,8 @@ FontCascade::CodePath FontCascade::codePath(const TextRun& run) const
         return Simple;
 #endif
 
-    if (m_fontDescription.featureSettings() && m_fontDescription.featureSettings()->size() > 0)
+    // FIXME: This shouldn't be necessary because Font::applyTransforms() should perform all necessary shaping.
+    if (m_fontDescription.featureSettings().size() > 0 || !m_fontDescription.variantSettings().isAllNormal())
         return Complex;
     
     if (run.length() > 1 && !WidthIterator::supportsTypesettingFeatures(*this))
index f41e4e9..df7eea7 100644 (file)
@@ -328,14 +328,14 @@ private:
             break;
         }
 
-        switch (m_fontDescription.commonLigaturesState()) {
-        case FontCascadeDescription::DisabledLigaturesState:
+        switch (m_fontDescription.variantCommonLigatures()) {
+        case FontVariantLigatures::No:
             features &= ~Ligatures;
             break;
-        case FontCascadeDescription::EnabledLigaturesState:
+        case FontVariantLigatures::Yes:
             features |= Ligatures;
             break;
-        case FontCascadeDescription::NormalLigaturesState:
+        default:
             break;
         }
 
index feff26f..46a5dd4 100644 (file)
 namespace WebCore {
 
 struct SameSizeAsFontCascadeDescription {
-    void* pointers[3];
-    float sizes[2];
-    // FIXME: Make them fit into one word.
-    uint32_t bitfields;
-    uint32_t bitfields2 : 8;
+    Vector<void*> vector;
+    void* string;
+    float size;
+    unsigned bitfields1;
+    unsigned bitfields2 : 22;
+    void* array;
+    float size2;
+    unsigned bitfields3 : 10;
 };
 
 COMPILE_ASSERT(sizeof(FontCascadeDescription) == sizeof(SameSizeAsFontCascadeDescription), FontCascadeDescription_should_stay_small);
@@ -55,6 +58,21 @@ FontDescription::FontDescription()
     , m_textRendering(AutoTextRendering)
     , m_script(localeToScriptCodeForFontSelection(m_locale))
     , m_fontSynthesis(FontSynthesisWeight | FontSynthesisStyle)
+    , m_variantCommonLigatures(static_cast<unsigned>(FontVariantLigatures::Normal))
+    , m_variantDiscretionaryLigatures(static_cast<unsigned>(FontVariantLigatures::Normal))
+    , m_variantHistoricalLigatures(static_cast<unsigned>(FontVariantLigatures::Normal))
+    , m_variantContextualAlternates(static_cast<unsigned>(FontVariantLigatures::Normal))
+    , m_variantPosition(static_cast<unsigned>(FontVariantPosition::Normal))
+    , m_variantCaps(static_cast<unsigned>(FontVariantCaps::Normal))
+    , m_variantNumericFigure(static_cast<unsigned>(FontVariantNumericFigure::Normal))
+    , m_variantNumericSpacing(static_cast<unsigned>(FontVariantNumericSpacing::Normal))
+    , m_variantNumericFraction(static_cast<unsigned>(FontVariantNumericFraction::Normal))
+    , m_variantNumericOrdinal(static_cast<unsigned>(FontVariantNumericOrdinal::Normal))
+    , m_variantNumericSlashedZero(static_cast<unsigned>(FontVariantNumericSlashedZero::Normal))
+    , m_variantAlternates(static_cast<unsigned>(FontVariantAlternates::Normal))
+    , m_variantEastAsianVariant(static_cast<unsigned>(FontVariantEastAsianVariant::Normal))
+    , m_variantEastAsianWidth(static_cast<unsigned>(FontVariantEastAsianWidth::Normal))
+    , m_variantEastAsianRuby(static_cast<unsigned>(FontVariantEastAsianRuby::Normal))
 {
 }
 
@@ -75,9 +93,6 @@ FontTraitsMask FontDescription::traitsMask() const
 FontCascadeDescription::FontCascadeDescription()
     : m_isAbsoluteSize(false)
     , m_kerning(AutoKerning)
-    , m_commonLigaturesState(NormalLigaturesState)
-    , m_discretionaryLigaturesState(NormalLigaturesState)
-    , m_historicalLigaturesState(NormalLigaturesState)
     , m_keywordSize(0)
     , m_fontSmoothing(AutoSmoothing)
     , m_isSpecifiedFont(false)
index c608a3c..e3c4e90 100644 (file)
@@ -60,8 +60,41 @@ public:
     FontOrientation orientation() const { return static_cast<FontOrientation>(m_orientation); }
     NonCJKGlyphOrientation nonCJKGlyphOrientation() const { return static_cast<NonCJKGlyphOrientation>(m_nonCJKGlyphOrientation); }
     FontWidthVariant widthVariant() const { return static_cast<FontWidthVariant>(m_widthVariant); }
-    FontFeatureSettings* featureSettings() const { return m_featureSettings.get(); }
+    const FontFeatureSettings& featureSettings() const { return m_featureSettings; }
     FontSynthesis fontSynthesis() const { return static_cast<FontSynthesis>(m_fontSynthesis); }
+    FontVariantLigatures variantCommonLigatures() const { return static_cast<FontVariantLigatures>(m_variantCommonLigatures); }
+    FontVariantLigatures variantDiscretionaryLigatures() const { return static_cast<FontVariantLigatures>(m_variantDiscretionaryLigatures); }
+    FontVariantLigatures variantHistoricalLigatures() const { return static_cast<FontVariantLigatures>(m_variantHistoricalLigatures); }
+    FontVariantLigatures variantContextualAlternates() const { return static_cast<FontVariantLigatures>(m_variantContextualAlternates); }
+    FontVariantPosition variantPosition() const { return static_cast<FontVariantPosition>(m_variantPosition); }
+    FontVariantCaps variantCaps() const { return static_cast<FontVariantCaps>(m_variantCaps); }
+    FontVariantNumericFigure variantNumericFigure() const { return static_cast<FontVariantNumericFigure>(m_variantNumericFigure); }
+    FontVariantNumericSpacing variantNumericSpacing() const { return static_cast<FontVariantNumericSpacing>(m_variantNumericSpacing); }
+    FontVariantNumericFraction variantNumericFraction() const { return static_cast<FontVariantNumericFraction>(m_variantNumericFraction); }
+    FontVariantNumericOrdinal variantNumericOrdinal() const { return static_cast<FontVariantNumericOrdinal>(m_variantNumericOrdinal); }
+    FontVariantNumericSlashedZero variantNumericSlashedZero() const { return static_cast<FontVariantNumericSlashedZero>(m_variantNumericSlashedZero); }
+    FontVariantAlternates variantAlternates() const { return static_cast<FontVariantAlternates>(m_variantAlternates); }
+    FontVariantEastAsianVariant variantEastAsianVariant() const { return static_cast<FontVariantEastAsianVariant>(m_variantEastAsianVariant); }
+    FontVariantEastAsianWidth variantEastAsianWidth() const { return static_cast<FontVariantEastAsianWidth>(m_variantEastAsianWidth); }
+    FontVariantEastAsianRuby variantEastAsianRuby() const { return static_cast<FontVariantEastAsianRuby>(m_variantEastAsianRuby); }
+    FontVariantSettings variantSettings() const
+    {
+        return { variantCommonLigatures(),
+            variantDiscretionaryLigatures(),
+            variantHistoricalLigatures(),
+            variantContextualAlternates(),
+            variantPosition(),
+            variantCaps(),
+            variantNumericFigure(),
+            variantNumericSpacing(),
+            variantNumericFraction(),
+            variantNumericOrdinal(),
+            variantNumericSlashedZero(),
+            variantAlternates(),
+            variantEastAsianVariant(),
+            variantEastAsianWidth(),
+            variantEastAsianRuby() };
+    }
 
     void setComputedSize(float s) { m_computedSize = clampToFloat(s); }
     void setItalic(FontItalic i) { m_italic = i; }
@@ -75,13 +108,28 @@ public:
     void setNonCJKGlyphOrientation(NonCJKGlyphOrientation orientation) { m_nonCJKGlyphOrientation = orientation; }
     void setWidthVariant(FontWidthVariant widthVariant) { m_widthVariant = widthVariant; } // Make sure new callers of this sync with FontPlatformData::isForTextCombine()!
     void setLocale(const AtomicString&);
-    void setFeatureSettings(PassRefPtr<FontFeatureSettings> settings) { m_featureSettings = settings; }
+    void setFeatureSettings(FontFeatureSettings&& settings) { m_featureSettings = WTF::move(settings); }
     void setFontSynthesis(FontSynthesis fontSynthesis) { m_fontSynthesis = fontSynthesis; }
+    void setVariantCommonLigatures(FontVariantLigatures variant) { m_variantCommonLigatures = static_cast<unsigned>(variant); }
+    void setVariantDiscretionaryLigatures(FontVariantLigatures variant) { m_variantDiscretionaryLigatures = static_cast<unsigned>(variant); }
+    void setVariantHistoricalLigatures(FontVariantLigatures variant) { m_variantHistoricalLigatures = static_cast<unsigned>(variant); }
+    void setVariantContextualAlternates(FontVariantLigatures variant) { m_variantContextualAlternates = static_cast<unsigned>(variant); }
+    void setVariantPosition(FontVariantPosition variant) { m_variantPosition = static_cast<unsigned>(variant); }
+    void setVariantCaps(FontVariantCaps variant) { m_variantCaps = static_cast<unsigned>(variant); }
+    void setVariantNumericFigure(FontVariantNumericFigure variant) { m_variantNumericFigure = static_cast<unsigned>(variant); }
+    void setVariantNumericSpacing(FontVariantNumericSpacing variant) { m_variantNumericSpacing = static_cast<unsigned>(variant); }
+    void setVariantNumericFraction(FontVariantNumericFraction variant) { m_variantNumericFraction = static_cast<unsigned>(variant); }
+    void setVariantNumericOrdinal(FontVariantNumericOrdinal variant) { m_variantNumericOrdinal = static_cast<unsigned>(variant); }
+    void setVariantNumericSlashedZero(FontVariantNumericSlashedZero variant) { m_variantNumericSlashedZero = static_cast<unsigned>(variant); }
+    void setVariantAlternates(FontVariantAlternates variant) { m_variantAlternates = static_cast<unsigned>(variant); }
+    void setVariantEastAsianVariant(FontVariantEastAsianVariant variant) { m_variantEastAsianVariant = static_cast<unsigned>(variant); }
+    void setVariantEastAsianWidth(FontVariantEastAsianWidth variant) { m_variantEastAsianWidth = static_cast<unsigned>(variant); }
+    void setVariantEastAsianRuby(FontVariantEastAsianRuby variant) { m_variantEastAsianRuby = static_cast<unsigned>(variant); }
 
     FontTraitsMask traitsMask() const;
 
 private:
-    RefPtr<FontFeatureSettings> m_featureSettings;
+    FontFeatureSettings m_featureSettings;
     AtomicString m_locale;
 
     float m_computedSize { 0 }; // Computed size adjusted for the minimum font size and the zoom factor.
@@ -95,6 +143,21 @@ private:
     unsigned m_textRendering : 2; // TextRenderingMode
     unsigned m_script : 7; // Used to help choose an appropriate font for generic font families.
     unsigned m_fontSynthesis : 2; // FontSynthesis type
+    unsigned m_variantCommonLigatures : 2; // FontVariantLigatures
+    unsigned m_variantDiscretionaryLigatures : 2; // FontVariantLigatures
+    unsigned m_variantHistoricalLigatures : 2; // FontVariantLigatures
+    unsigned m_variantContextualAlternates : 2; // FontVariantLigatures
+    unsigned m_variantPosition : 2; // FontVariantPosition
+    unsigned m_variantCaps : 3; // FontVariantCaps
+    unsigned m_variantNumericFigure : 2; // FontVariantNumericFigure
+    unsigned m_variantNumericSpacing : 2; // FontVariantNumericSpacing
+    unsigned m_variantNumericFraction : 2; // FontVariantNumericFraction
+    unsigned m_variantNumericOrdinal : 1; // FontVariantNumericOrdinal
+    unsigned m_variantNumericSlashedZero : 1; // FontVariantNumericSlashedZero
+    unsigned m_variantAlternates : 1; // FontVariantAlternates
+    unsigned m_variantEastAsianVariant : 3; // FontVariantEastAsianVariant
+    unsigned m_variantEastAsianWidth : 2; // FontVariantEastAsianWidth
+    unsigned m_variantEastAsianRuby : 1; // FontVariantEastAsianRuby
 };
 
 inline bool FontDescription::operator==(const FontDescription& other) const
@@ -110,7 +173,22 @@ inline bool FontDescription::operator==(const FontDescription& other) const
         && m_widthVariant == other.m_widthVariant
         && m_locale == other.m_locale
         && m_featureSettings == other.m_featureSettings
-        && m_fontSynthesis == other.m_fontSynthesis;
+        && m_fontSynthesis == other.m_fontSynthesis
+        && m_variantCommonLigatures == other.m_variantCommonLigatures
+        && m_variantDiscretionaryLigatures == other.m_variantDiscretionaryLigatures
+        && m_variantHistoricalLigatures == other.m_variantHistoricalLigatures
+        && m_variantContextualAlternates == other.m_variantContextualAlternates
+        && m_variantPosition == other.m_variantPosition
+        && m_variantCaps == other.m_variantCaps
+        && m_variantNumericFigure == other.m_variantNumericFigure
+        && m_variantNumericSpacing == other.m_variantNumericSpacing
+        && m_variantNumericFraction == other.m_variantNumericFraction
+        && m_variantNumericOrdinal == other.m_variantNumericOrdinal
+        && m_variantNumericSlashedZero == other.m_variantNumericSlashedZero
+        && m_variantAlternates == other.m_variantAlternates
+        && m_variantEastAsianVariant == other.m_variantEastAsianVariant
+        && m_variantEastAsianWidth == other.m_variantEastAsianWidth
+        && m_variantEastAsianRuby == other.m_variantEastAsianRuby;
 }
 
 // FIXME: Move to a file of its own.
@@ -118,8 +196,6 @@ class FontCascadeDescription : public FontDescription {
 public:
     enum Kerning { AutoKerning, NormalKerning, NoneKerning };
 
-    enum LigaturesState { NormalLigaturesState, DisabledLigaturesState, EnabledLigaturesState };
-
     FontCascadeDescription();
 
     bool operator==(const FontCascadeDescription&) const;
@@ -139,9 +215,6 @@ public:
     bool useFixedDefaultSize() const { return familyCount() == 1 && firstFamily() == monospaceFamily; }
 
     Kerning kerning() const { return static_cast<Kerning>(m_kerning); }
-    LigaturesState commonLigaturesState() const { return static_cast<LigaturesState>(m_commonLigaturesState); }
-    LigaturesState discretionaryLigaturesState() const { return static_cast<LigaturesState>(m_discretionaryLigaturesState); }
-    LigaturesState historicalLigaturesState() const { return static_cast<LigaturesState>(m_historicalLigaturesState); }
     unsigned keywordSize() const { return m_keywordSize; }
     CSSValueID keywordSizeAsIdentifier() const
     {
@@ -158,9 +231,6 @@ public:
     void setSpecifiedSize(float s) { m_specifiedSize = clampToFloat(s); }
     void setIsAbsoluteSize(bool s) { m_isAbsoluteSize = s; }
     void setKerning(Kerning kerning) { m_kerning = kerning; }
-    void setCommonLigaturesState(LigaturesState commonLigaturesState) { m_commonLigaturesState = commonLigaturesState; }
-    void setDiscretionaryLigaturesState(LigaturesState discretionaryLigaturesState) { m_discretionaryLigaturesState = discretionaryLigaturesState; }
-    void setHistoricalLigaturesState(LigaturesState historicalLigaturesState) { m_historicalLigaturesState = historicalLigaturesState; }
     void setKeywordSize(unsigned size)
     {
         ASSERT(size <= 8);
@@ -196,6 +266,9 @@ public:
     static TextRenderingMode initialTextRenderingMode() { return AutoTextRendering; }
     static FontSynthesis initialFontSynthesis() { return FontSynthesisWeight | FontSynthesisStyle; }
     static const AtomicString& initialLocale() { return nullAtom; }
+    static FontVariantPosition initialVariantPosition() { return FontVariantPosition::Normal; }
+    static FontVariantCaps initialVariantCaps() { return FontVariantCaps::Normal; }
+    static FontVariantAlternates initialVariantAlternates() { return FontVariantAlternates::Normal; }
 
 private:
     RefCountedArray<AtomicString> m_families { 1 };
@@ -205,9 +278,6 @@ private:
     unsigned m_isAbsoluteSize : 1; // Whether or not CSS specified an explicit size
                                   // (logical sizes like "medium" don't count).
     unsigned m_kerning : 2; // Kerning
-    unsigned m_commonLigaturesState : 2;
-    unsigned m_discretionaryLigaturesState : 2;
-    unsigned m_historicalLigaturesState : 2;
 
     unsigned m_keywordSize : 4; // We cache whether or not a font is currently represented by a CSS keyword (e.g., medium).  If so,
                            // then we can accurately translate across different generic families to adjust for different preference settings
@@ -224,9 +294,6 @@ inline bool FontCascadeDescription::operator==(const FontCascadeDescription& oth
         && m_specifiedSize == other.m_specifiedSize
         && m_isAbsoluteSize == other.m_isAbsoluteSize
         && m_kerning == other.m_kerning
-        && m_commonLigaturesState == other.m_commonLigaturesState
-        && m_discretionaryLigaturesState == other.m_discretionaryLigaturesState
-        && m_historicalLigaturesState == other.m_historicalLigaturesState
         && m_keywordSize == other.m_keywordSize
         && m_fontSmoothing == other.m_fontSmoothing
         && m_isSpecifiedFont == other.m_isSpecifiedFont;
index 947beee..420ed24 100644 (file)
 
 namespace WebCore {
 
-FontFeature::FontFeature(const AtomicString& tag, int value)
+FontFeature::FontFeature(const FontFeatureTag& tag, int value)
     : m_tag(tag)
     , m_value(value)
 {
 }
 
-bool FontFeature::operator==(const FontFeature& other) const
+FontFeature::FontFeature(FontFeatureTag&& tag, int value)
+    : m_tag(WTF::move(tag))
+    , m_value(value)
 {
-    return m_tag == other.m_tag && m_value == other.m_value;
 }
 
-bool FontFeature::operator<(const FontFeature& other) const
+bool FontFeature::operator==(const FontFeature& other) const
 {
-    return (m_tag.impl() < other.m_tag.impl()) || (m_tag.impl() == other.m_tag.impl() && m_value < other.m_value);
+    return m_tag == other.m_tag && m_value == other.m_value;
 }
 
-Ref<FontFeatureSettings> FontFeatureSettings::create()
+bool FontFeature::operator<(const FontFeature& other) const
 {
-    return adoptRef(*new FontFeatureSettings);
+    return (m_tag < other.m_tag) || (m_tag == other.m_tag && m_value < other.m_value);
 }
 
 void FontFeatureSettings::insert(FontFeature&& feature)
@@ -66,7 +67,7 @@ unsigned FontFeatureSettings::hash() const
 {
     IntegerHasher hasher;
     for (auto& feature : m_list) {
-        hasher.add(feature.tag().impl()->existingHash());
+        hasher.add(FontFeatureTagHash::hash(feature.tag()));
         hasher.add(feature.value());
     }
     return hasher.hash();
index 7220428..acfdd1d 100644 (file)
@@ -26,6 +26,7 @@
 #ifndef FontFeatureSettings_h
 #define FontFeatureSettings_h
 
+#include <array>
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
 
 namespace WebCore {
 
+typedef std::array<char, 4> FontFeatureTag;
+
+inline FontFeatureTag fontFeatureTag(const char arr[4]) { return {{ arr[0], arr[1], arr[2], arr[3] }}; }
+
+struct FontFeatureTagHash {
+    static unsigned hash(const FontFeatureTag& characters) { return (characters[0] << 24) | (characters[1] << 16) | (characters[2] << 8) | characters[3]; }
+    static bool equal(const FontFeatureTag& a, const FontFeatureTag& b) { return a == b; }
+    static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+struct FontFeatureTagHashTraits : WTF::GenericHashTraits<FontFeatureTag> {
+    static const bool emptyValueIsZero = true;
+    static void constructDeletedValue(FontFeatureTag& slot) { new (NotNull, std::addressof(slot)) FontFeatureTag({{ -1, -1, -1, -1 }}); }
+    static bool isDeletedValue(const FontFeatureTag& value) { return value == FontFeatureTag({{ -1, -1, -1, -1 }}); }
+};
+
 class FontFeature {
 public:
-    FontFeature(const AtomicString& tag, int value);
+    FontFeature() = delete;
+    FontFeature(const FontFeatureTag&, int value);
+    FontFeature(FontFeatureTag&&, int value);
 
     bool operator==(const FontFeature& other) const;
     bool operator<(const FontFeature& other) const;
 
-    const AtomicString& tag() const { return m_tag; }
+    const FontFeatureTag& tag() const { return m_tag; }
     int value() const { return m_value; }
     bool enabled() const { return value(); }
 
 private:
-    AtomicString m_tag;
-    const int m_value { 0 };
+    FontFeatureTag m_tag;
+    int m_value;
 };
 
-class FontFeatureSettings : public RefCounted<FontFeatureSettings> {
+class FontFeatureSettings {
 public:
-    static Ref<FontFeatureSettings> create();
-
     void insert(FontFeature&&);
+    bool operator==(const FontFeatureSettings& other) const { return m_list == other.m_list; }
 
     size_t size() const { return m_list.size(); }
     const FontFeature& operator[](int index) const { return m_list[index]; }
     const FontFeature& at(size_t index) const { return m_list.at(index); }
 
+    Vector<FontFeature>::const_iterator begin() const { return m_list.begin(); }
+    Vector<FontFeature>::const_iterator end() const { return m_list.end(); }
+
     unsigned hash() const;
 
 private:
-    FontFeatureSettings() { }
     Vector<FontFeature> m_list;
 };
 
index 097c633..ef73255 100644 (file)
@@ -47,9 +47,14 @@ static inline void appendRawTrueTypeFeature(CFMutableArrayRef features, int type
     CFArrayAppendValue(features, feature.get());
 }
 
+static inline bool tagEquals(FontFeatureTag tag, const char comparison[4])
+{
+    return equalIgnoringASCIICase(tag.data(), comparison, 4);
+}
+
 static inline void appendTrueTypeFeature(CFMutableArrayRef features, const FontFeature& feature)
 {
-    if (equalIgnoringASCIICase(feature.tag(), "liga") || equalIgnoringASCIICase(feature.tag(), "clig")) {
+    if (tagEquals(feature.tag(), "liga") || tagEquals(feature.tag(), "clig")) {
         if (feature.enabled()) {
             appendRawTrueTypeFeature(features, kLigaturesType, kCommonLigaturesOnSelector);
             appendRawTrueTypeFeature(features, kLigaturesType, kContextualLigaturesOnSelector);
@@ -57,79 +62,79 @@ static inline void appendTrueTypeFeature(CFMutableArrayRef features, const FontF
             appendRawTrueTypeFeature(features, kLigaturesType, kCommonLigaturesOffSelector);
             appendRawTrueTypeFeature(features, kLigaturesType, kContextualLigaturesOffSelector);
         }
-    } else if (equalIgnoringASCIICase(feature.tag(), "dlig")) {
+    } else if (tagEquals(feature.tag(), "dlig")) {
         if (feature.enabled())
             appendRawTrueTypeFeature(features, kLigaturesType, kRareLigaturesOnSelector);
         else
             appendRawTrueTypeFeature(features, kLigaturesType, kRareLigaturesOffSelector);
-    } else if (equalIgnoringASCIICase(feature.tag(), "hlig")) {
+    } else if (tagEquals(feature.tag(), "hlig")) {
         if (feature.enabled())
             appendRawTrueTypeFeature(features, kLigaturesType, kHistoricalLigaturesOnSelector);
         else
             appendRawTrueTypeFeature(features, kLigaturesType, kHistoricalLigaturesOffSelector);
-    } else if (equalIgnoringASCIICase(feature.tag(), "calt")) {
+    } else if (tagEquals(feature.tag(), "calt")) {
         if (feature.enabled())
             appendRawTrueTypeFeature(features, kContextualAlternatesType, kContextualAlternatesOnSelector);
         else
             appendRawTrueTypeFeature(features, kContextualAlternatesType, kContextualAlternatesOffSelector);
-    } else if (equalIgnoringASCIICase(feature.tag(), "subs") && feature.enabled())
+    } else if (tagEquals(feature.tag(), "subs") && feature.enabled())
         appendRawTrueTypeFeature(features, kVerticalPositionType, kInferiorsSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "sups") && feature.enabled())
+    else if (tagEquals(feature.tag(), "sups") && feature.enabled())
         appendRawTrueTypeFeature(features, kVerticalPositionType, kSuperiorsSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "smcp") && feature.enabled())
+    else if (tagEquals(feature.tag(), "smcp") && feature.enabled())
         appendRawTrueTypeFeature(features, kLowerCaseType, kLowerCaseSmallCapsSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "c2sc") && feature.enabled())
+    else if (tagEquals(feature.tag(), "c2sc") && feature.enabled())
         appendRawTrueTypeFeature(features, kUpperCaseType, kUpperCaseSmallCapsSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "pcap") && feature.enabled())
+    else if (tagEquals(feature.tag(), "pcap") && feature.enabled())
         appendRawTrueTypeFeature(features, kLowerCaseType, kLowerCasePetiteCapsSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "c2pc") && feature.enabled())
+    else if (tagEquals(feature.tag(), "c2pc") && feature.enabled())
         appendRawTrueTypeFeature(features, kUpperCaseType, kUpperCasePetiteCapsSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "unic") && feature.enabled())
+    else if (tagEquals(feature.tag(), "unic") && feature.enabled())
         appendRawTrueTypeFeature(features, kLetterCaseType, 14);
-    else if (equalIgnoringASCIICase(feature.tag(), "titl") && feature.enabled())
+    else if (tagEquals(feature.tag(), "titl") && feature.enabled())
         appendRawTrueTypeFeature(features, kStyleOptionsType, kTitlingCapsSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "lnum") && feature.enabled())
+    else if (tagEquals(feature.tag(), "lnum") && feature.enabled())
         appendRawTrueTypeFeature(features, kNumberCaseType, kUpperCaseNumbersSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "onum") && feature.enabled())
+    else if (tagEquals(feature.tag(), "onum") && feature.enabled())
         appendRawTrueTypeFeature(features, kNumberCaseType, kLowerCaseNumbersSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "pnum") && feature.enabled())
+    else if (tagEquals(feature.tag(), "pnum") && feature.enabled())
         appendRawTrueTypeFeature(features, kNumberSpacingType, kProportionalNumbersSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "tnum") && feature.enabled())
+    else if (tagEquals(feature.tag(), "tnum") && feature.enabled())
         appendRawTrueTypeFeature(features, kNumberSpacingType, kMonospacedNumbersSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "frac") && feature.enabled())
+    else if (tagEquals(feature.tag(), "frac") && feature.enabled())
         appendRawTrueTypeFeature(features, kFractionsType, kDiagonalFractionsSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "afrc") && feature.enabled())
+    else if (tagEquals(feature.tag(), "afrc") && feature.enabled())
         appendRawTrueTypeFeature(features, kFractionsType, kVerticalFractionsSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "ordn") && feature.enabled())
+    else if (tagEquals(feature.tag(), "ordn") && feature.enabled())
         appendRawTrueTypeFeature(features, kVerticalPositionType, kOrdinalsSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "zero") && feature.enabled())
+    else if (tagEquals(feature.tag(), "zero") && feature.enabled())
         appendRawTrueTypeFeature(features, kTypographicExtrasType, kSlashedZeroOnSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "hist") && feature.enabled())
+    else if (tagEquals(feature.tag(), "hist") && feature.enabled())
         appendRawTrueTypeFeature(features, kLigaturesType, kHistoricalLigaturesOnSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "jp78") && feature.enabled())
+    else if (tagEquals(feature.tag(), "jp78") && feature.enabled())
         appendRawTrueTypeFeature(features, kCharacterShapeType, kJIS1978CharactersSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "jp83") && feature.enabled())
+    else if (tagEquals(feature.tag(), "jp83") && feature.enabled())
         appendRawTrueTypeFeature(features, kCharacterShapeType, kJIS1983CharactersSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "jp90") && feature.enabled())
+    else if (tagEquals(feature.tag(), "jp90") && feature.enabled())
         appendRawTrueTypeFeature(features, kCharacterShapeType, kJIS1990CharactersSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "jp04") && feature.enabled())
+    else if (tagEquals(feature.tag(), "jp04") && feature.enabled())
         appendRawTrueTypeFeature(features, kCharacterShapeType, kJIS2004CharactersSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "smpl") && feature.enabled())
+    else if (tagEquals(feature.tag(), "smpl") && feature.enabled())
         appendRawTrueTypeFeature(features, kCharacterShapeType, kSimplifiedCharactersSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "trad") && feature.enabled())
+    else if (tagEquals(feature.tag(), "trad") && feature.enabled())
         appendRawTrueTypeFeature(features, kCharacterShapeType, kTraditionalCharactersSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "fwid") && feature.enabled())
+    else if (tagEquals(feature.tag(), "fwid") && feature.enabled())
         appendRawTrueTypeFeature(features, kTextSpacingType, kMonospacedTextSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "pwid") && feature.enabled())
+    else if (tagEquals(feature.tag(), "pwid") && feature.enabled())
         appendRawTrueTypeFeature(features, kTextSpacingType, kProportionalTextSelector);
-    else if (equalIgnoringASCIICase(feature.tag(), "ruby") && feature.enabled())
+    else if (tagEquals(feature.tag(), "ruby") && feature.enabled())
         appendRawTrueTypeFeature(features, kRubyKanaType, kRubyKanaOnSelector);
 }
 
 static inline void appendOpenTypeFeature(CFMutableArrayRef features, const FontFeature& feature)
 {
 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000)
-    RetainPtr<CFStringRef> featureKey = feature.tag().string().createCFString();
+    RetainPtr<CFStringRef> featureKey = adoptCF(CFStringCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(feature.tag().data()), feature.tag().size() * sizeof(FontFeatureTag::value_type), kCFStringEncodingASCII, false));
     int rawFeatureValue = feature.value();
     RetainPtr<CFNumberRef> featureValue = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &rawFeatureValue));
     CFTypeRef featureDictionaryKeys[] = { kCTFontOpenTypeFeatureTag, kCTFontOpenTypeFeatureValue };
@@ -142,17 +147,197 @@ static inline void appendOpenTypeFeature(CFMutableArrayRef features, const FontF
 #endif
 }
 
-RetainPtr<CTFontRef> preparePlatformFont(CTFontRef originalFont, TextRenderingMode textRenderingMode, const FontFeatureSettings* features)
+typedef HashMap<FontFeatureTag, int, FontFeatureTagHash, FontFeatureTagHashTraits> FeaturesMap;
+
+static FeaturesMap computeFeatureSettingsFromVariants(const FontVariantSettings& variantSettings)
+{
+    FeaturesMap result;
+
+    switch (variantSettings.commonLigatures) {
+    case FontVariantLigatures::Yes:
+        result.add(fontFeatureTag("liga"), 1);
+        result.add(fontFeatureTag("clig"), 1);
+        break;
+    case FontVariantLigatures::No:
+        result.add(fontFeatureTag("liga"), 0);
+        result.add(fontFeatureTag("clig"), 0);
+        break;
+    default:
+        break;
+    }
+
+    switch (variantSettings.discretionaryLigatures) {
+    case FontVariantLigatures::Yes:
+        result.add(fontFeatureTag("dlig"), 1);
+        break;
+    case FontVariantLigatures::No:
+        result.add(fontFeatureTag("dlig"), 0);
+        break;
+    default:
+        break;
+    }
+
+    switch (variantSettings.historicalLigatures) {
+    case FontVariantLigatures::Yes:
+        result.add(fontFeatureTag("hlig"), 1);
+        break;
+    case FontVariantLigatures::No:
+        result.add(fontFeatureTag("hlig"), 0);
+        break;
+    default:
+        break;
+    }
+
+    switch (variantSettings.contextualAlternates) {
+    case FontVariantLigatures::Yes:
+        result.add(fontFeatureTag("calt"), 1);
+        break;
+    case FontVariantLigatures::No:
+        result.add(fontFeatureTag("calt"), 0);
+        break;
+    default:
+        break;
+    }
+
+    switch (variantSettings.position) {
+    case FontVariantPosition::Subscript:
+        result.add(fontFeatureTag("subs"), 1);
+        break;
+    case FontVariantPosition::Superscript:
+        result.add(fontFeatureTag("sups"), 1);
+        break;
+    default:
+        break;
+    }
+
+    switch (variantSettings.caps) {
+    case FontVariantCaps::AllSmall:
+        result.add(fontFeatureTag("c2sc"), 1);
+        FALLTHROUGH;
+    case FontVariantCaps::Small:
+        result.add(fontFeatureTag("smcp"), 1);
+        break;
+    case FontVariantCaps::AllPetite:
+        result.add(fontFeatureTag("c2pc"), 1);
+        FALLTHROUGH;
+    case FontVariantCaps::Petite:
+        result.add(fontFeatureTag("pcap"), 1);
+        break;
+    case FontVariantCaps::Unicase:
+        result.add(fontFeatureTag("unic"), 1);
+        break;
+    case FontVariantCaps::Titling:
+        result.add(fontFeatureTag("titl"), 1);
+        break;
+    default:
+        break;
+    }
+
+    switch (variantSettings.numericFigure) {
+    case FontVariantNumericFigure::LiningNumbers:
+        result.add(fontFeatureTag("lnum"), 1);
+        break;
+    case FontVariantNumericFigure::OldStyleNumbers:
+        result.add(fontFeatureTag("onum"), 1);
+        break;
+    default:
+        break;
+    }
+
+    switch (variantSettings.numericSpacing) {
+    case FontVariantNumericSpacing::ProportionalNumbers:
+        result.add(fontFeatureTag("pnum"), 1);
+        break;
+    case FontVariantNumericSpacing::TabularNumbers:
+        result.add(fontFeatureTag("tnum"), 1);
+        break;
+    default:
+        break;
+    }
+
+    switch (variantSettings.numericFraction) {
+    case FontVariantNumericFraction::DiagonalFractions:
+        result.add(fontFeatureTag("frac"), 1);
+        break;
+    case FontVariantNumericFraction::StackedFractions:
+        result.add(fontFeatureTag("afrc"), 1);
+        break;
+    default:
+        break;
+    }
+
+    if (variantSettings.numericOrdinal == FontVariantNumericOrdinal::Yes)
+        result.add(fontFeatureTag("ordn"), 1);
+    if (variantSettings.numericSlashedZero == FontVariantNumericSlashedZero::Yes)
+        result.add(fontFeatureTag("zero"), 1);
+
+    switch (variantSettings.alternates) {
+    case FontVariantAlternates::HistoricalForms:
+        result.add(fontFeatureTag("hist"), 1);
+        break;
+    default:
+        break;
+    }
+
+    switch (variantSettings.eastAsianVariant) {
+    case FontVariantEastAsianVariant::Jis78:
+        result.add(fontFeatureTag("jp78"), 1);
+        break;
+    case FontVariantEastAsianVariant::Jis83:
+        result.add(fontFeatureTag("jp83"), 1);
+        break;
+    case FontVariantEastAsianVariant::Jis90:
+        result.add(fontFeatureTag("jp90"), 1);
+        break;
+    case FontVariantEastAsianVariant::Jis04:
+        result.add(fontFeatureTag("jp04"), 1);
+        break;
+    case FontVariantEastAsianVariant::Simplified:
+        result.add(fontFeatureTag("smpl"), 1);
+        break;
+    case FontVariantEastAsianVariant::Traditional:
+        result.add(fontFeatureTag("trad"), 1);
+        break;
+    default:
+        break;
+    }
+
+    switch (variantSettings.eastAsianWidth) {
+    case FontVariantEastAsianWidth::FullWidth:
+        result.add(fontFeatureTag("fwid"), 1);
+        break;
+    case FontVariantEastAsianWidth::ProportionalWidth:
+        result.add(fontFeatureTag("pwid"), 1);
+        break;
+    default:
+        break;
+    }
+
+    if (variantSettings.eastAsianRuby == FontVariantEastAsianRuby::Yes)
+        result.add(fontFeatureTag("ruby"), 1);
+
+    return result;
+}
+
+RetainPtr<CTFontRef> preparePlatformFont(CTFontRef originalFont, TextRenderingMode textRenderingMode, const FontFeatureSettings& features, const FontVariantSettings& variantSettings)
 {
-    if (!originalFont || ((!features || !features->size()) && (textRenderingMode != OptimizeLegibility)))
+    if (!originalFont || (!features.size() && (textRenderingMode != OptimizeLegibility) && variantSettings.isAllNormal()))
         return originalFont;
 
+    // FIXME: We don't consult with the @font-face first, like the spec says we should.
+
+    // Spec says that font-feature-settings should override font-variant-*.
+    auto fontFeatureSettingsFromVariants = computeFeatureSettingsFromVariants(variantSettings);
+    for (auto& newFeature : features)
+        fontFeatureSettingsFromVariants.set(newFeature.tag(), newFeature.value());
+
     RetainPtr<CFMutableDictionaryRef> attributes = adoptCF(CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
-    if (features && features->size()) {
-        RetainPtr<CFMutableArrayRef> featureArray = adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, features->size(), &kCFTypeArrayCallBacks));
-        for (size_t i = 0; i < features->size(); ++i) {
-            appendTrueTypeFeature(featureArray.get(), features->at(i));
-            appendOpenTypeFeature(featureArray.get(), features->at(i));
+    if (fontFeatureSettingsFromVariants.size()) {
+        RetainPtr<CFMutableArrayRef> featureArray = adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, features.size(), &kCFTypeArrayCallBacks));
+        for (auto& p : fontFeatureSettingsFromVariants) {
+            auto feature = FontFeature(p.key, p.value);
+            appendTrueTypeFeature(featureArray.get(), feature);
+            appendOpenTypeFeature(featureArray.get(), feature);
         }
         CFDictionaryAddValue(attributes.get(), kCTFontFeatureSettingsAttribute, featureArray.get());
     }
@@ -410,27 +595,29 @@ void FontCache::setFontWhitelist(const Vector<String>& inputWhitelist)
 }
 
 #if ENABLE(PLATFORM_FONT_LOOKUP)
-static RetainPtr<CTFontRef> platformFontLookupWithFamily(const AtomicString& family, CTFontSymbolicTraits requestedTraits, FontWeight weight, const FontFeatureSettings* featureSettings, TextRenderingMode textRenderingMode, float size)
+static RetainPtr<CTFontRef> platformFontLookupWithFamily(const AtomicString& family, CTFontSymbolicTraits requestedTraits, FontWeight weight, const FontFeatureSettings& featureSettings, const FontVariantSettings& variantSettings, TextRenderingMode textRenderingMode, float size)
 {
     const auto& whitelist = fontWhitelist();
     if (whitelist.size() && !whitelist.contains(family))
         return nullptr;
 
     auto foundFont = adoptCF(CTFontCreateForCSS(family.string().createCFString().get(), toCoreTextFontWeight(weight), requestedTraits, size));
-    return preparePlatformFont(foundFont.get(), textRenderingMode, featureSettings);
+    return preparePlatformFont(foundFont.get(), textRenderingMode, featureSettings, variantSettings);
 }
 #endif
 
-static RetainPtr<CTFontRef> fontWithFamily(const AtomicString& family, CTFontSymbolicTraits desiredTraits, FontWeight weight, const FontFeatureSettings* featureSettings, TextRenderingMode textRenderingMode, float size)
+static RetainPtr<CTFontRef> fontWithFamily(const AtomicString& family, CTFontSymbolicTraits desiredTraits, FontWeight weight, const FontFeatureSettings& featureSettings, const FontVariantSettings& variantSettings, const TextRenderingMode& textRenderingMode, float size)
 {
     if (family.isEmpty())
         return nullptr;
     if (auto specialCase = platformFontWithFamilySpecialCase(family, weight, desiredTraits, size))
         return specialCase;
 #if ENABLE(PLATFORM_FONT_LOOKUP)
-    return platformFontLookupWithFamily(family, desiredTraits, weight, featureSettings, textRenderingMode, size);
+    return platformFontLookupWithFamily(family, desiredTraits, weight, featureSettings, variantSettings, textRenderingMode, size);
 #else
-    return platformFontWithFamily(family, desiredTraits, weight, featureSettings, textRenderingMode, size);
+    UNUSED_PARAM(featureSettings);
+    UNUSED_PARAM(variantSettings);
+    return platformFontWithFamily(family, desiredTraits, weight, textRenderingMode, size);
 #endif
 }
 
@@ -471,7 +658,7 @@ std::unique_ptr<FontPlatformData> FontCache::createFontPlatformData(const FontDe
     CTFontSymbolicTraits traits = computeTraits(fontDescription);
     float size = fontDescription.computedPixelSize();
 
-    RetainPtr<CTFontRef> font = fontWithFamily(family, traits, fontDescription.weight(), fontDescription.featureSettings(), fontDescription.textRenderingMode(), size);
+    RetainPtr<CTFontRef> font = fontWithFamily(family, traits, fontDescription.weight(), fontDescription.featureSettings(), fontDescription.variantSettings(), fontDescription.textRenderingMode(), size);
 
 #if PLATFORM(MAC)
     if (!font) {
@@ -482,7 +669,7 @@ std::unique_ptr<FontPlatformData> FontCache::createFontPlatformData(const FontDe
         // Ignore the result because we want to use our own algorithm to actually find the font.
         autoActivateFont(family.string(), size);
 
-        font = fontWithFamily(family, traits, fontDescription.weight(), fontDescription.featureSettings(), fontDescription.textRenderingMode(), size);
+        font = fontWithFamily(family, traits, fontDescription.weight(), fontDescription.featureSettings(), fontDescription.variantSettings(), fontDescription.textRenderingMode(), size);
     }
 #endif
 
@@ -526,7 +713,7 @@ RefPtr<Font> FontCache::systemFallbackForCharacters(const FontDescription& descr
 
     const FontPlatformData& platformData = originalFontData->platformData();
     RetainPtr<CTFontRef> result = platformLookupFallbackFont(platformData.font(), description.weight(), description.locale(), characters, length);
-    result = preparePlatformFont(result.get(), description.textRenderingMode(), description.featureSettings());
+    result = preparePlatformFont(result.get(), description.textRenderingMode(), description.featureSettings(), description.variantSettings());
     if (!result)
         return lastResortFallbackFont(description);
 
index c0331a4..3481973 100644 (file)
@@ -352,16 +352,14 @@ void HarfBuzzShaper::setFontFeatures()
         ASSERT_NOT_REACHED();
     }
 
-    FontFeatureSettings* settings = description.featureSettings();
-    if (!settings)
-        return;
+    const FontFeatureSettings& settings = description.featureSettings();
 
-    unsigned numFeatures = settings->size();
+    unsigned numFeatures = settings.size();
     for (unsigned i = 0; i < numFeatures; ++i) {
         hb_feature_t feature;
-        auto& tag = settings->at(i).tag();
+        auto& tag = settings[i].tag();
         feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]);
-        feature.value = settings->at(i).value();
+        feature.value = settings[i].value();
         feature.start = 0;
         feature.end = static_cast<unsigned>(-1);
         m_features.append(feature);
index 46c90e6..1d93acb 100644 (file)
@@ -254,7 +254,7 @@ RetainPtr<CTFontRef> platformFontWithFamilySpecialCase(const AtomicString& famil
 }
 
 #if !ENABLE(PLATFORM_FONT_LOOKUP)
-RetainPtr<CTFontRef> platformFontWithFamily(const AtomicString& family, CTFontSymbolicTraits requestedTraits, FontWeight weight, const FontFeatureSettings*, TextRenderingMode, float size)
+RetainPtr<CTFontRef> platformFontWithFamily(const AtomicString& family, CTFontSymbolicTraits requestedTraits, FontWeight weight, TextRenderingMode, float size)
 {
     NSFontManager *fontManager = [NSFontManager sharedFontManager];
     NSString *availableFamily;
index 1c0783e..84c9f9c 100644 (file)
@@ -41,7 +41,7 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(const FontDescription&
     FontWidthVariant widthVariant = fontDescription.widthVariant();
 #if CORETEXT_WEB_FONTS
     RetainPtr<CTFontRef> font = adoptCF(CTFontCreateWithFontDescriptor(m_fontDescriptor.get(), size, nullptr));
-    font = preparePlatformFont(font.get(), fontDescription.textRenderingMode(), fontDescription.featureSettings());
+    font = preparePlatformFont(font.get(), fontDescription.textRenderingMode(), fontDescription.featureSettings(), fontDescription.variantSettings());
     return FontPlatformData(font.get(), size, bold, italic, orientation, widthVariant, fontDescription.textRenderingMode());
 #else
     return FontPlatformData(m_cgFont.get(), size, bold, italic, orientation, widthVariant, fontDescription.textRenderingMode());
index b279d6f..87e1c4e 100644 (file)
@@ -72,6 +72,119 @@ enum FontSynthesisValues {
 typedef unsigned FontSynthesis;
 const unsigned FontSynthesisWidth = 2;
 
+enum class FontVariantLigatures {
+    Normal,
+    Yes,
+    No
+};
+
+enum class FontVariantPosition {
+    Normal,
+    Subscript,
+    Superscript
+};
+
+enum class FontVariantCaps {
+    Normal,
+    Small,
+    AllSmall,
+    Petite,
+    AllPetite,
+    Unicase,
+    Titling
+};
+
+enum class FontVariantNumericFigure {
+    Normal,
+    LiningNumbers,
+    OldStyleNumbers
+};
+
+enum class FontVariantNumericSpacing {
+    Normal,
+    ProportionalNumbers,
+    TabularNumbers
+};
+
+enum class FontVariantNumericFraction {
+    Normal,
+    DiagonalFractions,
+    StackedFractions
+};
+
+enum class FontVariantNumericOrdinal {
+    Normal,
+    Yes
+};
+
+enum class FontVariantNumericSlashedZero {
+    Normal,
+    Yes
+};
+
+enum class FontVariantAlternates {
+    Normal,
+    HistoricalForms
+};
+
+enum class FontVariantEastAsianVariant {
+    Normal,
+    Jis78,
+    Jis83,
+    Jis90,
+    Jis04,
+    Simplified,
+    Traditional
+};
+
+enum class FontVariantEastAsianWidth {
+    Normal,
+    FullWidth,
+    ProportionalWidth
+};
+
+enum class FontVariantEastAsianRuby {
+    Normal,
+    Yes
+};
+
+struct FontVariantSettings {
+    bool isAllNormal() const
+    {
+        return commonLigatures == FontVariantLigatures::Normal
+            && discretionaryLigatures == FontVariantLigatures::Normal
+            && historicalLigatures == FontVariantLigatures::Normal
+            && contextualAlternates == FontVariantLigatures::Normal
+            && position == FontVariantPosition::Normal
+            && caps == FontVariantCaps::Normal
+            && numericFigure == FontVariantNumericFigure::Normal
+            && numericSpacing == FontVariantNumericSpacing::Normal
+            && numericFraction == FontVariantNumericFraction::Normal
+            && numericOrdinal == FontVariantNumericOrdinal::Normal
+            && numericSlashedZero == FontVariantNumericSlashedZero::Normal
+            && alternates == FontVariantAlternates::Normal
+            && eastAsianVariant == FontVariantEastAsianVariant::Normal
+            && eastAsianWidth == FontVariantEastAsianWidth::Normal
+            && eastAsianRuby == FontVariantEastAsianRuby::Normal;
+    }
+
+    FontVariantLigatures commonLigatures;
+    FontVariantLigatures discretionaryLigatures;
+    FontVariantLigatures historicalLigatures;
+    FontVariantLigatures contextualAlternates;
+    FontVariantPosition position;
+    FontVariantCaps caps;
+    FontVariantNumericFigure numericFigure;
+    FontVariantNumericSpacing numericSpacing;
+    FontVariantNumericFraction numericFraction;
+    FontVariantNumericOrdinal numericOrdinal;
+    FontVariantNumericSlashedZero numericSlashedZero;
+    FontVariantAlternates alternates;
+    FontVariantEastAsianVariant eastAsianVariant;
+    FontVariantEastAsianWidth eastAsianWidth;
+    FontVariantEastAsianRuby eastAsianRuby;
+};
+
 enum FontWidthVariant {
     RegularWidth,
     HalfWidth,
index 422c662..666f259 100644 (file)
@@ -1237,7 +1237,7 @@ void RenderThemeIOS::updateCachedSystemFontDescription(CSSValueID valueID, FontC
 
     ASSERT(fontDescriptor);
     RetainPtr<CTFontRef> font = adoptCF(CTFontCreateWithFontDescriptor(fontDescriptor.get(), 0, nullptr));
-    font = preparePlatformFont(font.get(), fontDescription.textRenderingMode(), fontDescription.featureSettings());
+    font = preparePlatformFont(font.get(), fontDescription.textRenderingMode(), fontDescription.featureSettings(), fontDescription.variantSettings());
     fontDescription.setIsAbsoluteSize(true);
     fontDescription.setOneFamily(textStyle);
     fontDescription.setSpecifiedSize(CTFontGetSize(font.get()));
index c492243..0668940 100644 (file)
@@ -83,6 +83,7 @@ struct WordTrailingSpace {
         m_state = WordTrailingSpaceState::Computed;
         return m_width;
     }
+
 private:
     enum class WordTrailingSpaceState { Uninitialized, Computed };
     WordTrailingSpaceState m_state { WordTrailingSpaceState::Uninitialized };
index 711d4ca..0f416b1 100644 (file)
@@ -1,3 +1,15 @@
+2015-09-23  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [Cocoa] [Font Features] Implement font-variant-*
+        https://bugs.webkit.org/show_bug.cgi?id=148413
+
+        Reviewed by Darin Adler.
+
+        Update test font to use "lnum" feature.
+
+        * FontWithFeatures/FontWithFeatures/FontCreator.cpp:
+        (Generator::appendGSUBTable):
+
 2015-09-22  Andy Estes  <aestes@apple.com>
 
         ContentFiltering.AllowDownloadAfterAddData is very flaky
index 647818f..7a3e141 100644 (file)
@@ -470,7 +470,7 @@ private:
 
     void appendGSUBTable()
     {
-        std::vector<std::array<char, 5>> features {{"liga"}, {"clig"}, {"dlig"}, {"hlig"}, {"calt"}, {"subs"}, {"sups"}, {"smcp"}, {"c2sc"}, {"pcap"}, {"c2pc"}, {"unic"}, {"titl"}, {"onum"}, {"pnum"}, {"tnum"}, {"frac"}, {"afrc"}, {"ordn"}, {"zero"}, {"hist"}, {"jp78"}, {"jp83"}, {"jp90"}, {"jp04"}, {"smpl"}, {"trad"}, {"fwid"}, {"pwid"}, {"ruby"}};
+        std::vector<std::array<char, 5>> features {{"liga"}, {"clig"}, {"dlig"}, {"hlig"}, {"calt"}, {"subs"}, {"sups"}, {"smcp"}, {"c2sc"}, {"pcap"}, {"c2pc"}, {"unic"}, {"titl"}, {"lnum"}, {"onum"}, {"pnum"}, {"tnum"}, {"frac"}, {"afrc"}, {"ordn"}, {"zero"}, {"hist"}, {"jp78"}, {"jp83"}, {"jp90"}, {"jp04"}, {"smpl"}, {"trad"}, {"fwid"}, {"pwid"}, {"ruby"}};
         auto tableLocation = result.size();
         auto headerSize = 10;