SharedFontList.h (15015B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #ifndef SharedFontList_h 6 #define SharedFontList_h 7 8 #include "gfxFontEntry.h" 9 #include <atomic> 10 11 class gfxCharacterMap; 12 struct gfxFontStyle; 13 struct GlobalFontMatch; 14 15 namespace mozilla { 16 namespace fontlist { 17 18 class FontList; // See the separate SharedFontList-impl.h header 19 20 /** 21 * A Pointer in the shared font list contains a packed index/offset pair, 22 * with a 12-bit index into the array of shared-memory blocks, and a 20-bit 23 * offset into the block. 24 * The maximum size of each block is therefore 2^20 bytes (1 MB) if sub-parts 25 * of the block are to be allocated; however, a larger block (up to 2^32 bytes) 26 * can be created and used as a single allocation if necessary. 27 */ 28 struct Pointer { 29 private: 30 friend class FontList; 31 static const uint32_t kIndexBits = 12u; 32 static const uint32_t kBlockShift = 20u; 33 static_assert(kIndexBits + kBlockShift == 32u, "bad Pointer bit count"); 34 35 static const uint32_t kNullValue = 0xffffffffu; 36 static const uint32_t kOffsetMask = (1u << kBlockShift) - 1; 37 38 public: 39 static Pointer Null() { return Pointer(); } 40 41 Pointer() : mBlockAndOffset(kNullValue) {} 42 43 Pointer(uint32_t aBlock, uint32_t aOffset) 44 : mBlockAndOffset((aBlock << kBlockShift) | aOffset) { 45 MOZ_ASSERT(aBlock < (1u << kIndexBits) && aOffset < (1u << kBlockShift)); 46 } 47 48 Pointer(const Pointer& aOther) { 49 mBlockAndOffset.store(aOther.mBlockAndOffset); 50 } 51 52 Pointer(Pointer&& aOther) { mBlockAndOffset.store(aOther.mBlockAndOffset); } 53 54 /** 55 * Check if a Pointer has the null value. 56 * 57 * NOTE! 58 * In a child process, it is possible that conversion to a "real" pointer 59 * using ToPtr() will fail even when IsNull() is false, so calling code 60 * that may run in child processes must be prepared to handle this. 61 */ 62 bool IsNull() const { return mBlockAndOffset == kNullValue; } 63 64 uint32_t Block() const { return mBlockAndOffset >> kBlockShift; } 65 66 uint32_t Offset() const { return mBlockAndOffset & kOffsetMask; } 67 68 /** 69 * Convert a fontlist::Pointer to a standard C++ pointer. This requires the 70 * FontList, which will know where the shared memory block is mapped in 71 * the current process's address space. 72 * 73 * aSize is the expected size of the pointed-to object, for bounds checking. 74 * 75 * NOTE! 76 * In child processes this may fail and return nullptr, even if IsNull() is 77 * false, in cases where the font list is in the process of being rebuilt. 78 */ 79 void* ToPtr(FontList* aFontList, size_t aSize) const; 80 81 template <typename T> 82 T* ToPtr(FontList* aFontList) const { 83 return static_cast<T*>(ToPtr(aFontList, sizeof(T))); 84 } 85 86 template <typename T> 87 T* ToArray(FontList* aFontList, size_t aCount) const { 88 return static_cast<T*>(ToPtr(aFontList, sizeof(T) * aCount)); 89 } 90 91 Pointer& operator=(const Pointer& aOther) { 92 mBlockAndOffset.store(aOther.mBlockAndOffset); 93 return *this; 94 } 95 96 Pointer& operator=(Pointer&& aOther) { 97 mBlockAndOffset.store(aOther.mBlockAndOffset); 98 return *this; 99 } 100 101 // We store the block index and the offset within the block as a single 102 // atomic 32-bit value so we can safely modify a Pointer without other 103 // processes seeing a broken (partially-updated) value. 104 std::atomic<uint32_t> mBlockAndOffset; 105 }; 106 107 /** 108 * Family and face names are stored as String records, which hold a length 109 * (in utf-8 code units) and a Pointer to the string's UTF-8 characters. 110 */ 111 struct String { 112 String() : mPointer(Pointer::Null()), mLength(0) {} 113 114 String(FontList* aList, const nsACString& aString) 115 : mPointer(Pointer::Null()) { 116 Assign(aString, aList); 117 } 118 119 const nsCString AsString(FontList* aList) const { 120 MOZ_ASSERT(!mPointer.IsNull()); 121 // It's tempting to use AssignLiteral here so that we get an nsCString that 122 // simply wraps the character data in the shmem block without needing to 123 // allocate or copy. But that's unsafe because in the event of font-list 124 // reinitalization, that shared memory will be unmapped; then any copy of 125 // the nsCString that may still be around will crash if accessed. 126 return nsCString(mPointer.ToArray<const char>(aList, mLength), mLength); 127 } 128 129 void Assign(const nsACString& aString, FontList* aList); 130 131 const char* BeginReading(FontList* aList) const { 132 MOZ_ASSERT(!mPointer.IsNull()); 133 auto* str = mPointer.ToArray<const char>(aList, mLength); 134 return str ? str : ""; 135 } 136 137 uint32_t Length() const { return mLength; } 138 139 /** 140 * Return whether the String has been set to a value. 141 * 142 * NOTE! 143 * In a child process, accessing the value could fail even if IsNull() 144 * returned false. In this case, the nsCString constructor used by AsString() 145 * will be passed a null pointer, and return an empty string despite the 146 * non-zero Length() recorded here. 147 */ 148 bool IsNull() const { return mPointer.IsNull(); } 149 150 private: 151 Pointer mPointer; 152 uint32_t mLength; 153 }; 154 155 /** 156 * A Face record represents an individual font resource; it has the style 157 * properties needed for font matching, as well as a pointer to a character 158 * map that records the supported character set. This may be Null if we have 159 * not yet loaded the data. 160 * The mDescriptor and mIndex fields provide the information needed to 161 * instantiate a (platform-specific) font reference that can be used with 162 * platform font APIs; their content depends on the requirements of the 163 * platform APIs (e.g. font PostScript name, file pathname, serialized 164 * fontconfig pattern, etc). 165 */ 166 struct Face { 167 // Data required to initialize a Face 168 struct InitData { 169 nsCString mDescriptor; // descriptor that can be used to instantiate a 170 // platform font reference 171 uint16_t mIndex; // an index used with descriptor (on some platforms) 172 #ifdef MOZ_WIDGET_GTK 173 uint16_t mSize; // pixel size if bitmap; zero indicates scalable 174 #endif 175 bool mFixedPitch; // is the face fixed-pitch (monospaced)? 176 mozilla::WeightRange mWeight; // CSS font-weight value 177 mozilla::StretchRange mStretch; // CSS font-stretch value 178 mozilla::SlantStyleRange mStyle; // CSS font-style value 179 RefPtr<gfxCharacterMap> mCharMap; // character map, or null if not loaded 180 }; 181 182 // Note that mCharacterMap is not set from the InitData by this constructor; 183 // the caller must use SetCharacterMap to handle that separately if required. 184 Face(FontList* aList, const InitData& aData) 185 : mDescriptor(aList, aData.mDescriptor), 186 mIndex(aData.mIndex), 187 #ifdef MOZ_WIDGET_GTK 188 mSize(aData.mSize), 189 #endif 190 mFixedPitch(aData.mFixedPitch), 191 mWeight(aData.mWeight), 192 mStretch(aData.mStretch), 193 mStyle(aData.mStyle), 194 mCharacterMap(Pointer::Null()) { 195 } 196 197 bool HasValidDescriptor() const { 198 return !mDescriptor.IsNull() && mIndex != uint16_t(-1); 199 } 200 201 void SetCharacterMap(FontList* aList, gfxCharacterMap* aCharMap, 202 const Family* aFamily); 203 204 String mDescriptor; 205 uint16_t mIndex; 206 #ifdef MOZ_WIDGET_GTK 207 uint16_t mSize; 208 #endif 209 bool mFixedPitch; 210 mozilla::WeightRange mWeight; 211 mozilla::StretchRange mStretch; 212 mozilla::SlantStyleRange mStyle; 213 Pointer mCharacterMap; 214 }; 215 216 /** 217 * A Family record represents an available (installed) font family; it has 218 * a name (for display purposes) and a key (lowercased, for case-insensitive 219 * lookups), as well as a pointer to an array of Faces. Depending on the 220 * platform, the array of faces may be lazily initialized the first time we 221 * want to use the family. 222 */ 223 struct Family { 224 static constexpr uint32_t kNoIndex = uint32_t(-1); 225 226 // Data required to initialize a Family 227 struct InitData { 228 InitData(const nsACString& aKey, // lookup key (lowercased) 229 const nsACString& aName, // display name 230 uint32_t aIndex = kNoIndex, // [win] system collection index 231 FontVisibility aVisibility = FontVisibility::Unknown, 232 bool aBundled = false, // [win] font was bundled with the app 233 // rather than system-installed 234 bool aBadUnderline = false, // underline-position in font is bad 235 bool aForceClassic = false, // [win] use "GDI classic" rendering 236 bool aAltLocale = false // font is alternate localized family 237 ) 238 : mKey(aKey), 239 mName(aName), 240 mIndex(aIndex), 241 mVisibility(aVisibility), 242 mBundled(aBundled), 243 mBadUnderline(aBadUnderline), 244 mForceClassic(aForceClassic), 245 mAltLocale(aAltLocale) {} 246 bool operator<(const InitData& aRHS) const { return mKey < aRHS.mKey; } 247 bool operator==(const InitData& aRHS) const { 248 return mKey == aRHS.mKey && mName == aRHS.mName && 249 mVisibility == aRHS.mVisibility && mBundled == aRHS.mBundled && 250 mBadUnderline == aRHS.mBadUnderline; 251 } 252 nsCString mKey; 253 nsCString mName; 254 uint32_t mIndex; 255 FontVisibility mVisibility; 256 bool mBundled; 257 bool mBadUnderline; 258 bool mForceClassic; 259 bool mAltLocale; 260 }; 261 262 /** 263 * Font families are considered "simple" if they contain only 4 faces with 264 * style attributes corresponding to Regular, Bold, Italic, and BoldItalic 265 * respectively, or a subset of these (e.g. only Regular and Bold). In this 266 * case, the faces are stored at predefined positions in the mFaces array, 267 * and a simplified (faster) style-matching algorithm can be used. 268 */ 269 enum { 270 // Indexes into mFaces for families where mIsSimple is true 271 kRegularFaceIndex = 0, 272 kBoldFaceIndex = 1, 273 kItalicFaceIndex = 2, 274 kBoldItalicFaceIndex = 3, 275 // mask values for selecting face with bold and/or italic attributes 276 kBoldMask = 0x01, 277 kItalicMask = 0x02 278 }; 279 280 Family(FontList* aList, const InitData& aData); 281 282 void AddFaces(FontList* aList, const nsTArray<Face::InitData>& aFaces); 283 284 void SetFacePtrs(FontList* aList, nsTArray<Pointer>& aFaces); 285 286 const String& Key() const { return mKey; } 287 288 const String& DisplayName() const { return mName; } 289 290 uint32_t Index() const { return mIndex; } 291 bool IsBundled() const { return mIsBundled; } 292 293 uint32_t NumFaces() const { 294 MOZ_ASSERT(IsInitialized()); 295 return mFaceCount; 296 } 297 298 Pointer* Faces(FontList* aList) const { 299 MOZ_ASSERT(IsInitialized()); 300 return mFaces.ToArray<Pointer>(aList, mFaceCount); 301 } 302 303 FontVisibility Visibility() const { return mVisibility; } 304 bool IsHidden() const { return Visibility() == FontVisibility::Hidden; } 305 306 bool IsBadUnderlineFamily() const { return mIsBadUnderlineFamily; } 307 bool IsForceClassic() const { return mIsForceClassic; } 308 bool IsSimple() const { return mIsSimple; } 309 bool IsAltLocaleFamily() const { return mIsAltLocale; } 310 311 // IsInitialized indicates whether the family has been populated with faces, 312 // and is therefore ready to use. 313 // It is possible that character maps have not yet been loaded. 314 bool IsInitialized() const { return !mFaces.IsNull(); } 315 316 // IsFullyInitialized indicates that not only faces but also character maps 317 // have been set up, so the family can be searched without the possibility 318 // that IPC messaging will be triggered. 319 bool IsFullyInitialized() const { 320 return IsInitialized() && !mCharacterMap.IsNull(); 321 } 322 323 void FindAllFacesForStyle(FontList* aList, const gfxFontStyle& aStyle, 324 nsTArray<Face*>& aFaceList, 325 bool aIgnoreSizeTolerance = false) const; 326 327 Face* FindFaceForStyle(FontList* aList, const gfxFontStyle& aStyle, 328 bool aIgnoreSizeTolerance = false) const; 329 330 void SearchAllFontsForChar(FontList* aList, GlobalFontMatch* aMatchData); 331 332 void SetupFamilyCharMap(FontList* aList); 333 334 // Return the index of this family in the font-list's Families() or 335 // AliasFamilies() list, and which of those it belongs to. 336 // Returns Nothing if the family cannot be found. 337 mozilla::Maybe<std::pair<uint32_t, bool>> FindIndex(FontList* aList) const; 338 339 private: 340 // Returns true if there are specifically-sized bitmap faces in the list, 341 // so size selection still needs to be done. (Currently only on Linux.) 342 bool FindAllFacesForStyleInternal(FontList* aList, const gfxFontStyle& aStyle, 343 nsTArray<Face*>& aFaceList) const; 344 345 std::atomic<uint32_t> mFaceCount; 346 String mKey; 347 String mName; 348 Pointer mCharacterMap; // If non-null, union of character coverage of all 349 // faces in the family 350 Pointer mFaces; // Pointer to array of |mFaceCount| face pointers 351 uint32_t mIndex; // [win] Top bit set indicates app-bundled font family 352 FontVisibility mVisibility; 353 bool mIsSimple; // family allows simplified style matching: mFaces contains 354 // exactly 4 entries [Regular, Bold, Italic, BoldItalic]. 355 bool mIsBundled : 1; 356 bool mIsBadUnderlineFamily : 1; 357 bool mIsForceClassic : 1; 358 bool mIsAltLocale : 1; 359 }; 360 361 /** 362 * For platforms where we build an index of local font face names (PS-name 363 * and fullname of the font) to support @font-face{src:local(...)}, we map 364 * each face name to an index into the family list, and an index into the 365 * family's list of faces. 366 */ 367 struct LocalFaceRec { 368 /** 369 * The InitData struct needs to record the family name rather than index, 370 * as we may be collecting these records at the same time as building the 371 * family list, so we don't yet know the final family index. 372 * Likewise, in some cases we don't know the final face index because the 373 * faces may be re-sorted to fit into predefined positions in a "simple" 374 * family (if we're reading names before the family has been fully set up). 375 * In that case, we'll store uint32_t(-1) as mFaceIndex, and record the 376 * string descriptor instead. 377 * When actually recorded in the FontList's mLocalFaces array, the family 378 * will be stored as a simple index into the mFamilies array, and the face 379 * as an index into the family's mFaces. 380 */ 381 struct InitData { 382 nsCString mFamilyName; 383 nsCString mFaceDescriptor; 384 uint32_t mFaceIndex = uint32_t(-1); 385 InitData(const nsACString& aFamily, const nsACString& aFace) 386 : mFamilyName(aFamily), mFaceDescriptor(aFace) {} 387 InitData(const nsACString& aFamily, uint32_t aFaceIndex) 388 : mFamilyName(aFamily), mFaceIndex(aFaceIndex) {} 389 InitData() = default; 390 }; 391 String mKey; 392 uint32_t mFamilyIndex; // Index into the font list's Families array 393 uint32_t mFaceIndex; // Index into the family's Faces array 394 }; 395 396 } // namespace fontlist 397 } // namespace mozilla 398 399 #undef ERROR // This is defined via Windows.h, but conflicts with some bindings 400 // code when this gets included in the same compilation unit. 401 402 #endif /* SharedFontList_h */