summaryrefslogtreecommitdiffstats
path: root/widget/IconLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'widget/IconLoader.cpp')
-rw-r--r--widget/IconLoader.cpp132
1 files changed, 132 insertions, 0 deletions
diff --git a/widget/IconLoader.cpp b/widget/IconLoader.cpp
new file mode 100644
index 0000000000..5c0488e3e2
--- /dev/null
+++ b/widget/IconLoader.cpp
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "mozilla/widget/IconLoader.h"
+#include "gfxPlatform.h"
+#include "imgIContainer.h"
+#include "imgLoader.h"
+#include "imgRequestProxy.h"
+#include "mozilla/dom/Document.h"
+#include "nsContentUtils.h"
+#include "nsIContent.h"
+#include "nsIContentPolicy.h"
+
+using namespace mozilla;
+
+namespace mozilla::widget {
+
+NS_IMPL_ISUPPORTS(IconLoader, imgINotificationObserver)
+
+IconLoader::IconLoader(Listener* aListener) : mListener(aListener) {}
+
+IconLoader::~IconLoader() { Destroy(); }
+
+void IconLoader::Destroy() {
+ if (mIconRequest) {
+ mIconRequest->CancelAndForgetObserver(NS_BINDING_ABORTED);
+ mIconRequest = nullptr;
+ }
+ mListener = nullptr;
+}
+
+nsresult IconLoader::LoadIcon(nsIURI* aIconURI, nsINode* aNode,
+ bool aIsInternalIcon) {
+ if (mIconRequest) {
+ // Another icon request is already in flight. Kill it.
+ mIconRequest->CancelWithReason(
+ NS_BINDING_ABORTED, "Another icon request is already in flight"_ns);
+ mIconRequest = nullptr;
+ }
+
+ if (!aNode) {
+ return NS_ERROR_FAILURE;
+ }
+
+ RefPtr<mozilla::dom::Document> document = aNode->OwnerDoc();
+
+ nsCOMPtr<nsILoadGroup> loadGroup = document->GetDocumentLoadGroup();
+ if (!loadGroup) {
+ return NS_ERROR_FAILURE;
+ }
+
+ RefPtr<imgLoader> loader = nsContentUtils::GetImgLoaderForDocument(document);
+ if (!loader) {
+ return NS_ERROR_FAILURE;
+ }
+
+ nsresult rv;
+ if (aIsInternalIcon) {
+ rv = loader->LoadImage(
+ aIconURI, nullptr, nullptr, nullptr, 0, loadGroup, this, nullptr,
+ nullptr, nsIRequest::LOAD_NORMAL, nullptr,
+ nsIContentPolicy::TYPE_INTERNAL_IMAGE, u""_ns,
+ /* aUseUrgentStartForChannel */ false, /* aLinkPreload */ false, 0,
+ getter_AddRefs(mIconRequest));
+ } else {
+ // TODO: nsIContentPolicy::TYPE_INTERNAL_IMAGE may not be the correct
+ // policy. See bug 1691868 for more details.
+ rv = loader->LoadImage(
+ aIconURI, nullptr, nullptr, aNode->NodePrincipal(), 0, loadGroup, this,
+ aNode, document, nsIRequest::LOAD_NORMAL, nullptr,
+ nsIContentPolicy::TYPE_INTERNAL_IMAGE, u""_ns,
+ /* aUseUrgentStartForChannel */ false,
+ /* aLinkPreload */ false, 0, getter_AddRefs(mIconRequest));
+ }
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ return NS_OK;
+}
+
+//
+// imgINotificationObserver
+//
+
+void IconLoader::Notify(imgIRequest* aRequest, int32_t aType,
+ const nsIntRect* aData) {
+ if (aType == imgINotificationObserver::LOAD_COMPLETE) {
+ // Make sure the image loaded successfully.
+ uint32_t status = imgIRequest::STATUS_ERROR;
+ if (NS_FAILED(aRequest->GetImageStatus(&status)) ||
+ (status & imgIRequest::STATUS_ERROR)) {
+ mIconRequest->CancelWithReason(NS_BINDING_ABORTED,
+ "GetImageStatus failed"_ns);
+ mIconRequest = nullptr;
+ return;
+ }
+
+ nsCOMPtr<imgIContainer> image;
+ aRequest->GetImage(getter_AddRefs(image));
+ MOZ_ASSERT(image);
+
+ // Ask the image to decode at its intrinsic size.
+ int32_t width = 0, height = 0;
+ image->GetWidth(&width);
+ image->GetHeight(&height);
+ image->RequestDecodeForSize(nsIntSize(width, height),
+ imgIContainer::FLAG_HIGH_QUALITY_SCALING);
+ }
+
+ if (aType == imgINotificationObserver::FRAME_COMPLETE) {
+ nsCOMPtr<imgIContainer> image;
+ aRequest->GetImage(getter_AddRefs(image));
+ MOZ_ASSERT(image);
+
+ if (mListener) {
+ mListener->OnComplete(image);
+ }
+ return;
+ }
+
+ if (aType == imgINotificationObserver::DECODE_COMPLETE) {
+ if (mIconRequest && mIconRequest == aRequest) {
+ mIconRequest->CancelWithReason(NS_BINDING_ABORTED, "DECODE_COMPLETE"_ns);
+ mIconRequest = nullptr;
+ }
+ }
+}
+
+} // namespace mozilla::widget