diff options
Diffstat (limited to 'widget/IconLoader.cpp')
-rw-r--r-- | widget/IconLoader.cpp | 132 |
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 |