Thu, 15 Jan 2015 15:59:08 +0100
Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #include "SVGDocumentWrapper.h" |
michael@0 | 7 | |
michael@0 | 8 | #include "mozilla/dom/Element.h" |
michael@0 | 9 | #include "nsICategoryManager.h" |
michael@0 | 10 | #include "nsIChannel.h" |
michael@0 | 11 | #include "nsIContentViewer.h" |
michael@0 | 12 | #include "nsIDocument.h" |
michael@0 | 13 | #include "nsIDocumentLoaderFactory.h" |
michael@0 | 14 | #include "nsIDOMSVGLength.h" |
michael@0 | 15 | #include "nsIHttpChannel.h" |
michael@0 | 16 | #include "nsIObserverService.h" |
michael@0 | 17 | #include "nsIParser.h" |
michael@0 | 18 | #include "nsIPresShell.h" |
michael@0 | 19 | #include "nsIRequest.h" |
michael@0 | 20 | #include "nsIStreamListener.h" |
michael@0 | 21 | #include "nsIXMLContentSink.h" |
michael@0 | 22 | #include "nsNetCID.h" |
michael@0 | 23 | #include "nsComponentManagerUtils.h" |
michael@0 | 24 | #include "nsSMILAnimationController.h" |
michael@0 | 25 | #include "nsServiceManagerUtils.h" |
michael@0 | 26 | #include "mozilla/dom/SVGSVGElement.h" |
michael@0 | 27 | #include "nsSVGEffects.h" |
michael@0 | 28 | #include "mozilla/dom/SVGAnimatedLength.h" |
michael@0 | 29 | #include "nsMimeTypes.h" |
michael@0 | 30 | #include "DOMSVGLength.h" |
michael@0 | 31 | |
michael@0 | 32 | // undef the GetCurrentTime macro defined in WinBase.h from the MS Platform SDK |
michael@0 | 33 | #undef GetCurrentTime |
michael@0 | 34 | |
michael@0 | 35 | using namespace mozilla::dom; |
michael@0 | 36 | |
michael@0 | 37 | namespace mozilla { |
michael@0 | 38 | namespace image { |
michael@0 | 39 | |
michael@0 | 40 | NS_IMPL_ISUPPORTS(SVGDocumentWrapper, |
michael@0 | 41 | nsIStreamListener, |
michael@0 | 42 | nsIRequestObserver, |
michael@0 | 43 | nsIObserver, |
michael@0 | 44 | nsISupportsWeakReference) |
michael@0 | 45 | |
michael@0 | 46 | SVGDocumentWrapper::SVGDocumentWrapper() |
michael@0 | 47 | : mIgnoreInvalidation(false), |
michael@0 | 48 | mRegisteredForXPCOMShutdown(false) |
michael@0 | 49 | { |
michael@0 | 50 | } |
michael@0 | 51 | |
michael@0 | 52 | SVGDocumentWrapper::~SVGDocumentWrapper() |
michael@0 | 53 | { |
michael@0 | 54 | DestroyViewer(); |
michael@0 | 55 | if (mRegisteredForXPCOMShutdown) { |
michael@0 | 56 | UnregisterForXPCOMShutdown(); |
michael@0 | 57 | } |
michael@0 | 58 | } |
michael@0 | 59 | |
michael@0 | 60 | void |
michael@0 | 61 | SVGDocumentWrapper::DestroyViewer() |
michael@0 | 62 | { |
michael@0 | 63 | if (mViewer) { |
michael@0 | 64 | mViewer->GetDocument()->OnPageHide(false, nullptr); |
michael@0 | 65 | mViewer->Close(nullptr); |
michael@0 | 66 | mViewer->Destroy(); |
michael@0 | 67 | mViewer = nullptr; |
michael@0 | 68 | } |
michael@0 | 69 | } |
michael@0 | 70 | |
michael@0 | 71 | bool |
michael@0 | 72 | SVGDocumentWrapper::GetWidthOrHeight(Dimension aDimension, |
michael@0 | 73 | int32_t& aResult) |
michael@0 | 74 | { |
michael@0 | 75 | SVGSVGElement* rootElem = GetRootSVGElem(); |
michael@0 | 76 | NS_ABORT_IF_FALSE(rootElem, "root elem missing or of wrong type"); |
michael@0 | 77 | |
michael@0 | 78 | // Get the width or height SVG object |
michael@0 | 79 | nsRefPtr<SVGAnimatedLength> domAnimLength; |
michael@0 | 80 | if (aDimension == eWidth) { |
michael@0 | 81 | domAnimLength = rootElem->Width(); |
michael@0 | 82 | } else { |
michael@0 | 83 | NS_ABORT_IF_FALSE(aDimension == eHeight, "invalid dimension"); |
michael@0 | 84 | domAnimLength = rootElem->Height(); |
michael@0 | 85 | } |
michael@0 | 86 | NS_ENSURE_TRUE(domAnimLength, false); |
michael@0 | 87 | |
michael@0 | 88 | // Get the animated value from the object |
michael@0 | 89 | nsRefPtr<DOMSVGLength> domLength = domAnimLength->AnimVal(); |
michael@0 | 90 | NS_ENSURE_TRUE(domLength, false); |
michael@0 | 91 | |
michael@0 | 92 | // Check if it's a percent value (and fail if so) |
michael@0 | 93 | uint16_t unitType; |
michael@0 | 94 | nsresult rv = domLength->GetUnitType(&unitType); |
michael@0 | 95 | NS_ENSURE_SUCCESS(rv, false); |
michael@0 | 96 | if (unitType == nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE) { |
michael@0 | 97 | return false; |
michael@0 | 98 | } |
michael@0 | 99 | |
michael@0 | 100 | // Non-percent value - woot! Grab it & return it. |
michael@0 | 101 | float floatLength; |
michael@0 | 102 | rv = domLength->GetValue(&floatLength); |
michael@0 | 103 | NS_ENSURE_SUCCESS(rv, false); |
michael@0 | 104 | |
michael@0 | 105 | aResult = nsSVGUtils::ClampToInt(floatLength); |
michael@0 | 106 | |
michael@0 | 107 | return true; |
michael@0 | 108 | } |
michael@0 | 109 | |
michael@0 | 110 | nsIFrame* |
michael@0 | 111 | SVGDocumentWrapper::GetRootLayoutFrame() |
michael@0 | 112 | { |
michael@0 | 113 | Element* rootElem = GetRootSVGElem(); |
michael@0 | 114 | return rootElem ? rootElem->GetPrimaryFrame() : nullptr; |
michael@0 | 115 | } |
michael@0 | 116 | |
michael@0 | 117 | void |
michael@0 | 118 | SVGDocumentWrapper::UpdateViewportBounds(const nsIntSize& aViewportSize) |
michael@0 | 119 | { |
michael@0 | 120 | NS_ABORT_IF_FALSE(!mIgnoreInvalidation, "shouldn't be reentrant"); |
michael@0 | 121 | mIgnoreInvalidation = true; |
michael@0 | 122 | |
michael@0 | 123 | nsIntRect currentBounds; |
michael@0 | 124 | mViewer->GetBounds(currentBounds); |
michael@0 | 125 | |
michael@0 | 126 | // If the bounds have changed, we need to do a layout flush. |
michael@0 | 127 | if (currentBounds.Size() != aViewportSize) { |
michael@0 | 128 | mViewer->SetBounds(nsIntRect(nsIntPoint(0, 0), aViewportSize)); |
michael@0 | 129 | FlushLayout(); |
michael@0 | 130 | } |
michael@0 | 131 | |
michael@0 | 132 | mIgnoreInvalidation = false; |
michael@0 | 133 | } |
michael@0 | 134 | |
michael@0 | 135 | void |
michael@0 | 136 | SVGDocumentWrapper::FlushImageTransformInvalidation() |
michael@0 | 137 | { |
michael@0 | 138 | NS_ABORT_IF_FALSE(!mIgnoreInvalidation, "shouldn't be reentrant"); |
michael@0 | 139 | |
michael@0 | 140 | SVGSVGElement* svgElem = GetRootSVGElem(); |
michael@0 | 141 | if (!svgElem) |
michael@0 | 142 | return; |
michael@0 | 143 | |
michael@0 | 144 | mIgnoreInvalidation = true; |
michael@0 | 145 | svgElem->FlushImageTransformInvalidation(); |
michael@0 | 146 | FlushLayout(); |
michael@0 | 147 | mIgnoreInvalidation = false; |
michael@0 | 148 | } |
michael@0 | 149 | |
michael@0 | 150 | bool |
michael@0 | 151 | SVGDocumentWrapper::IsAnimated() |
michael@0 | 152 | { |
michael@0 | 153 | nsIDocument* doc = mViewer->GetDocument(); |
michael@0 | 154 | return doc && doc->HasAnimationController() && |
michael@0 | 155 | doc->GetAnimationController()->HasRegisteredAnimations(); |
michael@0 | 156 | } |
michael@0 | 157 | |
michael@0 | 158 | void |
michael@0 | 159 | SVGDocumentWrapper::StartAnimation() |
michael@0 | 160 | { |
michael@0 | 161 | // Can be called for animated images during shutdown, after we've |
michael@0 | 162 | // already Observe()'d XPCOM shutdown and cleared out our mViewer pointer. |
michael@0 | 163 | if (!mViewer) |
michael@0 | 164 | return; |
michael@0 | 165 | |
michael@0 | 166 | nsIDocument* doc = mViewer->GetDocument(); |
michael@0 | 167 | if (doc) { |
michael@0 | 168 | nsSMILAnimationController* controller = doc->GetAnimationController(); |
michael@0 | 169 | if (controller) { |
michael@0 | 170 | controller->Resume(nsSMILTimeContainer::PAUSE_IMAGE); |
michael@0 | 171 | } |
michael@0 | 172 | doc->SetImagesNeedAnimating(true); |
michael@0 | 173 | } |
michael@0 | 174 | } |
michael@0 | 175 | |
michael@0 | 176 | void |
michael@0 | 177 | SVGDocumentWrapper::StopAnimation() |
michael@0 | 178 | { |
michael@0 | 179 | // Can be called for animated images during shutdown, after we've |
michael@0 | 180 | // already Observe()'d XPCOM shutdown and cleared out our mViewer pointer. |
michael@0 | 181 | if (!mViewer) |
michael@0 | 182 | return; |
michael@0 | 183 | |
michael@0 | 184 | nsIDocument* doc = mViewer->GetDocument(); |
michael@0 | 185 | if (doc) { |
michael@0 | 186 | nsSMILAnimationController* controller = doc->GetAnimationController(); |
michael@0 | 187 | if (controller) { |
michael@0 | 188 | controller->Pause(nsSMILTimeContainer::PAUSE_IMAGE); |
michael@0 | 189 | } |
michael@0 | 190 | doc->SetImagesNeedAnimating(false); |
michael@0 | 191 | } |
michael@0 | 192 | } |
michael@0 | 193 | |
michael@0 | 194 | void |
michael@0 | 195 | SVGDocumentWrapper::ResetAnimation() |
michael@0 | 196 | { |
michael@0 | 197 | SVGSVGElement* svgElem = GetRootSVGElem(); |
michael@0 | 198 | if (!svgElem) |
michael@0 | 199 | return; |
michael@0 | 200 | |
michael@0 | 201 | svgElem->SetCurrentTime(0.0f); |
michael@0 | 202 | } |
michael@0 | 203 | |
michael@0 | 204 | float |
michael@0 | 205 | SVGDocumentWrapper::GetCurrentTime() |
michael@0 | 206 | { |
michael@0 | 207 | SVGSVGElement* svgElem = GetRootSVGElem(); |
michael@0 | 208 | return svgElem ? svgElem->GetCurrentTime() |
michael@0 | 209 | : 0.0f; |
michael@0 | 210 | } |
michael@0 | 211 | |
michael@0 | 212 | void |
michael@0 | 213 | SVGDocumentWrapper::SetCurrentTime(float aTime) |
michael@0 | 214 | { |
michael@0 | 215 | SVGSVGElement* svgElem = GetRootSVGElem(); |
michael@0 | 216 | if (svgElem && svgElem->GetCurrentTime() != aTime) { |
michael@0 | 217 | svgElem->SetCurrentTime(aTime); |
michael@0 | 218 | } |
michael@0 | 219 | } |
michael@0 | 220 | |
michael@0 | 221 | /** nsIStreamListener methods **/ |
michael@0 | 222 | |
michael@0 | 223 | /* void onDataAvailable (in nsIRequest request, in nsISupports ctxt, |
michael@0 | 224 | in nsIInputStream inStr, in unsigned long sourceOffset, |
michael@0 | 225 | in unsigned long count); */ |
michael@0 | 226 | NS_IMETHODIMP |
michael@0 | 227 | SVGDocumentWrapper::OnDataAvailable(nsIRequest* aRequest, nsISupports* ctxt, |
michael@0 | 228 | nsIInputStream* inStr, |
michael@0 | 229 | uint64_t sourceOffset, |
michael@0 | 230 | uint32_t count) |
michael@0 | 231 | { |
michael@0 | 232 | return mListener->OnDataAvailable(aRequest, ctxt, inStr, |
michael@0 | 233 | sourceOffset, count); |
michael@0 | 234 | } |
michael@0 | 235 | |
michael@0 | 236 | /** nsIRequestObserver methods **/ |
michael@0 | 237 | |
michael@0 | 238 | /* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */ |
michael@0 | 239 | NS_IMETHODIMP |
michael@0 | 240 | SVGDocumentWrapper::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt) |
michael@0 | 241 | { |
michael@0 | 242 | nsresult rv = SetupViewer(aRequest, |
michael@0 | 243 | getter_AddRefs(mViewer), |
michael@0 | 244 | getter_AddRefs(mLoadGroup)); |
michael@0 | 245 | |
michael@0 | 246 | if (NS_SUCCEEDED(rv) && |
michael@0 | 247 | NS_SUCCEEDED(mListener->OnStartRequest(aRequest, nullptr))) { |
michael@0 | 248 | mViewer->GetDocument()->SetIsBeingUsedAsImage(); |
michael@0 | 249 | StopAnimation(); // otherwise animations start automatically in helper doc |
michael@0 | 250 | |
michael@0 | 251 | rv = mViewer->Init(nullptr, nsIntRect(0, 0, 0, 0)); |
michael@0 | 252 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 253 | rv = mViewer->Open(nullptr, nullptr); |
michael@0 | 254 | } |
michael@0 | 255 | } |
michael@0 | 256 | return rv; |
michael@0 | 257 | } |
michael@0 | 258 | |
michael@0 | 259 | |
michael@0 | 260 | /* void onStopRequest (in nsIRequest request, in nsISupports ctxt, |
michael@0 | 261 | in nsresult status); */ |
michael@0 | 262 | NS_IMETHODIMP |
michael@0 | 263 | SVGDocumentWrapper::OnStopRequest(nsIRequest* aRequest, nsISupports* ctxt, |
michael@0 | 264 | nsresult status) |
michael@0 | 265 | { |
michael@0 | 266 | if (mListener) { |
michael@0 | 267 | mListener->OnStopRequest(aRequest, ctxt, status); |
michael@0 | 268 | mListener = nullptr; |
michael@0 | 269 | } |
michael@0 | 270 | |
michael@0 | 271 | return NS_OK; |
michael@0 | 272 | } |
michael@0 | 273 | |
michael@0 | 274 | /** nsIObserver Methods **/ |
michael@0 | 275 | NS_IMETHODIMP |
michael@0 | 276 | SVGDocumentWrapper::Observe(nsISupports* aSubject, |
michael@0 | 277 | const char* aTopic, |
michael@0 | 278 | const char16_t *aData) |
michael@0 | 279 | { |
michael@0 | 280 | if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { |
michael@0 | 281 | // Sever ties from rendering observers to helper-doc's root SVG node |
michael@0 | 282 | SVGSVGElement* svgElem = GetRootSVGElem(); |
michael@0 | 283 | if (svgElem) { |
michael@0 | 284 | nsSVGEffects::RemoveAllRenderingObservers(svgElem); |
michael@0 | 285 | } |
michael@0 | 286 | |
michael@0 | 287 | // Clean up at XPCOM shutdown time. |
michael@0 | 288 | DestroyViewer(); |
michael@0 | 289 | if (mListener) |
michael@0 | 290 | mListener = nullptr; |
michael@0 | 291 | if (mLoadGroup) |
michael@0 | 292 | mLoadGroup = nullptr; |
michael@0 | 293 | |
michael@0 | 294 | // Turn off "registered" flag, or else we'll try to unregister when we die. |
michael@0 | 295 | // (No need for that now, and the try would fail anyway -- it's too late.) |
michael@0 | 296 | mRegisteredForXPCOMShutdown = false; |
michael@0 | 297 | } else { |
michael@0 | 298 | NS_ERROR("Unexpected observer topic."); |
michael@0 | 299 | } |
michael@0 | 300 | return NS_OK; |
michael@0 | 301 | } |
michael@0 | 302 | |
michael@0 | 303 | /** Private helper methods **/ |
michael@0 | 304 | |
michael@0 | 305 | // This method is largely cribbed from |
michael@0 | 306 | // nsExternalResourceMap::PendingLoad::SetupViewer. |
michael@0 | 307 | nsresult |
michael@0 | 308 | SVGDocumentWrapper::SetupViewer(nsIRequest* aRequest, |
michael@0 | 309 | nsIContentViewer** aViewer, |
michael@0 | 310 | nsILoadGroup** aLoadGroup) |
michael@0 | 311 | { |
michael@0 | 312 | nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest)); |
michael@0 | 313 | NS_ENSURE_TRUE(chan, NS_ERROR_UNEXPECTED); |
michael@0 | 314 | |
michael@0 | 315 | // Check for HTTP error page |
michael@0 | 316 | nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest)); |
michael@0 | 317 | if (httpChannel) { |
michael@0 | 318 | bool requestSucceeded; |
michael@0 | 319 | if (NS_FAILED(httpChannel->GetRequestSucceeded(&requestSucceeded)) || |
michael@0 | 320 | !requestSucceeded) { |
michael@0 | 321 | return NS_ERROR_FAILURE; |
michael@0 | 322 | } |
michael@0 | 323 | } |
michael@0 | 324 | |
michael@0 | 325 | // Give this document its own loadgroup |
michael@0 | 326 | nsCOMPtr<nsILoadGroup> loadGroup; |
michael@0 | 327 | chan->GetLoadGroup(getter_AddRefs(loadGroup)); |
michael@0 | 328 | |
michael@0 | 329 | nsCOMPtr<nsILoadGroup> newLoadGroup = |
michael@0 | 330 | do_CreateInstance(NS_LOADGROUP_CONTRACTID); |
michael@0 | 331 | NS_ENSURE_TRUE(newLoadGroup, NS_ERROR_OUT_OF_MEMORY); |
michael@0 | 332 | newLoadGroup->SetLoadGroup(loadGroup); |
michael@0 | 333 | |
michael@0 | 334 | nsCOMPtr<nsICategoryManager> catMan = |
michael@0 | 335 | do_GetService(NS_CATEGORYMANAGER_CONTRACTID); |
michael@0 | 336 | NS_ENSURE_TRUE(catMan, NS_ERROR_NOT_AVAILABLE); |
michael@0 | 337 | nsXPIDLCString contractId; |
michael@0 | 338 | nsresult rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", IMAGE_SVG_XML, |
michael@0 | 339 | getter_Copies(contractId)); |
michael@0 | 340 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 341 | nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory = |
michael@0 | 342 | do_GetService(contractId); |
michael@0 | 343 | NS_ENSURE_TRUE(docLoaderFactory, NS_ERROR_NOT_AVAILABLE); |
michael@0 | 344 | |
michael@0 | 345 | nsCOMPtr<nsIContentViewer> viewer; |
michael@0 | 346 | nsCOMPtr<nsIStreamListener> listener; |
michael@0 | 347 | rv = docLoaderFactory->CreateInstance("external-resource", chan, |
michael@0 | 348 | newLoadGroup, |
michael@0 | 349 | IMAGE_SVG_XML, nullptr, nullptr, |
michael@0 | 350 | getter_AddRefs(listener), |
michael@0 | 351 | getter_AddRefs(viewer)); |
michael@0 | 352 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 353 | |
michael@0 | 354 | NS_ENSURE_TRUE(viewer, NS_ERROR_UNEXPECTED); |
michael@0 | 355 | |
michael@0 | 356 | nsCOMPtr<nsIParser> parser = do_QueryInterface(listener); |
michael@0 | 357 | NS_ENSURE_TRUE(parser, NS_ERROR_UNEXPECTED); |
michael@0 | 358 | |
michael@0 | 359 | // XML-only, because this is for SVG content |
michael@0 | 360 | nsIContentSink* sink = parser->GetContentSink(); |
michael@0 | 361 | nsCOMPtr<nsIXMLContentSink> xmlSink = do_QueryInterface(sink); |
michael@0 | 362 | NS_ENSURE_TRUE(sink, NS_ERROR_UNEXPECTED); |
michael@0 | 363 | |
michael@0 | 364 | listener.swap(mListener); |
michael@0 | 365 | viewer.forget(aViewer); |
michael@0 | 366 | newLoadGroup.forget(aLoadGroup); |
michael@0 | 367 | |
michael@0 | 368 | RegisterForXPCOMShutdown(); |
michael@0 | 369 | return NS_OK; |
michael@0 | 370 | } |
michael@0 | 371 | |
michael@0 | 372 | void |
michael@0 | 373 | SVGDocumentWrapper::RegisterForXPCOMShutdown() |
michael@0 | 374 | { |
michael@0 | 375 | NS_ABORT_IF_FALSE(!mRegisteredForXPCOMShutdown, |
michael@0 | 376 | "re-registering for XPCOM shutdown"); |
michael@0 | 377 | // Listen for xpcom-shutdown so that we can drop references to our |
michael@0 | 378 | // helper-document at that point. (Otherwise, we won't get cleaned up |
michael@0 | 379 | // until imgLoader::Shutdown, which can happen after the JAR service |
michael@0 | 380 | // and RDF service have been unregistered.) |
michael@0 | 381 | nsresult rv; |
michael@0 | 382 | nsCOMPtr<nsIObserverService> obsSvc = do_GetService(OBSERVER_SVC_CID, &rv); |
michael@0 | 383 | if (NS_FAILED(rv) || |
michael@0 | 384 | NS_FAILED(obsSvc->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, |
michael@0 | 385 | true))) { |
michael@0 | 386 | NS_WARNING("Failed to register as observer of XPCOM shutdown"); |
michael@0 | 387 | } else { |
michael@0 | 388 | mRegisteredForXPCOMShutdown = true; |
michael@0 | 389 | } |
michael@0 | 390 | } |
michael@0 | 391 | |
michael@0 | 392 | void |
michael@0 | 393 | SVGDocumentWrapper::UnregisterForXPCOMShutdown() |
michael@0 | 394 | { |
michael@0 | 395 | NS_ABORT_IF_FALSE(mRegisteredForXPCOMShutdown, |
michael@0 | 396 | "unregistering for XPCOM shutdown w/out being registered"); |
michael@0 | 397 | |
michael@0 | 398 | nsresult rv; |
michael@0 | 399 | nsCOMPtr<nsIObserverService> obsSvc = do_GetService(OBSERVER_SVC_CID, &rv); |
michael@0 | 400 | if (NS_FAILED(rv) || |
michael@0 | 401 | NS_FAILED(obsSvc->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) { |
michael@0 | 402 | NS_WARNING("Failed to unregister as observer of XPCOM shutdown"); |
michael@0 | 403 | } else { |
michael@0 | 404 | mRegisteredForXPCOMShutdown = false; |
michael@0 | 405 | } |
michael@0 | 406 | } |
michael@0 | 407 | |
michael@0 | 408 | void |
michael@0 | 409 | SVGDocumentWrapper::FlushLayout() |
michael@0 | 410 | { |
michael@0 | 411 | nsCOMPtr<nsIPresShell> presShell; |
michael@0 | 412 | mViewer->GetPresShell(getter_AddRefs(presShell)); |
michael@0 | 413 | if (presShell) { |
michael@0 | 414 | presShell->FlushPendingNotifications(Flush_Layout); |
michael@0 | 415 | } |
michael@0 | 416 | } |
michael@0 | 417 | |
michael@0 | 418 | nsIDocument* |
michael@0 | 419 | SVGDocumentWrapper::GetDocument() |
michael@0 | 420 | { |
michael@0 | 421 | if (!mViewer) |
michael@0 | 422 | return nullptr; |
michael@0 | 423 | |
michael@0 | 424 | return mViewer->GetDocument(); // May be nullptr. |
michael@0 | 425 | } |
michael@0 | 426 | |
michael@0 | 427 | SVGSVGElement* |
michael@0 | 428 | SVGDocumentWrapper::GetRootSVGElem() |
michael@0 | 429 | { |
michael@0 | 430 | if (!mViewer) |
michael@0 | 431 | return nullptr; // Can happen during destruction |
michael@0 | 432 | |
michael@0 | 433 | nsIDocument* doc = mViewer->GetDocument(); |
michael@0 | 434 | if (!doc) |
michael@0 | 435 | return nullptr; // Can happen during destruction |
michael@0 | 436 | |
michael@0 | 437 | Element* rootElem = mViewer->GetDocument()->GetRootElement(); |
michael@0 | 438 | if (!rootElem || !rootElem->IsSVG(nsGkAtoms::svg)) { |
michael@0 | 439 | return nullptr; |
michael@0 | 440 | } |
michael@0 | 441 | |
michael@0 | 442 | return static_cast<SVGSVGElement*>(rootElem); |
michael@0 | 443 | } |
michael@0 | 444 | |
michael@0 | 445 | } // namespace image |
michael@0 | 446 | } // namespace mozilla |