Merge mozilla-central to autoland on a CLOSED TREE
[gecko.git] / widget / IconLoader.cpp
blob5c0488e3e21ebcc69474ced1995ec153d228eab2
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/. */
6 #include "mozilla/widget/IconLoader.h"
7 #include "gfxPlatform.h"
8 #include "imgIContainer.h"
9 #include "imgLoader.h"
10 #include "imgRequestProxy.h"
11 #include "mozilla/dom/Document.h"
12 #include "nsContentUtils.h"
13 #include "nsIContent.h"
14 #include "nsIContentPolicy.h"
16 using namespace mozilla;
18 namespace mozilla::widget {
20 NS_IMPL_ISUPPORTS(IconLoader, imgINotificationObserver)
22 IconLoader::IconLoader(Listener* aListener) : mListener(aListener) {}
24 IconLoader::~IconLoader() { Destroy(); }
26 void IconLoader::Destroy() {
27 if (mIconRequest) {
28 mIconRequest->CancelAndForgetObserver(NS_BINDING_ABORTED);
29 mIconRequest = nullptr;
31 mListener = nullptr;
34 nsresult IconLoader::LoadIcon(nsIURI* aIconURI, nsINode* aNode,
35 bool aIsInternalIcon) {
36 if (mIconRequest) {
37 // Another icon request is already in flight. Kill it.
38 mIconRequest->CancelWithReason(
39 NS_BINDING_ABORTED, "Another icon request is already in flight"_ns);
40 mIconRequest = nullptr;
43 if (!aNode) {
44 return NS_ERROR_FAILURE;
47 RefPtr<mozilla::dom::Document> document = aNode->OwnerDoc();
49 nsCOMPtr<nsILoadGroup> loadGroup = document->GetDocumentLoadGroup();
50 if (!loadGroup) {
51 return NS_ERROR_FAILURE;
54 RefPtr<imgLoader> loader = nsContentUtils::GetImgLoaderForDocument(document);
55 if (!loader) {
56 return NS_ERROR_FAILURE;
59 nsresult rv;
60 if (aIsInternalIcon) {
61 rv = loader->LoadImage(
62 aIconURI, nullptr, nullptr, nullptr, 0, loadGroup, this, nullptr,
63 nullptr, nsIRequest::LOAD_NORMAL, nullptr,
64 nsIContentPolicy::TYPE_INTERNAL_IMAGE, u""_ns,
65 /* aUseUrgentStartForChannel */ false, /* aLinkPreload */ false, 0,
66 getter_AddRefs(mIconRequest));
67 } else {
68 // TODO: nsIContentPolicy::TYPE_INTERNAL_IMAGE may not be the correct
69 // policy. See bug 1691868 for more details.
70 rv = loader->LoadImage(
71 aIconURI, nullptr, nullptr, aNode->NodePrincipal(), 0, loadGroup, this,
72 aNode, document, nsIRequest::LOAD_NORMAL, nullptr,
73 nsIContentPolicy::TYPE_INTERNAL_IMAGE, u""_ns,
74 /* aUseUrgentStartForChannel */ false,
75 /* aLinkPreload */ false, 0, getter_AddRefs(mIconRequest));
77 if (NS_FAILED(rv)) {
78 return rv;
81 return NS_OK;
85 // imgINotificationObserver
88 void IconLoader::Notify(imgIRequest* aRequest, int32_t aType,
89 const nsIntRect* aData) {
90 if (aType == imgINotificationObserver::LOAD_COMPLETE) {
91 // Make sure the image loaded successfully.
92 uint32_t status = imgIRequest::STATUS_ERROR;
93 if (NS_FAILED(aRequest->GetImageStatus(&status)) ||
94 (status & imgIRequest::STATUS_ERROR)) {
95 mIconRequest->CancelWithReason(NS_BINDING_ABORTED,
96 "GetImageStatus failed"_ns);
97 mIconRequest = nullptr;
98 return;
101 nsCOMPtr<imgIContainer> image;
102 aRequest->GetImage(getter_AddRefs(image));
103 MOZ_ASSERT(image);
105 // Ask the image to decode at its intrinsic size.
106 int32_t width = 0, height = 0;
107 image->GetWidth(&width);
108 image->GetHeight(&height);
109 image->RequestDecodeForSize(nsIntSize(width, height),
110 imgIContainer::FLAG_HIGH_QUALITY_SCALING);
113 if (aType == imgINotificationObserver::FRAME_COMPLETE) {
114 nsCOMPtr<imgIContainer> image;
115 aRequest->GetImage(getter_AddRefs(image));
116 MOZ_ASSERT(image);
118 if (mListener) {
119 mListener->OnComplete(image);
121 return;
124 if (aType == imgINotificationObserver::DECODE_COMPLETE) {
125 if (mIconRequest && mIconRequest == aRequest) {
126 mIconRequest->CancelWithReason(NS_BINDING_ABORTED, "DECODE_COMPLETE"_ns);
127 mIconRequest = nullptr;
132 } // namespace mozilla::widget