Bug 1382783 - Retarget non-HTTP image URIs (chrome, blob) to the image IO thread if not an SVG. r=tnikkel

Currently we only permit requests from HTTP channels to be retargeted to
the image IO thread. It was implemented this way originally in bug
867755 but it does not appear there was a specific reason for that.

The only kink in this is some browser chrome mochitests listen on debug
build only events to ensure certain chrome images are loaded and/or
drawn. As such, this patch ensures that those observer notifications
continue to be served, requiring a dispatch from the image IO thread to
the main thread.

Another issue to note is that SVGs must be processed on the main thread;
the underlying SVG document can only be accessed from it. We enforce
this by checking the content type. The possibility already exists that
an HTTP response could contain the wrong content type, and in that case,
we fail to decode the image, as there is no content sniffing support for
SVG. Thus there should be no additional risk taken by using the image IO
thread from other non-HTTP channels (if they don't specify the SVG
content type, it is not rendered today, and if they do, it will remain
on the main thread as it is today).

We also ignore data URIs. The specification requires that we process
these images sychronously. See bug 1325080 for details.
This commit is contained in:
Andrew Osmond 2017-09-25 11:44:49 -04:00
Родитель c80e124562
Коммит f67ab8c057
4 изменённых файлов: 61 добавлений и 16 удалений

Просмотреть файл

@ -86,6 +86,30 @@ ComputeImageFlags(ImageURL* uri, const nsCString& aMimeType, bool isMultiPart)
return imageFlags;
}
#ifdef DEBUG
static void
NotifyImageLoading(ImageURL* aURI)
{
if (!NS_IsMainThread()) {
RefPtr<ImageURL> uri(aURI);
nsCOMPtr<nsIRunnable> ev =
NS_NewRunnableFunction("NotifyImageLoading", [uri] () -> void {
NotifyImageLoading(uri);
});
SystemGroup::Dispatch(TaskCategory::Other, ev.forget());
return;
}
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_WARNING_ASSERTION(obs, "Can't get an observer service handle");
if (obs) {
nsAutoCString spec;
aURI->GetSpec(spec);
obs->NotifyObservers(nullptr, "image-loading", NS_ConvertUTF8toUTF16(spec).get());
}
}
#endif
/* static */ already_AddRefed<Image>
ImageFactory::CreateImage(nsIRequest* aRequest,
ProgressTracker* aProgressTracker,
@ -102,14 +126,10 @@ ImageFactory::CreateImage(nsIRequest* aRequest,
#ifdef DEBUG
// Record the image load for startup performance testing.
if (NS_IsMainThread()) {
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_WARNING_ASSERTION(obs, "Can't get an observer service handle");
if (obs) {
nsAutoCString spec;
aURI->GetSpec(spec);
obs->NotifyObservers(nullptr, "image-loading", NS_ConvertUTF8toUTF16(spec).get());
}
bool match = false;
if ((NS_SUCCEEDED(aURI->SchemeIs("resource", &match)) && match) ||
(NS_SUCCEEDED(aURI->SchemeIs("chrome", &match)) && match)) {
NotifyImageLoading(aURI);
}
#endif

Просмотреть файл

@ -1700,6 +1700,12 @@ RasterImage::NotifyDrawingObservers()
return;
}
bool match = false;
if ((NS_FAILED(mURI->SchemeIs("resource", &match)) || !match) &&
(NS_FAILED(mURI->SchemeIs("chrome", &match)) || !match)) {
return;
}
// Record the image drawing for startup performance testing.
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_WARNING_ASSERTION(obs, "Can't get an observer service handle");

Просмотреть файл

@ -459,13 +459,26 @@ imgRequest::GetCurrentURI(nsIURI** aURI)
}
bool
imgRequest::IsChrome() const
imgRequest::IsScheme(const char* aScheme) const
{
bool isChrome = false;
if (NS_WARN_IF(NS_FAILED(mURI->SchemeIs("chrome", &isChrome)))) {
MOZ_ASSERT(aScheme);
bool isScheme = false;
if (NS_WARN_IF(NS_FAILED(mURI->SchemeIs(aScheme, &isScheme)))) {
return false;
}
return isChrome;
return isScheme;
}
bool
imgRequest::IsChrome() const
{
return IsScheme("chrome");
}
bool
imgRequest::IsData() const
{
return IsScheme("data");
}
nsresult
@ -819,13 +832,17 @@ imgRequest::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt)
this->Cancel(NS_IMAGELIB_ERROR_FAILURE);
}
// Try to retarget OnDataAvailable to a decode thread.
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
// Try to retarget OnDataAvailable to a decode thread. We must process data
// URIs synchronously as per the spec however.
if (!channel || IsData()) {
return NS_OK;
}
nsCOMPtr<nsIThreadRetargetableRequest> retargetable =
do_QueryInterface(aRequest);
if (httpChannel && retargetable) {
if (retargetable) {
nsAutoCString mimeType;
nsresult rv = httpChannel->GetContentType(mimeType);
nsresult rv = channel->GetContentType(mimeType);
if (NS_SUCCEEDED(rv) && !mimeType.EqualsLiteral(IMAGE_SVG_XML)) {
// Retarget OnDataAvailable to the DecodePool's IO thread.
nsCOMPtr<nsIEventTarget> target =

Просмотреть файл

@ -153,7 +153,9 @@ public:
// OK to use on any thread.
nsresult GetURI(ImageURL** aURI);
nsresult GetCurrentURI(nsIURI** aURI);
bool IsScheme(const char* aScheme) const;
bool IsChrome() const;
bool IsData() const;
nsresult GetImageErrorCode(void);