Bug 1700051: part 46) Const-qualify `mozInlineSpellStatus::mAnchorRange`. r=smaug
[gecko.git] / gfx / src / FontPropertyTypes.h
blob9da6ab939145fdeaa3b2c5273785bdbc58a3775c
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
11 #include <algorithm>
12 #include <cstdint>
13 #include <cmath>
14 #include <utility>
16 #include <ctype.h>
17 #include <stdlib.h>
18 #include <string.h>
20 #include "mozilla/Assertions.h"
21 #include "mozilla/TextUtils.h"
22 #include "nsString.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.
29 namespace mozilla {
31 /**
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.
36 * uint16_t)
37 * * NOTE that T must NOT be plain /int/, as that would result in
38 * ambiguity between constructors from /int/ and /T/, which mean
39 * different things.
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 {
54 public:
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);
93 protected:
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);
124 InternalType mValue;
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> {
135 public:
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;
160 private:
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,
179 * but could occur.
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> {
188 public:
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;
230 private:
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> {
261 public:
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) {
279 return Normal();
281 if (strcmp(aString, "italic") == 0) {
282 return Italic();
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());
302 return ToFloat();
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 {
312 if (IsNormal()) {
313 aOutString.Append("normal");
314 } else if (IsItalic()) {
315 aOutString.Append("italic");
316 } else {
317 aOutString.AppendPrintf("%gdeg", ObliqueAngle());
321 typedef int16_t InternalType;
323 private:
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).
341 template <class T>
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!");
347 public:
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();
402 * FIXME:
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)));
413 protected:
414 std::pair<T, T> mValues;
417 class WeightRange : public FontPropertyRange<FontWeight> {
418 public:
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());
428 if (!IsSingle()) {
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> {
441 public:
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());
451 if (!IsSingle()) {
452 aOutString.Append(aDelim);
453 aOutString.AppendFloat(Max().Percentage());
457 static StretchRange FromScalar(ScalarType aScalar) {
458 return StretchRange(
459 FontStretch(FontStretch::InternalType(aScalar >> 16)),
460 FontStretch(FontStretch::InternalType(aScalar & 0xffff)));
464 class SlantStyleRange : public FontPropertyRange<FontSlantStyle> {
465 public:
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);
475 if (!IsSingle()) {
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