Files
palemoon27/image/SVGDocumentWrapper.cpp
T
roytam1 9af8eeaf15 import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1125514 - Use jemalloc's metadata statistics to compute bookkeeping. r=glandium (541dbcfc6f)
- Bug 1201462 - Don't count arena allocated metadata once per bin. r=glandium (57e7c31081)
- back some warnings (377df69d65)
- Bug 1219501. In imagelib, initialize the number of cores to at least 1 in case of error. r=seth (3d7d1635f0)
- Bug 1219501. Limit total number of image decoding threads to 32 regardless of number asked for. r=seth (829a7a623d)
- Bug 1213744 (Part 1) - Support zero-size frame rects and detecting the end of the frame in Downscaler. r=tn (05e29075cc)
- Bug 1213744 (Part 2) - Clamp the GIF frame rect to the visible rect for DDD and don't decode outside it. r=tn (8a25e10a3e)
- Bug 1194837. Don't use the inverse orientation matrix when computing the image space invalidate rect. r=seth (cb5e4c2643)
- Bug 1214054 - Don't fire DECODE_COMPLETE in VectorImage::OnSVGDocumetError(). r=dholbert (bb7c34e46f)
- Bug 1195878 - If we detect animation during a full decode, drop the results of the full decode on the floor. r=tn (a765af2b68)
- Bug 1210553 - Remove the alternate flags arguments from SurfaceCache's Lookup functions. r=dholbert (15c6124f98)
- Bug 1217320 - Remove more XPIDL signature comments in .cpp files. r=froydnj (411ac93047)
- Bug 1186796 - Replace nsBaseHashtable::EnumerateRead() calls in image/ with iterators r=njn (665773ae6d)
- Bug 1186792 - Replace nsBaseHashtable::EnumerateRead() calls in hal/ with iterators. r=dhylands. (d57c6b11da)
- Bug 1187142 - Replace nsBaseHashtable::Enumerate() calls in hal/ with iterators. r=dhylands. (ec05c5b125)
- Bug 1186793 - Replace nsBaseHashtable::EnumerateRead() calls in gfx/ with iterators r=njn (9b3cdd92ce)
- Bug 1215900 - Fix clang's -Wimplicit-fallthrough warnings in gfx/ipc/ GfxMessageUtils.h. r=mstange (f55605f1fe)
- Bug 618898 - Part 1: Add WGL_NV_DX_interop. r=jgilbert (73390398ed)
- Bug 618898 - Add D3D11SharedSurfaceInterop. r=jgilbert (3dde956b85)
- Bug 1208513 - Resurrect SharedSurface_GLTexture for use on iOS r=jgilbert (b0fdc90414)
- Bug 1150760 - Don't call workaround unless necessary. - r=kamidphish (9bdd135931)
- Bug 1151106 - let debugger stop on each iteration of a "for(;;)" loop; r=jimb (b1b921c3a7)
- Bug 1223652 - Remove redundant else block after return statement in CGBlockScopeList::findEnclosingScope. r=arai (f1368bfc73)
- Bug 1219515 - IonMonkey: Fix ThrowIfNotConstructing was not declared. r=evilpie (1d6cedad10)
- Bug 1224044 - Use stable hashing in SavedFramePtrHasher r=terrence (4389cf1b70)
- Bug 1206596: Change js::SavedStacks to use mozilla::FastBernoulliTrial. r=fitzgen (1c4a8d1929)
- Bug 1206357: Add mfbt/FastBernoulliTrial.h, implementing efficient random sampling. r=waldo (7143e53dba)
- No bug: Fix comment in mfbt/FastBernoulliTrial.h. DONTBUILD r=me (e3343f8d9d)
- Bug 1217919 - Separate dynamic module scopes from those of function calls r=shu (521f6826e5)
- Bug 1202568 - Cherry-pick warning fixes from upstream double-conversion. r=Ms2ger (ef738f753b)
- add back some disabled android stuff (0351b0c518)
- Bug 1135261 - return new window from window.open in desktop runtime; r=marco,smaug,junior,wesj (fa4d8f2468)
- Bug 898075 - Remove the mozbrowserasyncscroll event from Gecko. r=botond,kanru,sicking (b1fdcb7630)
- namespace (91374d2db8)
2022-12-30 09:29:16 +08:00

427 lines
11 KiB
C++

/* -*- 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 "SVGDocumentWrapper.h"
#include "mozilla/dom/Element.h"
#include "nsICategoryManager.h"
#include "nsIChannel.h"
#include "nsIContentViewer.h"
#include "nsIDocument.h"
#include "nsIDocumentLoaderFactory.h"
#include "nsIDOMSVGLength.h"
#include "nsIHttpChannel.h"
#include "nsIObserverService.h"
#include "nsIParser.h"
#include "nsIPresShell.h"
#include "nsIRequest.h"
#include "nsIStreamListener.h"
#include "nsIXMLContentSink.h"
#include "nsNetCID.h"
#include "nsComponentManagerUtils.h"
#include "nsSMILAnimationController.h"
#include "nsServiceManagerUtils.h"
#include "mozilla/dom/SVGSVGElement.h"
#include "nsSVGEffects.h"
#include "mozilla/dom/SVGAnimatedLength.h"
#include "nsMimeTypes.h"
#include "DOMSVGLength.h"
#include "nsDocument.h"
// undef the GetCurrentTime macro defined in WinBase.h from the MS Platform SDK
#undef GetCurrentTime
namespace mozilla {
using namespace dom;
using namespace gfx;
namespace image {
NS_IMPL_ISUPPORTS(SVGDocumentWrapper,
nsIStreamListener,
nsIRequestObserver,
nsIObserver,
nsISupportsWeakReference)
SVGDocumentWrapper::SVGDocumentWrapper()
: mIgnoreInvalidation(false),
mRegisteredForXPCOMShutdown(false)
{ }
SVGDocumentWrapper::~SVGDocumentWrapper()
{
DestroyViewer();
if (mRegisteredForXPCOMShutdown) {
UnregisterForXPCOMShutdown();
}
}
void
SVGDocumentWrapper::DestroyViewer()
{
if (mViewer) {
mViewer->GetDocument()->OnPageHide(false, nullptr);
mViewer->Close(nullptr);
mViewer->Destroy();
mViewer = nullptr;
}
}
nsIFrame*
SVGDocumentWrapper::GetRootLayoutFrame()
{
Element* rootElem = GetRootSVGElem();
return rootElem ? rootElem->GetPrimaryFrame() : nullptr;
}
void
SVGDocumentWrapper::UpdateViewportBounds(const nsIntSize& aViewportSize)
{
MOZ_ASSERT(!mIgnoreInvalidation, "shouldn't be reentrant");
mIgnoreInvalidation = true;
nsIntRect currentBounds;
mViewer->GetBounds(currentBounds);
// If the bounds have changed, we need to do a layout flush.
if (currentBounds.Size() != aViewportSize) {
mViewer->SetBounds(IntRect(IntPoint(0, 0), aViewportSize));
FlushLayout();
}
mIgnoreInvalidation = false;
}
void
SVGDocumentWrapper::FlushImageTransformInvalidation()
{
MOZ_ASSERT(!mIgnoreInvalidation, "shouldn't be reentrant");
SVGSVGElement* svgElem = GetRootSVGElem();
if (!svgElem) {
return;
}
mIgnoreInvalidation = true;
svgElem->FlushImageTransformInvalidation();
FlushLayout();
mIgnoreInvalidation = false;
}
bool
SVGDocumentWrapper::IsAnimated()
{
nsIDocument* doc = mViewer->GetDocument();
return doc && doc->HasAnimationController() &&
doc->GetAnimationController()->HasRegisteredAnimations();
}
void
SVGDocumentWrapper::StartAnimation()
{
// Can be called for animated images during shutdown, after we've
// already Observe()'d XPCOM shutdown and cleared out our mViewer pointer.
if (!mViewer) {
return;
}
nsIDocument* doc = mViewer->GetDocument();
if (doc) {
nsSMILAnimationController* controller = doc->GetAnimationController();
if (controller) {
controller->Resume(nsSMILTimeContainer::PAUSE_IMAGE);
}
doc->SetImagesNeedAnimating(true);
}
}
void
SVGDocumentWrapper::StopAnimation()
{
// Can be called for animated images during shutdown, after we've
// already Observe()'d XPCOM shutdown and cleared out our mViewer pointer.
if (!mViewer) {
return;
}
nsIDocument* doc = mViewer->GetDocument();
if (doc) {
nsSMILAnimationController* controller = doc->GetAnimationController();
if (controller) {
controller->Pause(nsSMILTimeContainer::PAUSE_IMAGE);
}
doc->SetImagesNeedAnimating(false);
}
}
void
SVGDocumentWrapper::ResetAnimation()
{
SVGSVGElement* svgElem = GetRootSVGElem();
if (!svgElem) {
return;
}
svgElem->SetCurrentTime(0.0f);
}
float
SVGDocumentWrapper::GetCurrentTime()
{
SVGSVGElement* svgElem = GetRootSVGElem();
return svgElem ? svgElem->GetCurrentTime()
: 0.0f;
}
void
SVGDocumentWrapper::SetCurrentTime(float aTime)
{
SVGSVGElement* svgElem = GetRootSVGElem();
if (svgElem && svgElem->GetCurrentTime() != aTime) {
svgElem->SetCurrentTime(aTime);
}
}
void
SVGDocumentWrapper::TickRefreshDriver()
{
nsCOMPtr<nsIPresShell> presShell;
mViewer->GetPresShell(getter_AddRefs(presShell));
if (presShell) {
nsPresContext* presContext = presShell->GetPresContext();
if (presContext) {
presContext->RefreshDriver()->DoTick();
}
}
}
/** nsIStreamListener methods **/
NS_IMETHODIMP
SVGDocumentWrapper::OnDataAvailable(nsIRequest* aRequest, nsISupports* ctxt,
nsIInputStream* inStr,
uint64_t sourceOffset,
uint32_t count)
{
return mListener->OnDataAvailable(aRequest, ctxt, inStr,
sourceOffset, count);
}
/** nsIRequestObserver methods **/
NS_IMETHODIMP
SVGDocumentWrapper::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt)
{
nsresult rv = SetupViewer(aRequest,
getter_AddRefs(mViewer),
getter_AddRefs(mLoadGroup));
if (NS_SUCCEEDED(rv) &&
NS_SUCCEEDED(mListener->OnStartRequest(aRequest, nullptr))) {
mViewer->GetDocument()->SetIsBeingUsedAsImage();
StopAnimation(); // otherwise animations start automatically in helper doc
rv = mViewer->Init(nullptr, nsIntRect(0, 0, 0, 0));
if (NS_SUCCEEDED(rv)) {
rv = mViewer->Open(nullptr, nullptr);
}
}
return rv;
}
NS_IMETHODIMP
SVGDocumentWrapper::OnStopRequest(nsIRequest* aRequest, nsISupports* ctxt,
nsresult status)
{
if (mListener) {
mListener->OnStopRequest(aRequest, ctxt, status);
mListener = nullptr;
}
return NS_OK;
}
/** nsIObserver Methods **/
NS_IMETHODIMP
SVGDocumentWrapper::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
// Sever ties from rendering observers to helper-doc's root SVG node
SVGSVGElement* svgElem = GetRootSVGElem();
if (svgElem) {
nsSVGEffects::RemoveAllRenderingObservers(svgElem);
}
// Clean up at XPCOM shutdown time.
DestroyViewer();
if (mListener) {
mListener = nullptr;
}
if (mLoadGroup) {
mLoadGroup = nullptr;
}
// Turn off "registered" flag, or else we'll try to unregister when we die.
// (No need for that now, and the try would fail anyway -- it's too late.)
mRegisteredForXPCOMShutdown = false;
} else {
NS_ERROR("Unexpected observer topic.");
}
return NS_OK;
}
/** Private helper methods **/
// This method is largely cribbed from
// nsExternalResourceMap::PendingLoad::SetupViewer.
nsresult
SVGDocumentWrapper::SetupViewer(nsIRequest* aRequest,
nsIContentViewer** aViewer,
nsILoadGroup** aLoadGroup)
{
nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
NS_ENSURE_TRUE(chan, NS_ERROR_UNEXPECTED);
// Check for HTTP error page
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
if (httpChannel) {
bool requestSucceeded;
if (NS_FAILED(httpChannel->GetRequestSucceeded(&requestSucceeded)) ||
!requestSucceeded) {
return NS_ERROR_FAILURE;
}
}
// Give this document its own loadgroup
nsCOMPtr<nsILoadGroup> loadGroup;
chan->GetLoadGroup(getter_AddRefs(loadGroup));
nsCOMPtr<nsILoadGroup> newLoadGroup =
do_CreateInstance(NS_LOADGROUP_CONTRACTID);
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);
nsXPIDLCString contractId;
nsresult rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", IMAGE_SVG_XML,
getter_Copies(contractId));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory =
do_GetService(contractId);
NS_ENSURE_TRUE(docLoaderFactory, NS_ERROR_NOT_AVAILABLE);
nsCOMPtr<nsIContentViewer> viewer;
nsCOMPtr<nsIStreamListener> listener;
rv = docLoaderFactory->CreateInstance("external-resource", chan,
newLoadGroup,
NS_LITERAL_CSTRING(IMAGE_SVG_XML),
nullptr, nullptr,
getter_AddRefs(listener),
getter_AddRefs(viewer));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(viewer, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIParser> parser = do_QueryInterface(listener);
NS_ENSURE_TRUE(parser, NS_ERROR_UNEXPECTED);
// XML-only, because this is for SVG content
nsIContentSink* sink = parser->GetContentSink();
nsCOMPtr<nsIXMLContentSink> xmlSink = do_QueryInterface(sink);
NS_ENSURE_TRUE(sink, NS_ERROR_UNEXPECTED);
listener.swap(mListener);
viewer.forget(aViewer);
newLoadGroup.forget(aLoadGroup);
RegisterForXPCOMShutdown();
return NS_OK;
}
void
SVGDocumentWrapper::RegisterForXPCOMShutdown()
{
MOZ_ASSERT(!mRegisteredForXPCOMShutdown,
"re-registering for XPCOM shutdown");
// Listen for xpcom-shutdown so that we can drop references to our
// helper-document at that point. (Otherwise, we won't get cleaned up
// until imgLoader::Shutdown, which can happen after the JAR service
// and RDF service have been unregistered.)
nsresult rv;
nsCOMPtr<nsIObserverService> obsSvc = do_GetService(OBSERVER_SVC_CID, &rv);
if (NS_FAILED(rv) ||
NS_FAILED(obsSvc->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
true))) {
NS_WARNING("Failed to register as observer of XPCOM shutdown");
} else {
mRegisteredForXPCOMShutdown = true;
}
}
void
SVGDocumentWrapper::UnregisterForXPCOMShutdown()
{
MOZ_ASSERT(mRegisteredForXPCOMShutdown,
"unregistering for XPCOM shutdown w/out being registered");
nsresult rv;
nsCOMPtr<nsIObserverService> obsSvc = do_GetService(OBSERVER_SVC_CID, &rv);
if (NS_FAILED(rv) ||
NS_FAILED(obsSvc->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
NS_WARNING("Failed to unregister as observer of XPCOM shutdown");
} else {
mRegisteredForXPCOMShutdown = false;
}
}
void
SVGDocumentWrapper::FlushLayout()
{
nsCOMPtr<nsIPresShell> presShell;
mViewer->GetPresShell(getter_AddRefs(presShell));
if (presShell) {
presShell->FlushPendingNotifications(Flush_Layout);
}
}
nsIDocument*
SVGDocumentWrapper::GetDocument()
{
if (!mViewer) {
return nullptr;
}
return mViewer->GetDocument(); // May be nullptr.
}
SVGSVGElement*
SVGDocumentWrapper::GetRootSVGElem()
{
if (!mViewer) {
return nullptr; // Can happen during destruction
}
nsIDocument* doc = mViewer->GetDocument();
if (!doc) {
return nullptr; // Can happen during destruction
}
Element* rootElem = mViewer->GetDocument()->GetRootElement();
if (!rootElem || !rootElem->IsSVGElement(nsGkAtoms::svg)) {
return nullptr;
}
return static_cast<SVGSVGElement*>(rootElem);
}
} // namespace image
} // namespace mozilla