diff options
Diffstat (limited to 'layout/style/FontPreloader.cpp')
-rw-r--r-- | layout/style/FontPreloader.cpp | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/layout/style/FontPreloader.cpp b/layout/style/FontPreloader.cpp new file mode 100644 index 0000000000..3fc56a33bd --- /dev/null +++ b/layout/style/FontPreloader.cpp @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "FontPreloader.h" + +#include "gfxUserFontSet.h" +#include "nsIClassOfService.h" +#include "nsIHttpChannel.h" +#include "nsISupportsPriority.h" + +namespace mozilla { + +FontPreloader::FontPreloader() + : FetchPreloader(nsIContentPolicy::TYPE_INTERNAL_FONT_PRELOAD) {} + +void FontPreloader::PrioritizeAsPreload() { PrioritizeAsPreload(Channel()); } + +nsresult FontPreloader::CreateChannel( + nsIChannel** aChannel, nsIURI* aURI, const CORSMode aCORSMode, + const dom::ReferrerPolicy& aReferrerPolicy, dom::Document* aDocument, + nsILoadGroup* aLoadGroup, nsIInterfaceRequestor* aCallbacks) { + return BuildChannel(aChannel, aURI, aCORSMode, aReferrerPolicy, nullptr, + nullptr, aDocument, aLoadGroup, aCallbacks, true); +} + +// static +void FontPreloader::PrioritizeAsPreload(nsIChannel* aChannel) { + nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(aChannel)); + if (cos) { + cos->AddClassFlags(nsIClassOfService::Unblocked); + } +} + +// static +nsresult FontPreloader::BuildChannel( + nsIChannel** aChannel, nsIURI* aURI, const CORSMode aCORSMode, + const dom::ReferrerPolicy& aReferrerPolicy, + gfxUserFontEntry* aUserFontEntry, const gfxFontFaceSrc* aFontFaceSrc, + dom::Document* aDocument, nsILoadGroup* aLoadGroup, + nsIInterfaceRequestor* aCallbacks, bool aIsPreload) { + nsresult rv; + + nsIPrincipal* principal = + aUserFontEntry ? (aUserFontEntry->GetPrincipal() + ? aUserFontEntry->GetPrincipal()->NodePrincipal() + : nullptr) + : aDocument->NodePrincipal(); + + // aCORSMode is ignored. We always load as crossorigin=anonymous, but a + // preload started with anything other then "anonymous" will never be found. + + uint32_t securityFlags = 0; + if (aURI->SchemeIs("file")) { + securityFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT; + } else { + securityFlags = nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT; + } + + nsContentPolicyType contentPolicyType = + aIsPreload ? nsIContentPolicy::TYPE_INTERNAL_FONT_PRELOAD + : nsIContentPolicy::TYPE_FONT; + + nsCOMPtr<nsIChannel> channel; + // Note we are calling NS_NewChannelWithTriggeringPrincipal() with both a + // node and a principal. This is because the document where the font is + // being loaded might have a different origin from the principal of the + // stylesheet that initiated the font load. + rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel), aURI, + aDocument, principal, securityFlags, + contentPolicyType, + nullptr, // PerformanceStorage + aLoadGroup); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel)); + if (httpChannel) { + rv = httpChannel->SetRequestHeader( + "Accept"_ns, + nsLiteralCString("application/font-woff2;q=1.0,application/" + "font-woff;q=0.9,*/*;q=0.8"), + false); + NS_ENSURE_SUCCESS(rv, rv); + + if (aFontFaceSrc) { + rv = httpChannel->SetReferrerInfo(aFontFaceSrc->mReferrerInfo); + Unused << NS_WARN_IF(NS_FAILED(rv)); + + // For WOFF and WOFF2, we should tell servers/proxies/etc NOT to try + // and apply additional compression at the content-encoding layer + if (aFontFaceSrc->mFormatFlags & (gfxUserFontSet::FLAG_FORMAT_WOFF | + gfxUserFontSet::FLAG_FORMAT_WOFF2)) { + rv = httpChannel->SetRequestHeader("Accept-Encoding"_ns, "identity"_ns, + false); + NS_ENSURE_SUCCESS(rv, rv); + } + } else { + nsCOMPtr<nsIReferrerInfo> referrerInfo = new dom::ReferrerInfo( + aDocument->GetDocumentURIAsReferrer(), aReferrerPolicy); + rv = httpChannel->SetReferrerInfoWithoutClone(referrerInfo); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + } + } + + nsCOMPtr<nsISupportsPriority> priorityChannel(do_QueryInterface(channel)); + if (priorityChannel) { + priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGH); + } + nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel)); + if (cos) { + cos->AddClassFlags(nsIClassOfService::TailForbidden); + } + + channel.forget(aChannel); + return NS_OK; +} + +} // namespace mozilla |