1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /* font specific types shared by both thebes and layout */
8 #ifndef GFX_FONT_PROPERTY_TYPES_H
9 #define GFX_FONT_PROPERTY_TYPES_H
20 #include "mozilla/Assertions.h"
21 #include "mozilla/TextUtils.h"
25 * This file is separate from gfxFont.h so that layout can include it
26 * without bringing in gfxFont.h and everything it includes.
32 * Generic template for font property type classes that use a fixed-point
33 * internal representation.
34 * Template parameters:
35 * InternalType - the integer type to use as the internal representation (e.g.
37 * * NOTE that T must NOT be plain /int/, as that would result in
38 * ambiguity between constructors from /int/ and /T/, which mean
40 * FractionBits - number of bits to use for the fractional part
41 * Min, Max - [inclusive] limits to the range of values that may be stored
42 * Values are constructed from and exposed as floating-point, but stored
43 * internally as fixed point, so there will be a quantization effect on
44 * fractional values, depending on the number of fractional bits used.
45 * Using (16-bit) fixed-point types rather than floats for these style
46 * attributes reduces the memory footprint of gfxFontEntry and gfxFontStyle;
47 * it will also tend to reduce the number of distinct font instances that
48 * get created, particularly when styles are animated or set to arbitrary
49 * values (e.g. by sliders in the UI), which should reduce pressure on
50 * graphics resources and improve cache hit rates.
52 template <class InternalType
, unsigned FractionBits
, int Min
, int Max
>
53 class FontPropertyValue
{
55 // Initialize to the minimum value by default.
56 constexpr FontPropertyValue() : FontPropertyValue(Min
) {}
58 explicit FontPropertyValue(const FontPropertyValue
& aOther
) = default;
59 FontPropertyValue
& operator=(const FontPropertyValue
& aOther
) = default;
61 bool operator==(const FontPropertyValue
& aOther
) const {
62 return mValue
== aOther
.mValue
;
64 bool operator!=(const FontPropertyValue
& aOther
) const {
65 return mValue
!= aOther
.mValue
;
67 bool operator<(const FontPropertyValue
& aOther
) const {
68 return mValue
< aOther
.mValue
;
70 bool operator>(const FontPropertyValue
& aOther
) const {
71 return mValue
> aOther
.mValue
;
73 bool operator<=(const FontPropertyValue
& aOther
) const {
74 return mValue
<= aOther
.mValue
;
76 bool operator>=(const FontPropertyValue
& aOther
) const {
77 return mValue
>= aOther
.mValue
;
80 // The difference between two values, returned as a raw floating-point number
81 // (which might not be a valid property value in its own right).
82 float operator-(const FontPropertyValue
& aOther
) const {
83 return (mValue
- aOther
.mValue
) * kInverseScale
;
86 /// Return the raw internal representation, for purposes of hashing.
87 /// (Do not try to interpret the numeric value of this.)
88 uint16_t ForHash() const { return uint16_t(mValue
); }
90 static constexpr const float kMin
= float(Min
);
91 static constexpr const float kMax
= float(Max
);
94 // Construct from a floating-point or integer value, checking that it is
95 // within the allowed range and converting to fixed-point representation.
96 explicit constexpr FontPropertyValue(float aValue
)
97 : mValue(std::round(aValue
* kScale
)) {
98 MOZ_ASSERT(aValue
>= kMin
&& aValue
<= kMax
);
100 explicit constexpr FontPropertyValue(int aValue
)
101 : mValue(static_cast<InternalType
>(aValue
* kScale
)) {
102 MOZ_ASSERT(aValue
>= Min
&& aValue
<= Max
);
105 // Construct directly from a fixed-point value of type T, with no check;
106 // note that there may be special "flag" values that are outside the normal
107 // min/max range (e.g. for font-style:italic, distinct from oblique angle).
108 explicit constexpr FontPropertyValue(InternalType aValue
) : mValue(aValue
) {}
110 // This is protected as it may not be the most appropriate accessor for a
111 // given instance to expose. It's up to each individual property to provide
112 // public accessors that forward to this as required.
113 float ToFloat() const { return mValue
* kInverseScale
; }
114 int ToIntRounded() const { return (mValue
+ kPointFive
) >> FractionBits
; }
116 static constexpr int kScale
= 1 << FractionBits
;
117 static constexpr float kInverseScale
= 1.0f
/ kScale
;
118 static const unsigned kFractionBits
= FractionBits
;
120 // Constant representing 0.5 in the internal representation (note this
121 // assumes that kFractionBits is greater than zero!)
122 static const InternalType kPointFive
= 1u << (kFractionBits
- 1);
128 * font-weight: range 1..1000, fractional values permitted; keywords
129 * 'normal', 'bold' aliased to 400, 700 respectively; relative keywords
130 * 'lighter', 'bolder' (not currently handled here).
132 * We use an unsigned 10.6 fixed-point value (range 0.0 - 1023.984375)
134 class FontWeight final
: public FontPropertyValue
<uint16_t, 6, 1, 1000> {
136 constexpr FontWeight() = default;
138 explicit constexpr FontWeight(float aValue
) : FontPropertyValue(aValue
) {}
141 * CSS font weights can have fractional values, but this constructor exists
142 * for convenience when writing constants such as FontWeight(700) in code.
144 explicit constexpr FontWeight(int aValue
) : FontPropertyValue(aValue
) {}
146 static constexpr FontWeight
Normal() { return FontWeight(kNormal
); }
148 static constexpr FontWeight
Thin() { return FontWeight(kThin
); }
150 static constexpr FontWeight
Bold() { return FontWeight(kBold
); }
152 bool IsNormal() const { return mValue
== kNormal
; }
153 bool IsBold() const { return mValue
>= kBoldThreshold
; }
155 float ToFloat() const { return FontPropertyValue::ToFloat(); }
156 int ToIntRounded() const { return FontPropertyValue::ToIntRounded(); }
158 typedef uint16_t InternalType
;
161 friend class WeightRange
;
163 explicit constexpr FontWeight(InternalType aValue
)
164 : FontPropertyValue(aValue
) {}
166 static const InternalType kNormal
= 400u << kFractionBits
;
167 static const InternalType kBold
= 700u << kFractionBits
;
168 static const InternalType kBoldThreshold
= 600u << kFractionBits
;
169 static const InternalType kThin
= 100u << kFractionBits
;
170 static const InternalType kExtraBold
= 900u << kFractionBits
;
174 * font-stretch is represented as a percentage relative to 'normal'.
176 * css-fonts says the value must be >= 0%, and normal is 100%. Keywords
177 * from ultra-condensed to ultra-expanded are aliased to percentages
178 * from 50% to 200%; values outside that range are unlikely to be common,
181 * Like font-weight, we use an unsigned 10.6 fixed-point value (range
182 * 0.0 - 1023.984375).
184 * We arbitrarily limit here to 1000%. (If that becomes a problem, we
185 * could reduce the number of fractional bits and increase the limit.)
187 class FontStretch final
: public FontPropertyValue
<uint16_t, 6, 0, 1000> {
189 constexpr FontStretch() = default;
191 explicit constexpr FontStretch(float aPercent
)
192 : FontPropertyValue(aPercent
) {}
194 static constexpr FontStretch
Normal() { return FontStretch(kNormal
); }
195 static constexpr FontStretch
UltraCondensed() {
196 return FontStretch(kUltraCondensed
);
198 static constexpr FontStretch
ExtraCondensed() {
199 return FontStretch(kExtraCondensed
);
201 static constexpr FontStretch
Condensed() { return FontStretch(kCondensed
); }
202 static constexpr FontStretch
SemiCondensed() {
203 return FontStretch(kSemiCondensed
);
205 static constexpr FontStretch
SemiExpanded() {
206 return FontStretch(kSemiExpanded
);
208 static constexpr FontStretch
Expanded() { return FontStretch(kExpanded
); }
209 static constexpr FontStretch
ExtraExpanded() {
210 return FontStretch(kExtraExpanded
);
212 static constexpr FontStretch
UltraExpanded() {
213 return FontStretch(kUltraExpanded
);
216 // The style system represents percentages in the 0.0..1.0 range, and
217 // FontStretch does it in the 0.0..100.0 range.
219 // TODO(emilio): We should consider changing this class to deal with the same
220 // range as the style system.
221 static FontStretch
FromStyle(float aStylePercentage
) {
222 return FontStretch(std::min(aStylePercentage
* 100.0f
, float(kMax
)));
225 bool IsNormal() const { return mValue
== kNormal
; }
226 float Percentage() const { return ToFloat(); }
228 typedef uint16_t InternalType
;
231 friend class StretchRange
;
233 explicit constexpr FontStretch(InternalType aValue
)
234 : FontPropertyValue(aValue
) {}
236 static const InternalType kUltraCondensed
= 50u << kFractionBits
;
237 static const InternalType kExtraCondensed
=
238 (62u << kFractionBits
) + kPointFive
;
239 static const InternalType kCondensed
= 75u << kFractionBits
;
240 static const InternalType kSemiCondensed
=
241 (87u << kFractionBits
) + kPointFive
;
242 static const InternalType kNormal
= 100u << kFractionBits
;
243 static const InternalType kSemiExpanded
=
244 (112u << kFractionBits
) + kPointFive
;
245 static const InternalType kExpanded
= 125u << kFractionBits
;
246 static const InternalType kExtraExpanded
= 150u << kFractionBits
;
247 static const InternalType kUltraExpanded
= 200u << kFractionBits
;
251 * font-style: normal | italic | oblique <angle>?
252 * values of <angle> below -90 or above 90 not permitted
253 * - Use a signed 8.8 fixed-point value
254 * (representable range -128.0 - 127.99609375)
255 * - Define min value (-128.0) as meaning 'normal'
256 * - Define max value (127.99609375) as 'italic'
257 * - Other values represent 'oblique <angle>'
258 * - Note that 'oblique 0deg' is distinct from 'normal' (should it be?)
260 class FontSlantStyle final
: public FontPropertyValue
<int16_t, 8, -90, 90> {
262 const static constexpr float kDefaultAngle
= 14.0;
264 constexpr FontSlantStyle() = default;
266 static constexpr FontSlantStyle
Normal() { return FontSlantStyle(kNormal
); }
268 static constexpr FontSlantStyle
Italic() { return FontSlantStyle(kItalic
); }
270 static constexpr FontSlantStyle
Oblique(float aAngle
= kDefaultAngle
) {
271 return FontSlantStyle(aAngle
);
274 // Create from a string as generated by ToString. This is for internal use
275 // when serializing/deserializing entries for the startupcache, and is not
276 // intended to parse arbitrary (untrusted) strings.
277 static FontSlantStyle
FromString(const char* aString
) {
278 if (strcmp(aString
, "normal") == 0) {
281 if (strcmp(aString
, "italic") == 0) {
284 if (mozilla::IsAsciiDigit(aString
[0]) && strstr(aString
, "deg")) {
285 float angle
= strtof(aString
, nullptr);
286 return Oblique(angle
);
288 // Not recognized as an oblique angle; maybe it's from a startup-cache
289 // created by an older version. The style field there used a simple 0/1
290 // for normal/italic respectively.
291 return aString
[0] == '0' ? Normal() : Italic();
294 bool IsNormal() const { return mValue
== kNormal
; }
295 bool IsItalic() const { return mValue
== kItalic
; }
296 bool IsOblique() const { return mValue
!= kItalic
&& mValue
!= kNormal
; }
298 float ObliqueAngle() const {
299 // It's not meaningful to get the oblique angle from a style that is
300 // actually 'normal' or 'italic'.
301 MOZ_ASSERT(IsOblique());
306 * Write a string representation of the value to aOutString.
308 * NOTE that this APPENDS to the output string, it does not replace
309 * any existing contents.
311 void ToString(nsACString
& aOutString
) const {
313 aOutString
.Append("normal");
314 } else if (IsItalic()) {
315 aOutString
.Append("italic");
317 aOutString
.AppendPrintf("%gdeg", ObliqueAngle());
321 typedef int16_t InternalType
;
324 friend class SlantStyleRange
;
326 explicit constexpr FontSlantStyle(InternalType aConstant
)
327 : FontPropertyValue(aConstant
) {}
329 explicit constexpr FontSlantStyle(float aAngle
) : FontPropertyValue(aAngle
) {}
331 static const InternalType kNormal
= INT16_MIN
;
332 static const InternalType kItalic
= INT16_MAX
;
336 * Convenience type to hold a <min, max> pair representing a range of values.
338 * The min and max are both inclusive, so when min == max the range represents
339 * a single value (not an empty range).
342 class FontPropertyRange
{
343 // This implementation assumes the underlying property type is a 16-bit value
344 // (see FromScalar and AsScalar below).
345 static_assert(sizeof(T
) == 2, "FontPropertyValue should be a 16-bit type!");
349 * Construct a range from given minimum and maximum values (inclusive).
351 FontPropertyRange(T aMin
, T aMax
) : mValues(aMin
, aMax
) {
352 MOZ_ASSERT(aMin
<= aMax
);
356 * Construct a range representing a single value (min==max).
358 explicit FontPropertyRange(T aValue
) : mValues(aValue
, aValue
) {}
360 explicit FontPropertyRange(const FontPropertyRange
& aOther
) = default;
361 FontPropertyRange
& operator=(const FontPropertyRange
& aOther
) = default;
363 T
Min() const { return mValues
.first
; }
364 T
Max() const { return mValues
.second
; }
367 * Clamp the given value to this range.
369 * (We can't use mozilla::Clamp here because it only accepts integral types.)
371 T
Clamp(T aValue
) const {
372 return aValue
<= Min() ? Min() : (aValue
>= Max() ? Max() : aValue
);
376 * Return whether the range consists of a single unique value.
378 bool IsSingle() const { return Min() == Max(); }
380 bool operator==(const FontPropertyRange
& aOther
) const {
381 return mValues
== aOther
.mValues
;
383 bool operator!=(const FontPropertyRange
& aOther
) const {
384 return mValues
!= aOther
.mValues
;
388 * Conversion of the property range to/from a single 32-bit scalar value,
389 * suitable for IPC serialization, hashing, caching.
391 * No assumptions should be made about the numeric value of the scalar.
393 * This depends on the underlying property type being a 16-bit value!
395 typedef uint32_t ScalarType
;
397 ScalarType
AsScalar() const {
398 return (mValues
.first
.ForHash() << 16) | mValues
.second
.ForHash();
403 * FromScalar is defined in each individual subclass, because I can't
404 * persuade the compiler to accept a definition here in the template. :\
406 static FontPropertyRange FromScalar(ScalarType aScalar)
408 return FontPropertyRange(T(typename T::InternalType(aScalar >> 16)),
409 T(typename T::InternalType(aScalar & 0xffff)));
414 std::pair
<T
, T
> mValues
;
417 class WeightRange
: public FontPropertyRange
<FontWeight
> {
419 WeightRange(FontWeight aMin
, FontWeight aMax
)
420 : FontPropertyRange(aMin
, aMax
) {}
422 explicit WeightRange(FontWeight aWeight
) : FontPropertyRange(aWeight
) {}
424 WeightRange(const WeightRange
& aOther
) = default;
426 void ToString(nsACString
& aOutString
, const char* aDelim
= "..") const {
427 aOutString
.AppendFloat(Min().ToFloat());
429 aOutString
.Append(aDelim
);
430 aOutString
.AppendFloat(Max().ToFloat());
434 static WeightRange
FromScalar(ScalarType aScalar
) {
435 return WeightRange(FontWeight(FontWeight::InternalType(aScalar
>> 16)),
436 FontWeight(FontWeight::InternalType(aScalar
& 0xffff)));
440 class StretchRange
: public FontPropertyRange
<FontStretch
> {
442 StretchRange(FontStretch aMin
, FontStretch aMax
)
443 : FontPropertyRange(aMin
, aMax
) {}
445 explicit StretchRange(FontStretch aStretch
) : FontPropertyRange(aStretch
) {}
447 StretchRange(const StretchRange
& aOther
) = default;
449 void ToString(nsACString
& aOutString
, const char* aDelim
= "..") const {
450 aOutString
.AppendFloat(Min().Percentage());
452 aOutString
.Append(aDelim
);
453 aOutString
.AppendFloat(Max().Percentage());
457 static StretchRange
FromScalar(ScalarType aScalar
) {
459 FontStretch(FontStretch::InternalType(aScalar
>> 16)),
460 FontStretch(FontStretch::InternalType(aScalar
& 0xffff)));
464 class SlantStyleRange
: public FontPropertyRange
<FontSlantStyle
> {
466 SlantStyleRange(FontSlantStyle aMin
, FontSlantStyle aMax
)
467 : FontPropertyRange(aMin
, aMax
) {}
469 explicit SlantStyleRange(FontSlantStyle aStyle
) : FontPropertyRange(aStyle
) {}
471 SlantStyleRange(const SlantStyleRange
& aOther
) = default;
473 void ToString(nsACString
& aOutString
, const char* aDelim
= "..") const {
474 Min().ToString(aOutString
);
476 aOutString
.Append(aDelim
);
477 Max().ToString(aOutString
);
481 static SlantStyleRange
FromScalar(ScalarType aScalar
) {
482 return SlantStyleRange(
483 FontSlantStyle(FontSlantStyle::InternalType(aScalar
>> 16)),
484 FontSlantStyle(FontSlantStyle::InternalType(aScalar
& 0xffff)));
488 } // namespace mozilla
490 #endif // GFX_FONT_PROPERTY_TYPES_H