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