зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1706080 - [css-fonts] Implement 'font-synthesis: small-caps'. r=jfkthame
Differential Revision: https://phabricator.services.mozilla.com/D114313
This commit is contained in:
Родитель
4498297532
Коммит
14c9063444
|
@ -6393,7 +6393,9 @@ exports.CSS_PROPERTIES = {
|
|||
"values": [
|
||||
"inherit",
|
||||
"initial",
|
||||
"none",
|
||||
"revert",
|
||||
"small-caps",
|
||||
"style",
|
||||
"unset",
|
||||
"weight"
|
||||
|
|
|
@ -82,8 +82,9 @@ struct nsFont final {
|
|||
// that include an 'opsz' axis
|
||||
uint8_t opticalSizing = NS_FONT_OPTICAL_SIZING_AUTO;
|
||||
|
||||
// Synthesis setting, controls use of fake bolding/italics
|
||||
uint8_t synthesis = NS_FONT_SYNTHESIS_WEIGHT | NS_FONT_SYNTHESIS_STYLE;
|
||||
// Synthesis setting, controls use of fake bolding/italics/small-caps
|
||||
uint8_t synthesis = NS_FONT_SYNTHESIS_WEIGHT | NS_FONT_SYNTHESIS_STYLE |
|
||||
NS_FONT_SYNTHESIS_SMALL_CAPS;
|
||||
|
||||
// initialize the font with a fontlist
|
||||
nsFont(const mozilla::StyleFontFamily&, mozilla::Length aSize);
|
||||
|
|
|
@ -123,7 +123,8 @@ nsFontMetrics::nsFontMetrics(const nsFont& aFont, const Params& aParams,
|
|||
gfxFloat(aFont.size.ToAppUnits()) / mP2A, aFont.sizeAdjust,
|
||||
aFont.family.is_system_font, mDeviceContext->IsPrinterContext(),
|
||||
aFont.synthesis & NS_FONT_SYNTHESIS_WEIGHT,
|
||||
aFont.synthesis & NS_FONT_SYNTHESIS_STYLE, aFont.languageOverride);
|
||||
aFont.synthesis & NS_FONT_SYNTHESIS_STYLE,
|
||||
aFont.synthesis & NS_FONT_SYNTHESIS_SMALL_CAPS, aFont.languageOverride);
|
||||
|
||||
aFont.AddFontFeaturesToStyle(&style, mOrientation == eVertical);
|
||||
style.featureValueLookup = aParams.featureValueLookup;
|
||||
|
|
|
@ -4032,6 +4032,7 @@ gfxFontStyle::gfxFontStyle()
|
|||
useGrayscaleAntialiasing(false),
|
||||
allowSyntheticWeight(true),
|
||||
allowSyntheticStyle(true),
|
||||
allowSyntheticSmallCaps(true),
|
||||
noFallbackVariantFeatures(true) {}
|
||||
|
||||
gfxFontStyle::gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight,
|
||||
|
@ -4039,6 +4040,7 @@ gfxFontStyle::gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight,
|
|||
const FontSizeAdjust& aSizeAdjust, bool aSystemFont,
|
||||
bool aPrinterFont, bool aAllowWeightSynthesis,
|
||||
bool aAllowStyleSynthesis,
|
||||
bool aAllowSmallCapsSynthesis,
|
||||
uint32_t aLanguageOverride)
|
||||
: size(aSize),
|
||||
baselineOffset(0.0f),
|
||||
|
@ -4054,6 +4056,7 @@ gfxFontStyle::gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight,
|
|||
useGrayscaleAntialiasing(false),
|
||||
allowSyntheticWeight(aAllowWeightSynthesis),
|
||||
allowSyntheticStyle(aAllowStyleSynthesis),
|
||||
allowSyntheticSmallCaps(aAllowSmallCapsSynthesis),
|
||||
noFallbackVariantFeatures(true) {
|
||||
MOZ_ASSERT(!mozilla::IsNaN(size));
|
||||
|
||||
|
|
|
@ -103,7 +103,8 @@ struct gfxFontStyle {
|
|||
gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight, FontStretch aStretch,
|
||||
gfxFloat aSize, const FontSizeAdjust& aSizeAdjust,
|
||||
bool aSystemFont, bool aPrinterFont, bool aWeightSynthesis,
|
||||
bool aStyleSynthesis, uint32_t aLanguageOverride);
|
||||
bool aStyleSynthesis, bool aSmallCapsSynthesis,
|
||||
uint32_t aLanguageOverride);
|
||||
// Features are composed of (1) features from style rules (2) features
|
||||
// from feature settings rules and (3) family-specific features. (1) and
|
||||
// (3) are guaranteed to be mutually exclusive
|
||||
|
@ -198,6 +199,7 @@ struct gfxFontStyle {
|
|||
// Whether synthetic styles are allowed
|
||||
bool allowSyntheticWeight : 1;
|
||||
bool allowSyntheticStyle : 1;
|
||||
bool allowSyntheticSmallCaps : 1;
|
||||
|
||||
// some variant features require fallback which complicates the shaping
|
||||
// code, so set up a bool to indicate when shaping with fallback is needed
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
#define NS_FONT_SYNTHESIS_WEIGHT 0x1
|
||||
#define NS_FONT_SYNTHESIS_STYLE 0x2
|
||||
#define NS_FONT_SYNTHESIS_SMALL_CAPS 0x4
|
||||
|
||||
#define NS_FONT_OPTICAL_SIZING_AUTO 0
|
||||
#define NS_FONT_OPTICAL_SIZING_NONE 1
|
||||
|
|
|
@ -2758,6 +2758,7 @@ void gfxFontGroup::InitScriptRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
|
|||
matchedFont = nullptr;
|
||||
}
|
||||
} else if (mStyle.variantCaps != NS_FONT_VARIANT_CAPS_NORMAL &&
|
||||
mStyle.allowSyntheticSmallCaps &&
|
||||
!matchedFont->SupportsVariantCaps(
|
||||
aRunScript, mStyle.variantCaps, petiteToSmallCaps,
|
||||
syntheticLower, syntheticUpper)) {
|
||||
|
|
|
@ -5761,8 +5761,8 @@ var gCSSProperties = {
|
|||
applies_to_marker: true,
|
||||
applies_to_placeholder: true,
|
||||
applies_to_cue: true,
|
||||
initial_values: ["weight style"],
|
||||
other_values: ["none", "weight", "style"],
|
||||
initial_values: ["weight style small-caps"],
|
||||
other_values: ["none", "weight", "style", "small-caps"],
|
||||
invalid_values: [
|
||||
"weight none",
|
||||
"style none",
|
||||
|
@ -5770,6 +5770,8 @@ var gCSSProperties = {
|
|||
"weight 10px",
|
||||
"weight weight",
|
||||
"style style",
|
||||
"small-caps none",
|
||||
"small-caps small-caps",
|
||||
],
|
||||
},
|
||||
"font-variant": {
|
||||
|
|
|
@ -7618,6 +7618,13 @@
|
|||
mirror: always
|
||||
rust: true
|
||||
|
||||
# Is 'font-synthesis: small-caps' supported?
|
||||
- name: layout.css.font-synthesis-small-caps.enabled
|
||||
type: RelaxedAtomicBool
|
||||
value: true
|
||||
mirror: always
|
||||
rust: true
|
||||
|
||||
# Whether frame visibility tracking is enabled globally.
|
||||
- name: layout.framevisibility.enabled
|
||||
type: bool
|
||||
|
|
|
@ -1950,23 +1950,24 @@ impl Parse for FontFeatureSettings {
|
|||
Debug,
|
||||
MallocSizeOf,
|
||||
PartialEq,
|
||||
SpecifiedValueInfo,
|
||||
ToComputedValue,
|
||||
ToResolvedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
/// Whether user agents are allowed to synthesize bold or oblique font faces
|
||||
/// when a font family lacks bold or italic faces
|
||||
/// when a font family lacks those faces, or a small-caps variant when this is
|
||||
/// not supported by the face.
|
||||
pub struct FontSynthesis {
|
||||
/// If a `font-weight` is requested that the font family does not contain,
|
||||
/// the user agent may synthesize the requested weight from the weights
|
||||
/// that do exist in the font family.
|
||||
#[css(represents_keyword)]
|
||||
pub weight: bool,
|
||||
/// If a font-style is requested that the font family does not contain,
|
||||
/// the user agent may synthesize the requested style from the normal face in the font family.
|
||||
#[css(represents_keyword)]
|
||||
pub style: bool,
|
||||
/// This bit controls whether the user agent is allowed to synthesize small caps variant
|
||||
/// when a font face lacks it.
|
||||
pub small_caps: bool,
|
||||
}
|
||||
|
||||
impl FontSynthesis {
|
||||
|
@ -1976,6 +1977,7 @@ impl FontSynthesis {
|
|||
FontSynthesis {
|
||||
weight: true,
|
||||
style: true,
|
||||
small_caps: true,
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
|
@ -1984,8 +1986,14 @@ impl FontSynthesis {
|
|||
FontSynthesis {
|
||||
weight: false,
|
||||
style: false,
|
||||
small_caps: false,
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
/// Return true if this is the 'none' value
|
||||
pub fn is_none(&self) -> bool {
|
||||
*self == Self::none()
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for FontSynthesis {
|
||||
|
@ -1993,26 +2001,23 @@ impl Parse for FontSynthesis {
|
|||
_: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<FontSynthesis, ParseError<'i>> {
|
||||
let mut result = FontSynthesis {
|
||||
weight: false,
|
||||
style: false,
|
||||
};
|
||||
try_match_ident_ignore_ascii_case! { input,
|
||||
"none" => Ok(result),
|
||||
"weight" => {
|
||||
result.weight = true;
|
||||
if input.try_parse(|input| input.expect_ident_matching("style")).is_ok() {
|
||||
result.style = true;
|
||||
use crate::values::SelectorParseErrorKind;
|
||||
let mut result = Self::none();
|
||||
while let Ok(ident) = input.try_parse(|i| i.expect_ident_cloned()) {
|
||||
match_ignore_ascii_case! { &ident,
|
||||
"none" if result.is_none() => return Ok(result),
|
||||
"weight" if !result.weight => result.weight = true,
|
||||
"style" if !result.style => result.style = true,
|
||||
"small-caps" if !result.small_caps &&
|
||||
static_prefs::pref!("layout.css.font-synthesis-small-caps.enabled")
|
||||
=> result.small_caps = true,
|
||||
_ => return Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident))),
|
||||
}
|
||||
Ok(result)
|
||||
},
|
||||
"style" => {
|
||||
result.style = true;
|
||||
if input.try_parse(|input| input.expect_ident_matching("weight")).is_ok() {
|
||||
result.weight = true;
|
||||
}
|
||||
if !result.is_none() {
|
||||
Ok(result)
|
||||
},
|
||||
} else {
|
||||
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2022,14 +2027,41 @@ impl ToCss for FontSynthesis {
|
|||
where
|
||||
W: Write,
|
||||
{
|
||||
if self.weight && self.style {
|
||||
dest.write_str("weight style")
|
||||
} else if self.style {
|
||||
dest.write_str("style")
|
||||
} else if self.weight {
|
||||
dest.write_str("weight")
|
||||
} else {
|
||||
dest.write_str("none")
|
||||
if self.is_none() {
|
||||
return dest.write_str("none");
|
||||
}
|
||||
|
||||
let mut need_space = false;
|
||||
if self.weight {
|
||||
dest.write_str("weight")?;
|
||||
need_space = true;
|
||||
}
|
||||
if self.style {
|
||||
if need_space {
|
||||
dest.write_str(" ")?;
|
||||
}
|
||||
dest.write_str("style")?;
|
||||
need_space = true;
|
||||
}
|
||||
if self.small_caps {
|
||||
if need_space {
|
||||
dest.write_str(" ")?;
|
||||
}
|
||||
dest.write_str("small-caps")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl SpecifiedValueInfo for FontSynthesis {
|
||||
fn collect_completion_keywords(f: KeywordsCollectFn) {
|
||||
f(&[
|
||||
"none",
|
||||
"weight",
|
||||
"style",
|
||||
]);
|
||||
if static_prefs::pref!("layout.css.font-synthesis-small-caps.enabled") {
|
||||
f(&["small-caps"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2042,6 +2074,7 @@ impl From<u8> for FontSynthesis {
|
|||
FontSynthesis {
|
||||
weight: bits & structs::NS_FONT_SYNTHESIS_WEIGHT as u8 != 0,
|
||||
style: bits & structs::NS_FONT_SYNTHESIS_STYLE as u8 != 0,
|
||||
small_caps: bits & structs::NS_FONT_SYNTHESIS_SMALL_CAPS as u8 != 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2058,6 +2091,9 @@ impl From<FontSynthesis> for u8 {
|
|||
if v.style {
|
||||
bits |= structs::NS_FONT_SYNTHESIS_STYLE as u8;
|
||||
}
|
||||
if v.small_caps {
|
||||
bits |= structs::NS_FONT_SYNTHESIS_SMALL_CAPS as u8;
|
||||
}
|
||||
bits
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>Reference: 'font-synthesis:none' with a font that support small-caps</title>
|
||||
<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: fwf;
|
||||
src: url(support/fonts/FontWithFancyFeatures.otf);
|
||||
}
|
||||
.test {
|
||||
font: 2em/1 fwf;
|
||||
}
|
||||
</style>
|
||||
|
||||
<p>Test passes if there are four check marks (✓), and zero crosses (✗). </p>
|
||||
<p class="test">CCC C</p>
|
|
@ -0,0 +1,21 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>CSS Test: 'font-synthesis:none' with a font that support small-caps</title>
|
||||
<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-fonts/#font-synthesis">
|
||||
<link rel="match" href="font-synthesis-06-ref.html">
|
||||
<meta name="assert" content="font-synthesis:none should not affect a font that supports small-caps">
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: fwf;
|
||||
src: url(support/fonts/FontWithFancyFeatures.otf);
|
||||
}
|
||||
.test {
|
||||
font: 2em/1 fwf;
|
||||
font-variant: small-caps;
|
||||
font-synthesis: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<p>Test passes if there are four check marks (✓), and zero crosses (✗). </p>
|
||||
<p class="test">JJJ J</p>
|
|
@ -0,0 +1,16 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>Reference: 'font-synthesis:none' with a font that doesn't support small-caps</title>
|
||||
<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: Lato;
|
||||
src: url(support/fonts/Lato-Medium.ttf);
|
||||
}
|
||||
.test {
|
||||
font: 2em/1 Lato;
|
||||
}
|
||||
</style>
|
||||
|
||||
<p>Test passes if "A" is upper-case and "bcd e" is lower-case.</p>
|
||||
<p class="test">Abcd e</p>
|
|
@ -0,0 +1,21 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>CSS Test: 'font-synthesis:none' with a font that doesn't support small-caps</title>
|
||||
<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-fonts/#font-synthesis">
|
||||
<link rel="match" href="font-synthesis-07-ref.html">
|
||||
<meta name="assert" content="font-synthesis:none inhibits synthesising small-caps">
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: Lato;
|
||||
src: url(support/fonts/Lato-Medium.ttf);
|
||||
}
|
||||
.test {
|
||||
font: 2em/1 Lato;
|
||||
font-variant: small-caps;
|
||||
font-synthesis: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<p>Test passes if "A" is upper-case and "bcd e" is lower-case.</p>
|
||||
<p class="test">Abcd e</p>
|
|
@ -35,7 +35,7 @@ assert_inherited('font-size', mediumFontSize /* medium */, '123px');
|
|||
assert_inherited('font-size-adjust', 'none', '1.5');
|
||||
assert_inherited('font-stretch', '100%' /* normal */, '75%');
|
||||
assert_inherited('font-style', 'normal', 'italic');
|
||||
assert_inherited('font-synthesis', 'weight style', 'none');
|
||||
assert_inherited('font-synthesis', 'weight style small-caps', 'none');
|
||||
assert_inherited('font-variant', 'normal', 'none');
|
||||
assert_inherited('font-variant-alternates', 'normal', 'historical-forms');
|
||||
assert_inherited('font-variant-caps', 'normal', 'small-caps');
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Fonts Module Level 3: getComputedStyle().fontSynthesis</title>
|
||||
<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-synthesis-prop">
|
||||
<title>CSS Fonts Module: getComputedStyle().fontSynthesis</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-fonts/#font-synthesis">
|
||||
<meta name="assert" content="font-synthesis computed value is as specified.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
@ -15,7 +15,11 @@
|
|||
test_computed_value('font-synthesis', 'none');
|
||||
test_computed_value('font-synthesis', 'weight');
|
||||
test_computed_value('font-synthesis', 'style');
|
||||
test_computed_value('font-synthesis', 'small-caps');
|
||||
test_computed_value('font-synthesis', 'style small-caps');
|
||||
test_computed_value('font-synthesis', 'weight small-caps');
|
||||
test_computed_value('font-synthesis', 'weight style');
|
||||
test_computed_value('font-synthesis', 'weight style small-caps');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Fonts Module Level 3: parsing font-synthesis with invalid values</title>
|
||||
<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-synthesis-prop">
|
||||
<meta name="assert" content="font-synthesis supports only the grammar 'none | [ weight || style ]'.">
|
||||
<title>CSS Fonts Module: parsing font-synthesis with invalid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-fonts/#font-synthesis">
|
||||
<meta name="assert" content="font-synthesis supports only the grammar 'none | [ weight || style || small-caps ]'.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
|
@ -13,6 +13,10 @@
|
|||
<script>
|
||||
test_invalid_value('font-synthesis', 'auto');
|
||||
test_invalid_value('font-synthesis', 'none weight');
|
||||
test_invalid_value('font-synthesis', 'none style');
|
||||
test_invalid_value('font-synthesis', 'style none');
|
||||
test_invalid_value('font-synthesis', 'none small-caps');
|
||||
test_invalid_value('font-synthesis', 'small-caps none');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Fonts Module Level 3: parsing font-synthesis with valid values</title>
|
||||
<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-synthesis-prop">
|
||||
<meta name="assert" content="font-synthesis supports the full grammar 'none | [ weight || style ]'.">
|
||||
<title>CSS Fonts Module: parsing font-synthesis with valid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-fonts/#font-synthesis">
|
||||
<meta name="assert" content="font-synthesis supports the full grammar 'none | [ weight || style || small-caps ]'.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
|
@ -14,7 +14,13 @@
|
|||
test_valid_value('font-synthesis', 'none');
|
||||
test_valid_value('font-synthesis', 'weight');
|
||||
test_valid_value('font-synthesis', 'style');
|
||||
test_valid_value('font-synthesis', 'small-caps');
|
||||
test_valid_value('font-synthesis', 'style weight', 'weight style');
|
||||
test_valid_value('font-synthesis', 'small-caps weight', 'weight small-caps');
|
||||
test_valid_value('font-synthesis', 'small-caps style', 'style small-caps');
|
||||
test_valid_value('font-synthesis', 'style weight small-caps', 'weight style small-caps');
|
||||
test_valid_value('font-synthesis', 'style small-caps weight ', 'weight style small-caps');
|
||||
test_valid_value('font-synthesis', 'small-caps style weight ', 'weight style small-caps');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Загрузка…
Ссылка в новой задаче