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:
@@ -7,7 +7,7 @@
|
|||||||
#include <math.h> // for floor, ceil
|
#include <math.h> // for floor, ceil
|
||||||
#include <algorithm> // for max
|
#include <algorithm> // for max
|
||||||
#include "gfxContext.h" // for gfxContext
|
#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 "gfxPlatform.h" // for gfxPlatform
|
||||||
#include "gfxPoint.h" // for gfxPoint
|
#include "gfxPoint.h" // for gfxPoint
|
||||||
#include "gfxRect.h" // for gfxRect
|
#include "gfxRect.h" // for gfxRect
|
||||||
@@ -134,7 +134,7 @@ nsFontMetrics::nsFontMetrics(const nsFont& aFont, const Params& aParams,
|
|||||||
mAllowForceGDIClassic,
|
mAllowForceGDIClassic,
|
||||||
#endif
|
#endif
|
||||||
aFont.synthesisWeight == StyleFontSynthesis::Auto,
|
aFont.synthesisWeight == StyleFontSynthesis::Auto,
|
||||||
aFont.synthesisStyle == StyleFontSynthesisStyle::Auto,
|
aFont.synthesisStyle,
|
||||||
aFont.synthesisSmallCaps == StyleFontSynthesis::Auto,
|
aFont.synthesisSmallCaps == StyleFontSynthesis::Auto,
|
||||||
aFont.synthesisPosition == StyleFontSynthesis::Auto,
|
aFont.synthesisPosition == StyleFontSynthesis::Auto,
|
||||||
aFont.languageOverride);
|
aFont.languageOverride);
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ namespace fontlist {
|
|||||||
|
|
||||||
static double WSSDistance(const Face* aFace, const gfxFontStyle& aStyle) {
|
static double WSSDistance(const Face* aFace, const gfxFontStyle& aStyle) {
|
||||||
double stretchDist = StretchDistance(aFace->mStretch, aStyle.stretch);
|
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);
|
double weightDist = WeightDistance(aFace->mWeight, aStyle.weight);
|
||||||
|
|
||||||
// Sanity-check that the distances are within the expected range
|
// Sanity-check that the distances are within the expected range
|
||||||
|
|||||||
@@ -903,7 +903,7 @@ gfxFont* gfxFontconfigFontEntry::CreateFontInstance(
|
|||||||
|
|
||||||
// will synthetic oblique be applied using a transform?
|
// will synthetic oblique be applied using a transform?
|
||||||
if (IsUpright() && !aFontStyle->style.IsNormal() &&
|
if (IsUpright() && !aFontStyle->style.IsNormal() &&
|
||||||
aFontStyle->allowSyntheticStyle) {
|
aFontStyle->synthesisStyle != StyleFontSynthesisStyle::None) {
|
||||||
// disable embedded bitmaps (mimics behavior in 90-synthetic.conf)
|
// disable embedded bitmaps (mimics behavior in 90-synthetic.conf)
|
||||||
FcPatternDel(renderPattern, FC_EMBEDDED_BITMAP);
|
FcPatternDel(renderPattern, FC_EMBEDDED_BITMAP);
|
||||||
FcPatternAddBool(renderPattern, FC_EMBEDDED_BITMAP, FcFalse);
|
FcPatternAddBool(renderPattern, FC_EMBEDDED_BITMAP, FcFalse);
|
||||||
|
|||||||
@@ -922,7 +922,7 @@ float gfxFont::AngleForSyntheticOblique() const {
|
|||||||
if (mStyle.style == FontSlantStyle::NORMAL) {
|
if (mStyle.style == FontSlantStyle::NORMAL) {
|
||||||
return 0.0f; // Requested style is 'normal'.
|
return 0.0f; // Requested style is 'normal'.
|
||||||
}
|
}
|
||||||
if (!mStyle.allowSyntheticStyle) {
|
if (mStyle.synthesisStyle == StyleFontSynthesisStyle::None) {
|
||||||
return 0.0f; // Synthetic obliquing is disabled.
|
return 0.0f; // Synthetic obliquing is disabled.
|
||||||
}
|
}
|
||||||
if (!mFontEntry->MayUseSyntheticSlant()) {
|
if (!mFontEntry->MayUseSyntheticSlant()) {
|
||||||
@@ -930,11 +930,12 @@ float gfxFont::AngleForSyntheticOblique() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If style calls for italic, and face doesn't support it, use default
|
// 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()) {
|
if (mStyle.style.IsItalic()) {
|
||||||
return mFontEntry->SupportsItalic()
|
return mFontEntry->SupportsItalic() ? 0.0f
|
||||||
? 0.0f
|
: mStyle.synthesisStyle == StyleFontSynthesisStyle::Auto
|
||||||
: FontSlantStyle::DEFAULT_OBLIQUE_DEGREES;
|
? FontSlantStyle::DEFAULT_OBLIQUE_DEGREES
|
||||||
|
: 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// OK, we're going to use synthetic oblique: return the requested angle.
|
// OK, we're going to use synthetic oblique: return the requested angle.
|
||||||
@@ -4765,7 +4766,7 @@ gfxFontStyle::gfxFontStyle()
|
|||||||
#endif
|
#endif
|
||||||
useGrayscaleAntialiasing(false),
|
useGrayscaleAntialiasing(false),
|
||||||
allowSyntheticWeight(true),
|
allowSyntheticWeight(true),
|
||||||
allowSyntheticStyle(true),
|
synthesisStyle(StyleFontSynthesisStyle::Auto),
|
||||||
allowSyntheticSmallCaps(true),
|
allowSyntheticSmallCaps(true),
|
||||||
useSyntheticPosition(true),
|
useSyntheticPosition(true),
|
||||||
noFallbackVariantFeatures(true) {
|
noFallbackVariantFeatures(true) {
|
||||||
@@ -4779,7 +4780,7 @@ gfxFontStyle::gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight,
|
|||||||
bool aAllowForceGDIClassic,
|
bool aAllowForceGDIClassic,
|
||||||
#endif
|
#endif
|
||||||
bool aAllowWeightSynthesis,
|
bool aAllowWeightSynthesis,
|
||||||
bool aAllowStyleSynthesis,
|
StyleFontSynthesisStyle aStyleSynthesis,
|
||||||
bool aAllowSmallCapsSynthesis,
|
bool aAllowSmallCapsSynthesis,
|
||||||
bool aUsePositionSynthesis,
|
bool aUsePositionSynthesis,
|
||||||
StyleFontLanguageOverride aLanguageOverride)
|
StyleFontLanguageOverride aLanguageOverride)
|
||||||
@@ -4798,7 +4799,7 @@ gfxFontStyle::gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight,
|
|||||||
#endif
|
#endif
|
||||||
useGrayscaleAntialiasing(false),
|
useGrayscaleAntialiasing(false),
|
||||||
allowSyntheticWeight(aAllowWeightSynthesis),
|
allowSyntheticWeight(aAllowWeightSynthesis),
|
||||||
allowSyntheticStyle(aAllowStyleSynthesis),
|
synthesisStyle(aStyleSynthesis),
|
||||||
allowSyntheticSmallCaps(aAllowSmallCapsSynthesis),
|
allowSyntheticSmallCaps(aAllowSmallCapsSynthesis),
|
||||||
useSyntheticPosition(aUsePositionSynthesis),
|
useSyntheticPosition(aUsePositionSynthesis),
|
||||||
noFallbackVariantFeatures(true) {
|
noFallbackVariantFeatures(true) {
|
||||||
|
|||||||
@@ -102,7 +102,8 @@ struct gfxFontStyle {
|
|||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
bool aAllowForceGDIClassic,
|
bool aAllowForceGDIClassic,
|
||||||
#endif
|
#endif
|
||||||
bool aWeightSynthesis, bool aStyleSynthesis,
|
bool aWeightSynthesis,
|
||||||
|
mozilla::StyleFontSynthesisStyle aStyleSynthesis,
|
||||||
bool aSmallCapsSynthesis, bool aPositionSynthesis,
|
bool aSmallCapsSynthesis, bool aPositionSynthesis,
|
||||||
mozilla::StyleFontLanguageOverride aLanguageOverride);
|
mozilla::StyleFontLanguageOverride aLanguageOverride);
|
||||||
// Features are composed of (1) features from style rules (2) features
|
// 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)
|
// Whether synthetic styles are allowed (required, in the case of position)
|
||||||
bool allowSyntheticWeight : 1;
|
bool allowSyntheticWeight : 1;
|
||||||
bool allowSyntheticStyle : 1;
|
mozilla::StyleFontSynthesisStyle synthesisStyle : 2;
|
||||||
bool allowSyntheticSmallCaps : 1;
|
bool allowSyntheticSmallCaps : 1;
|
||||||
bool useSyntheticPosition : 1;
|
bool useSyntheticPosition : 1;
|
||||||
|
|
||||||
@@ -243,7 +244,7 @@ struct gfxFontStyle {
|
|||||||
(stretch == other.stretch) && (variantCaps == other.variantCaps) &&
|
(stretch == other.stretch) && (variantCaps == other.variantCaps) &&
|
||||||
(variantSubSuper == other.variantSubSuper) &&
|
(variantSubSuper == other.variantSubSuper) &&
|
||||||
(allowSyntheticWeight == other.allowSyntheticWeight) &&
|
(allowSyntheticWeight == other.allowSyntheticWeight) &&
|
||||||
(allowSyntheticStyle == other.allowSyntheticStyle) &&
|
(synthesisStyle == other.synthesisStyle) &&
|
||||||
(allowSyntheticSmallCaps == other.allowSyntheticSmallCaps) &&
|
(allowSyntheticSmallCaps == other.allowSyntheticSmallCaps) &&
|
||||||
(useSyntheticPosition == other.useSyntheticPosition) &&
|
(useSyntheticPosition == other.useSyntheticPosition) &&
|
||||||
(systemFont == other.systemFont) &&
|
(systemFont == other.systemFont) &&
|
||||||
|
|||||||
@@ -1535,8 +1535,9 @@ static inline double WeightStyleStretchDistance(
|
|||||||
gfxFontEntry* aFontEntry, const gfxFontStyle& aTargetStyle) {
|
gfxFontEntry* aFontEntry, const gfxFontStyle& aTargetStyle) {
|
||||||
double stretchDist =
|
double stretchDist =
|
||||||
StretchDistance(aFontEntry->Stretch(), aTargetStyle.stretch);
|
StretchDistance(aFontEntry->Stretch(), aTargetStyle.stretch);
|
||||||
double styleDist =
|
double styleDist = StyleDistance(
|
||||||
StyleDistance(aFontEntry->SlantStyle(), aTargetStyle.style);
|
aFontEntry->SlantStyle(), aTargetStyle.style,
|
||||||
|
aTargetStyle.synthesisStyle != StyleFontSynthesisStyle::ObliqueOnly);
|
||||||
double weightDist = WeightDistance(aFontEntry->Weight(), aTargetStyle.weight);
|
double weightDist = WeightDistance(aFontEntry->Weight(), aTargetStyle.weight);
|
||||||
|
|
||||||
// Sanity-check that the distances are within the expected range
|
// Sanity-check that the distances are within the expected range
|
||||||
|
|||||||
@@ -1224,9 +1224,10 @@ constexpr double kStretchFactor = 1.0e8;
|
|||||||
constexpr double kStyleFactor = 1.0e4;
|
constexpr double kStyleFactor = 1.0e4;
|
||||||
constexpr double kWeightFactor = 1.0e0;
|
constexpr double kWeightFactor = 1.0e0;
|
||||||
|
|
||||||
// style distance ==> [0,500]
|
// style distance ==> [0,900]
|
||||||
static inline double StyleDistance(const mozilla::SlantStyleRange& aRange,
|
static inline double StyleDistance(const mozilla::SlantStyleRange& aRange,
|
||||||
mozilla::FontSlantStyle aTargetStyle) {
|
mozilla::FontSlantStyle aTargetStyle,
|
||||||
|
bool aItalicToObliqueFallback) {
|
||||||
const mozilla::FontSlantStyle minStyle = aRange.Min();
|
const mozilla::FontSlantStyle minStyle = aRange.Min();
|
||||||
if (aTargetStyle == minStyle) {
|
if (aTargetStyle == minStyle) {
|
||||||
return 0.0; // styles match exactly ==> 0
|
return 0.0; // styles match exactly ==> 0
|
||||||
@@ -1240,6 +1241,10 @@ static inline double StyleDistance(const mozilla::SlantStyleRange& aRange,
|
|||||||
// vice versa
|
// vice versa
|
||||||
const double kNegate = 200.0;
|
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 (aTargetStyle.IsNormal()) {
|
||||||
if (minStyle.IsItalic()) {
|
if (minStyle.IsItalic()) {
|
||||||
// italic is worse than any non-negative oblique;
|
// 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.
|
// Must be a font with an 'ital' axis, so consider this a match.
|
||||||
return 0.0;
|
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();
|
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
|
// Add 1.0 to ensure italic vs non-italic never returns 0.0, even if the
|
||||||
// angle matches.
|
// angle matches.
|
||||||
return minAngle - kDefaultAngle + 1.0;
|
return fallbackBias + minAngle - targetAngle + 1.0;
|
||||||
}
|
}
|
||||||
const double maxAngle = maxStyle.ObliqueAngle();
|
const double maxAngle = maxStyle.ObliqueAngle();
|
||||||
if (maxAngle >= kDefaultAngle) {
|
if (maxAngle >= targetAngle) {
|
||||||
return 1.0;
|
return fallbackBias + 1.0;
|
||||||
}
|
}
|
||||||
if (maxAngle > 0.0) {
|
if (maxAngle > 0.0) {
|
||||||
// wrong direction but still > 0, add bias of 100
|
// 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
|
// 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
|
// target is oblique <angle>: four different cases depending on
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
Reference in New Issue
Block a user