Bug 1157064 - font-display descriptor parsing. r=dbaron
authorJohn Daggett <jdaggett@mozilla.com>
Thu, 07 Jan 2016 14:02:58 +0900
changeset 301137 5fe7d4e2fd2c30be2a60d201e9325f25fb59aeb8
parent 301136 dd7c4f457433d5a9f65a4a6007dbfe389081c248
child 301138 6d9b17e5e7b55c4a9be4b6739d46a11106eab1f3
push id8978
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 14:05:32 +0000
treeherdermozilla-aurora@b9a803752a2c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs1157064
milestone46.0a1
Bug 1157064 - font-display descriptor parsing. r=dbaron
gfx/thebes/gfxFontConstants.h
layout/style/nsCSSFontDescList.h
layout/style/nsCSSKeywordList.h
layout/style/nsCSSParser.cpp
layout/style/nsCSSProps.cpp
layout/style/nsCSSProps.h
layout/style/nsCSSRules.cpp
layout/style/test/test_font_face_parser.html
modules/libpref/init/all.js
--- a/gfx/thebes/gfxFontConstants.h
+++ b/gfx/thebes/gfxFontConstants.h
@@ -36,16 +36,22 @@
 
 #define NS_FONT_KERNING_AUTO                        0
 #define NS_FONT_KERNING_NONE                        1
 #define NS_FONT_KERNING_NORMAL                      2
 
 #define NS_FONT_SYNTHESIS_WEIGHT                    0x1
 #define NS_FONT_SYNTHESIS_STYLE                     0x2
 
+#define NS_FONT_DISPLAY_AUTO            0
+#define NS_FONT_DISPLAY_BLOCK           1
+#define NS_FONT_DISPLAY_SWAP            2
+#define NS_FONT_DISPLAY_FALLBACK        3
+#define NS_FONT_DISPLAY_OPTIONAL        4
+
 enum {
     eFeatureAlternates_historical,
     eFeatureAlternates_stylistic,
     eFeatureAlternates_styleset,
     eFeatureAlternates_character_variant,
     eFeatureAlternates_swash,
     eFeatureAlternates_ornaments,
     eFeatureAlternates_annotation,
--- a/layout/style/nsCSSFontDescList.h
+++ b/layout/style/nsCSSFontDescList.h
@@ -6,8 +6,9 @@
 CSS_FONT_DESC(font-family, Family)
 CSS_FONT_DESC(font-style, Style)
 CSS_FONT_DESC(font-weight, Weight)
 CSS_FONT_DESC(font-stretch, Stretch)
 CSS_FONT_DESC(src, Src)
 CSS_FONT_DESC(unicode-range, UnicodeRange)
 CSS_FONT_DESC(font-feature-settings, FontFeatureSettings)
 CSS_FONT_DESC(font-language-override, FontLanguageOverride)
+CSS_FONT_DESC(font-display, Display)
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -256,16 +256,17 @@ CSS_KEY(end, end)
 CSS_KEY(ethiopic-numeric, ethiopic_numeric)
 CSS_KEY(ex, ex)
 CSS_KEY(exclusion, exclusion)
 CSS_KEY(expanded, expanded)
 CSS_KEY(extends, extends)
 CSS_KEY(extra-condensed, extra_condensed)
 CSS_KEY(extra-expanded, extra_expanded)
 CSS_KEY(ew-resize, ew_resize)
+CSS_KEY(fallback, fallback)
 CSS_KEY(fantasy, fantasy)
 CSS_KEY(farthest-side, farthest_side)
 CSS_KEY(farthest-corner, farthest_corner)
 CSS_KEY(fill, fill)
 CSS_KEY(filled, filled)
 CSS_KEY(fill-box, fill_box)
 CSS_KEY(fixed, fixed)
 CSS_KEY(flat, flat)
@@ -404,16 +405,17 @@ CSS_KEY(numeric, numeric)
 CSS_KEY(ns-resize, ns_resize)
 CSS_KEY(nw-resize, nw_resize)
 CSS_KEY(nwse-resize, nwse_resize)
 CSS_KEY(oblique, oblique)
 CSS_KEY(oldstyle-nums, oldstyle_nums)
 CSS_KEY(opacity, opacity)
 CSS_KEY(open, open)
 CSS_KEY(open-quote, open_quote)
+CSS_KEY(optional, optional)
 CSS_KEY(ordinal, ordinal)
 CSS_KEY(ornaments, ornaments)
 CSS_KEY(outset, outset)
 CSS_KEY(outside, outside)
 CSS_KEY(over, over)
 CSS_KEY(overlay, overlay)
 CSS_KEY(overline, overline)
 CSS_KEY(paint, paint)
@@ -543,16 +545,17 @@ CSS_KEY(stroke-box, stroke_box)
 CSS_KEY(style, style)
 CSS_KEY(styleset, styleset)
 CSS_KEY(stylistic, stylistic)
 CSS_KEY(sub, sub)
 CSS_KEY(subgrid, subgrid)
 CSS_KEY(super, super)
 CSS_KEY(sw-resize, sw_resize)
 CSS_KEY(swash, swash)
+CSS_KEY(swap, swap)
 CSS_KEY(table, table)
 CSS_KEY(table-caption, table_caption)
 CSS_KEY(table-cell, table_cell)
 CSS_KEY(table-column, table_column)
 CSS_KEY(table-column-group, table_column_group)
 CSS_KEY(table-footer-group, table_footer_group)
 CSS_KEY(table-header-group, table_header_group)
 CSS_KEY(table-row, table_row)
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -3943,17 +3943,19 @@ CSSParserImpl::ParseFontDescriptor(nsCSS
     REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon);
     OUTPUT_ERROR();
     return false;
   }
 
   nsCSSFontDesc descID = nsCSSProps::LookupFontDesc(descName);
   nsCSSValue value;
 
-  if (descID == eCSSFontDesc_UNKNOWN) {
+  if (descID == eCSSFontDesc_UNKNOWN ||
+      (descID == eCSSFontDesc_Display &&
+       !Preferences::GetBool("layout.css.font-display.enabled"))) {
     if (NonMozillaVendorIdentifier(descName)) {
       // silently skip other vendors' extensions
       SkipDeclaration(true);
       return true;
     } else {
       REPORT_UNEXPECTED_P(PEUnknownFontDesc, descName);
       return false;
     }
@@ -11598,16 +11600,20 @@ CSSParserImpl::ParseFontDescriptorValue(
     return true;
   }
 
   case eCSSFontDesc_Style:
     // property is VARIANT_HMK|VARIANT_SYSFONT
     return ParseSingleTokenVariant(aValue, VARIANT_KEYWORD | VARIANT_NORMAL,
                                    nsCSSProps::kFontStyleKTable);
 
+  case eCSSFontDesc_Display:
+    return ParseSingleTokenVariant(aValue, VARIANT_KEYWORD,
+                                   nsCSSProps::kFontDisplayKTable);
+
   case eCSSFontDesc_Weight:
     return (ParseFontWeight(aValue) &&
             aValue.GetUnit() != eCSSUnit_Inherit &&
             aValue.GetUnit() != eCSSUnit_Initial &&
             aValue.GetUnit() != eCSSUnit_Unset &&
             (aValue.GetUnit() != eCSSUnit_Enumerated ||
              (aValue.GetIntValue() != NS_STYLE_FONT_WEIGHT_BOLDER &&
               aValue.GetIntValue() != NS_STYLE_FONT_WEIGHT_LIGHTER)));
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -608,27 +608,42 @@ nsCSSProps::LookupPropertyByIDLName(cons
   return LookupPropertyByIDLName(NS_ConvertUTF16toUTF8(aPropertyIDLName),
                                  aEnabled);
 }
 
 nsCSSFontDesc
 nsCSSProps::LookupFontDesc(const nsACString& aFontDesc)
 {
   MOZ_ASSERT(gFontDescTable, "no lookup table, needs addref");
-  return nsCSSFontDesc(gFontDescTable->Lookup(aFontDesc));
+  nsCSSFontDesc which = nsCSSFontDesc(gFontDescTable->Lookup(aFontDesc));
+
+  if (which == eCSSFontDesc_Display &&
+      !Preferences::GetBool("layout.css.font-display.enabled")) {
+    which = eCSSFontDesc_UNKNOWN;
+  } else if (which == eCSSFontDesc_UNKNOWN) {
+    // check for unprefixed font-feature-settings/font-language-override
+    nsAutoCString prefixedProp;
+    prefixedProp.AppendLiteral("-moz-");
+    prefixedProp.Append(aFontDesc);
+    which = nsCSSFontDesc(gFontDescTable->Lookup(prefixedProp));
+  }
+  return which;
 }
 
 nsCSSFontDesc
 nsCSSProps::LookupFontDesc(const nsAString& aFontDesc)
 {
   MOZ_ASSERT(gFontDescTable, "no lookup table, needs addref");
   nsCSSFontDesc which = nsCSSFontDesc(gFontDescTable->Lookup(aFontDesc));
 
-  // check for unprefixed font-feature-settings/font-language-override
-  if (which == eCSSFontDesc_UNKNOWN) {
+  if (which == eCSSFontDesc_Display &&
+      !Preferences::GetBool("layout.css.font-display.enabled")) {
+    which = eCSSFontDesc_UNKNOWN;
+  } else if (which == eCSSFontDesc_UNKNOWN) {
+    // check for unprefixed font-feature-settings/font-language-override
     nsAutoString prefixedProp;
     prefixedProp.AppendLiteral("-moz-");
     prefixedProp.Append(aFontDesc);
     which = nsCSSFontDesc(gFontDescTable->Lookup(prefixedProp));
   }
   return which;
 }
 
@@ -1376,16 +1391,25 @@ KTableEntry nsCSSProps::kFloatKTable[] =
 };
 
 const KTableEntry nsCSSProps::kFloatEdgeKTable[] = {
   { eCSSKeyword_content_box, NS_STYLE_FLOAT_EDGE_CONTENT },
   { eCSSKeyword_margin_box, NS_STYLE_FLOAT_EDGE_MARGIN },
   { eCSSKeyword_UNKNOWN, -1 }
 };
 
+const KTableEntry nsCSSProps::kFontDisplayKTable[] = {
+  { eCSSKeyword_auto, NS_FONT_DISPLAY_AUTO },
+  { eCSSKeyword_block, NS_FONT_DISPLAY_BLOCK },
+  { eCSSKeyword_swap, NS_FONT_DISPLAY_SWAP },
+  { eCSSKeyword_fallback, NS_FONT_DISPLAY_FALLBACK },
+  { eCSSKeyword_optional, NS_FONT_DISPLAY_OPTIONAL },
+  { eCSSKeyword_UNKNOWN, -1 }
+};
+
 const KTableEntry nsCSSProps::kFontKTable[] = {
   // CSS2.
   { eCSSKeyword_caption, NS_STYLE_FONT_CAPTION },
   { eCSSKeyword_icon, NS_STYLE_FONT_ICON },
   { eCSSKeyword_menu, NS_STYLE_FONT_MENU },
   { eCSSKeyword_message_box, NS_STYLE_FONT_MESSAGE_BOX },
   { eCSSKeyword_small_caption, NS_STYLE_FONT_SMALL_CAPTION },
   { eCSSKeyword_status_bar, NS_STYLE_FONT_STATUS_BAR },
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -736,16 +736,17 @@ public:
   static const KTableEntry kJustifyContentKTable[];
   // ------------------------------------------------------------------
   static const KTableEntry kFlexDirectionKTable[];
   static const KTableEntry kFlexWrapKTable[];
   // Not const because we modify its entries when the pref
   // "layout.css.float-logical-values.enabled" changes:
   static KTableEntry kFloatKTable[];
   static const KTableEntry kFloatEdgeKTable[];
+  static const KTableEntry kFontDisplayKTable[];
   static const KTableEntry kFontKTable[];
   static const KTableEntry kFontKerningKTable[];
   static const KTableEntry kFontSizeKTable[];
   static const KTableEntry kFontSmoothingKTable[];
   static const KTableEntry kFontStretchKTable[];
   static const KTableEntry kFontStyleKTable[];
   static const KTableEntry kFontSynthesisKTable[];
   static const KTableEntry kFontVariantKTable[];
--- a/layout/style/nsCSSRules.cpp
+++ b/layout/style/nsCSSRules.cpp
@@ -1297,16 +1297,23 @@ nsCSSFontFaceStyleDecl::GetPropertyValue
     nsStyleUtil::AppendFontFeatureSettings(val, aResult);
     return NS_OK;
 
   case eCSSFontDesc_FontLanguageOverride:
     val.AppendToString(eCSSProperty_font_language_override, aResult,
                        nsCSSValue::eNormalized);
     return NS_OK;
 
+  case eCSSFontDesc_Display:
+    NS_ASSERTION(val.GetUnit() == eCSSUnit_Enumerated,
+                 "unknown unit for font-display descriptor");
+    AppendASCIItoUTF16(nsCSSProps::ValueToKeyword(val.GetIntValue(),
+                                       nsCSSProps::kFontDisplayKTable), aResult);
+    return NS_OK;
+
   case eCSSFontDesc_Src:
     nsStyleUtil::AppendSerializedFontSrc(val, aResult);
     return NS_OK;
 
   case eCSSFontDesc_UnicodeRange:
     nsStyleUtil::AppendUnicodeRange(val, aResult);
     return NS_OK;
 
--- a/layout/style/test/test_font_face_parser.html
+++ b/layout/style/test/test_font_face_parser.html
@@ -9,16 +9,17 @@
 <body>
 <p>@font-face parsing (<a
   target="_blank"
   href="https://bugzilla.mozilla.org/show_bug.cgi?id=441469"
 >bug 441469</a>)</p>
 <pre id="display"></pre>
 <style type="text/css" id="testbox"></style>
 <script class="testbody" type="text/javascript">
+function runTest() {
   function _(b) { return "@font-face { " + b + " }"; };
   var testset = [
     // Complete nonsense - shouldn't make a font-face rule at all.
     { rule: "@font-face;" },
     { rule: "font-face { }" },
     { rule: "@fontface { }" },
     { rule: "@namespace foo url(http://example.com/foo);" },
 
@@ -282,16 +283,34 @@
 
     // incorrect font-language-override
     { rule: _("font-language-override: TRK"), d: {} },
     { rule: _("font-language-override: none;"), d: {} },
     { rule: _("font-language-override: 0;"), d: {} },
     { rule: _("font-language-override: #999;"), d: {} },
     { rule: _("font-language-override: 'TRK' 'SRB'"), d: {} },
     { rule: _("font-language-override: 'TRK', 'SRB'"), d: {} },
+
+    // font-display:
+    { rule: _("font-display: auto;"),
+      d: { "font-display" : "auto" } },
+    { rule: _("font-display: block;"),
+      d: { "font-display" : "block" } },
+    { rule: _("font-display: swap;"),
+      d: { "font-display" : "swap" } },
+    { rule: _("font-display: fallback;"),
+      d: { "font-display" : "fallback" } },
+    { rule: _("font-display: optional;"),
+      d: { "font-display" : "optional" } },
+
+    // incorrect font-display
+    { rule: _("font-display: hidden"), d: {} },
+    { rule: _("font-display: swap 3"), d: {} },
+    { rule: _("font-display: block 2 swap 0"), d: {} },
+    { rule: _("font-display: all"), d: {} },
   ];
 
   var display = document.getElementById("display");
   var sheet = document.styleSheets[1];
 
   for (var curTest = 0; curTest < testset.length; curTest++) {
     try {
       while(sheet.cssRules.length > 0)
@@ -347,11 +366,17 @@
           isnot(sheet.cssRules[0].type, 5 /*FONT_FACE_RULE*/,
                 testset[curTest].rule + " rule type (1 non-fontface)");
         }
       }
     } catch (e) {
       ok(false, testset[curTest].rule, "During test: " + e);
     }
   }
+  SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({ set: [["layout.css.font-display.enabled", true]] },
+                          runTest);
 </script>
 </body>
 </html>
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2292,16 +2292,19 @@ pref("layout.css.text-align-true-value.e
 pref("layout.css.float-logical-values.enabled", true);
 #else
 pref("layout.css.float-logical-values.enabled", false);
 #endif
 
 // Is support for the CSS4 image-orientation property enabled?
 pref("layout.css.image-orientation.enabled", true);
 
+// Is support for the font-display @font-face descriptor enabled?
+pref("layout.css.font-display.enabled", false);
+
 // Are sets of prefixed properties supported?
 pref("layout.css.prefixes.border-image", true);
 pref("layout.css.prefixes.transforms", true);
 pref("layout.css.prefixes.transitions", true);
 pref("layout.css.prefixes.animations", true);
 pref("layout.css.prefixes.box-sizing", true);
 pref("layout.css.prefixes.font-features", true);
 pref("layout.css.prefixes.gradients", true);