Bug 1945641 - patch 2 - Support the font-synthesis-style:oblique-only value in font selection & rendering. r=layout-reviewers,emilio

Differential Revision: https://phabricator.services.mozilla.com/D236913
This commit is contained in:
Jonathan Kew
2025-02-07 10:29:26 +00:00
parent b2e556747a
commit a458fbcccc
9 changed files with 104 additions and 25 deletions

View File

@@ -7,7 +7,7 @@
#include <math.h> // for floor, ceil
#include <algorithm> // for max
#include "gfxContext.h" // for gfxContext
#include "gfxFontConstants.h" // for NS_FONT_SYNTHESIS_*
#include "gfxFontConstants.h" // for NS_FONT_{SUB,SUPER}SCRIPT_OFFSET_RATIO
#include "gfxPlatform.h" // for gfxPlatform
#include "gfxPoint.h" // for gfxPoint
#include "gfxRect.h" // for gfxRect
@@ -134,7 +134,7 @@ nsFontMetrics::nsFontMetrics(const nsFont& aFont, const Params& aParams,
mAllowForceGDIClassic,
#endif
aFont.synthesisWeight == StyleFontSynthesis::Auto,
aFont.synthesisStyle == StyleFontSynthesisStyle::Auto,
aFont.synthesisStyle,
aFont.synthesisSmallCaps == StyleFontSynthesis::Auto,
aFont.synthesisPosition == StyleFontSynthesis::Auto,
aFont.languageOverride);

View File

@@ -24,7 +24,9 @@ namespace fontlist {
static double WSSDistance(const Face* aFace, const gfxFontStyle& aStyle) {
double stretchDist = StretchDistance(aFace->mStretch, aStyle.stretch);
double styleDist = StyleDistance(aFace->mStyle, aStyle.style);
double styleDist = StyleDistance(
aFace->mStyle, aStyle.style,
aStyle.synthesisStyle != StyleFontSynthesisStyle::ObliqueOnly);
double weightDist = WeightDistance(aFace->mWeight, aStyle.weight);
// Sanity-check that the distances are within the expected range

View File

@@ -903,7 +903,7 @@ gfxFont* gfxFontconfigFontEntry::CreateFontInstance(
// will synthetic oblique be applied using a transform?
if (IsUpright() && !aFontStyle->style.IsNormal() &&
aFontStyle->allowSyntheticStyle) {
aFontStyle->synthesisStyle != StyleFontSynthesisStyle::None) {
// disable embedded bitmaps (mimics behavior in 90-synthetic.conf)
FcPatternDel(renderPattern, FC_EMBEDDED_BITMAP);
FcPatternAddBool(renderPattern, FC_EMBEDDED_BITMAP, FcFalse);

View File

@@ -922,7 +922,7 @@ float gfxFont::AngleForSyntheticOblique() const {
if (mStyle.style == FontSlantStyle::NORMAL) {
return 0.0f; // Requested style is 'normal'.
}
if (!mStyle.allowSyntheticStyle) {
if (mStyle.synthesisStyle == StyleFontSynthesisStyle::None) {
return 0.0f; // Synthetic obliquing is disabled.
}
if (!mFontEntry->MayUseSyntheticSlant()) {
@@ -930,11 +930,12 @@ float gfxFont::AngleForSyntheticOblique() const {
}
// If style calls for italic, and face doesn't support it, use default
// oblique angle as a simulation.
// oblique angle as a simulation, but only if synthesis setting allows it.
if (mStyle.style.IsItalic()) {
return mFontEntry->SupportsItalic()
? 0.0f
: FontSlantStyle::DEFAULT_OBLIQUE_DEGREES;
return mFontEntry->SupportsItalic() ? 0.0f
: mStyle.synthesisStyle == StyleFontSynthesisStyle::Auto
? FontSlantStyle::DEFAULT_OBLIQUE_DEGREES
: 0.0f;
}
// OK, we're going to use synthetic oblique: return the requested angle.
@@ -4765,7 +4766,7 @@ gfxFontStyle::gfxFontStyle()
#endif
useGrayscaleAntialiasing(false),
allowSyntheticWeight(true),
allowSyntheticStyle(true),
synthesisStyle(StyleFontSynthesisStyle::Auto),
allowSyntheticSmallCaps(true),
useSyntheticPosition(true),
noFallbackVariantFeatures(true) {
@@ -4779,7 +4780,7 @@ gfxFontStyle::gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight,
bool aAllowForceGDIClassic,
#endif
bool aAllowWeightSynthesis,
bool aAllowStyleSynthesis,
StyleFontSynthesisStyle aStyleSynthesis,
bool aAllowSmallCapsSynthesis,
bool aUsePositionSynthesis,
StyleFontLanguageOverride aLanguageOverride)
@@ -4798,7 +4799,7 @@ gfxFontStyle::gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight,
#endif
useGrayscaleAntialiasing(false),
allowSyntheticWeight(aAllowWeightSynthesis),
allowSyntheticStyle(aAllowStyleSynthesis),
synthesisStyle(aStyleSynthesis),
allowSyntheticSmallCaps(aAllowSmallCapsSynthesis),
useSyntheticPosition(aUsePositionSynthesis),
noFallbackVariantFeatures(true) {

View File

@@ -102,7 +102,8 @@ struct gfxFontStyle {
#ifdef XP_WIN
bool aAllowForceGDIClassic,
#endif
bool aWeightSynthesis, bool aStyleSynthesis,
bool aWeightSynthesis,
mozilla::StyleFontSynthesisStyle aStyleSynthesis,
bool aSmallCapsSynthesis, bool aPositionSynthesis,
mozilla::StyleFontLanguageOverride aLanguageOverride);
// Features are composed of (1) features from style rules (2) features
@@ -198,7 +199,7 @@ struct gfxFontStyle {
// Whether synthetic styles are allowed (required, in the case of position)
bool allowSyntheticWeight : 1;
bool allowSyntheticStyle : 1;
mozilla::StyleFontSynthesisStyle synthesisStyle : 2;
bool allowSyntheticSmallCaps : 1;
bool useSyntheticPosition : 1;
@@ -243,7 +244,7 @@ struct gfxFontStyle {
(stretch == other.stretch) && (variantCaps == other.variantCaps) &&
(variantSubSuper == other.variantSubSuper) &&
(allowSyntheticWeight == other.allowSyntheticWeight) &&
(allowSyntheticStyle == other.allowSyntheticStyle) &&
(synthesisStyle == other.synthesisStyle) &&
(allowSyntheticSmallCaps == other.allowSyntheticSmallCaps) &&
(useSyntheticPosition == other.useSyntheticPosition) &&
(systemFont == other.systemFont) &&

View File

@@ -1535,8 +1535,9 @@ static inline double WeightStyleStretchDistance(
gfxFontEntry* aFontEntry, const gfxFontStyle& aTargetStyle) {
double stretchDist =
StretchDistance(aFontEntry->Stretch(), aTargetStyle.stretch);
double styleDist =
StyleDistance(aFontEntry->SlantStyle(), aTargetStyle.style);
double styleDist = StyleDistance(
aFontEntry->SlantStyle(), aTargetStyle.style,
aTargetStyle.synthesisStyle != StyleFontSynthesisStyle::ObliqueOnly);
double weightDist = WeightDistance(aFontEntry->Weight(), aTargetStyle.weight);
// Sanity-check that the distances are within the expected range

View File

@@ -1224,9 +1224,10 @@ constexpr double kStretchFactor = 1.0e8;
constexpr double kStyleFactor = 1.0e4;
constexpr double kWeightFactor = 1.0e0;
// style distance ==> [0,500]
// style distance ==> [0,900]
static inline double StyleDistance(const mozilla::SlantStyleRange& aRange,
mozilla::FontSlantStyle aTargetStyle) {
mozilla::FontSlantStyle aTargetStyle,
bool aItalicToObliqueFallback) {
const mozilla::FontSlantStyle minStyle = aRange.Min();
if (aTargetStyle == minStyle) {
return 0.0; // styles match exactly ==> 0
@@ -1240,6 +1241,10 @@ static inline double StyleDistance(const mozilla::SlantStyleRange& aRange,
// vice versa
const double kNegate = 200.0;
// bias added for oblique faces when italic is requested, and only-oblique
// font-synthesis-style is in effect
const double kBadFallback = 400.0;
if (aTargetStyle.IsNormal()) {
if (minStyle.IsItalic()) {
// italic is worse than any non-negative oblique;
@@ -1269,22 +1274,31 @@ static inline double StyleDistance(const mozilla::SlantStyleRange& aRange,
// Must be a font with an 'ital' axis, so consider this a match.
return 0.0;
}
double targetAngle = kDefaultAngle;
double fallbackBias = 0.0;
if (!aItalicToObliqueFallback) {
// If 'font-style-synthesis: oblique-only' is applied, we should not use
// oblique as a fallback for italic, so we add a large "fallback bias" to
// all results here, and prefer an angle as close to zero as possible.
targetAngle = 0.0;
fallbackBias = kBadFallback;
}
const double minAngle = minStyle.ObliqueAngle();
if (minAngle >= kDefaultAngle) {
if (minAngle >= targetAngle) {
// Add 1.0 to ensure italic vs non-italic never returns 0.0, even if the
// angle matches.
return minAngle - kDefaultAngle + 1.0;
return fallbackBias + minAngle - targetAngle + 1.0;
}
const double maxAngle = maxStyle.ObliqueAngle();
if (maxAngle >= kDefaultAngle) {
return 1.0;
if (maxAngle >= targetAngle) {
return fallbackBias + 1.0;
}
if (maxAngle > 0.0) {
// wrong direction but still > 0, add bias of 100
return kReverse + (kDefaultAngle - maxAngle);
return fallbackBias + kReverse + (targetAngle - maxAngle);
}
// negative oblique angle, add bias of 300
return kReverse + kNegate + (kDefaultAngle - maxAngle);
return fallbackBias + kReverse + kNegate + (targetAngle - maxAngle);
}
// target is oblique <angle>: four different cases depending on

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS font-synthesis-style:oblique-only reference</title>
<style>
@font-face {
font-family: test;
src: url("resources/markA.ttf");
}
div {
font: 50px test;
}
</style>
<div>A</div>
<div>A</div>
<div>A</div>
<div>A</div>
<div>A</div>

View File

@@ -0,0 +1,40 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS font-synthesis-style:oblique-only test</title>
<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#font-synthesis-style">
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/9390#issuecomment-2625297188">
<meta name="assert" content="font-synthesis-style: oblique-only blocks italic-to-oblique fallback">
<link rel="match" href="font-synthesis-style-oblique-only-ref.html">
<style>
@font-face {
font-family: test;
font-style: normal;
src: url("resources/markA.ttf");
}
@font-face {
font-family: test;
font-style: oblique;
src: url("resources/markB.ttf");
}
div {
font: 50px test;
}
</style>
<!-- normal: this should use markA -->
<div style="font-style: normal">A</div>
<!-- oblique: should use markB -->
<div style="font-style: oblique">B</div>
<!-- italic: should use markB (oblique) as fallback for italic -->
<div style="font-style: italic">B</div>
<!-- italic with synthesis:none: should use markB, as oblique fallback (not synthesis!) is allowed -->
<div style="font-style: italic; font-synthesis-style: none">B</div>
<!-- italic with synthesis:oblique-only: should use markA, as oblique fallback is disabled -->
<div style="font-style: italic; font-synthesis-style: oblique-only">A</div>