Bug 1533428 - patch 5 - Move the helper functions that measure the 'distance' between values of font properties (weight, stretch, style) to gfxFontUtils.h. r=jwatt

This will allow upcoming shared font-list to use the same helpers as the existing code.

Differential Revision: https://phabricator.services.mozilla.com/D22926

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jonathan Kew 2019-04-01 14:33:04 +00:00
Родитель f5e8791f61
Коммит 27e809db53
2 изменённых файлов: 245 добавлений и 242 удалений

Просмотреть файл

@ -1246,250 +1246,13 @@ gfxFontEntry* gfxFontFamily::FindFontForStyle(const gfxFontStyle& aFontStyle,
return nullptr;
}
// style distance ==> [0,500]
static inline double StyleDistance(const gfxFontEntry* aFontEntry,
FontSlantStyle aTargetStyle) {
const FontSlantStyle minStyle = aFontEntry->SlantStyle().Min();
if (aTargetStyle == minStyle) {
return 0.0; // styles match exactly ==> 0
}
// bias added to angle difference when searching in the non-preferred
// direction from a target angle
const double kReverse = 100.0;
// bias added when we've crossed from positive to negative angles or
// vice versa
const double kNegate = 200.0;
if (aTargetStyle.IsNormal()) {
if (minStyle.IsOblique()) {
// to distinguish oblique 0deg from normal, we add 1.0 to the angle
const double minAngle = minStyle.ObliqueAngle();
if (minAngle >= 0.0) {
return 1.0 + minAngle;
}
const FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
const double maxAngle = maxStyle.ObliqueAngle();
if (maxAngle >= 0.0) {
// [min,max] range includes 0.0, so just return our minimum
return 1.0;
}
// negative oblique is even worse than italic
return kNegate - maxAngle;
}
// must be italic, which is worse than any non-negative oblique;
// treat as a match in the wrong search direction
MOZ_ASSERT(minStyle.IsItalic());
return kReverse;
}
const double kDefaultAngle = FontSlantStyle::Oblique().ObliqueAngle();
if (aTargetStyle.IsItalic()) {
if (minStyle.IsOblique()) {
const double minAngle = minStyle.ObliqueAngle();
if (minAngle >= kDefaultAngle) {
return 1.0 + (minAngle - kDefaultAngle);
}
const FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
const double maxAngle = maxStyle.ObliqueAngle();
if (maxAngle >= kDefaultAngle) {
return 1.0;
}
if (maxAngle > 0.0) {
// wrong direction but still > 0, add bias of 100
return kReverse + (kDefaultAngle - maxAngle);
}
// negative oblique angle, add bias of 300
return kReverse + kNegate + (kDefaultAngle - maxAngle);
}
// normal is worse than oblique > 0, but better than oblique <= 0
MOZ_ASSERT(minStyle.IsNormal());
return kNegate;
}
// target is oblique <angle>: four different cases depending on
// the value of the <angle>, which determines the preferred direction
// of search
const double targetAngle = aTargetStyle.ObliqueAngle();
if (targetAngle >= kDefaultAngle) {
if (minStyle.IsOblique()) {
const double minAngle = minStyle.ObliqueAngle();
if (minAngle >= targetAngle) {
return minAngle - targetAngle;
}
const FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
const double maxAngle = maxStyle.ObliqueAngle();
if (maxAngle >= targetAngle) {
return 0.0;
}
if (maxAngle > 0.0) {
return kReverse + (targetAngle - maxAngle);
}
return kReverse + kNegate + (targetAngle - maxAngle);
}
if (minStyle.IsItalic()) {
return kReverse + kNegate;
}
return kReverse + kNegate + 1.0;
}
if (targetAngle <= -kDefaultAngle) {
if (minStyle.IsOblique()) {
const FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
const double maxAngle = maxStyle.ObliqueAngle();
if (maxAngle <= targetAngle) {
return targetAngle - maxAngle;
}
const double minAngle = minStyle.ObliqueAngle();
if (minAngle <= targetAngle) {
return 0.0;
}
if (minAngle < 0.0) {
return kReverse + (minAngle - targetAngle);
}
return kReverse + kNegate + (minAngle - targetAngle);
}
if (minStyle.IsItalic()) {
return kReverse + kNegate;
}
return kReverse + kNegate + 1.0;
}
if (targetAngle >= 0.0) {
if (minStyle.IsOblique()) {
const double minAngle = minStyle.ObliqueAngle();
if (minAngle > targetAngle) {
return kReverse + (minAngle - targetAngle);
}
const FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
const double maxAngle = maxStyle.ObliqueAngle();
if (maxAngle >= targetAngle) {
return 0.0;
}
if (maxAngle > 0.0) {
return targetAngle - maxAngle;
}
return kReverse + kNegate + (targetAngle - maxAngle);
}
if (minStyle.IsItalic()) {
return kReverse + kNegate - 2.0;
}
return kReverse + kNegate - 1.0;
}
// last case: (targetAngle < 0.0 && targetAngle > kDefaultAngle)
if (minStyle.IsOblique()) {
const FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
const double maxAngle = maxStyle.ObliqueAngle();
if (maxAngle < targetAngle) {
return kReverse + (targetAngle - maxAngle);
}
const double minAngle = minStyle.ObliqueAngle();
if (minAngle <= targetAngle) {
return 0.0;
}
if (minAngle < 0.0) {
return minAngle - targetAngle;
}
return kReverse + kNegate + (minAngle - targetAngle);
}
if (minStyle.IsItalic()) {
return kReverse + kNegate - 2.0;
}
return kReverse + kNegate - 1.0;
}
// stretch distance ==> [0,2000]
static inline double StretchDistance(const gfxFontEntry* aFontEntry,
FontStretch aTargetStretch) {
const double kReverseDistance = 1000.0;
FontStretch minStretch = aFontEntry->Stretch().Min();
FontStretch maxStretch = aFontEntry->Stretch().Max();
// The stretch value is a (non-negative) percentage; currently we support
// values in the range 0 .. 1000. (If the upper limit is ever increased,
// the kReverseDistance value used here may need to be adjusted.)
// If aTargetStretch is >100, we prefer larger values if available;
// if <=100, we prefer smaller values if available.
if (aTargetStretch < minStretch) {
if (aTargetStretch > FontStretch::Normal()) {
return minStretch - aTargetStretch;
}
return (minStretch - aTargetStretch) + kReverseDistance;
}
if (aTargetStretch > maxStretch) {
if (aTargetStretch <= FontStretch::Normal()) {
return aTargetStretch - maxStretch;
}
return (aTargetStretch - maxStretch) + kReverseDistance;
}
return 0.0;
}
// Calculate weight distance with values in the range (0..1000). In general,
// heavier weights match towards even heavier weights while lighter weights
// match towards even lighter weights. Target weight values in the range
// [400..500] are special, since they will first match up to 500, then down
// towards 0, then up again towards 999.
//
// Example: with target 600 and font weight 800, distance will be 200. With
// target 300 and font weight 600, distance will be 900, since heavier
// weights are farther away than lighter weights. If the target is 5 and the
// font weight 995, the distance would be 1590 for the same reason.
// weight distance ==> [0,1600]
static inline double WeightDistance(const gfxFontEntry* aFontEntry,
FontWeight aTargetWeight) {
const double kNotWithinCentralRange = 100.0;
const double kReverseDistance = 600.0;
FontWeight minWeight = aFontEntry->Weight().Min();
FontWeight maxWeight = aFontEntry->Weight().Max();
if (aTargetWeight >= minWeight && aTargetWeight <= maxWeight) {
// Target is within the face's range, so it's a perfect match
return 0.0;
}
if (aTargetWeight < FontWeight(400)) {
// Requested a lighter-than-400 weight
if (maxWeight < aTargetWeight) {
return aTargetWeight - maxWeight;
}
// Add reverse-search penalty for bolder faces
return (minWeight - aTargetWeight) + kReverseDistance;
}
if (aTargetWeight > FontWeight(500)) {
// Requested a bolder-than-500 weight
if (minWeight > aTargetWeight) {
return minWeight - aTargetWeight;
}
// Add reverse-search penalty for lighter faces
return (aTargetWeight - maxWeight) + kReverseDistance;
}
// Special case for requested weight in the [400..500] range
if (minWeight > aTargetWeight) {
if (minWeight <= FontWeight(500)) {
// Bolder weight up to 500 is first choice
return minWeight - aTargetWeight;
}
// Other bolder weights get a reverse-search penalty
return (minWeight - aTargetWeight) + kReverseDistance;
}
// Lighter weights are not as good as bolder ones within [400..500]
return (aTargetWeight - maxWeight) + kNotWithinCentralRange;
}
static inline double WeightStyleStretchDistance(
gfxFontEntry* aFontEntry, const gfxFontStyle& aTargetStyle) {
double stretchDist = StretchDistance(aFontEntry, aTargetStyle.stretch);
double styleDist = StyleDistance(aFontEntry, aTargetStyle.style);
double weightDist = WeightDistance(aFontEntry, aTargetStyle.weight);
double stretchDist =
StretchDistance(aFontEntry->Stretch(), aTargetStyle.stretch);
double styleDist =
StyleDistance(aFontEntry->SlantStyle(), aTargetStyle.style);
double weightDist = WeightDistance(aFontEntry->Weight(), aTargetStyle.weight);
// Sanity-check that the distances are within the expected range
// (update if implementation of the distance functions is changed).

Просмотреть файл

@ -992,4 +992,244 @@ class gfxFontUtils {
static const mozilla::Encoding* gMSFontNameCharsets[];
};
// style distance ==> [0,500]
static inline double StyleDistance(const mozilla::SlantStyleRange& aRange,
mozilla::FontSlantStyle aTargetStyle) {
const mozilla::FontSlantStyle minStyle = aRange.Min();
if (aTargetStyle == minStyle) {
return 0.0; // styles match exactly ==> 0
}
// bias added to angle difference when searching in the non-preferred
// direction from a target angle
const double kReverse = 100.0;
// bias added when we've crossed from positive to negative angles or
// vice versa
const double kNegate = 200.0;
if (aTargetStyle.IsNormal()) {
if (minStyle.IsOblique()) {
// to distinguish oblique 0deg from normal, we add 1.0 to the angle
const double minAngle = minStyle.ObliqueAngle();
if (minAngle >= 0.0) {
return 1.0 + minAngle;
}
const mozilla::FontSlantStyle maxStyle = aRange.Max();
const double maxAngle = maxStyle.ObliqueAngle();
if (maxAngle >= 0.0) {
// [min,max] range includes 0.0, so just return our minimum
return 1.0;
}
// negative oblique is even worse than italic
return kNegate - maxAngle;
}
// must be italic, which is worse than any non-negative oblique;
// treat as a match in the wrong search direction
MOZ_ASSERT(minStyle.IsItalic());
return kReverse;
}
const double kDefaultAngle =
mozilla::FontSlantStyle::Oblique().ObliqueAngle();
if (aTargetStyle.IsItalic()) {
if (minStyle.IsOblique()) {
const double minAngle = minStyle.ObliqueAngle();
if (minAngle >= kDefaultAngle) {
return 1.0 + (minAngle - kDefaultAngle);
}
const mozilla::FontSlantStyle maxStyle = aRange.Max();
const double maxAngle = maxStyle.ObliqueAngle();
if (maxAngle >= kDefaultAngle) {
return 1.0;
}
if (maxAngle > 0.0) {
// wrong direction but still > 0, add bias of 100
return kReverse + (kDefaultAngle - maxAngle);
}
// negative oblique angle, add bias of 300
return kReverse + kNegate + (kDefaultAngle - maxAngle);
}
// normal is worse than oblique > 0, but better than oblique <= 0
MOZ_ASSERT(minStyle.IsNormal());
return kNegate;
}
// target is oblique <angle>: four different cases depending on
// the value of the <angle>, which determines the preferred direction
// of search
const double targetAngle = aTargetStyle.ObliqueAngle();
if (targetAngle >= kDefaultAngle) {
if (minStyle.IsOblique()) {
const double minAngle = minStyle.ObliqueAngle();
if (minAngle >= targetAngle) {
return minAngle - targetAngle;
}
const mozilla::FontSlantStyle maxStyle = aRange.Max();
const double maxAngle = maxStyle.ObliqueAngle();
if (maxAngle >= targetAngle) {
return 0.0;
}
if (maxAngle > 0.0) {
return kReverse + (targetAngle - maxAngle);
}
return kReverse + kNegate + (targetAngle - maxAngle);
}
if (minStyle.IsItalic()) {
return kReverse + kNegate;
}
return kReverse + kNegate + 1.0;
}
if (targetAngle <= -kDefaultAngle) {
if (minStyle.IsOblique()) {
const mozilla::FontSlantStyle maxStyle = aRange.Max();
const double maxAngle = maxStyle.ObliqueAngle();
if (maxAngle <= targetAngle) {
return targetAngle - maxAngle;
}
const double minAngle = minStyle.ObliqueAngle();
if (minAngle <= targetAngle) {
return 0.0;
}
if (minAngle < 0.0) {
return kReverse + (minAngle - targetAngle);
}
return kReverse + kNegate + (minAngle - targetAngle);
}
if (minStyle.IsItalic()) {
return kReverse + kNegate;
}
return kReverse + kNegate + 1.0;
}
if (targetAngle >= 0.0) {
if (minStyle.IsOblique()) {
const double minAngle = minStyle.ObliqueAngle();
if (minAngle > targetAngle) {
return kReverse + (minAngle - targetAngle);
}
const mozilla::FontSlantStyle maxStyle = aRange.Max();
const double maxAngle = maxStyle.ObliqueAngle();
if (maxAngle >= targetAngle) {
return 0.0;
}
if (maxAngle > 0.0) {
return targetAngle - maxAngle;
}
return kReverse + kNegate + (targetAngle - maxAngle);
}
if (minStyle.IsItalic()) {
return kReverse + kNegate - 2.0;
}
return kReverse + kNegate - 1.0;
}
// last case: (targetAngle < 0.0 && targetAngle > kDefaultAngle)
if (minStyle.IsOblique()) {
const mozilla::FontSlantStyle maxStyle = aRange.Max();
const double maxAngle = maxStyle.ObliqueAngle();
if (maxAngle < targetAngle) {
return kReverse + (targetAngle - maxAngle);
}
const double minAngle = minStyle.ObliqueAngle();
if (minAngle <= targetAngle) {
return 0.0;
}
if (minAngle < 0.0) {
return minAngle - targetAngle;
}
return kReverse + kNegate + (minAngle - targetAngle);
}
if (minStyle.IsItalic()) {
return kReverse + kNegate - 2.0;
}
return kReverse + kNegate - 1.0;
}
// stretch distance ==> [0,2000]
static inline double StretchDistance(const mozilla::StretchRange& aRange,
mozilla::FontStretch aTargetStretch) {
const double kReverseDistance = 1000.0;
mozilla::FontStretch minStretch = aRange.Min();
mozilla::FontStretch maxStretch = aRange.Max();
// The stretch value is a (non-negative) percentage; currently we support
// values in the range 0 .. 1000. (If the upper limit is ever increased,
// the kReverseDistance value used here may need to be adjusted.)
// If aTargetStretch is >100, we prefer larger values if available;
// if <=100, we prefer smaller values if available.
if (aTargetStretch < minStretch) {
if (aTargetStretch > mozilla::FontStretch::Normal()) {
return minStretch - aTargetStretch;
}
return (minStretch - aTargetStretch) + kReverseDistance;
}
if (aTargetStretch > maxStretch) {
if (aTargetStretch <= mozilla::FontStretch::Normal()) {
return aTargetStretch - maxStretch;
}
return (aTargetStretch - maxStretch) + kReverseDistance;
}
return 0.0;
}
// Calculate weight distance with values in the range (0..1000). In general,
// heavier weights match towards even heavier weights while lighter weights
// match towards even lighter weights. Target weight values in the range
// [400..500] are special, since they will first match up to 500, then down
// towards 0, then up again towards 999.
//
// Example: with target 600 and font weight 800, distance will be 200. With
// target 300 and font weight 600, distance will be 900, since heavier
// weights are farther away than lighter weights. If the target is 5 and the
// font weight 995, the distance would be 1590 for the same reason.
// weight distance ==> [0,1600]
static inline double WeightDistance(const mozilla::WeightRange& aRange,
mozilla::FontWeight aTargetWeight) {
const double kNotWithinCentralRange = 100.0;
const double kReverseDistance = 600.0;
mozilla::FontWeight minWeight = aRange.Min();
mozilla::FontWeight maxWeight = aRange.Max();
if (aTargetWeight >= minWeight && aTargetWeight <= maxWeight) {
// Target is within the face's range, so it's a perfect match
return 0.0;
}
if (aTargetWeight < mozilla::FontWeight(400)) {
// Requested a lighter-than-400 weight
if (maxWeight < aTargetWeight) {
return aTargetWeight - maxWeight;
}
// Add reverse-search penalty for bolder faces
return (minWeight - aTargetWeight) + kReverseDistance;
}
if (aTargetWeight > mozilla::FontWeight(500)) {
// Requested a bolder-than-500 weight
if (minWeight > aTargetWeight) {
return minWeight - aTargetWeight;
}
// Add reverse-search penalty for lighter faces
return (aTargetWeight - maxWeight) + kReverseDistance;
}
// Special case for requested weight in the [400..500] range
if (minWeight > aTargetWeight) {
if (minWeight <= mozilla::FontWeight(500)) {
// Bolder weight up to 500 is first choice
return minWeight - aTargetWeight;
}
// Other bolder weights get a reverse-search penalty
return (minWeight - aTargetWeight) + kReverseDistance;
}
// Lighter weights are not as good as bolder ones within [400..500]
return (aTargetWeight - maxWeight) + kNotWithinCentralRange;
}
#endif /* GFX_FONT_UTILS_H */