mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 196078 - Part 2: Support displaying arbitrary text/* MIME types as plain text, r=smaug,necko-reviewers,valentin
This patch refactors how we check for text formats when deciding how to handle resources, such that more text MIME types will be rendered in-browser, rather than downloaded. This change requires us to move more away from using the Gecko-Content-Viewers category in the category manager for this decision, as we need to handle an unlimited number of MIME types behind the scenes. Support for Gecko-Content-Viewers was left in for both the in-tree use for application/http-index-format and dynamically determining whether image/avif and image/jxl are supported, as well as for the message/rfc822 type used by Thunderbird. Differential Revision: https://phabricator.services.mozilla.com/D212078
This commit is contained in:
parent
205b94f6af
commit
58ee355a1b
@ -17,10 +17,9 @@ webidl Document;
|
||||
|
||||
/**
|
||||
* To get a component that implements nsIDocumentLoaderFactory
|
||||
* for a given mimetype, use nsICategoryManager to find an entry
|
||||
* with the mimetype as its name in the category "Gecko-Content-Viewers".
|
||||
* The value of the entry is the contractid of the component.
|
||||
* The component is a service, so use GetService, not CreateInstance to get it.
|
||||
* for a given mimetype, use nsContentUtils::FindInternalDocumentViewer.
|
||||
* This will look up the MIME type within the "Gecko-Content-Viewers" category,
|
||||
* with additional handlers for other content types.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(e795239e-9d3c-47c4-b063-9e600fb3b287)]
|
||||
|
@ -1081,21 +1081,13 @@ nsresult ExternalResourceMap::PendingLoad::SetupViewer(
|
||||
new LoadgroupCallbacks(callbacks);
|
||||
newLoadGroup->SetNotificationCallbacks(newCallbacks);
|
||||
|
||||
// This is some serious hackery cribbed from docshell
|
||||
nsCOMPtr<nsICategoryManager> catMan =
|
||||
do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(catMan, NS_ERROR_NOT_AVAILABLE);
|
||||
nsCString contractId;
|
||||
nsresult rv =
|
||||
catMan->GetCategoryEntry("Gecko-Content-Viewers", type, contractId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory =
|
||||
do_GetService(contractId.get());
|
||||
nsContentUtils::FindInternalDocumentViewer(type);
|
||||
NS_ENSURE_TRUE(docLoaderFactory, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
nsCOMPtr<nsIDocumentViewer> viewer;
|
||||
nsCOMPtr<nsIStreamListener> listener;
|
||||
rv = docLoaderFactory->CreateInstance(
|
||||
nsresult rv = docLoaderFactory->CreateInstance(
|
||||
"external-resource", chan, newLoadGroup, type, nullptr, nullptr,
|
||||
getter_AddRefs(listener), getter_AddRefs(viewer));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -4626,28 +4626,66 @@ bool nsContentUtils::IsChildOfSameType(Document* aDoc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsJSONType(const nsACString& aContentType) {
|
||||
return aContentType.EqualsLiteral(TEXT_JSON) ||
|
||||
aContentType.EqualsLiteral(APPLICATION_JSON);
|
||||
}
|
||||
|
||||
static bool IsNonPlainTextType(const nsACString& aContentType) {
|
||||
// MIME type suffixes which should not be plain text.
|
||||
static constexpr std::string_view kNonPlainTextTypes[] = {
|
||||
"html",
|
||||
"xml",
|
||||
"xsl",
|
||||
"calendar",
|
||||
"x-calendar",
|
||||
"x-vcalendar",
|
||||
"vcalendar",
|
||||
"vcard",
|
||||
"x-vcard",
|
||||
"directory",
|
||||
"ldif",
|
||||
"qif",
|
||||
"x-qif",
|
||||
"x-csv",
|
||||
"x-vcf",
|
||||
"rtf",
|
||||
"comma-separated-values",
|
||||
"csv",
|
||||
"tab-separated-values",
|
||||
"tsv",
|
||||
"ofx",
|
||||
"vnd.sun.j2me.app-descriptor",
|
||||
"x-ms-iqy",
|
||||
"x-ms-odc",
|
||||
"x-ms-rqy",
|
||||
"x-ms-contact"};
|
||||
|
||||
// Trim off the "text/" prefix for comparison.
|
||||
MOZ_ASSERT(StringBeginsWith(aContentType, "text/"_ns));
|
||||
std::string_view suffix = aContentType;
|
||||
suffix.remove_prefix(5);
|
||||
|
||||
for (std::string_view type : kNonPlainTextTypes) {
|
||||
if (type == suffix) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool nsContentUtils::IsPlainTextType(const nsACString& aContentType) {
|
||||
// NOTE: if you add a type here, add it to the content_types array in
|
||||
// layout/build/components.conf as well.
|
||||
return aContentType.EqualsLiteral(TEXT_PLAIN) ||
|
||||
aContentType.EqualsLiteral(TEXT_CSS) ||
|
||||
aContentType.EqualsLiteral(TEXT_CACHE_MANIFEST) ||
|
||||
aContentType.EqualsLiteral(TEXT_VTT) ||
|
||||
aContentType.EqualsLiteral(APPLICATION_JAVASCRIPT) ||
|
||||
aContentType.EqualsLiteral(APPLICATION_XJAVASCRIPT) ||
|
||||
aContentType.EqualsLiteral(TEXT_ECMASCRIPT) ||
|
||||
aContentType.EqualsLiteral(APPLICATION_ECMASCRIPT) ||
|
||||
aContentType.EqualsLiteral(TEXT_JAVASCRIPT) ||
|
||||
aContentType.EqualsLiteral(APPLICATION_JSON) ||
|
||||
aContentType.EqualsLiteral(TEXT_JSON) ||
|
||||
aContentType.EqualsLiteral(TEXT_EVENT_STREAM);
|
||||
// All `text/*`, any JSON type and any JavaScript type are considered "plain
|
||||
// text" types for the purposes of how to render them as a document.
|
||||
return (StringBeginsWith(aContentType, "text/"_ns) &&
|
||||
!IsNonPlainTextType(aContentType)) ||
|
||||
IsJSONType(aContentType) || IsJavascriptMIMEType(aContentType);
|
||||
}
|
||||
|
||||
bool nsContentUtils::IsUtf8OnlyPlainTextType(const nsACString& aContentType) {
|
||||
// NOTE: This must be a subset of the list in IsPlainTextType().
|
||||
return aContentType.EqualsLiteral(TEXT_CACHE_MANIFEST) ||
|
||||
aContentType.EqualsLiteral(APPLICATION_JSON) ||
|
||||
aContentType.EqualsLiteral(TEXT_JSON) ||
|
||||
return IsJSONType(aContentType) ||
|
||||
aContentType.EqualsLiteral(TEXT_CACHE_MANIFEST) ||
|
||||
aContentType.EqualsLiteral(TEXT_VTT);
|
||||
}
|
||||
|
||||
@ -7213,9 +7251,12 @@ nsContentUtils::FindInternalDocumentViewer(const nsACString& aType,
|
||||
return docFactory.forget();
|
||||
}
|
||||
|
||||
if (DecoderTraits::IsSupportedInVideoDocument(aType)) {
|
||||
docFactory =
|
||||
do_GetService("@mozilla.org/content/document-loader-factory;1");
|
||||
// If the type wasn't registered in `Gecko-Content-Viewers`, check if it's
|
||||
// another type which we may dynamically support, such as `text/*` types or
|
||||
// video document types. These types are all backed by the nsContentDLF.
|
||||
if (IsPlainTextType(aType) ||
|
||||
DecoderTraits::IsSupportedInVideoDocument(aType)) {
|
||||
docFactory = do_GetService(CONTENT_DLF_CONTRACTID);
|
||||
if (docFactory && aLoaderType) {
|
||||
*aLoaderType = TYPE_CONTENT;
|
||||
}
|
||||
@ -7925,32 +7966,40 @@ void nsContentUtils::DestroyMatchString(void* aData) {
|
||||
}
|
||||
}
|
||||
|
||||
bool nsContentUtils::IsJavascriptMIMEType(const nsAString& aMIMEType) {
|
||||
// Table ordered from most to least likely JS MIME types.
|
||||
static const char* jsTypes[] = {"text/javascript",
|
||||
"text/ecmascript",
|
||||
"application/javascript",
|
||||
"application/ecmascript",
|
||||
"application/x-javascript",
|
||||
"application/x-ecmascript",
|
||||
"text/javascript1.0",
|
||||
"text/javascript1.1",
|
||||
"text/javascript1.2",
|
||||
"text/javascript1.3",
|
||||
"text/javascript1.4",
|
||||
"text/javascript1.5",
|
||||
"text/jscript",
|
||||
"text/livescript",
|
||||
"text/x-ecmascript",
|
||||
"text/x-javascript",
|
||||
nullptr};
|
||||
// Table ordered from most to least likely JS MIME types.
|
||||
static constexpr std::string_view kJavascriptMIMETypes[] = {
|
||||
"text/javascript",
|
||||
"text/ecmascript",
|
||||
"application/javascript",
|
||||
"application/ecmascript",
|
||||
"application/x-javascript",
|
||||
"application/x-ecmascript",
|
||||
"text/javascript1.0",
|
||||
"text/javascript1.1",
|
||||
"text/javascript1.2",
|
||||
"text/javascript1.3",
|
||||
"text/javascript1.4",
|
||||
"text/javascript1.5",
|
||||
"text/jscript",
|
||||
"text/livescript",
|
||||
"text/x-ecmascript",
|
||||
"text/x-javascript"};
|
||||
|
||||
for (uint32_t i = 0; jsTypes[i]; ++i) {
|
||||
if (aMIMEType.LowerCaseEqualsASCII(jsTypes[i])) {
|
||||
bool nsContentUtils::IsJavascriptMIMEType(const nsAString& aMIMEType) {
|
||||
for (std::string_view type : kJavascriptMIMETypes) {
|
||||
if (aMIMEType.LowerCaseEqualsASCII(type.data(), type.length())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool nsContentUtils::IsJavascriptMIMEType(const nsACString& aMIMEType) {
|
||||
for (std::string_view type : kJavascriptMIMETypes) {
|
||||
if (aMIMEType.LowerCaseEqualsASCII(type.data(), type.length())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2764,6 +2764,7 @@ class nsContentUtils {
|
||||
static bool IsJavaScriptLanguage(const nsString& aName);
|
||||
|
||||
static bool IsJavascriptMIMEType(const nsAString& aMIMEType);
|
||||
static bool IsJavascriptMIMEType(const nsACString& aMIMEType);
|
||||
|
||||
static void SplitMimeType(const nsAString& aValue, nsString& aType,
|
||||
nsString& aParams);
|
||||
|
@ -131,20 +131,13 @@ gfxSVGGlyphsDocument* gfxSVGGlyphs::FindOrCreateGlyphsDocument(
|
||||
}
|
||||
|
||||
nsresult gfxSVGGlyphsDocument::SetupPresentation() {
|
||||
nsCOMPtr<nsICategoryManager> catMan =
|
||||
do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
|
||||
nsCString contractId;
|
||||
nsresult rv = catMan->GetCategoryEntry("Gecko-Content-Viewers",
|
||||
"image/svg+xml", contractId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory =
|
||||
do_GetService(contractId.get());
|
||||
nsContentUtils::FindInternalDocumentViewer("image/svg+xml"_ns);
|
||||
NS_ASSERTION(docLoaderFactory, "Couldn't get DocumentLoaderFactory");
|
||||
|
||||
nsCOMPtr<nsIDocumentViewer> viewer;
|
||||
rv = docLoaderFactory->CreateInstanceForDocument(nullptr, mDocument, nullptr,
|
||||
getter_AddRefs(viewer));
|
||||
nsresult rv = docLoaderFactory->CreateInstanceForDocument(
|
||||
nullptr, mDocument, nullptr, getter_AddRefs(viewer));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
auto upem = mOwner->FontEntry()->UnitsPerEm();
|
||||
|
@ -283,20 +283,14 @@ nsresult SVGDocumentWrapper::SetupViewer(nsIRequest* aRequest,
|
||||
NS_ENSURE_TRUE(newLoadGroup, NS_ERROR_OUT_OF_MEMORY);
|
||||
newLoadGroup->SetLoadGroup(loadGroup);
|
||||
|
||||
nsCOMPtr<nsICategoryManager> catMan =
|
||||
do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(catMan, NS_ERROR_NOT_AVAILABLE);
|
||||
nsCString contractId;
|
||||
nsresult rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", IMAGE_SVG_XML,
|
||||
contractId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory =
|
||||
do_GetService(contractId.get());
|
||||
nsContentUtils::FindInternalDocumentViewer(
|
||||
nsLiteralCString(IMAGE_SVG_XML));
|
||||
NS_ENSURE_TRUE(docLoaderFactory, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
nsCOMPtr<nsIDocumentViewer> viewer;
|
||||
nsCOMPtr<nsIStreamListener> listener;
|
||||
rv = docLoaderFactory->CreateInstance(
|
||||
nsresult rv = docLoaderFactory->CreateInstance(
|
||||
"external-resource", chan, newLoadGroup, nsLiteralCString(IMAGE_SVG_XML),
|
||||
nullptr, nullptr, getter_AddRefs(listener), getter_AddRefs(viewer));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -14,24 +14,14 @@ UnloadFunc = 'nsLayoutModuleDtor'
|
||||
Priority = 100
|
||||
|
||||
content_types = [
|
||||
'application/ecmascript',
|
||||
'application/javascript',
|
||||
'application/json',
|
||||
'application/mathml+xml',
|
||||
'application/rdf+xml',
|
||||
'application/vnd.wap.xhtml+xml',
|
||||
'application/x-javascript',
|
||||
'application/x-view-source',
|
||||
'application/xhtml+xml',
|
||||
'application/xml',
|
||||
'image/svg+xml',
|
||||
'text/cache-manifest',
|
||||
'text/css',
|
||||
'text/ecmascript',
|
||||
'text/event-stream',
|
||||
'text/html',
|
||||
'text/javascript',
|
||||
'text/json',
|
||||
'text/plain',
|
||||
'text/rdf',
|
||||
'text/vtt',
|
||||
|
@ -61,4 +61,7 @@ add_task(async function test_display_plaintext_type() {
|
||||
await expectOutcome("application/json", "jsonviewer");
|
||||
// NOTE: text/json does not load JSON viewer?
|
||||
await expectOutcome("text/json", "text");
|
||||
|
||||
// Unknown text/ types should be loadable as plain text documents.
|
||||
await expectOutcome("text/unknown-type", "text");
|
||||
});
|
||||
|
@ -166,11 +166,12 @@ HttpIndexViewer.prototype = {
|
||||
|
||||
aChannel.contentType = contentType;
|
||||
|
||||
let contract = Services.catMan.getCategoryEntry(
|
||||
"Gecko-Content-Viewers",
|
||||
contentType
|
||||
);
|
||||
let factory = Cc[contract].getService(Ci.nsIDocumentLoaderFactory);
|
||||
// NOTE: This assumes that both text/html and text/plain will continue to be
|
||||
// handled by nsContentDLF. If this ever changes this logic will need to be
|
||||
// updated.
|
||||
let factory = Cc[
|
||||
"@mozilla.org/content/document-loader-factory;1"
|
||||
].getService(Ci.nsIDocumentLoaderFactory);
|
||||
|
||||
let listener = {};
|
||||
let res = factory.createInstance(
|
||||
|
Loading…
Reference in New Issue
Block a user