Line data Source code
1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/. */
5 :
6 : #include "mozilla/DebugOnly.h"
7 : #include "mozilla/MathAlgorithms.h"
8 :
9 : #include "mozilla/Logging.h"
10 :
11 : #include "gfxFontEntry.h"
12 : #include "gfxTextRun.h"
13 : #include "gfxPlatform.h"
14 : #include "nsGkAtoms.h"
15 :
16 : #include "gfxTypes.h"
17 : #include "gfxContext.h"
18 : #include "gfxFontConstants.h"
19 : #include "gfxHarfBuzzShaper.h"
20 : #include "gfxUserFontSet.h"
21 : #include "gfxPlatformFontList.h"
22 : #include "nsUnicodeProperties.h"
23 : #include "nsMathUtils.h"
24 : #include "nsBidiUtils.h"
25 : #include "nsUnicodeRange.h"
26 : #include "nsStyleConsts.h"
27 : #include "mozilla/AppUnits.h"
28 : #include "mozilla/FloatingPoint.h"
29 : #include "mozilla/Likely.h"
30 : #include "mozilla/MemoryReporting.h"
31 : #include "mozilla/Preferences.h"
32 : #include "mozilla/Services.h"
33 : #include "mozilla/Telemetry.h"
34 : #include "gfxSVGGlyphs.h"
35 : #include "gfx2DGlue.h"
36 :
37 : #include "cairo.h"
38 :
39 : #include "harfbuzz/hb.h"
40 : #include "harfbuzz/hb-ot.h"
41 : #include "graphite2/Font.h"
42 :
43 : #include <algorithm>
44 :
45 : using namespace mozilla;
46 : using namespace mozilla::gfx;
47 : using namespace mozilla::unicode;
48 : using mozilla::services::GetObserverService;
49 :
50 : void
51 0 : gfxCharacterMap::NotifyReleased()
52 : {
53 0 : gfxPlatformFontList *fontlist = gfxPlatformFontList::PlatformFontList();
54 0 : if (mShared) {
55 0 : fontlist->RemoveCmap(this);
56 : }
57 0 : delete this;
58 0 : }
59 :
60 0 : gfxFontEntry::gfxFontEntry() :
61 : mStyle(NS_FONT_STYLE_NORMAL), mFixedPitch(false),
62 : mIsValid(true),
63 : mIsBadUnderlineFont(false),
64 : mIsUserFontContainer(false),
65 : mIsDataUserFont(false),
66 : mIsLocalUserFont(false),
67 : mStandardFace(false),
68 : mSymbolFont(false),
69 : mIgnoreGDEF(false),
70 : mIgnoreGSUB(false),
71 : mSVGInitialized(false),
72 : mHasSpaceFeaturesInitialized(false),
73 : mHasSpaceFeatures(false),
74 : mHasSpaceFeaturesKerning(false),
75 : mHasSpaceFeaturesNonKerning(false),
76 : mSkipDefaultFeatureSpaceCheck(false),
77 : mGraphiteSpaceContextualsInitialized(false),
78 : mHasGraphiteSpaceContextuals(false),
79 : mSpaceGlyphIsInvisible(false),
80 : mSpaceGlyphIsInvisibleInitialized(false),
81 : mCheckedForGraphiteTables(false),
82 : mHasCmapTable(false),
83 : mGrFaceInitialized(false),
84 : mCheckedForColorGlyph(false),
85 : mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
86 : mUVSOffset(0), mUVSData(nullptr),
87 : mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
88 : mCOLR(nullptr),
89 : mCPAL(nullptr),
90 : mUnitsPerEm(0),
91 : mHBFace(nullptr),
92 : mGrFace(nullptr),
93 : mGrFaceRefCnt(0),
94 0 : mComputedSizeOfUserFont(0)
95 : {
96 0 : memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
97 0 : memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
98 0 : }
99 :
100 107 : gfxFontEntry::gfxFontEntry(const nsAString& aName, bool aIsStandardFace) :
101 : mName(aName), mStyle(NS_FONT_STYLE_NORMAL), mFixedPitch(false),
102 : mIsValid(true),
103 : mIsBadUnderlineFont(false),
104 : mIsUserFontContainer(false),
105 : mIsDataUserFont(false),
106 : mIsLocalUserFont(false), mStandardFace(aIsStandardFace),
107 : mSymbolFont(false),
108 : mIgnoreGDEF(false),
109 : mIgnoreGSUB(false),
110 : mSVGInitialized(false),
111 : mHasSpaceFeaturesInitialized(false),
112 : mHasSpaceFeatures(false),
113 : mHasSpaceFeaturesKerning(false),
114 : mHasSpaceFeaturesNonKerning(false),
115 : mSkipDefaultFeatureSpaceCheck(false),
116 : mGraphiteSpaceContextualsInitialized(false),
117 : mHasGraphiteSpaceContextuals(false),
118 : mSpaceGlyphIsInvisible(false),
119 : mSpaceGlyphIsInvisibleInitialized(false),
120 : mCheckedForGraphiteTables(false),
121 : mHasCmapTable(false),
122 : mGrFaceInitialized(false),
123 : mCheckedForColorGlyph(false),
124 : mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
125 : mUVSOffset(0), mUVSData(nullptr),
126 : mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
127 : mCOLR(nullptr),
128 : mCPAL(nullptr),
129 : mUnitsPerEm(0),
130 : mHBFace(nullptr),
131 : mGrFace(nullptr),
132 : mGrFaceRefCnt(0),
133 107 : mComputedSizeOfUserFont(0)
134 : {
135 107 : memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
136 107 : memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
137 107 : }
138 :
139 0 : gfxFontEntry::~gfxFontEntry()
140 : {
141 : // Should not be dropped by stylo
142 0 : MOZ_ASSERT(NS_IsMainThread());
143 0 : if (mCOLR) {
144 0 : hb_blob_destroy(mCOLR);
145 : }
146 :
147 0 : if (mCPAL) {
148 0 : hb_blob_destroy(mCPAL);
149 : }
150 :
151 : // For downloaded fonts, we need to tell the user font cache that this
152 : // entry is being deleted.
153 0 : if (mIsDataUserFont) {
154 0 : gfxUserFontSet::UserFontCache::ForgetFont(this);
155 : }
156 :
157 0 : if (mFeatureInputs) {
158 0 : for (auto iter = mFeatureInputs->Iter(); !iter.Done(); iter.Next()) {
159 0 : hb_set_t*& set = iter.Data();
160 0 : hb_set_destroy(set);
161 : }
162 : }
163 :
164 : // By the time the entry is destroyed, all font instances that were
165 : // using it should already have been deleted, and so the HB and/or Gr
166 : // face objects should have been released.
167 0 : MOZ_ASSERT(!mHBFace);
168 0 : MOZ_ASSERT(!mGrFaceInitialized);
169 0 : }
170 :
171 0 : bool gfxFontEntry::IsSymbolFont()
172 : {
173 0 : return mSymbolFont;
174 : }
175 :
176 0 : bool gfxFontEntry::TestCharacterMap(uint32_t aCh)
177 : {
178 0 : if (!mCharacterMap) {
179 0 : ReadCMAP();
180 0 : NS_ASSERTION(mCharacterMap, "failed to initialize character map");
181 : }
182 0 : return mCharacterMap->test(aCh);
183 : }
184 :
185 0 : nsresult gfxFontEntry::InitializeUVSMap()
186 : {
187 : // mUVSOffset will not be initialized
188 : // until cmap is initialized.
189 0 : if (!mCharacterMap) {
190 0 : ReadCMAP();
191 0 : NS_ASSERTION(mCharacterMap, "failed to initialize character map");
192 : }
193 :
194 0 : if (!mUVSOffset) {
195 0 : return NS_ERROR_FAILURE;
196 : }
197 :
198 0 : if (!mUVSData) {
199 0 : const uint32_t kCmapTag = TRUETYPE_TAG('c','m','a','p');
200 0 : AutoTable cmapTable(this, kCmapTag);
201 0 : if (!cmapTable) {
202 0 : mUVSOffset = 0; // don't bother to read the table again
203 0 : return NS_ERROR_FAILURE;
204 : }
205 :
206 0 : UniquePtr<uint8_t[]> uvsData;
207 : unsigned int cmapLen;
208 0 : const char* cmapData = hb_blob_get_data(cmapTable, &cmapLen);
209 0 : nsresult rv = gfxFontUtils::ReadCMAPTableFormat14(
210 0 : (const uint8_t*)cmapData + mUVSOffset,
211 0 : cmapLen - mUVSOffset, uvsData);
212 :
213 0 : if (NS_FAILED(rv)) {
214 0 : mUVSOffset = 0; // don't bother to read the table again
215 0 : return rv;
216 : }
217 :
218 0 : mUVSData = Move(uvsData);
219 : }
220 :
221 0 : return NS_OK;
222 : }
223 :
224 0 : uint16_t gfxFontEntry::GetUVSGlyph(uint32_t aCh, uint32_t aVS)
225 : {
226 0 : InitializeUVSMap();
227 :
228 0 : if (mUVSData) {
229 0 : return gfxFontUtils::MapUVSToGlyphFormat14(mUVSData.get(), aCh, aVS);
230 : }
231 :
232 0 : return 0;
233 : }
234 :
235 0 : bool gfxFontEntry::SupportsScriptInGSUB(const hb_tag_t* aScriptTags)
236 : {
237 0 : hb_face_t *face = GetHBFace();
238 0 : if (!face) {
239 0 : return false;
240 : }
241 :
242 : unsigned int index;
243 : hb_tag_t chosenScript;
244 : bool found =
245 0 : hb_ot_layout_table_choose_script(face, TRUETYPE_TAG('G','S','U','B'),
246 0 : aScriptTags, &index, &chosenScript);
247 0 : hb_face_destroy(face);
248 :
249 0 : return found && chosenScript != TRUETYPE_TAG('D','F','L','T');
250 : }
251 :
252 0 : nsresult gfxFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
253 : {
254 0 : NS_ASSERTION(false, "using default no-op implementation of ReadCMAP");
255 0 : mCharacterMap = new gfxCharacterMap();
256 0 : return NS_OK;
257 : }
258 :
259 : nsString
260 0 : gfxFontEntry::RealFaceName()
261 : {
262 0 : AutoTable nameTable(this, TRUETYPE_TAG('n','a','m','e'));
263 0 : if (nameTable) {
264 0 : nsAutoString name;
265 0 : nsresult rv = gfxFontUtils::GetFullNameFromTable(nameTable, name);
266 0 : if (NS_SUCCEEDED(rv)) {
267 0 : return name;
268 : }
269 : }
270 0 : return Name();
271 : }
272 :
273 : gfxFont*
274 9 : gfxFontEntry::FindOrMakeFont(const gfxFontStyle *aStyle,
275 : bool aNeedsBold,
276 : gfxCharacterMap* aUnicodeRangeMap)
277 : {
278 : // the font entry name is the psname, not the family name
279 : gfxFont* font =
280 9 : gfxFontCache::GetCache()->Lookup(this, aStyle, aUnicodeRangeMap);
281 :
282 9 : if (!font) {
283 8 : gfxFont *newFont = CreateFontInstance(aStyle, aNeedsBold);
284 8 : if (!newFont) {
285 0 : return nullptr;
286 : }
287 8 : if (!newFont->Valid()) {
288 0 : delete newFont;
289 0 : return nullptr;
290 : }
291 8 : font = newFont;
292 8 : font->SetUnicodeRangeMap(aUnicodeRangeMap);
293 8 : gfxFontCache::GetCache()->AddNew(font);
294 : }
295 9 : return font;
296 : }
297 :
298 : uint16_t
299 2 : gfxFontEntry::UnitsPerEm()
300 : {
301 2 : if (!mUnitsPerEm) {
302 4 : AutoTable headTable(this, TRUETYPE_TAG('h','e','a','d'));
303 2 : if (headTable) {
304 : uint32_t len;
305 : const HeadTable* head =
306 2 : reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable,
307 2 : &len));
308 2 : if (len >= sizeof(HeadTable)) {
309 2 : mUnitsPerEm = head->unitsPerEm;
310 : }
311 : }
312 :
313 : // if we didn't find a usable 'head' table, or if the value was
314 : // outside the valid range, record it as invalid
315 2 : if (mUnitsPerEm < kMinUPEM || mUnitsPerEm > kMaxUPEM) {
316 0 : mUnitsPerEm = kInvalidUPEM;
317 : }
318 : }
319 2 : return mUnitsPerEm;
320 : }
321 :
322 : bool
323 0 : gfxFontEntry::HasSVGGlyph(uint32_t aGlyphId)
324 : {
325 0 : NS_ASSERTION(mSVGInitialized, "SVG data has not yet been loaded. TryGetSVGData() first.");
326 0 : return mSVGGlyphs->HasSVGGlyph(aGlyphId);
327 : }
328 :
329 : bool
330 0 : gfxFontEntry::GetSVGGlyphExtents(DrawTarget* aDrawTarget, uint32_t aGlyphId,
331 : gfxRect *aResult)
332 : {
333 0 : MOZ_ASSERT(mSVGInitialized,
334 : "SVG data has not yet been loaded. TryGetSVGData() first.");
335 0 : MOZ_ASSERT(mUnitsPerEm >= kMinUPEM && mUnitsPerEm <= kMaxUPEM,
336 : "font has invalid unitsPerEm");
337 :
338 : cairo_matrix_t fontMatrix;
339 0 : cairo_get_font_matrix(gfxFont::RefCairo(aDrawTarget), &fontMatrix);
340 :
341 : gfxMatrix svgToAppSpace(fontMatrix.xx, fontMatrix.yx,
342 : fontMatrix.xy, fontMatrix.yy,
343 0 : fontMatrix.x0, fontMatrix.y0);
344 0 : svgToAppSpace.PreScale(1.0f / mUnitsPerEm, 1.0f / mUnitsPerEm);
345 :
346 0 : return mSVGGlyphs->GetGlyphExtents(aGlyphId, svgToAppSpace, aResult);
347 : }
348 :
349 : void
350 0 : gfxFontEntry::RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId,
351 : SVGContextPaint* aContextPaint)
352 : {
353 0 : NS_ASSERTION(mSVGInitialized, "SVG data has not yet been loaded. TryGetSVGData() first.");
354 0 : mSVGGlyphs->RenderGlyph(aContext, aGlyphId, aContextPaint);
355 0 : }
356 :
357 : bool
358 92 : gfxFontEntry::TryGetSVGData(gfxFont* aFont)
359 : {
360 92 : if (!gfxPlatform::GetPlatform()->OpenTypeSVGEnabled()) {
361 0 : return false;
362 : }
363 :
364 92 : if (!mSVGInitialized) {
365 2 : mSVGInitialized = true;
366 :
367 : // If UnitsPerEm is not known/valid, we can't use SVG glyphs
368 2 : if (UnitsPerEm() == kInvalidUPEM) {
369 2 : return false;
370 : }
371 :
372 : // We don't use AutoTable here because we'll pass ownership of this
373 : // blob to the gfxSVGGlyphs, once we've confirmed the table exists
374 2 : hb_blob_t *svgTable = GetFontTable(TRUETYPE_TAG('S','V','G',' '));
375 2 : if (!svgTable) {
376 2 : return false;
377 : }
378 :
379 : // gfxSVGGlyphs will hb_blob_destroy() the table when it is finished
380 : // with it.
381 0 : mSVGGlyphs = MakeUnique<gfxSVGGlyphs>(svgTable, this);
382 : }
383 :
384 90 : if (mSVGGlyphs && !mFontsUsingSVGGlyphs.Contains(aFont)) {
385 0 : mFontsUsingSVGGlyphs.AppendElement(aFont);
386 : }
387 :
388 90 : return !!mSVGGlyphs;
389 : }
390 :
391 : void
392 0 : gfxFontEntry::NotifyFontDestroyed(gfxFont* aFont)
393 : {
394 0 : mFontsUsingSVGGlyphs.RemoveElement(aFont);
395 0 : }
396 :
397 : void
398 0 : gfxFontEntry::NotifyGlyphsChanged()
399 : {
400 0 : for (uint32_t i = 0, count = mFontsUsingSVGGlyphs.Length(); i < count; ++i) {
401 0 : gfxFont* font = mFontsUsingSVGGlyphs[i];
402 0 : font->NotifyGlyphsChanged();
403 : }
404 0 : }
405 :
406 : bool
407 29 : gfxFontEntry::TryGetColorGlyphs()
408 : {
409 29 : if (mCheckedForColorGlyph) {
410 27 : return (mCOLR && mCPAL);
411 : }
412 :
413 2 : mCheckedForColorGlyph = true;
414 :
415 2 : mCOLR = GetFontTable(TRUETYPE_TAG('C', 'O', 'L', 'R'));
416 2 : if (!mCOLR) {
417 2 : return false;
418 : }
419 :
420 0 : mCPAL = GetFontTable(TRUETYPE_TAG('C', 'P', 'A', 'L'));
421 0 : if (!mCPAL) {
422 0 : hb_blob_destroy(mCOLR);
423 0 : mCOLR = nullptr;
424 0 : return false;
425 : }
426 :
427 : // validation COLR and CPAL table
428 0 : if (gfxFontUtils::ValidateColorGlyphs(mCOLR, mCPAL)) {
429 0 : return true;
430 : }
431 :
432 0 : hb_blob_destroy(mCOLR);
433 0 : hb_blob_destroy(mCPAL);
434 0 : mCOLR = nullptr;
435 0 : mCPAL = nullptr;
436 0 : return false;
437 : }
438 :
439 : /**
440 : * FontTableBlobData
441 : *
442 : * See FontTableHashEntry for the general strategy.
443 : */
444 :
445 : class gfxFontEntry::FontTableBlobData {
446 : public:
447 14 : explicit FontTableBlobData(nsTArray<uint8_t>&& aBuffer)
448 14 : : mTableData(Move(aBuffer))
449 : , mHashtable(nullptr)
450 14 : , mHashKey(0)
451 : {
452 14 : MOZ_COUNT_CTOR(FontTableBlobData);
453 14 : }
454 :
455 18 : ~FontTableBlobData() {
456 9 : MOZ_COUNT_DTOR(FontTableBlobData);
457 9 : if (mHashtable && mHashKey) {
458 9 : mHashtable->RemoveEntry(mHashKey);
459 : }
460 9 : }
461 :
462 : // Useful for creating blobs
463 14 : const char *GetTable() const
464 : {
465 14 : return reinterpret_cast<const char*>(mTableData.Elements());
466 : }
467 14 : uint32_t GetTableLength() const { return mTableData.Length(); }
468 :
469 : // Tell this FontTableBlobData to remove the HashEntry when this is
470 : // destroyed.
471 14 : void ManageHashEntry(nsTHashtable<FontTableHashEntry> *aHashtable,
472 : uint32_t aHashKey)
473 : {
474 14 : mHashtable = aHashtable;
475 14 : mHashKey = aHashKey;
476 14 : }
477 :
478 : // Disconnect from the HashEntry (because the blob has already been
479 : // removed from the hashtable).
480 9 : void ForgetHashEntry()
481 : {
482 9 : mHashtable = nullptr;
483 9 : mHashKey = 0;
484 9 : }
485 :
486 0 : size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
487 0 : return mTableData.ShallowSizeOfExcludingThis(aMallocSizeOf);
488 : }
489 0 : size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
490 0 : return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
491 : }
492 :
493 : private:
494 : // The font table data block
495 : nsTArray<uint8_t> mTableData;
496 :
497 : // The blob destroy function needs to know the owning hashtable
498 : // and the hashtable key, so that it can remove the entry.
499 : nsTHashtable<FontTableHashEntry> *mHashtable;
500 : uint32_t mHashKey;
501 :
502 : // not implemented
503 : FontTableBlobData(const FontTableBlobData&);
504 : };
505 :
506 : hb_blob_t *
507 14 : gfxFontEntry::FontTableHashEntry::
508 : ShareTableAndGetBlob(nsTArray<uint8_t>&& aTable,
509 : nsTHashtable<FontTableHashEntry> *aHashtable)
510 : {
511 14 : Clear();
512 : // adopts elements of aTable
513 28 : mSharedBlobData = new FontTableBlobData(Move(aTable));
514 :
515 14 : mBlob = hb_blob_create(mSharedBlobData->GetTable(),
516 14 : mSharedBlobData->GetTableLength(),
517 : HB_MEMORY_MODE_READONLY,
518 14 : mSharedBlobData, DeleteFontTableBlobData);
519 14 : if (mBlob == hb_blob_get_empty() ) {
520 : // The FontTableBlobData was destroyed during hb_blob_create().
521 : // The (empty) blob is still be held in the hashtable with a strong
522 : // reference.
523 0 : return hb_blob_reference(mBlob);
524 : }
525 :
526 : // Tell the FontTableBlobData to remove this hash entry when destroyed.
527 : // The hashtable does not keep a strong reference.
528 14 : mSharedBlobData->ManageHashEntry(aHashtable, GetKey());
529 14 : return mBlob;
530 : }
531 :
532 : void
533 30 : gfxFontEntry::FontTableHashEntry::Clear()
534 : {
535 : // If the FontTableBlobData is managing the hash entry, then the blob is
536 : // not owned by this HashEntry; otherwise there is strong reference to the
537 : // blob that must be removed.
538 30 : if (mSharedBlobData) {
539 9 : mSharedBlobData->ForgetHashEntry();
540 9 : mSharedBlobData = nullptr;
541 21 : } else if (mBlob) {
542 0 : hb_blob_destroy(mBlob);
543 : }
544 30 : mBlob = nullptr;
545 30 : }
546 :
547 : // a hb_destroy_func for hb_blob_create
548 :
549 : /* static */ void
550 9 : gfxFontEntry::FontTableHashEntry::DeleteFontTableBlobData(void *aBlobData)
551 : {
552 9 : delete static_cast<FontTableBlobData*>(aBlobData);
553 9 : }
554 :
555 : hb_blob_t *
556 1 : gfxFontEntry::FontTableHashEntry::GetBlob() const
557 : {
558 1 : return hb_blob_reference(mBlob);
559 : }
560 :
561 : bool
562 22 : gfxFontEntry::GetExistingFontTable(uint32_t aTag, hb_blob_t **aBlob)
563 : {
564 22 : if (!mFontTableCache) {
565 : // we do this here rather than on fontEntry construction
566 : // because not all shapers will access the table cache at all
567 2 : mFontTableCache = MakeUnique<nsTHashtable<FontTableHashEntry>>(8);
568 : }
569 :
570 22 : FontTableHashEntry *entry = mFontTableCache->GetEntry(aTag);
571 22 : if (!entry) {
572 21 : return false;
573 : }
574 :
575 1 : *aBlob = entry->GetBlob();
576 1 : return true;
577 : }
578 :
579 : hb_blob_t *
580 21 : gfxFontEntry::ShareFontTableAndGetBlob(uint32_t aTag,
581 : nsTArray<uint8_t>* aBuffer)
582 : {
583 21 : if (MOZ_UNLIKELY(!mFontTableCache)) {
584 : // we do this here rather than on fontEntry construction
585 : // because not all shapers will access the table cache at all
586 0 : mFontTableCache = MakeUnique<nsTHashtable<FontTableHashEntry>>(8);
587 : }
588 :
589 21 : FontTableHashEntry *entry = mFontTableCache->PutEntry(aTag);
590 21 : if (MOZ_UNLIKELY(!entry)) { // OOM
591 0 : return nullptr;
592 : }
593 :
594 21 : if (!aBuffer) {
595 : // ensure the entry is null
596 7 : entry->Clear();
597 7 : return nullptr;
598 : }
599 :
600 14 : return entry->ShareTableAndGetBlob(Move(*aBuffer), mFontTableCache.get());
601 : }
602 :
603 : already_AddRefed<gfxCharacterMap>
604 0 : gfxFontEntry::GetCMAPFromFontInfo(FontInfoData *aFontInfoData,
605 : uint32_t& aUVSOffset,
606 : bool& aSymbolFont)
607 : {
608 0 : if (!aFontInfoData || !aFontInfoData->mLoadCmaps) {
609 0 : return nullptr;
610 : }
611 :
612 0 : return aFontInfoData->GetCMAP(mName, aUVSOffset, aSymbolFont);
613 : }
614 :
615 : hb_blob_t *
616 22 : gfxFontEntry::GetFontTable(uint32_t aTag)
617 : {
618 : hb_blob_t *blob;
619 22 : if (GetExistingFontTable(aTag, &blob)) {
620 1 : return blob;
621 : }
622 :
623 42 : nsTArray<uint8_t> buffer;
624 21 : bool haveTable = NS_SUCCEEDED(CopyFontTable(aTag, buffer));
625 :
626 21 : return ShareFontTableAndGetBlob(aTag, haveTable ? &buffer : nullptr);
627 : }
628 :
629 : // callback for HarfBuzz to get a font table (in hb_blob_t form)
630 : // from the font entry (passed as aUserData)
631 : /*static*/ hb_blob_t *
632 14 : gfxFontEntry::HBGetTable(hb_face_t *face, uint32_t aTag, void *aUserData)
633 : {
634 14 : gfxFontEntry *fontEntry = static_cast<gfxFontEntry*>(aUserData);
635 :
636 : // bug 589682 - ignore the GDEF table in buggy fonts (applies to
637 : // Italic and BoldItalic faces of Times New Roman)
638 18 : if (aTag == TRUETYPE_TAG('G','D','E','F') &&
639 4 : fontEntry->IgnoreGDEF()) {
640 0 : return nullptr;
641 : }
642 :
643 : // bug 721719 - ignore the GSUB table in buggy fonts (applies to Roboto,
644 : // at least on some Android ICS devices; set in gfxFT2FontList.cpp)
645 18 : if (aTag == TRUETYPE_TAG('G','S','U','B') &&
646 4 : fontEntry->IgnoreGSUB()) {
647 0 : return nullptr;
648 : }
649 :
650 14 : return fontEntry->GetFontTable(aTag);
651 : }
652 :
653 : /*static*/ void
654 2 : gfxFontEntry::HBFaceDeletedCallback(void *aUserData)
655 : {
656 2 : gfxFontEntry *fe = static_cast<gfxFontEntry*>(aUserData);
657 2 : fe->ForgetHBFace();
658 2 : }
659 :
660 : void
661 2 : gfxFontEntry::ForgetHBFace()
662 : {
663 2 : mHBFace = nullptr;
664 2 : }
665 :
666 : hb_face_t*
667 4 : gfxFontEntry::GetHBFace()
668 : {
669 4 : if (!mHBFace) {
670 4 : mHBFace = hb_face_create_for_tables(HBGetTable, this,
671 : HBFaceDeletedCallback);
672 4 : return mHBFace;
673 : }
674 0 : return hb_face_reference(mHBFace);
675 : }
676 :
677 : /*static*/ const void*
678 0 : gfxFontEntry::GrGetTable(const void *aAppFaceHandle, unsigned int aName,
679 : size_t *aLen)
680 : {
681 : gfxFontEntry *fontEntry =
682 0 : static_cast<gfxFontEntry*>(const_cast<void*>(aAppFaceHandle));
683 0 : hb_blob_t *blob = fontEntry->GetFontTable(aName);
684 0 : if (blob) {
685 : unsigned int blobLength;
686 0 : const void *tableData = hb_blob_get_data(blob, &blobLength);
687 0 : fontEntry->mGrTableMap->Put(tableData, blob);
688 0 : *aLen = blobLength;
689 0 : return tableData;
690 : }
691 0 : *aLen = 0;
692 0 : return nullptr;
693 : }
694 :
695 : /*static*/ void
696 0 : gfxFontEntry::GrReleaseTable(const void *aAppFaceHandle,
697 : const void *aTableBuffer)
698 : {
699 : gfxFontEntry *fontEntry =
700 0 : static_cast<gfxFontEntry*>(const_cast<void*>(aAppFaceHandle));
701 : void* value;
702 0 : if (fontEntry->mGrTableMap->Remove(aTableBuffer, &value)) {
703 0 : hb_blob_destroy(static_cast<hb_blob_t*>(value));
704 : }
705 0 : }
706 :
707 : gr_face*
708 0 : gfxFontEntry::GetGrFace()
709 : {
710 0 : if (!mGrFaceInitialized) {
711 : gr_face_ops faceOps = {
712 : sizeof(gr_face_ops),
713 : GrGetTable,
714 : GrReleaseTable
715 0 : };
716 0 : mGrTableMap = new nsDataHashtable<nsPtrHashKey<const void>,void*>;
717 0 : mGrFace = gr_make_face_with_ops(this, &faceOps, gr_face_default);
718 0 : mGrFaceInitialized = true;
719 : }
720 0 : ++mGrFaceRefCnt;
721 0 : return mGrFace;
722 : }
723 :
724 : void
725 0 : gfxFontEntry::ReleaseGrFace(gr_face *aFace)
726 : {
727 0 : MOZ_ASSERT(aFace == mGrFace); // sanity-check
728 0 : MOZ_ASSERT(mGrFaceRefCnt > 0);
729 0 : if (--mGrFaceRefCnt == 0) {
730 0 : gr_face_destroy(mGrFace);
731 0 : mGrFace = nullptr;
732 0 : mGrFaceInitialized = false;
733 0 : delete mGrTableMap;
734 0 : mGrTableMap = nullptr;
735 : }
736 0 : }
737 :
738 : void
739 0 : gfxFontEntry::DisconnectSVG()
740 : {
741 0 : if (mSVGInitialized && mSVGGlyphs) {
742 0 : mSVGGlyphs = nullptr;
743 0 : mSVGInitialized = false;
744 : }
745 0 : }
746 :
747 : bool
748 2 : gfxFontEntry::HasFontTable(uint32_t aTableTag)
749 : {
750 4 : AutoTable table(this, aTableTag);
751 4 : return table && hb_blob_get_length(table) > 0;
752 : }
753 :
754 : void
755 2 : gfxFontEntry::CheckForGraphiteTables()
756 : {
757 2 : mHasGraphiteTables = HasFontTable(TRUETYPE_TAG('S','i','l','f'));
758 2 : }
759 :
760 : bool
761 0 : gfxFontEntry::HasGraphiteSpaceContextuals()
762 : {
763 0 : if (!mGraphiteSpaceContextualsInitialized) {
764 0 : gr_face* face = GetGrFace();
765 0 : if (face) {
766 0 : const gr_faceinfo* faceInfo = gr_face_info(face, 0);
767 0 : mHasGraphiteSpaceContextuals =
768 0 : faceInfo->space_contextuals != gr_faceinfo::gr_space_none;
769 : }
770 0 : ReleaseGrFace(face); // always balance GetGrFace, even if face is null
771 0 : mGraphiteSpaceContextualsInitialized = true;
772 : }
773 0 : return mHasGraphiteSpaceContextuals;
774 : }
775 :
776 : #define FEATURE_SCRIPT_MASK 0x000000ff // script index replaces low byte of tag
777 :
778 : static_assert(int(Script::NUM_SCRIPT_CODES) <= FEATURE_SCRIPT_MASK, "Too many script codes");
779 :
780 : // high-order three bytes of tag with script in low-order byte
781 : #define SCRIPT_FEATURE(s,tag) (((~FEATURE_SCRIPT_MASK) & (tag)) | \
782 : ((FEATURE_SCRIPT_MASK) & static_cast<uint32_t>(s)))
783 :
784 : bool
785 0 : gfxFontEntry::SupportsOpenTypeFeature(Script aScript, uint32_t aFeatureTag)
786 : {
787 0 : if (!mSupportedFeatures) {
788 0 : mSupportedFeatures = MakeUnique<nsDataHashtable<nsUint32HashKey,bool>>();
789 : }
790 :
791 : // note: high-order three bytes *must* be unique for each feature
792 : // listed below (see SCRIPT_FEATURE macro def'n)
793 0 : NS_ASSERTION(aFeatureTag == HB_TAG('s','m','c','p') ||
794 : aFeatureTag == HB_TAG('c','2','s','c') ||
795 : aFeatureTag == HB_TAG('p','c','a','p') ||
796 : aFeatureTag == HB_TAG('c','2','p','c') ||
797 : aFeatureTag == HB_TAG('s','u','p','s') ||
798 : aFeatureTag == HB_TAG('s','u','b','s') ||
799 : aFeatureTag == HB_TAG('v','e','r','t'),
800 : "use of unknown feature tag");
801 :
802 : // note: graphite feature support uses the last script index
803 0 : NS_ASSERTION(int(aScript) < FEATURE_SCRIPT_MASK - 1,
804 : "need to bump the size of the feature shift");
805 :
806 0 : uint32_t scriptFeature = SCRIPT_FEATURE(aScript, aFeatureTag);
807 : bool result;
808 0 : if (mSupportedFeatures->Get(scriptFeature, &result)) {
809 0 : return result;
810 : }
811 :
812 0 : result = false;
813 :
814 0 : hb_face_t *face = GetHBFace();
815 :
816 0 : if (hb_ot_layout_has_substitution(face)) {
817 : hb_script_t hbScript =
818 0 : gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript);
819 :
820 : // Get the OpenType tag(s) that match this script code
821 : hb_tag_t scriptTags[4] = {
822 : HB_TAG_NONE,
823 : HB_TAG_NONE,
824 : HB_TAG_NONE,
825 : HB_TAG_NONE
826 0 : };
827 0 : hb_ot_tags_from_script(hbScript, &scriptTags[0], &scriptTags[1]);
828 :
829 : // Replace the first remaining NONE with DEFAULT
830 0 : hb_tag_t* scriptTag = &scriptTags[0];
831 0 : while (*scriptTag != HB_TAG_NONE) {
832 0 : ++scriptTag;
833 : }
834 0 : *scriptTag = HB_OT_TAG_DEFAULT_SCRIPT;
835 :
836 : // Now check for 'smcp' under the first of those scripts that is present
837 0 : const hb_tag_t kGSUB = HB_TAG('G','S','U','B');
838 0 : scriptTag = &scriptTags[0];
839 0 : while (*scriptTag != HB_TAG_NONE) {
840 : unsigned int scriptIndex;
841 0 : if (hb_ot_layout_table_find_script(face, kGSUB, *scriptTag,
842 : &scriptIndex)) {
843 0 : if (hb_ot_layout_language_find_feature(face, kGSUB,
844 : scriptIndex,
845 : HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
846 : aFeatureTag, nullptr)) {
847 0 : result = true;
848 : }
849 0 : break;
850 : }
851 0 : ++scriptTag;
852 : }
853 : }
854 :
855 0 : hb_face_destroy(face);
856 :
857 0 : mSupportedFeatures->Put(scriptFeature, result);
858 :
859 0 : return result;
860 : }
861 :
862 : const hb_set_t*
863 0 : gfxFontEntry::InputsForOpenTypeFeature(Script aScript, uint32_t aFeatureTag)
864 : {
865 0 : if (!mFeatureInputs) {
866 0 : mFeatureInputs = MakeUnique<nsDataHashtable<nsUint32HashKey,hb_set_t*>>();
867 : }
868 :
869 0 : NS_ASSERTION(aFeatureTag == HB_TAG('s','u','p','s') ||
870 : aFeatureTag == HB_TAG('s','u','b','s'),
871 : "use of unknown feature tag");
872 :
873 0 : uint32_t scriptFeature = SCRIPT_FEATURE(aScript, aFeatureTag);
874 : hb_set_t *inputGlyphs;
875 0 : if (mFeatureInputs->Get(scriptFeature, &inputGlyphs)) {
876 0 : return inputGlyphs;
877 : }
878 :
879 0 : inputGlyphs = hb_set_create();
880 :
881 0 : hb_face_t *face = GetHBFace();
882 :
883 0 : if (hb_ot_layout_has_substitution(face)) {
884 : hb_script_t hbScript =
885 0 : gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript);
886 :
887 : // Get the OpenType tag(s) that match this script code
888 : hb_tag_t scriptTags[4] = {
889 : HB_TAG_NONE,
890 : HB_TAG_NONE,
891 : HB_TAG_NONE,
892 : HB_TAG_NONE
893 0 : };
894 0 : hb_ot_tags_from_script(hbScript, &scriptTags[0], &scriptTags[1]);
895 :
896 : // Replace the first remaining NONE with DEFAULT
897 0 : hb_tag_t* scriptTag = &scriptTags[0];
898 0 : while (*scriptTag != HB_TAG_NONE) {
899 0 : ++scriptTag;
900 : }
901 0 : *scriptTag = HB_OT_TAG_DEFAULT_SCRIPT;
902 :
903 0 : const hb_tag_t kGSUB = HB_TAG('G','S','U','B');
904 0 : hb_tag_t features[2] = { aFeatureTag, HB_TAG_NONE };
905 0 : hb_set_t *featurelookups = hb_set_create();
906 : hb_ot_layout_collect_lookups(face, kGSUB, scriptTags, nullptr,
907 0 : features, featurelookups);
908 0 : hb_codepoint_t index = -1;
909 0 : while (hb_set_next(featurelookups, &index)) {
910 : hb_ot_layout_lookup_collect_glyphs(face, kGSUB, index,
911 : nullptr, inputGlyphs,
912 0 : nullptr, nullptr);
913 : }
914 0 : hb_set_destroy(featurelookups);
915 : }
916 :
917 0 : hb_face_destroy(face);
918 :
919 0 : mFeatureInputs->Put(scriptFeature, inputGlyphs);
920 0 : return inputGlyphs;
921 : }
922 :
923 : bool
924 0 : gfxFontEntry::SupportsGraphiteFeature(uint32_t aFeatureTag)
925 : {
926 0 : if (!mSupportedFeatures) {
927 0 : mSupportedFeatures = MakeUnique<nsDataHashtable<nsUint32HashKey,bool>>();
928 : }
929 :
930 : // note: high-order three bytes *must* be unique for each feature
931 : // listed below (see SCRIPT_FEATURE macro def'n)
932 0 : NS_ASSERTION(aFeatureTag == HB_TAG('s','m','c','p') ||
933 : aFeatureTag == HB_TAG('c','2','s','c') ||
934 : aFeatureTag == HB_TAG('p','c','a','p') ||
935 : aFeatureTag == HB_TAG('c','2','p','c') ||
936 : aFeatureTag == HB_TAG('s','u','p','s') ||
937 : aFeatureTag == HB_TAG('s','u','b','s'),
938 : "use of unknown feature tag");
939 :
940 : // graphite feature check uses the last script slot
941 0 : uint32_t scriptFeature = SCRIPT_FEATURE(FEATURE_SCRIPT_MASK, aFeatureTag);
942 : bool result;
943 0 : if (mSupportedFeatures->Get(scriptFeature, &result)) {
944 0 : return result;
945 : }
946 :
947 0 : gr_face* face = GetGrFace();
948 0 : result = face ? gr_face_find_fref(face, aFeatureTag) != nullptr : false;
949 0 : ReleaseGrFace(face);
950 :
951 0 : mSupportedFeatures->Put(scriptFeature, result);
952 :
953 0 : return result;
954 : }
955 :
956 : bool
957 0 : gfxFontEntry::GetColorLayersInfo(uint32_t aGlyphId,
958 : const mozilla::gfx::Color& aDefaultColor,
959 : nsTArray<uint16_t>& aLayerGlyphs,
960 : nsTArray<mozilla::gfx::Color>& aLayerColors)
961 : {
962 0 : return gfxFontUtils::GetColorGlyphLayers(mCOLR,
963 : mCPAL,
964 : aGlyphId,
965 : aDefaultColor,
966 : aLayerGlyphs,
967 0 : aLayerColors);
968 : }
969 :
970 : size_t
971 0 : gfxFontEntry::FontTableHashEntry::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
972 : {
973 0 : size_t n = 0;
974 0 : if (mBlob) {
975 0 : n += aMallocSizeOf(mBlob);
976 : }
977 0 : if (mSharedBlobData) {
978 0 : n += mSharedBlobData->SizeOfIncludingThis(aMallocSizeOf);
979 : }
980 0 : return n;
981 : }
982 :
983 : void
984 0 : gfxFontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
985 : FontListSizes* aSizes) const
986 : {
987 0 : aSizes->mFontListSize += mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
988 :
989 : // cmaps are shared so only non-shared cmaps are included here
990 0 : if (mCharacterMap && mCharacterMap->mBuildOnTheFly) {
991 0 : aSizes->mCharMapsSize +=
992 0 : mCharacterMap->SizeOfIncludingThis(aMallocSizeOf);
993 : }
994 0 : if (mFontTableCache) {
995 0 : aSizes->mFontTableCacheSize +=
996 0 : mFontTableCache->SizeOfIncludingThis(aMallocSizeOf);
997 : }
998 :
999 : // If the font has UVS data, we count that as part of the character map.
1000 0 : if (mUVSData) {
1001 0 : aSizes->mCharMapsSize += aMallocSizeOf(mUVSData.get());
1002 : }
1003 :
1004 : // The following, if present, are essentially cached forms of font table
1005 : // data, so we'll accumulate them together with the basic table cache.
1006 0 : if (mUserFontData) {
1007 0 : aSizes->mFontTableCacheSize +=
1008 0 : mUserFontData->SizeOfIncludingThis(aMallocSizeOf);
1009 : }
1010 0 : if (mSVGGlyphs) {
1011 0 : aSizes->mFontTableCacheSize +=
1012 0 : mSVGGlyphs->SizeOfIncludingThis(aMallocSizeOf);
1013 : }
1014 0 : if (mSupportedFeatures) {
1015 0 : aSizes->mFontTableCacheSize +=
1016 0 : mSupportedFeatures->ShallowSizeOfIncludingThis(aMallocSizeOf);
1017 : }
1018 0 : if (mFeatureInputs) {
1019 0 : aSizes->mFontTableCacheSize +=
1020 0 : mFeatureInputs->ShallowSizeOfIncludingThis(aMallocSizeOf);
1021 0 : for (auto iter = mFeatureInputs->ConstIter(); !iter.Done();
1022 0 : iter.Next()) {
1023 : // There's no API to get the real size of an hb_set, so we'll use
1024 : // an approximation based on knowledge of the implementation.
1025 0 : aSizes->mFontTableCacheSize += 8192; // vector of 64K bits
1026 : }
1027 : }
1028 : // We don't include the size of mCOLR/mCPAL here, because (depending on the
1029 : // font backend implementation) they will either wrap blocks of data owned
1030 : // by the system (and potentially shared), or tables that are in our font
1031 : // table cache and therefore already counted.
1032 0 : }
1033 :
1034 : void
1035 0 : gfxFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
1036 : FontListSizes* aSizes) const
1037 : {
1038 0 : aSizes->mFontListSize += aMallocSizeOf(this);
1039 0 : AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
1040 0 : }
1041 :
1042 : // This is used to report the size of an individual downloaded font in the
1043 : // user font cache. (Fonts that are part of the platform font list accumulate
1044 : // their sizes to the font list's reporter using the AddSizeOf... methods
1045 : // above.)
1046 : size_t
1047 0 : gfxFontEntry::ComputedSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
1048 : {
1049 0 : FontListSizes s = { 0 };
1050 0 : AddSizeOfExcludingThis(aMallocSizeOf, &s);
1051 :
1052 : // When reporting memory used for the main platform font list,
1053 : // where we're typically summing the totals for a few hundred font faces,
1054 : // we report the fields of FontListSizes separately.
1055 : // But for downloaded user fonts, the actual resource data (added below)
1056 : // will dominate, and the minor overhead of these pieces isn't worth
1057 : // splitting out for an individual font.
1058 0 : size_t result = s.mFontListSize + s.mFontTableCacheSize + s.mCharMapsSize;
1059 :
1060 0 : if (mIsDataUserFont) {
1061 0 : MOZ_ASSERT(mComputedSizeOfUserFont > 0, "user font with no data?");
1062 0 : result += mComputedSizeOfUserFont;
1063 : }
1064 :
1065 0 : return result;
1066 : }
1067 :
1068 : //////////////////////////////////////////////////////////////////////////////
1069 : //
1070 : // class gfxFontFamily
1071 : //
1072 : //////////////////////////////////////////////////////////////////////////////
1073 :
1074 : // we consider faces with mStandardFace == true to be "less than" those with false,
1075 : // because during style matching, earlier entries are tried first
1076 : class FontEntryStandardFaceComparator {
1077 : public:
1078 0 : bool Equals(const RefPtr<gfxFontEntry>& a, const RefPtr<gfxFontEntry>& b) const {
1079 0 : return a->mStandardFace == b->mStandardFace;
1080 : }
1081 0 : bool LessThan(const RefPtr<gfxFontEntry>& a, const RefPtr<gfxFontEntry>& b) const {
1082 0 : return (a->mStandardFace == true && b->mStandardFace == false);
1083 : }
1084 : };
1085 :
1086 : void
1087 0 : gfxFontFamily::SortAvailableFonts()
1088 : {
1089 0 : mAvailableFonts.Sort(FontEntryStandardFaceComparator());
1090 0 : }
1091 :
1092 : bool
1093 0 : gfxFontFamily::HasOtherFamilyNames()
1094 : {
1095 : // need to read in other family names to determine this
1096 0 : if (!mOtherFamilyNamesInitialized) {
1097 0 : ReadOtherFamilyNames(gfxPlatformFontList::PlatformFontList()); // sets mHasOtherFamilyNames
1098 : }
1099 0 : return mHasOtherFamilyNames;
1100 : }
1101 :
1102 : gfxFontEntry*
1103 3 : gfxFontFamily::FindFontForStyle(const gfxFontStyle& aFontStyle,
1104 : bool& aNeedsSyntheticBold)
1105 : {
1106 6 : AutoTArray<gfxFontEntry*,4> matched;
1107 3 : FindAllFontsForStyle(aFontStyle, matched, aNeedsSyntheticBold);
1108 3 : if (!matched.IsEmpty()) {
1109 3 : return matched[0];
1110 : }
1111 0 : return nullptr;
1112 : }
1113 :
1114 : #define STYLE_SHIFT 2 // number of bits to contain style distance
1115 :
1116 : // style distance ==> [0,2]
1117 : static inline uint32_t
1118 115 : StyleDistance(uint32_t aFontStyle, uint32_t aTargetStyle)
1119 : {
1120 115 : if (aFontStyle == aTargetStyle) {
1121 59 : return 0; // styles match exactly ==> 0
1122 : }
1123 56 : if (aFontStyle == NS_FONT_STYLE_NORMAL ||
1124 : aTargetStyle == NS_FONT_STYLE_NORMAL) {
1125 56 : return 2; // one is normal (but not the other) ==> 2
1126 : }
1127 0 : return 1; // neither is normal; must be italic vs oblique ==> 1
1128 : }
1129 :
1130 : #define REVERSE_STRETCH_DISTANCE 5
1131 :
1132 : // stretch distance ==> [0,13]
1133 : static inline uint32_t
1134 115 : StretchDistance(int16_t aFontStretch, int16_t aTargetStretch)
1135 : {
1136 115 : int32_t distance = 0;
1137 115 : if (aTargetStretch != aFontStretch) {
1138 : // stretch values are in the range -4 .. +4
1139 : // if aTargetStretch is positive, we prefer more-positive values;
1140 : // if zero or negative, prefer more-negative
1141 32 : if (aTargetStretch > 0) {
1142 0 : distance = (aFontStretch - aTargetStretch);
1143 : } else {
1144 32 : distance = (aTargetStretch - aFontStretch);
1145 : }
1146 : // if the computed "distance" here is negative, it means that
1147 : // aFontEntry lies in the "non-preferred" direction from aTargetStretch,
1148 : // so we treat that as larger than any preferred-direction distance
1149 : // (max possible is 4) by adding an extra 5 to the absolute value
1150 32 : if (distance < 0) {
1151 0 : distance = -distance + REVERSE_STRETCH_DISTANCE;
1152 : }
1153 : }
1154 115 : return uint32_t(distance);
1155 : }
1156 :
1157 : // CSS currently limits font weights to multiples of 100 but the weight
1158 : // matching code below does not assume this.
1159 : //
1160 : // Calculate weight distance with values in the range (0..1000). In general,
1161 : // heavier weights match towards even heavier weights while lighter weights
1162 : // match towards even lighter weights. Target weight values in the range
1163 : // [400..500] are special, since they will first match up to 500, then down
1164 : // towards 0, then up again towards 999.
1165 : //
1166 : // Example: with target 600 and font weight 800, distance will be 200. With
1167 : // target 300 and font weight 600, distance will be 900, since heavier
1168 : // weights are farther away than lighter weights. If the target is 5 and the
1169 : // font weight 995, the distance would be 1590 for the same reason.
1170 :
1171 : #define REVERSE_WEIGHT_DISTANCE 600
1172 : #define WEIGHT_SHIFT 11 // number of bits to contain weight distance
1173 :
1174 : // weight distance ==> [0,1598]
1175 : static inline uint32_t
1176 115 : WeightDistance(uint32_t aFontWeight, uint32_t aTargetWeight)
1177 : {
1178 : // Compute a measure of the "distance" between the requested
1179 : // weight and the given fontEntry
1180 :
1181 115 : int32_t distance = 0, addedDistance = 0;
1182 115 : if (aTargetWeight != aFontWeight) {
1183 61 : if (aTargetWeight > 500) {
1184 0 : distance = aFontWeight - aTargetWeight;
1185 61 : } else if (aTargetWeight < 400) {
1186 0 : distance = aTargetWeight - aFontWeight;
1187 : } else {
1188 : // special case - target is between 400 and 500
1189 :
1190 : // font weights between 400 and 500 are close
1191 61 : if (aFontWeight >= 400 && aFontWeight <= 500) {
1192 4 : if (aFontWeight < aTargetWeight) {
1193 0 : distance = 500 - aFontWeight;
1194 : } else {
1195 2 : distance = aFontWeight - aTargetWeight;
1196 : }
1197 : } else {
1198 : // font weights outside use rule for target weights < 400 with
1199 : // added distance to separate from font weights in
1200 : // the [400..500] range
1201 59 : distance = aTargetWeight - aFontWeight;
1202 59 : addedDistance = 100;
1203 : }
1204 : }
1205 61 : if (distance < 0) {
1206 54 : distance = -distance + REVERSE_WEIGHT_DISTANCE;
1207 : }
1208 61 : distance += addedDistance;
1209 : }
1210 115 : return uint32_t(distance);
1211 : }
1212 :
1213 : #define MAX_DISTANCE 0xffffffff
1214 :
1215 : static inline uint32_t
1216 115 : WeightStyleStretchDistance(gfxFontEntry* aFontEntry,
1217 : const gfxFontStyle& aTargetStyle)
1218 : {
1219 : // weight/style/stretch priority: stretch >> style >> weight
1220 : uint32_t stretchDist =
1221 115 : StretchDistance(aFontEntry->mStretch, aTargetStyle.stretch);
1222 115 : uint32_t styleDist = StyleDistance(aFontEntry->mStyle, aTargetStyle.style);
1223 : uint32_t weightDist =
1224 115 : WeightDistance(aFontEntry->Weight(), aTargetStyle.weight);
1225 :
1226 115 : NS_ASSERTION(weightDist < (1 << WEIGHT_SHIFT), "weight value out of bounds");
1227 115 : NS_ASSERTION(styleDist < (1 << STYLE_SHIFT), "slope value out of bounds");
1228 :
1229 230 : return (stretchDist << (STYLE_SHIFT + WEIGHT_SHIFT)) |
1230 115 : (styleDist << WEIGHT_SHIFT) |
1231 115 : weightDist;
1232 : }
1233 :
1234 : void
1235 19 : gfxFontFamily::FindAllFontsForStyle(const gfxFontStyle& aFontStyle,
1236 : nsTArray<gfxFontEntry*>& aFontEntryList,
1237 : bool& aNeedsSyntheticBold)
1238 : {
1239 19 : if (!mHasStyles) {
1240 0 : FindStyleVariations(); // collect faces for the family, if not already done
1241 : }
1242 :
1243 19 : NS_ASSERTION(mAvailableFonts.Length() > 0, "font family with no faces!");
1244 19 : NS_ASSERTION(aFontEntryList.IsEmpty(), "non-empty fontlist passed in");
1245 :
1246 19 : aNeedsSyntheticBold = false;
1247 :
1248 19 : int8_t baseWeight = aFontStyle.ComputeWeight();
1249 19 : bool wantBold = baseWeight >= 6;
1250 19 : gfxFontEntry *fe = nullptr;
1251 :
1252 : // If the family has only one face, we simply return it; no further
1253 : // checking needed
1254 19 : uint32_t count = mAvailableFonts.Length();
1255 19 : if (count == 1) {
1256 0 : fe = mAvailableFonts[0];
1257 0 : aNeedsSyntheticBold =
1258 0 : wantBold && !fe->IsBold() && aFontStyle.allowSyntheticWeight;
1259 0 : aFontEntryList.AppendElement(fe);
1260 0 : return;
1261 : }
1262 :
1263 : // Most families are "simple", having just Regular/Bold/Italic/BoldItalic,
1264 : // or some subset of these. In this case, we have exactly 4 entries in mAvailableFonts,
1265 : // stored in the above order; note that some of the entries may be nullptr.
1266 : // We can then pick the required entry based on whether the request is for
1267 : // bold or non-bold, italic or non-italic, without running the more complex
1268 : // matching algorithm used for larger families with many weights and/or widths.
1269 :
1270 19 : if (mIsSimpleFamily) {
1271 : // Family has no more than the "standard" 4 faces, at fixed indexes;
1272 : // calculate which one we want.
1273 : // Note that we cannot simply return it as not all 4 faces are necessarily present.
1274 5 : bool wantItalic = (aFontStyle.style != NS_FONT_STYLE_NORMAL);
1275 5 : uint8_t faceIndex = (wantItalic ? kItalicMask : 0) |
1276 5 : (wantBold ? kBoldMask : 0);
1277 :
1278 : // if the desired style is available, return it directly
1279 5 : fe = mAvailableFonts[faceIndex];
1280 5 : if (fe) {
1281 : // no need to set aNeedsSyntheticBold here as we matched the boldness request
1282 5 : aFontEntryList.AppendElement(fe);
1283 5 : return;
1284 : }
1285 :
1286 : // order to check fallback faces in a simple family, depending on requested style
1287 : static const uint8_t simpleFallbacks[4][3] = {
1288 : { kBoldFaceIndex, kItalicFaceIndex, kBoldItalicFaceIndex }, // fallbacks for Regular
1289 : { kRegularFaceIndex, kBoldItalicFaceIndex, kItalicFaceIndex },// Bold
1290 : { kBoldItalicFaceIndex, kRegularFaceIndex, kBoldFaceIndex }, // Italic
1291 : { kItalicFaceIndex, kBoldFaceIndex, kRegularFaceIndex } // BoldItalic
1292 : };
1293 0 : const uint8_t *order = simpleFallbacks[faceIndex];
1294 :
1295 0 : for (uint8_t trial = 0; trial < 3; ++trial) {
1296 : // check remaining faces in order of preference to find the first that actually exists
1297 0 : fe = mAvailableFonts[order[trial]];
1298 0 : if (fe) {
1299 0 : aNeedsSyntheticBold =
1300 0 : wantBold && !fe->IsBold() &&
1301 0 : aFontStyle.allowSyntheticWeight;
1302 0 : aFontEntryList.AppendElement(fe);
1303 0 : return;
1304 : }
1305 : }
1306 :
1307 : // this can't happen unless we have totally broken the font-list manager!
1308 0 : NS_NOTREACHED("no face found in simple font family!");
1309 : }
1310 :
1311 : // Pick the font(s) that are closest to the desired weight, style, and
1312 : // stretch. Iterate over all fonts, measuring the weight/style distance.
1313 : // Because of unicode-range values, there may be more than one font for a
1314 : // given but the 99% use case is only a single font entry per
1315 : // weight/style/stretch distance value. To optimize this, only add entries
1316 : // to the matched font array when another entry already has the same
1317 : // weight/style/stretch distance and add the last matched font entry. For
1318 : // normal platform fonts with a single font entry for each
1319 : // weight/style/stretch combination, only the last matched font entry will
1320 : // be added.
1321 :
1322 14 : uint32_t minDistance = MAX_DISTANCE;
1323 14 : gfxFontEntry* matched = nullptr;
1324 : // iterate in forward order so that faces like 'Bold' are matched before
1325 : // matching style distance faces such as 'Bold Outline' (see bug 1185812)
1326 129 : for (uint32_t i = 0; i < count; i++) {
1327 115 : fe = mAvailableFonts[i];
1328 : // weight/style/stretch priority: stretch >> style >> weight
1329 115 : uint32_t distance = WeightStyleStretchDistance(fe, aFontStyle);
1330 115 : if (distance < minDistance) {
1331 28 : matched = fe;
1332 28 : if (!aFontEntryList.IsEmpty()) {
1333 0 : aFontEntryList.Clear();
1334 : }
1335 28 : minDistance = distance;
1336 87 : } else if (distance == minDistance) {
1337 5 : if (matched) {
1338 5 : aFontEntryList.AppendElement(matched);
1339 : }
1340 5 : matched = fe;
1341 : }
1342 : }
1343 :
1344 14 : NS_ASSERTION(matched, "didn't match a font within a family");
1345 :
1346 14 : if (matched) {
1347 14 : aFontEntryList.AppendElement(matched);
1348 14 : if (!matched->IsBold() && aFontStyle.weight >= 600 &&
1349 0 : aFontStyle.allowSyntheticWeight) {
1350 0 : aNeedsSyntheticBold = true;
1351 : }
1352 : }
1353 : }
1354 :
1355 : void
1356 16 : gfxFontFamily::CheckForSimpleFamily()
1357 : {
1358 : // already checked this family
1359 16 : if (mIsSimpleFamily) {
1360 14 : return;
1361 : }
1362 :
1363 16 : uint32_t count = mAvailableFonts.Length();
1364 16 : if (count > 4 || count == 0) {
1365 11 : return; // can't be "simple" if there are >4 faces;
1366 : // if none then the family is unusable anyway
1367 : }
1368 :
1369 5 : if (count == 1) {
1370 0 : mIsSimpleFamily = true;
1371 0 : return;
1372 : }
1373 :
1374 5 : int16_t firstStretch = mAvailableFonts[0]->Stretch();
1375 :
1376 5 : gfxFontEntry *faces[4] = { 0 };
1377 12 : for (uint8_t i = 0; i < count; ++i) {
1378 10 : gfxFontEntry *fe = mAvailableFonts[i];
1379 10 : if (fe->Stretch() != firstStretch || fe->IsOblique()) {
1380 : // simple families don't have varying font-stretch or oblique
1381 3 : return;
1382 : }
1383 14 : uint8_t faceIndex = (fe->IsItalic() ? kItalicMask : 0) |
1384 14 : (fe->Weight() >= 600 ? kBoldMask : 0);
1385 7 : if (faces[faceIndex]) {
1386 0 : return; // two faces resolve to the same slot; family isn't "simple"
1387 : }
1388 7 : faces[faceIndex] = fe;
1389 : }
1390 :
1391 : // we have successfully slotted the available faces into the standard
1392 : // 4-face framework
1393 2 : mAvailableFonts.SetLength(4);
1394 10 : for (uint8_t i = 0; i < 4; ++i) {
1395 8 : if (mAvailableFonts[i].get() != faces[i]) {
1396 0 : mAvailableFonts[i].swap(faces[i]);
1397 : }
1398 : }
1399 :
1400 2 : mIsSimpleFamily = true;
1401 : }
1402 :
1403 : #ifdef DEBUG
1404 : bool
1405 21 : gfxFontFamily::ContainsFace(gfxFontEntry* aFontEntry) {
1406 21 : uint32_t i, numFonts = mAvailableFonts.Length();
1407 62 : for (i = 0; i < numFonts; i++) {
1408 62 : if (mAvailableFonts[i] == aFontEntry) {
1409 21 : return true;
1410 : }
1411 : // userfonts contain the actual real font entry
1412 41 : if (mAvailableFonts[i] && mAvailableFonts[i]->mIsUserFontContainer) {
1413 : gfxUserFontEntry* ufe =
1414 0 : static_cast<gfxUserFontEntry*>(mAvailableFonts[i].get());
1415 0 : if (ufe->GetPlatformFontEntry() == aFontEntry) {
1416 0 : return true;
1417 : }
1418 : }
1419 : }
1420 0 : return false;
1421 : }
1422 : #endif
1423 :
1424 0 : void gfxFontFamily::LocalizedName(nsAString& aLocalizedName)
1425 : {
1426 : // just return the primary name; subclasses should override
1427 0 : aLocalizedName = mName;
1428 0 : }
1429 :
1430 : // metric for how close a given font matches a style
1431 : static int32_t
1432 0 : CalcStyleMatch(gfxFontEntry *aFontEntry, const gfxFontStyle *aStyle)
1433 : {
1434 0 : int32_t rank = 0;
1435 0 : if (aStyle) {
1436 : // italics
1437 0 : bool wantUpright = (aStyle->style == NS_FONT_STYLE_NORMAL);
1438 0 : if (aFontEntry->IsUpright() == wantUpright) {
1439 0 : rank += 10;
1440 : }
1441 :
1442 : // measure of closeness of weight to the desired value
1443 0 : rank += 9 - DeprecatedAbs(aFontEntry->Weight() / 100 - aStyle->ComputeWeight());
1444 : } else {
1445 : // if no font to match, prefer non-bold, non-italic fonts
1446 0 : if (aFontEntry->IsUpright()) {
1447 0 : rank += 3;
1448 : }
1449 0 : if (!aFontEntry->IsBold()) {
1450 0 : rank += 2;
1451 : }
1452 : }
1453 :
1454 0 : return rank;
1455 : }
1456 :
1457 : #define RANK_MATCHED_CMAP 20
1458 :
1459 : void
1460 0 : gfxFontFamily::FindFontForChar(GlobalFontMatch *aMatchData)
1461 : {
1462 0 : if (mFamilyCharacterMapInitialized && !TestCharacterMap(aMatchData->mCh)) {
1463 : // none of the faces in the family support the required char,
1464 : // so bail out immediately
1465 0 : return;
1466 : }
1467 :
1468 : bool needsBold;
1469 : gfxFontEntry *fe =
1470 0 : FindFontForStyle(aMatchData->mStyle ? *aMatchData->mStyle
1471 : : gfxFontStyle(),
1472 0 : needsBold);
1473 :
1474 0 : if (fe && !fe->SkipDuringSystemFallback()) {
1475 0 : int32_t rank = 0;
1476 :
1477 0 : if (fe->HasCharacter(aMatchData->mCh)) {
1478 0 : rank += RANK_MATCHED_CMAP;
1479 0 : aMatchData->mCount++;
1480 :
1481 0 : LogModule* log = gfxPlatform::GetLog(eGfxLog_textrun);
1482 :
1483 0 : if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Debug))) {
1484 0 : uint32_t unicodeRange = FindCharUnicodeRange(aMatchData->mCh);
1485 0 : Script script = GetScriptCode(aMatchData->mCh);
1486 0 : MOZ_LOG(log, LogLevel::Debug,\
1487 : ("(textrun-systemfallback-fonts) char: u+%6.6x "
1488 : "unicode-range: %d script: %d match: [%s]\n",
1489 : aMatchData->mCh,
1490 : unicodeRange, int(script),
1491 : NS_ConvertUTF16toUTF8(fe->Name()).get()));
1492 : }
1493 : }
1494 :
1495 0 : aMatchData->mCmapsTested++;
1496 0 : if (rank == 0) {
1497 0 : return;
1498 : }
1499 :
1500 : // omitting from original windows code -- family name, lang group, pitch
1501 : // not available in current FontEntry implementation
1502 0 : rank += CalcStyleMatch(fe, aMatchData->mStyle);
1503 :
1504 : // xxx - add whether AAT font with morphing info for specific lang groups
1505 :
1506 0 : if (rank > aMatchData->mMatchRank
1507 0 : || (rank == aMatchData->mMatchRank &&
1508 0 : Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
1509 : {
1510 0 : aMatchData->mBestMatch = fe;
1511 0 : aMatchData->mMatchedFamily = this;
1512 0 : aMatchData->mMatchRank = rank;
1513 : }
1514 : }
1515 : }
1516 :
1517 : void
1518 0 : gfxFontFamily::SearchAllFontsForChar(GlobalFontMatch *aMatchData)
1519 : {
1520 0 : uint32_t i, numFonts = mAvailableFonts.Length();
1521 0 : for (i = 0; i < numFonts; i++) {
1522 0 : gfxFontEntry *fe = mAvailableFonts[i];
1523 0 : if (fe && fe->HasCharacter(aMatchData->mCh)) {
1524 0 : int32_t rank = RANK_MATCHED_CMAP;
1525 0 : rank += CalcStyleMatch(fe, aMatchData->mStyle);
1526 0 : if (rank > aMatchData->mMatchRank
1527 0 : || (rank == aMatchData->mMatchRank &&
1528 0 : Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
1529 : {
1530 0 : aMatchData->mBestMatch = fe;
1531 0 : aMatchData->mMatchedFamily = this;
1532 0 : aMatchData->mMatchRank = rank;
1533 : }
1534 : }
1535 : }
1536 0 : }
1537 :
1538 : /*virtual*/
1539 0 : gfxFontFamily::~gfxFontFamily()
1540 : {
1541 : // Should not be dropped by stylo
1542 0 : MOZ_ASSERT(NS_IsMainThread());
1543 0 : }
1544 :
1545 : /*static*/ void
1546 0 : gfxFontFamily::ReadOtherFamilyNamesForFace(const nsAString& aFamilyName,
1547 : const char *aNameData,
1548 : uint32_t aDataLength,
1549 : nsTArray<nsString>& aOtherFamilyNames,
1550 : bool useFullName)
1551 : {
1552 : const gfxFontUtils::NameHeader *nameHeader =
1553 0 : reinterpret_cast<const gfxFontUtils::NameHeader*>(aNameData);
1554 :
1555 0 : uint32_t nameCount = nameHeader->count;
1556 0 : if (nameCount * sizeof(gfxFontUtils::NameRecord) > aDataLength) {
1557 0 : NS_WARNING("invalid font (name records)");
1558 0 : return;
1559 : }
1560 :
1561 : const gfxFontUtils::NameRecord *nameRecord =
1562 0 : reinterpret_cast<const gfxFontUtils::NameRecord*>(aNameData + sizeof(gfxFontUtils::NameHeader));
1563 0 : uint32_t stringsBase = uint32_t(nameHeader->stringOffset);
1564 :
1565 0 : for (uint32_t i = 0; i < nameCount; i++, nameRecord++) {
1566 0 : uint32_t nameLen = nameRecord->length;
1567 0 : uint32_t nameOff = nameRecord->offset; // offset from base of string storage
1568 :
1569 0 : if (stringsBase + nameOff + nameLen > aDataLength) {
1570 0 : NS_WARNING("invalid font (name table strings)");
1571 0 : return;
1572 : }
1573 :
1574 0 : uint16_t nameID = nameRecord->nameID;
1575 0 : if ((useFullName && nameID == gfxFontUtils::NAME_ID_FULL) ||
1576 0 : (!useFullName && (nameID == gfxFontUtils::NAME_ID_FAMILY ||
1577 : nameID == gfxFontUtils::NAME_ID_PREFERRED_FAMILY))) {
1578 0 : nsAutoString otherFamilyName;
1579 0 : bool ok = gfxFontUtils::DecodeFontName(aNameData + stringsBase + nameOff,
1580 : nameLen,
1581 : uint32_t(nameRecord->platformID),
1582 : uint32_t(nameRecord->encodingID),
1583 : uint32_t(nameRecord->languageID),
1584 0 : otherFamilyName);
1585 : // add if not same as canonical family name
1586 0 : if (ok && otherFamilyName != aFamilyName) {
1587 0 : aOtherFamilyNames.AppendElement(otherFamilyName);
1588 : }
1589 : }
1590 : }
1591 : }
1592 :
1593 : // returns true if other names were found, false otherwise
1594 : bool
1595 0 : gfxFontFamily::ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList,
1596 : hb_blob_t *aNameTable,
1597 : bool useFullName)
1598 : {
1599 : uint32_t dataLength;
1600 0 : const char *nameData = hb_blob_get_data(aNameTable, &dataLength);
1601 0 : AutoTArray<nsString,4> otherFamilyNames;
1602 :
1603 0 : ReadOtherFamilyNamesForFace(mName, nameData, dataLength,
1604 0 : otherFamilyNames, useFullName);
1605 :
1606 0 : uint32_t n = otherFamilyNames.Length();
1607 0 : for (uint32_t i = 0; i < n; i++) {
1608 0 : aPlatformFontList->AddOtherFamilyName(this, otherFamilyNames[i]);
1609 : }
1610 :
1611 0 : return n != 0;
1612 : }
1613 :
1614 : void
1615 0 : gfxFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList)
1616 : {
1617 0 : if (mOtherFamilyNamesInitialized)
1618 0 : return;
1619 0 : mOtherFamilyNamesInitialized = true;
1620 :
1621 0 : FindStyleVariations();
1622 :
1623 : // read in other family names for the first face in the list
1624 0 : uint32_t i, numFonts = mAvailableFonts.Length();
1625 0 : const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
1626 :
1627 0 : for (i = 0; i < numFonts; ++i) {
1628 0 : gfxFontEntry *fe = mAvailableFonts[i];
1629 0 : if (!fe) {
1630 0 : continue;
1631 : }
1632 0 : gfxFontEntry::AutoTable nameTable(fe, kNAME);
1633 0 : if (!nameTable) {
1634 0 : continue;
1635 : }
1636 0 : mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aPlatformFontList,
1637 : nameTable);
1638 0 : break;
1639 : }
1640 :
1641 : // read in other names for the first face in the list with the assumption
1642 : // that if extra names don't exist in that face then they don't exist in
1643 : // other faces for the same font
1644 0 : if (!mHasOtherFamilyNames)
1645 0 : return;
1646 :
1647 : // read in names for all faces, needed to catch cases where fonts have
1648 : // family names for individual weights (e.g. Hiragino Kaku Gothic Pro W6)
1649 0 : for ( ; i < numFonts; i++) {
1650 0 : gfxFontEntry *fe = mAvailableFonts[i];
1651 0 : if (!fe) {
1652 0 : continue;
1653 : }
1654 0 : gfxFontEntry::AutoTable nameTable(fe, kNAME);
1655 0 : if (!nameTable) {
1656 0 : continue;
1657 : }
1658 0 : ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable);
1659 : }
1660 : }
1661 :
1662 : void
1663 0 : gfxFontFamily::ReadFaceNames(gfxPlatformFontList *aPlatformFontList,
1664 : bool aNeedFullnamePostscriptNames,
1665 : FontInfoData *aFontInfoData)
1666 : {
1667 : // if all needed names have already been read, skip
1668 0 : if (mOtherFamilyNamesInitialized &&
1669 0 : (mFaceNamesInitialized || !aNeedFullnamePostscriptNames))
1670 0 : return;
1671 :
1672 0 : bool asyncFontLoaderDisabled = false;
1673 :
1674 0 : if (!mOtherFamilyNamesInitialized &&
1675 0 : aFontInfoData &&
1676 0 : aFontInfoData->mLoadOtherNames &&
1677 0 : !asyncFontLoaderDisabled)
1678 : {
1679 0 : AutoTArray<nsString,4> otherFamilyNames;
1680 : bool foundOtherNames =
1681 0 : aFontInfoData->GetOtherFamilyNames(mName, otherFamilyNames);
1682 0 : if (foundOtherNames) {
1683 0 : uint32_t i, n = otherFamilyNames.Length();
1684 0 : for (i = 0; i < n; i++) {
1685 0 : aPlatformFontList->AddOtherFamilyName(this, otherFamilyNames[i]);
1686 : }
1687 : }
1688 0 : mOtherFamilyNamesInitialized = true;
1689 : }
1690 :
1691 : // if all needed data has been initialized, return
1692 0 : if (mOtherFamilyNamesInitialized &&
1693 0 : (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
1694 0 : return;
1695 : }
1696 :
1697 0 : FindStyleVariations(aFontInfoData);
1698 :
1699 : // check again, as style enumeration code may have loaded names
1700 0 : if (mOtherFamilyNamesInitialized &&
1701 0 : (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
1702 0 : return;
1703 : }
1704 :
1705 0 : uint32_t i, numFonts = mAvailableFonts.Length();
1706 0 : const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
1707 :
1708 0 : bool firstTime = true, readAllFaces = false;
1709 0 : for (i = 0; i < numFonts; ++i) {
1710 0 : gfxFontEntry *fe = mAvailableFonts[i];
1711 0 : if (!fe) {
1712 0 : continue;
1713 : }
1714 :
1715 0 : nsAutoString fullname, psname;
1716 0 : bool foundFaceNames = false;
1717 0 : if (!mFaceNamesInitialized &&
1718 0 : aNeedFullnamePostscriptNames &&
1719 0 : aFontInfoData &&
1720 0 : aFontInfoData->mLoadFaceNames) {
1721 0 : aFontInfoData->GetFaceNames(fe->Name(), fullname, psname);
1722 0 : if (!fullname.IsEmpty()) {
1723 0 : aPlatformFontList->AddFullname(fe, fullname);
1724 : }
1725 0 : if (!psname.IsEmpty()) {
1726 0 : aPlatformFontList->AddPostscriptName(fe, psname);
1727 : }
1728 0 : foundFaceNames = true;
1729 :
1730 : // found everything needed? skip to next font
1731 0 : if (mOtherFamilyNamesInitialized) {
1732 0 : continue;
1733 : }
1734 : }
1735 :
1736 : // load directly from the name table
1737 0 : gfxFontEntry::AutoTable nameTable(fe, kNAME);
1738 0 : if (!nameTable) {
1739 0 : continue;
1740 : }
1741 :
1742 0 : if (aNeedFullnamePostscriptNames && !foundFaceNames) {
1743 0 : if (gfxFontUtils::ReadCanonicalName(
1744 : nameTable, gfxFontUtils::NAME_ID_FULL, fullname) == NS_OK)
1745 : {
1746 0 : aPlatformFontList->AddFullname(fe, fullname);
1747 : }
1748 :
1749 0 : if (gfxFontUtils::ReadCanonicalName(
1750 : nameTable, gfxFontUtils::NAME_ID_POSTSCRIPT, psname) == NS_OK)
1751 : {
1752 0 : aPlatformFontList->AddPostscriptName(fe, psname);
1753 : }
1754 : }
1755 :
1756 0 : if (!mOtherFamilyNamesInitialized && (firstTime || readAllFaces)) {
1757 0 : bool foundOtherName = ReadOtherFamilyNamesForFace(aPlatformFontList,
1758 0 : nameTable);
1759 :
1760 : // if the first face has a different name, scan all faces, otherwise
1761 : // assume the family doesn't have other names
1762 0 : if (firstTime && foundOtherName) {
1763 0 : mHasOtherFamilyNames = true;
1764 0 : readAllFaces = true;
1765 : }
1766 0 : firstTime = false;
1767 : }
1768 :
1769 : // if not reading in any more names, skip other faces
1770 0 : if (!readAllFaces && !aNeedFullnamePostscriptNames) {
1771 0 : break;
1772 : }
1773 : }
1774 :
1775 0 : mFaceNamesInitialized = true;
1776 0 : mOtherFamilyNamesInitialized = true;
1777 : }
1778 :
1779 :
1780 : gfxFontEntry*
1781 0 : gfxFontFamily::FindFont(const nsAString& aPostscriptName)
1782 : {
1783 : // find the font using a simple linear search
1784 0 : uint32_t numFonts = mAvailableFonts.Length();
1785 0 : for (uint32_t i = 0; i < numFonts; i++) {
1786 0 : gfxFontEntry *fe = mAvailableFonts[i].get();
1787 0 : if (fe && fe->Name() == aPostscriptName)
1788 0 : return fe;
1789 : }
1790 0 : return nullptr;
1791 : }
1792 :
1793 : void
1794 0 : gfxFontFamily::ReadAllCMAPs(FontInfoData *aFontInfoData)
1795 : {
1796 0 : FindStyleVariations(aFontInfoData);
1797 :
1798 0 : uint32_t i, numFonts = mAvailableFonts.Length();
1799 0 : for (i = 0; i < numFonts; i++) {
1800 0 : gfxFontEntry *fe = mAvailableFonts[i];
1801 : // don't try to load cmaps for downloadable fonts not yet loaded
1802 0 : if (!fe || fe->mIsUserFontContainer) {
1803 0 : continue;
1804 : }
1805 0 : fe->ReadCMAP(aFontInfoData);
1806 0 : mFamilyCharacterMap.Union(*(fe->mCharacterMap));
1807 : }
1808 0 : mFamilyCharacterMap.Compact();
1809 0 : mFamilyCharacterMapInitialized = true;
1810 0 : }
1811 :
1812 : void
1813 0 : gfxFontFamily::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
1814 : FontListSizes* aSizes) const
1815 : {
1816 0 : aSizes->mFontListSize +=
1817 0 : mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1818 0 : aSizes->mCharMapsSize +=
1819 0 : mFamilyCharacterMap.SizeOfExcludingThis(aMallocSizeOf);
1820 :
1821 0 : aSizes->mFontListSize +=
1822 0 : mAvailableFonts.ShallowSizeOfExcludingThis(aMallocSizeOf);
1823 0 : for (uint32_t i = 0; i < mAvailableFonts.Length(); ++i) {
1824 0 : gfxFontEntry *fe = mAvailableFonts[i];
1825 0 : if (fe) {
1826 0 : fe->AddSizeOfIncludingThis(aMallocSizeOf, aSizes);
1827 : }
1828 : }
1829 0 : }
1830 :
1831 : void
1832 0 : gfxFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
1833 : FontListSizes* aSizes) const
1834 : {
1835 0 : aSizes->mFontListSize += aMallocSizeOf(this);
1836 0 : AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
1837 0 : }
|