Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/style/FontFace.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "mozilla/dom/FontFace.h"
8
9
#include <algorithm>
10
#include "mozilla/dom/CSSFontFaceRule.h"
11
#include "mozilla/dom/FontFaceBinding.h"
12
#include "mozilla/dom/FontFaceSet.h"
13
#include "mozilla/dom/Promise.h"
14
#include "mozilla/dom/TypedArray.h"
15
#include "mozilla/dom/UnionTypes.h"
16
#include "mozilla/CycleCollectedJSContext.h"
17
#include "mozilla/ServoBindings.h"
18
#include "mozilla/ServoCSSParser.h"
19
#include "mozilla/ServoStyleSet.h"
20
#include "mozilla/ServoUtils.h"
21
#include "mozilla/StaticPrefs.h"
22
#include "nsIDocument.h"
23
#include "nsStyleUtil.h"
24
#include "mozilla/net/ReferrerPolicy.h"
25
26
namespace mozilla {
27
namespace dom {
28
29
// -- FontFaceBufferSource ---------------------------------------------------
30
31
/**
32
 * An object that wraps a FontFace object and exposes its ArrayBuffer
33
 * or ArrayBufferView data in a form the user font set can consume.
34
 */
35
class FontFaceBufferSource : public gfxFontFaceBufferSource
36
{
37
public:
38
  explicit FontFaceBufferSource(FontFace* aFontFace)
39
0
    : mFontFace(aFontFace) {}
40
  virtual void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) override;
41
42
private:
43
  RefPtr<FontFace> mFontFace;
44
};
45
46
void
47
FontFaceBufferSource::TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength)
48
0
{
49
0
  MOZ_ASSERT(mFontFace, "only call TakeBuffer once on a given "
50
0
                        "FontFaceBufferSource object");
51
0
  mFontFace->TakeBuffer(aBuffer, aLength);
52
0
  mFontFace = nullptr;
53
0
}
54
55
// -- Utility functions ------------------------------------------------------
56
57
template<typename T>
58
static void
59
GetDataFrom(const T& aObject, uint8_t*& aBuffer, uint32_t& aLength)
60
0
{
61
0
  MOZ_ASSERT(!aBuffer);
62
0
  aObject.ComputeLengthAndData();
63
0
  // We use malloc here rather than a FallibleTArray or fallible
64
0
  // operator new[] since the gfxUserFontEntry will be calling free
65
0
  // on it.
66
0
  aBuffer = (uint8_t*) malloc(aObject.Length());
67
0
  if (!aBuffer) {
68
0
    return;
69
0
  }
70
0
  memcpy((void*) aBuffer, aObject.Data(), aObject.Length());
71
0
  aLength = aObject.Length();
72
0
}
Unexecuted instantiation: Unified_cpp_layout_style1.cpp:void mozilla::dom::GetDataFrom<mozilla::dom::TypedArray<unsigned char, &js::UnwrapArrayBuffer, &(JS_GetArrayBufferData(JSObject*, bool*, JS::AutoRequireNoGC const&)), &js::GetArrayBufferLengthAndData, &(JS_NewArrayBuffer(JSContext*, unsigned int))> >(mozilla::dom::TypedArray<unsigned char, &js::UnwrapArrayBuffer, &(JS_GetArrayBufferData(JSObject*, bool*, JS::AutoRequireNoGC const&)), &js::GetArrayBufferLengthAndData, &(JS_NewArrayBuffer(JSContext*, unsigned int))> const&, unsigned char*&, unsigned int&)
Unexecuted instantiation: Unified_cpp_layout_style1.cpp:void mozilla::dom::GetDataFrom<mozilla::dom::ArrayBufferView_base<&js::UnwrapArrayBufferView, &js::GetArrayBufferViewLengthAndData, &(JS_GetArrayBufferViewType(JSObject*))> >(mozilla::dom::ArrayBufferView_base<&js::UnwrapArrayBufferView, &js::GetArrayBufferViewLengthAndData, &(JS_GetArrayBufferViewType(JSObject*))> const&, unsigned char*&, unsigned int&)
73
74
// -- FontFace ---------------------------------------------------------------
75
76
NS_IMPL_CYCLE_COLLECTION_CLASS(FontFace)
77
78
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FontFace)
79
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
80
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoaded)
81
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet)
82
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOtherFontFaceSets)
83
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
84
85
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FontFace)
86
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
87
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoaded)
88
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
89
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOtherFontFaceSets)
90
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
91
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
92
93
0
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(FontFace)
94
0
  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
95
0
NS_IMPL_CYCLE_COLLECTION_TRACE_END
96
97
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FontFace)
98
0
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
99
0
  NS_INTERFACE_MAP_ENTRY(nsISupports)
100
0
NS_INTERFACE_MAP_END
101
102
NS_IMPL_CYCLE_COLLECTING_ADDREF(FontFace)
103
NS_IMPL_CYCLE_COLLECTING_RELEASE(FontFace)
104
105
FontFace::FontFace(nsISupports* aParent, FontFaceSet* aFontFaceSet)
106
  : mParent(aParent)
107
  , mLoadedRejection(NS_OK)
108
  , mStatus(FontFaceLoadStatus::Unloaded)
109
  , mSourceType(SourceType(0))
110
  , mSourceBuffer(nullptr)
111
  , mSourceBufferLength(0)
112
  , mFontFaceSet(aFontFaceSet)
113
  , mUnicodeRangeDirty(true)
114
  , mInFontFaceSet(false)
115
0
{
116
0
}
117
118
FontFace::~FontFace()
119
0
{
120
0
  // Assert that we don't drop any FontFace objects during a Servo traversal,
121
0
  // since PostTraversalTask objects can hold raw pointers to FontFaces.
122
0
  MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
123
0
124
0
  SetUserFontEntry(nullptr);
125
0
126
0
  if (mSourceBuffer) {
127
0
    free(mSourceBuffer);
128
0
  }
129
0
}
130
131
JSObject*
132
FontFace::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
133
0
{
134
0
  return FontFace_Binding::Wrap(aCx, this, aGivenProto);
135
0
}
136
137
static FontFaceLoadStatus
138
LoadStateToStatus(gfxUserFontEntry::UserFontLoadState aLoadState)
139
0
{
140
0
  switch (aLoadState) {
141
0
    case gfxUserFontEntry::UserFontLoadState::STATUS_NOT_LOADED:
142
0
      return FontFaceLoadStatus::Unloaded;
143
0
    case gfxUserFontEntry::UserFontLoadState::STATUS_LOAD_PENDING:
144
0
    case gfxUserFontEntry::UserFontLoadState::STATUS_LOADING:
145
0
      return FontFaceLoadStatus::Loading;
146
0
    case gfxUserFontEntry::UserFontLoadState::STATUS_LOADED:
147
0
      return FontFaceLoadStatus::Loaded;
148
0
    case gfxUserFontEntry::UserFontLoadState::STATUS_FAILED:
149
0
      return FontFaceLoadStatus::Error;
150
0
  }
151
0
  MOZ_ASSERT_UNREACHABLE("invalid aLoadState value");
152
0
  return FontFaceLoadStatus::Error;
153
0
}
154
155
already_AddRefed<FontFace>
156
FontFace::CreateForRule(nsISupports* aGlobal,
157
                        FontFaceSet* aFontFaceSet,
158
                        RawServoFontFaceRule* aRule)
159
0
{
160
0
  RefPtr<FontFace> obj = new FontFace(aGlobal, aFontFaceSet);
161
0
  obj->mRule = aRule;
162
0
  obj->mSourceType = eSourceType_FontFaceRule;
163
0
  obj->mInFontFaceSet = true;
164
0
  return obj.forget();
165
0
}
166
167
already_AddRefed<FontFace>
168
FontFace::Constructor(const GlobalObject& aGlobal,
169
                      const nsAString& aFamily,
170
                      const StringOrArrayBufferOrArrayBufferView& aSource,
171
                      const FontFaceDescriptors& aDescriptors,
172
                      ErrorResult& aRv)
173
0
{
174
0
  nsISupports* global = aGlobal.GetAsSupports();
175
0
  nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global);
176
0
  nsIDocument* doc = window->GetDoc();
177
0
  if (!doc) {
178
0
    aRv.Throw(NS_ERROR_FAILURE);
179
0
    return nullptr;
180
0
  }
181
0
182
0
  RefPtr<FontFace> obj = new FontFace(global, doc->Fonts());
183
0
  if (!obj->SetDescriptors(aFamily, aDescriptors)) {
184
0
    return obj.forget();
185
0
  }
186
0
187
0
  obj->InitializeSource(aSource);
188
0
  return obj.forget();
189
0
}
190
191
void
192
FontFace::InitializeSource(const StringOrArrayBufferOrArrayBufferView& aSource)
193
0
{
194
0
  if (aSource.IsString()) {
195
0
    IgnoredErrorResult rv;
196
0
    if (!SetDescriptor(eCSSFontDesc_Src, aSource.GetAsString(), rv)) {
197
0
      Reject(NS_ERROR_DOM_SYNTAX_ERR);
198
0
199
0
      SetStatus(FontFaceLoadStatus::Error);
200
0
      return;
201
0
    }
202
0
203
0
    mSourceType = eSourceType_URLs;
204
0
    return;
205
0
  }
206
0
207
0
  mSourceType = FontFace::eSourceType_Buffer;
208
0
209
0
  if (aSource.IsArrayBuffer()) {
210
0
    GetDataFrom(aSource.GetAsArrayBuffer(),
211
0
                mSourceBuffer, mSourceBufferLength);
212
0
  } else {
213
0
    MOZ_ASSERT(aSource.IsArrayBufferView());
214
0
    GetDataFrom(aSource.GetAsArrayBufferView(),
215
0
                mSourceBuffer, mSourceBufferLength);
216
0
  }
217
0
218
0
  SetStatus(FontFaceLoadStatus::Loading);
219
0
  DoLoad();
220
0
}
221
222
void
223
FontFace::GetFamily(nsString& aResult)
224
0
{
225
0
  mFontFaceSet->FlushUserFontSet();
226
0
227
0
  // Serialize the same way as in nsCSSFontFaceStyleDecl::GetPropertyValue.
228
0
  nsCSSValue value;
229
0
  GetDesc(eCSSFontDesc_Family, value);
230
0
231
0
  aResult.Truncate();
232
0
233
0
  if (value.GetUnit() == eCSSUnit_Null) {
234
0
    return;
235
0
  }
236
0
237
0
  nsDependentString family(value.GetStringBufferValue());
238
0
  if (!family.IsEmpty()) {
239
0
    // The string length can be zero when the author passed an invalid
240
0
    // family name or an invalid descriptor to the JS FontFace constructor.
241
0
    nsStyleUtil::AppendEscapedCSSString(family, aResult);
242
0
  }
243
0
}
244
245
void
246
FontFace::SetFamily(const nsAString& aValue, ErrorResult& aRv)
247
0
{
248
0
  mFontFaceSet->FlushUserFontSet();
249
0
  SetDescriptor(eCSSFontDesc_Family, aValue, aRv);
250
0
}
251
252
void
253
FontFace::GetStyle(nsString& aResult)
254
0
{
255
0
  mFontFaceSet->FlushUserFontSet();
256
0
  GetDesc(eCSSFontDesc_Style, aResult);
257
0
}
258
259
void
260
FontFace::SetStyle(const nsAString& aValue, ErrorResult& aRv)
261
0
{
262
0
  mFontFaceSet->FlushUserFontSet();
263
0
  SetDescriptor(eCSSFontDesc_Style, aValue, aRv);
264
0
}
265
266
void
267
FontFace::GetWeight(nsString& aResult)
268
0
{
269
0
  mFontFaceSet->FlushUserFontSet();
270
0
  GetDesc(eCSSFontDesc_Weight, aResult);
271
0
}
272
273
void
274
FontFace::SetWeight(const nsAString& aValue, ErrorResult& aRv)
275
0
{
276
0
  mFontFaceSet->FlushUserFontSet();
277
0
  SetDescriptor(eCSSFontDesc_Weight, aValue, aRv);
278
0
}
279
280
void
281
FontFace::GetStretch(nsString& aResult)
282
0
{
283
0
  mFontFaceSet->FlushUserFontSet();
284
0
  GetDesc(eCSSFontDesc_Stretch, aResult);
285
0
}
286
287
void
288
FontFace::SetStretch(const nsAString& aValue, ErrorResult& aRv)
289
0
{
290
0
  mFontFaceSet->FlushUserFontSet();
291
0
  SetDescriptor(eCSSFontDesc_Stretch, aValue, aRv);
292
0
}
293
294
void
295
FontFace::GetUnicodeRange(nsString& aResult)
296
0
{
297
0
  mFontFaceSet->FlushUserFontSet();
298
0
299
0
  // There is no eCSSProperty_unicode_range for us to pass in to GetDesc
300
0
  // to get a serialized (possibly defaulted) value, but that function
301
0
  // doesn't use the property ID for this descriptor anyway.
302
0
  GetDesc(eCSSFontDesc_UnicodeRange, aResult);
303
0
}
304
305
void
306
FontFace::SetUnicodeRange(const nsAString& aValue, ErrorResult& aRv)
307
0
{
308
0
  mFontFaceSet->FlushUserFontSet();
309
0
  SetDescriptor(eCSSFontDesc_UnicodeRange, aValue, aRv);
310
0
}
311
312
void
313
FontFace::GetVariant(nsString& aResult)
314
0
{
315
0
  mFontFaceSet->FlushUserFontSet();
316
0
317
0
  // XXX Just expose the font-variant descriptor as "normal" until we
318
0
  // support it properly (bug 1055385).
319
0
  aResult.AssignLiteral("normal");
320
0
}
321
322
void
323
FontFace::SetVariant(const nsAString& aValue, ErrorResult& aRv)
324
0
{
325
0
  mFontFaceSet->FlushUserFontSet();
326
0
327
0
  // XXX Ignore assignments to variant until we support font-variant
328
0
  // descriptors (bug 1055385).
329
0
}
330
331
void
332
FontFace::GetFeatureSettings(nsString& aResult)
333
0
{
334
0
  mFontFaceSet->FlushUserFontSet();
335
0
  GetDesc(eCSSFontDesc_FontFeatureSettings, aResult);
336
0
}
337
338
void
339
FontFace::SetFeatureSettings(const nsAString& aValue, ErrorResult& aRv)
340
0
{
341
0
  mFontFaceSet->FlushUserFontSet();
342
0
  SetDescriptor(eCSSFontDesc_FontFeatureSettings, aValue, aRv);
343
0
}
344
345
void
346
FontFace::GetVariationSettings(nsString& aResult)
347
0
{
348
0
  mFontFaceSet->FlushUserFontSet();
349
0
  GetDesc(eCSSFontDesc_FontVariationSettings, aResult);
350
0
}
351
352
void
353
FontFace::SetVariationSettings(const nsAString& aValue, ErrorResult& aRv)
354
0
{
355
0
  mFontFaceSet->FlushUserFontSet();
356
0
  SetDescriptor(eCSSFontDesc_FontVariationSettings, aValue, aRv);
357
0
}
358
359
void
360
FontFace::GetDisplay(nsString& aResult)
361
0
{
362
0
  mFontFaceSet->FlushUserFontSet();
363
0
  GetDesc(eCSSFontDesc_Display, aResult);
364
0
}
365
366
void
367
FontFace::SetDisplay(const nsAString& aValue, ErrorResult& aRv)
368
0
{
369
0
  mFontFaceSet->FlushUserFontSet();
370
0
  SetDescriptor(eCSSFontDesc_Display, aValue, aRv);
371
0
}
372
373
FontFaceLoadStatus
374
FontFace::Status()
375
0
{
376
0
  return mStatus;
377
0
}
378
379
Promise*
380
FontFace::Load(ErrorResult& aRv)
381
0
{
382
0
  MOZ_ASSERT(NS_IsMainThread());
383
0
384
0
  mFontFaceSet->FlushUserFontSet();
385
0
386
0
  EnsurePromise();
387
0
388
0
  if (!mLoaded) {
389
0
    aRv.Throw(NS_ERROR_FAILURE);
390
0
    return nullptr;
391
0
  }
392
0
393
0
  // Calling Load on a FontFace constructed with an ArrayBuffer data source,
394
0
  // or on one that is already loading (or has finished loading), has no
395
0
  // effect.
396
0
  if (mSourceType == eSourceType_Buffer ||
397
0
      mStatus != FontFaceLoadStatus::Unloaded) {
398
0
    return mLoaded;
399
0
  }
400
0
401
0
  // Calling the user font entry's Load method will end up setting our
402
0
  // status to Loading, but the spec requires us to set it to Loading
403
0
  // here.
404
0
  SetStatus(FontFaceLoadStatus::Loading);
405
0
406
0
  DoLoad();
407
0
408
0
  return mLoaded;
409
0
}
410
411
gfxUserFontEntry*
412
FontFace::CreateUserFontEntry()
413
0
{
414
0
  if (!mUserFontEntry) {
415
0
    MOZ_ASSERT(!HasRule(),
416
0
               "Rule backed FontFace objects should already have a user font "
417
0
               "entry by the time Load() can be called on them");
418
0
419
0
    RefPtr<gfxUserFontEntry> newEntry =
420
0
      mFontFaceSet->FindOrCreateUserFontEntryFromFontFace(this);
421
0
    if (newEntry) {
422
0
      SetUserFontEntry(newEntry);
423
0
    }
424
0
  }
425
0
426
0
  return mUserFontEntry;
427
0
}
428
429
void
430
FontFace::DoLoad()
431
0
{
432
0
  if (!CreateUserFontEntry()) {
433
0
    return;
434
0
  }
435
0
  mUserFontEntry->Load();
436
0
}
437
438
Promise*
439
FontFace::GetLoaded(ErrorResult& aRv)
440
0
{
441
0
  MOZ_ASSERT(NS_IsMainThread());
442
0
443
0
  mFontFaceSet->FlushUserFontSet();
444
0
445
0
  EnsurePromise();
446
0
447
0
  if (!mLoaded) {
448
0
    aRv.Throw(NS_ERROR_FAILURE);
449
0
    return nullptr;
450
0
  }
451
0
452
0
  return mLoaded;
453
0
}
454
455
void
456
FontFace::SetStatus(FontFaceLoadStatus aStatus)
457
0
{
458
0
  AssertIsMainThreadOrServoFontMetricsLocked();
459
0
460
0
  if (mStatus == aStatus) {
461
0
    return;
462
0
  }
463
0
464
0
  if (aStatus < mStatus) {
465
0
    // We're being asked to go backwards in status!  Normally, this shouldn't
466
0
    // happen.  But it can if the FontFace had a user font entry that had
467
0
    // loaded, but then was given a new one by FontFaceSet::InsertRuleFontFace
468
0
    // if we used a local() rule.  For now, just ignore the request to
469
0
    // go backwards in status.
470
0
    return;
471
0
  }
472
0
473
0
  mStatus = aStatus;
474
0
475
0
  if (mInFontFaceSet) {
476
0
    mFontFaceSet->OnFontFaceStatusChanged(this);
477
0
  }
478
0
479
0
  for (FontFaceSet* otherSet : mOtherFontFaceSets) {
480
0
    otherSet->OnFontFaceStatusChanged(this);
481
0
  }
482
0
483
0
  if (mStatus == FontFaceLoadStatus::Loaded) {
484
0
    if (mLoaded) {
485
0
      DoResolve();
486
0
    }
487
0
  } else if (mStatus == FontFaceLoadStatus::Error) {
488
0
    if (mSourceType == eSourceType_Buffer) {
489
0
      Reject(NS_ERROR_DOM_SYNTAX_ERR);
490
0
    } else {
491
0
      Reject(NS_ERROR_DOM_NETWORK_ERR);
492
0
    }
493
0
  }
494
0
}
495
496
void
497
FontFace::DoResolve()
498
0
{
499
0
  AssertIsMainThreadOrServoFontMetricsLocked();
500
0
501
0
  if (ServoStyleSet* ss = ServoStyleSet::Current()) {
502
0
    // See comments in Gecko_GetFontMetrics.
503
0
    ss->AppendTask(PostTraversalTask::ResolveFontFaceLoadedPromise(this));
504
0
    return;
505
0
  }
506
0
507
0
  mLoaded->MaybeResolve(this);
508
0
}
509
510
void
511
FontFace::DoReject(nsresult aResult)
512
0
{
513
0
  AssertIsMainThreadOrServoFontMetricsLocked();
514
0
515
0
  if (ServoStyleSet* ss = ServoStyleSet::Current()) {
516
0
    // See comments in Gecko_GetFontMetrics.
517
0
    ss->AppendTask(PostTraversalTask::RejectFontFaceLoadedPromise(this, aResult));
518
0
    return;
519
0
  }
520
0
521
0
  mLoaded->MaybeReject(aResult);
522
0
}
523
524
already_AddRefed<URLExtraData>
525
FontFace::GetURLExtraData() const
526
0
{
527
0
  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mParent);
528
0
  nsCOMPtr<nsIPrincipal> principal = global->PrincipalOrNull();
529
0
530
0
  nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mParent);
531
0
  nsCOMPtr<nsIURI> docURI = window->GetDocumentURI();
532
0
  nsCOMPtr<nsIURI> base = window->GetDocBaseURI();
533
0
534
0
  // We pass RP_Unset when creating URLExtraData object here because it's not
535
0
  // going to result to change referer policy in a resource request.
536
0
  RefPtr<URLExtraData> url = new URLExtraData(base, docURI, principal,
537
0
                                              net::RP_Unset);
538
0
  return url.forget();
539
0
}
540
541
bool
542
FontFace::SetDescriptor(nsCSSFontDesc aFontDesc,
543
                        const nsAString& aValue,
544
                        ErrorResult& aRv)
545
0
{
546
0
  // FIXME We probably don't need to distinguish between this anymore
547
0
  // since we have common backend now.
548
0
  NS_ASSERTION(!HasRule(),
549
0
               "we don't handle rule backed FontFace objects yet");
550
0
  if (HasRule()) {
551
0
    return false;
552
0
  }
553
0
554
0
  NS_ConvertUTF16toUTF8 value(aValue);
555
0
  RefPtr<URLExtraData> url = GetURLExtraData();
556
0
  if (!Servo_FontFaceRule_SetDescriptor(GetData(), aFontDesc, &value, url)) {
557
0
    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
558
0
    return false;
559
0
  }
560
0
561
0
  if (aFontDesc == eCSSFontDesc_UnicodeRange) {
562
0
    mUnicodeRangeDirty = true;
563
0
  }
564
0
565
0
  // XXX Setting descriptors doesn't actually have any effect on FontFace
566
0
  // objects that have started loading or have already been loaded.
567
0
  return true;
568
0
}
569
570
bool
571
FontFace::SetDescriptors(const nsAString& aFamily,
572
                         const FontFaceDescriptors& aDescriptors)
573
0
{
574
0
  MOZ_ASSERT(!HasRule());
575
0
  MOZ_ASSERT(!mDescriptors);
576
0
577
0
  IgnoredErrorResult rv;
578
0
  mDescriptors = Servo_FontFaceRule_CreateEmpty().Consume();
579
0
580
0
  // Parse all of the mDescriptors in aInitializer, which are the values
581
0
  // we got from the JS constructor.
582
0
  if (!SetDescriptor(eCSSFontDesc_Family, aFamily, rv) ||
583
0
      !SetDescriptor(eCSSFontDesc_Style, aDescriptors.mStyle, rv) ||
584
0
      !SetDescriptor(eCSSFontDesc_Weight, aDescriptors.mWeight, rv) ||
585
0
      !SetDescriptor(eCSSFontDesc_Stretch, aDescriptors.mStretch, rv) ||
586
0
      !SetDescriptor(eCSSFontDesc_UnicodeRange,
587
0
                     aDescriptors.mUnicodeRange, rv) ||
588
0
      !SetDescriptor(eCSSFontDesc_FontFeatureSettings,
589
0
                     aDescriptors.mFeatureSettings, rv) ||
590
0
      (StaticPrefs::layout_css_font_variations_enabled() &&
591
0
       !SetDescriptor(eCSSFontDesc_FontVariationSettings,
592
0
                      aDescriptors.mVariationSettings, rv)) ||
593
0
      !SetDescriptor(eCSSFontDesc_Display, aDescriptors.mDisplay, rv)) {
594
0
    // XXX Handle font-variant once we support it (bug 1055385).
595
0
596
0
    // If any of the descriptors failed to parse, none of them should be set
597
0
    // on the FontFace.
598
0
    mDescriptors = Servo_FontFaceRule_CreateEmpty().Consume();
599
0
600
0
    Reject(NS_ERROR_DOM_SYNTAX_ERR);
601
0
602
0
    SetStatus(FontFaceLoadStatus::Error);
603
0
    return false;
604
0
  }
605
0
606
0
  return true;
607
0
}
608
609
void
610
FontFace::GetDesc(nsCSSFontDesc aDescID, nsCSSValue& aResult) const
611
0
{
612
0
  aResult.Reset();
613
0
  Servo_FontFaceRule_GetDescriptor(GetData(), aDescID, &aResult);
614
0
}
615
616
void
617
FontFace::GetDesc(nsCSSFontDesc aDescID, nsString& aResult) const
618
0
{
619
0
  aResult.Truncate();
620
0
  Servo_FontFaceRule_GetDescriptorCssText(GetData(), aDescID, &aResult);
621
0
622
0
  // Fill in a default value for missing descriptors.
623
0
  if (aResult.IsEmpty()) {
624
0
    if (aDescID == eCSSFontDesc_UnicodeRange) {
625
0
      aResult.AssignLiteral("U+0-10FFFF");
626
0
    } else if (aDescID == eCSSFontDesc_Display) {
627
0
      aResult.AssignLiteral("auto");
628
0
    } else if (aDescID != eCSSFontDesc_Family &&
629
0
               aDescID != eCSSFontDesc_Src) {
630
0
      aResult.AssignLiteral("normal");
631
0
    }
632
0
  }
633
0
}
634
635
void
636
FontFace::SetUserFontEntry(gfxUserFontEntry* aEntry)
637
0
{
638
0
  if (mUserFontEntry) {
639
0
    mUserFontEntry->mFontFaces.RemoveElement(this);
640
0
  }
641
0
642
0
  mUserFontEntry = static_cast<Entry*>(aEntry);
643
0
  if (mUserFontEntry) {
644
0
    mUserFontEntry->mFontFaces.AppendElement(this);
645
0
646
0
    MOZ_ASSERT(mUserFontEntry->GetUserFontSet() ==
647
0
                 mFontFaceSet->GetUserFontSet(),
648
0
               "user font entry must be associated with the same user font set "
649
0
               "as the FontFace");
650
0
651
0
    // Our newly assigned user font entry might be in the process of or
652
0
    // finished loading, so set our status accordingly.  But only do so
653
0
    // if we're not going "backwards" in status, which could otherwise
654
0
    // happen in this case:
655
0
    //
656
0
    //   new FontFace("ABC", "url(x)").load();
657
0
    //
658
0
    // where the SetUserFontEntry call (from the after-initialization
659
0
    // DoLoad call) comes after the author's call to load(), which set mStatus
660
0
    // to Loading.
661
0
    FontFaceLoadStatus newStatus =
662
0
      LoadStateToStatus(mUserFontEntry->LoadState());
663
0
    if (newStatus > mStatus) {
664
0
      SetStatus(newStatus);
665
0
    }
666
0
  }
667
0
}
668
669
bool
670
FontFace::GetFamilyName(nsCString& aResult)
671
0
{
672
0
  nsCSSValue value;
673
0
  GetDesc(eCSSFontDesc_Family, value);
674
0
675
0
  if (value.GetUnit() == eCSSUnit_String) {
676
0
    nsString familyname;
677
0
    value.GetStringValue(familyname);
678
0
    AppendUTF16toUTF8(familyname, aResult);
679
0
  }
680
0
681
0
  return !aResult.IsEmpty();
682
0
}
683
684
void
685
FontFace::DisconnectFromRule()
686
0
{
687
0
  MOZ_ASSERT(HasRule());
688
0
689
0
  // Make a copy of the descriptors.
690
0
  mDescriptors = Servo_FontFaceRule_Clone(mRule).Consume();
691
0
  mRule = nullptr;
692
0
  mInFontFaceSet = false;
693
0
}
694
695
bool
696
FontFace::HasFontData() const
697
0
{
698
0
  return mSourceType == eSourceType_Buffer && mSourceBuffer;
699
0
}
700
701
void
702
FontFace::TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength)
703
0
{
704
0
  MOZ_ASSERT(HasFontData());
705
0
706
0
  aBuffer = mSourceBuffer;
707
0
  aLength = mSourceBufferLength;
708
0
709
0
  mSourceBuffer = nullptr;
710
0
  mSourceBufferLength = 0;
711
0
}
712
713
already_AddRefed<gfxFontFaceBufferSource>
714
FontFace::CreateBufferSource()
715
0
{
716
0
  RefPtr<FontFaceBufferSource> bufferSource = new FontFaceBufferSource(this);
717
0
  return bufferSource.forget();
718
0
}
719
720
bool
721
FontFace::IsInFontFaceSet(FontFaceSet* aFontFaceSet) const
722
0
{
723
0
  if (mFontFaceSet == aFontFaceSet) {
724
0
    return mInFontFaceSet;
725
0
  }
726
0
  return mOtherFontFaceSets.Contains(aFontFaceSet);
727
0
}
728
729
void
730
FontFace::AddFontFaceSet(FontFaceSet* aFontFaceSet)
731
0
{
732
0
  MOZ_ASSERT(!IsInFontFaceSet(aFontFaceSet));
733
0
734
0
  if (mFontFaceSet == aFontFaceSet) {
735
0
    mInFontFaceSet = true;
736
0
  } else {
737
0
    mOtherFontFaceSets.AppendElement(aFontFaceSet);
738
0
  }
739
0
}
740
741
void
742
FontFace::RemoveFontFaceSet(FontFaceSet* aFontFaceSet)
743
0
{
744
0
  MOZ_ASSERT(IsInFontFaceSet(aFontFaceSet));
745
0
746
0
  if (mFontFaceSet == aFontFaceSet) {
747
0
    mInFontFaceSet = false;
748
0
  } else {
749
0
    mOtherFontFaceSets.RemoveElement(aFontFaceSet);
750
0
  }
751
0
}
752
753
void
754
FontFace::Reject(nsresult aResult)
755
0
{
756
0
  AssertIsMainThreadOrServoFontMetricsLocked();
757
0
758
0
  if (mLoaded) {
759
0
    DoReject(aResult);
760
0
  } else if (mLoadedRejection == NS_OK) {
761
0
    mLoadedRejection = aResult;
762
0
  }
763
0
}
764
765
void
766
FontFace::EnsurePromise()
767
0
{
768
0
  MOZ_ASSERT(NS_IsMainThread());
769
0
770
0
  if (mLoaded) {
771
0
    return;
772
0
  }
773
0
774
0
  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mParent);
775
0
776
0
  // If the pref is not set, don't create the Promise (which the page wouldn't
777
0
  // be able to get to anyway) as it causes the window.FontFace constructor
778
0
  // to be created.
779
0
  if (global && FontFaceSet::PrefEnabled()) {
780
0
    ErrorResult rv;
781
0
    mLoaded = Promise::Create(global, rv);
782
0
783
0
    if (mStatus == FontFaceLoadStatus::Loaded) {
784
0
      mLoaded->MaybeResolve(this);
785
0
    } else if (mLoadedRejection != NS_OK) {
786
0
      mLoaded->MaybeReject(mLoadedRejection);
787
0
    }
788
0
  }
789
0
}
790
791
gfxCharacterMap*
792
FontFace::GetUnicodeRangeAsCharacterMap()
793
0
{
794
0
  if (!mUnicodeRangeDirty) {
795
0
    return mUnicodeRange;
796
0
  }
797
0
798
0
  nsCSSValue val;
799
0
  GetDesc(eCSSFontDesc_UnicodeRange, val);
800
0
801
0
  if (val.GetUnit() == eCSSUnit_Array) {
802
0
    mUnicodeRange = new gfxCharacterMap();
803
0
    const nsCSSValue::Array& sources = *val.GetArrayValue();
804
0
    MOZ_ASSERT(sources.Count() % 2 == 0,
805
0
               "odd number of entries in a unicode-range: array");
806
0
807
0
    for (uint32_t i = 0; i < sources.Count(); i += 2) {
808
0
      uint32_t min = sources[i].GetIntValue();
809
0
      uint32_t max = sources[i+1].GetIntValue();
810
0
      mUnicodeRange->SetRange(min, max);
811
0
    }
812
0
  } else {
813
0
    mUnicodeRange = nullptr;
814
0
  }
815
0
816
0
  mUnicodeRangeDirty = false;
817
0
  return mUnicodeRange;
818
0
}
819
820
// -- FontFace::Entry --------------------------------------------------------
821
822
/* virtual */ void
823
FontFace::Entry::SetLoadState(UserFontLoadState aLoadState)
824
0
{
825
0
  gfxUserFontEntry::SetLoadState(aLoadState);
826
0
827
0
  for (size_t i = 0; i < mFontFaces.Length(); i++) {
828
0
    mFontFaces[i]->SetStatus(LoadStateToStatus(aLoadState));
829
0
  }
830
0
}
831
832
/* virtual */ void
833
FontFace::Entry::GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult)
834
0
{
835
0
  aResult.Clear();
836
0
837
0
  for (FontFace* f : mFontFaces) {
838
0
    if (f->mInFontFaceSet) {
839
0
      aResult.AppendElement(f->mFontFaceSet->GetUserFontSet());
840
0
    }
841
0
    for (FontFaceSet* s : f->mOtherFontFaceSets) {
842
0
      aResult.AppendElement(s->GetUserFontSet());
843
0
    }
844
0
  }
845
0
846
0
  // Remove duplicates.
847
0
  aResult.Sort();
848
0
  auto it = std::unique(aResult.begin(), aResult.end());
849
0
  aResult.TruncateLength(it - aResult.begin());
850
0
}
851
852
} // namespace dom
853
} // namespace mozilla