FontFace.cpp (9507B)
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 11 #include "gfxFontUtils.h" 12 #include "mozilla/CycleCollectedJSContext.h" 13 #include "mozilla/ServoBindings.h" 14 #include "mozilla/ServoCSSParser.h" 15 #include "mozilla/ServoStyleSet.h" 16 #include "mozilla/ServoUtils.h" 17 #include "mozilla/StaticPrefs_layout.h" 18 #include "mozilla/dom/CSSFontFaceRule.h" 19 #include "mozilla/dom/FontFaceBinding.h" 20 #include "mozilla/dom/FontFaceImpl.h" 21 #include "mozilla/dom/FontFaceSet.h" 22 #include "mozilla/dom/Promise.h" 23 #include "mozilla/dom/TypedArray.h" 24 #include "mozilla/dom/UnionTypes.h" 25 #include "nsStyleUtil.h" 26 27 namespace mozilla::dom { 28 29 // -- Utility functions ------------------------------------------------------ 30 31 template <typename T> 32 static void GetDataFrom(const T& aObject, uint8_t*& aBuffer, 33 uint32_t& aLength) { 34 MOZ_ASSERT(!aBuffer); 35 // We need to use malloc here because the gfxUserFontEntry will be calling 36 // free on it, so the Vector's default AllocPolicy (MallocAllocPolicy) is 37 // fine. 38 Maybe<Vector<uint8_t>> buffer = 39 aObject.template CreateFromData<Vector<uint8_t>>(); 40 if (buffer.isNothing()) { 41 return; 42 } 43 aLength = buffer->length(); 44 aBuffer = buffer->extractOrCopyRawBuffer(); 45 } 46 47 // -- FontFace --------------------------------------------------------------- 48 49 NS_IMPL_CYCLE_COLLECTION_CLASS(FontFace) 50 51 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FontFace) 52 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoaded) 53 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 54 55 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FontFace) 56 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoaded) 57 tmp->Destroy(); 58 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER 59 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 60 61 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(FontFace) 62 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER 63 NS_IMPL_CYCLE_COLLECTION_TRACE_END 64 65 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FontFace) 66 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 67 NS_INTERFACE_MAP_ENTRY(nsISupports) 68 NS_INTERFACE_MAP_END 69 70 NS_IMPL_CYCLE_COLLECTING_ADDREF(FontFace) 71 NS_IMPL_CYCLE_COLLECTING_RELEASE(FontFace) 72 73 FontFace::FontFace(nsIGlobalObject* aParent) { BindToOwner(aParent); } 74 75 FontFace::~FontFace() { 76 // Assert that we don't drop any FontFace objects during a Servo traversal, 77 // since PostTraversalTask objects can hold raw pointers to FontFaces. 78 MOZ_ASSERT(!gfxFontUtils::IsInServoTraversal()); 79 Destroy(); 80 } 81 82 void FontFace::Destroy() { mImpl->Destroy(); } 83 84 void FontFace::DisconnectFromOwner() { 85 GlobalTeardownObserver::DisconnectFromOwner(); 86 if (mImpl) { 87 mImpl->StopKeepingOwnerAlive(); 88 } 89 } 90 91 JSObject* FontFace::WrapObject(JSContext* aCx, 92 JS::Handle<JSObject*> aGivenProto) { 93 return FontFace_Binding::Wrap(aCx, this, aGivenProto); 94 } 95 96 already_AddRefed<FontFace> FontFace::CreateForRule( 97 nsIGlobalObject* aGlobal, FontFaceSet* aFontFaceSet, 98 StyleLockedFontFaceRule* aRule) { 99 FontFaceSetImpl* setImpl = aFontFaceSet->GetImpl(); 100 MOZ_ASSERT(setImpl); 101 102 RefPtr<FontFace> obj = new FontFace(aGlobal); 103 obj->mImpl = FontFaceImpl::CreateForRule(obj, setImpl, aRule); 104 return obj.forget(); 105 } 106 107 already_AddRefed<FontFace> FontFace::Constructor( 108 const GlobalObject& aGlobal, const nsACString& aFamily, 109 const UTF8StringOrArrayBufferOrArrayBufferView& aSource, 110 const FontFaceDescriptors& aDescriptors, ErrorResult& aRv) { 111 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); 112 113 FontFaceSet* set = global->GetFonts(); 114 if (NS_WARN_IF(!set)) { 115 aRv.Throw(NS_ERROR_FAILURE); 116 return nullptr; 117 } 118 119 FontFaceSetImpl* setImpl = set->GetImpl(); 120 if (NS_WARN_IF(!setImpl)) { 121 aRv.Throw(NS_ERROR_FAILURE); 122 return nullptr; 123 } 124 125 RefPtr<FontFace> obj = new FontFace(global); 126 obj->mImpl = new FontFaceImpl(obj, setImpl); 127 if (!obj->mImpl->SetDescriptors(aFamily, aDescriptors)) { 128 return obj.forget(); 129 } 130 131 if (aSource.IsUTF8String()) { 132 obj->mImpl->InitializeSourceURL(aSource.GetAsUTF8String()); 133 } else { 134 uint8_t* buffer = nullptr; 135 uint32_t length = 0; 136 if (aSource.IsArrayBuffer()) { 137 GetDataFrom(aSource.GetAsArrayBuffer(), buffer, length); 138 } else if (aSource.IsArrayBufferView()) { 139 GetDataFrom(aSource.GetAsArrayBufferView(), buffer, length); 140 } else { 141 MOZ_ASSERT_UNREACHABLE("Unhandled source type!"); 142 return nullptr; 143 } 144 145 obj->mImpl->InitializeSourceBuffer(buffer, length); 146 } 147 148 return obj.forget(); 149 } 150 151 void FontFace::GetFamily(nsACString& aResult) { mImpl->GetFamily(aResult); } 152 153 void FontFace::SetFamily(const nsACString& aValue, ErrorResult& aRv) { 154 mImpl->SetFamily(aValue, aRv); 155 } 156 157 void FontFace::GetStyle(nsACString& aResult) { mImpl->GetStyle(aResult); } 158 159 void FontFace::SetStyle(const nsACString& aValue, ErrorResult& aRv) { 160 mImpl->SetStyle(aValue, aRv); 161 } 162 163 void FontFace::GetWeight(nsACString& aResult) { mImpl->GetWeight(aResult); } 164 165 void FontFace::SetWeight(const nsACString& aValue, ErrorResult& aRv) { 166 mImpl->SetWeight(aValue, aRv); 167 } 168 169 void FontFace::GetStretch(nsACString& aResult) { mImpl->GetStretch(aResult); } 170 171 void FontFace::SetStretch(const nsACString& aValue, ErrorResult& aRv) { 172 mImpl->SetStretch(aValue, aRv); 173 } 174 175 void FontFace::GetUnicodeRange(nsACString& aResult) { 176 mImpl->GetUnicodeRange(aResult); 177 } 178 179 void FontFace::SetUnicodeRange(const nsACString& aValue, ErrorResult& aRv) { 180 mImpl->SetUnicodeRange(aValue, aRv); 181 } 182 183 void FontFace::GetVariant(nsACString& aResult) { mImpl->GetVariant(aResult); } 184 185 void FontFace::SetVariant(const nsACString& aValue, ErrorResult& aRv) { 186 mImpl->SetVariant(aValue, aRv); 187 } 188 189 void FontFace::GetFeatureSettings(nsACString& aResult) { 190 mImpl->GetFeatureSettings(aResult); 191 } 192 193 void FontFace::SetFeatureSettings(const nsACString& aValue, ErrorResult& aRv) { 194 mImpl->SetFeatureSettings(aValue, aRv); 195 } 196 197 void FontFace::GetVariationSettings(nsACString& aResult) { 198 mImpl->GetVariationSettings(aResult); 199 } 200 201 void FontFace::SetVariationSettings(const nsACString& aValue, 202 ErrorResult& aRv) { 203 mImpl->SetVariationSettings(aValue, aRv); 204 } 205 206 void FontFace::GetDisplay(nsACString& aResult) { mImpl->GetDisplay(aResult); } 207 208 void FontFace::SetDisplay(const nsACString& aValue, ErrorResult& aRv) { 209 mImpl->SetDisplay(aValue, aRv); 210 } 211 212 void FontFace::GetAscentOverride(nsACString& aResult) { 213 mImpl->GetAscentOverride(aResult); 214 } 215 216 void FontFace::SetAscentOverride(const nsACString& aValue, ErrorResult& aRv) { 217 mImpl->SetAscentOverride(aValue, aRv); 218 } 219 220 void FontFace::GetDescentOverride(nsACString& aResult) { 221 mImpl->GetDescentOverride(aResult); 222 } 223 224 void FontFace::SetDescentOverride(const nsACString& aValue, ErrorResult& aRv) { 225 mImpl->SetDescentOverride(aValue, aRv); 226 } 227 228 void FontFace::GetLineGapOverride(nsACString& aResult) { 229 mImpl->GetLineGapOverride(aResult); 230 } 231 232 void FontFace::SetLineGapOverride(const nsACString& aValue, ErrorResult& aRv) { 233 mImpl->SetLineGapOverride(aValue, aRv); 234 } 235 236 void FontFace::GetSizeAdjust(nsACString& aResult) { 237 mImpl->GetSizeAdjust(aResult); 238 } 239 240 void FontFace::SetSizeAdjust(const nsACString& aValue, ErrorResult& aRv) { 241 mImpl->SetSizeAdjust(aValue, aRv); 242 } 243 244 FontFaceLoadStatus FontFace::Status() { return mImpl->Status(); } 245 246 Promise* FontFace::Load(ErrorResult& aRv) { 247 EnsurePromise(); 248 249 if (!mLoaded) { 250 aRv.Throw(NS_ERROR_FAILURE); 251 return nullptr; 252 } 253 254 mImpl->Load(aRv); 255 return mLoaded; 256 } 257 258 Promise* FontFace::GetLoaded(ErrorResult& aRv) { 259 EnsurePromise(); 260 261 if (!mLoaded) { 262 aRv.Throw(NS_ERROR_FAILURE); 263 return nullptr; 264 } 265 266 return mLoaded; 267 } 268 269 void FontFace::MaybeResolve() { 270 gfxFontUtils::AssertSafeThreadOrServoFontMetricsLocked(); 271 272 if (!mLoaded) { 273 return; 274 } 275 276 if (ServoStyleSet* ss = gfxFontUtils::CurrentServoStyleSet()) { 277 // See comments in Gecko_GetFontMetrics. 278 ss->AppendTask(PostTraversalTask::ResolveFontFaceLoadedPromise(this)); 279 return; 280 } 281 282 mLoaded->MaybeResolve(this); 283 } 284 285 void FontFace::MaybeReject(FontFaceLoadedRejectReason aReason, 286 nsCString&& aMessage) { 287 gfxFontUtils::AssertSafeThreadOrServoFontMetricsLocked(); 288 289 if (ServoStyleSet* ss = gfxFontUtils::CurrentServoStyleSet()) { 290 // See comments in Gecko_GetFontMetrics. 291 ss->AppendTask(PostTraversalTask::RejectFontFaceLoadedPromise( 292 this, aReason, std::move(aMessage))); 293 return; 294 } 295 296 if (mLoaded) { 297 switch (aReason) { 298 case FontFaceLoadedRejectReason::Network: 299 mLoaded->MaybeRejectWithNetworkError(aMessage); 300 break; 301 case FontFaceLoadedRejectReason::Syntax: 302 mLoaded->MaybeRejectWithSyntaxError(aMessage); 303 break; 304 } 305 } else if (!mLoadedRejection) { 306 mLoadedRejection = MakeUnique<FontFaceLoadedRejection>( 307 FontFaceLoadedRejection{aReason, std::move(aMessage)}); 308 } 309 } 310 311 void FontFace::EnsurePromise() { 312 if (mLoaded || !mImpl || !GetOwnerGlobal()) { 313 return; 314 } 315 316 mLoaded = Promise::CreateInfallible(GetOwnerGlobal()); 317 318 if (mImpl->Status() == FontFaceLoadStatus::Loaded) { 319 mLoaded->MaybeResolve(this); 320 } else if (mLoadedRejection) { 321 auto rejection = std::move(mLoadedRejection); 322 MaybeReject(rejection->mReason, std::move(rejection->mMessage)); 323 } 324 } 325 326 } // namespace mozilla::dom