void ProgressTracker::SyncNotify(IProgressObserver* aObserver) { MOZ_ASSERT(NS_IsMainThread()); nsRefPtr<Image> image = GetImage(); nsAutoCString spec; if (image && image->GetURI()) { image->GetURI()->GetSpec(spec); } LOG_SCOPE_WITH_PARAM(GetImgLog(), "ProgressTracker::SyncNotify", "uri", spec.get()); nsIntRect rect; if (image) { if (NS_FAILED(image->GetWidth(&rect.width)) || NS_FAILED(image->GetHeight(&rect.height))) { // Either the image has no intrinsic size, or it has an error. rect = GetMaxSizedIntRect(); } } ObserverArray array; array.AppendElement(aObserver); SyncNotifyInternal(array, !!image, mProgress, rect); }
void VectorImage::OnSVGDocumentLoaded() { MOZ_ASSERT(mSVGDocumentWrapper->GetRootSVGElem(), "Should have parsed successfully"); MOZ_ASSERT(!mIsFullyLoaded && !mHaveAnimations, "These flags shouldn't get set until OnSVGDocumentLoaded. " "Duplicate calls to OnSVGDocumentLoaded?"); CancelAllListeners(); // XXX Flushing is wasteful if embedding frame hasn't had initial reflow. mSVGDocumentWrapper->FlushLayout(); mIsFullyLoaded = true; mHaveAnimations = mSVGDocumentWrapper->IsAnimated(); // Start listening to our image for rendering updates. mRenderingObserver = new SVGRootRenderingObserver(mSVGDocumentWrapper, this); // Tell *our* observers that we're done loading. if (mProgressTracker) { mProgressTracker->SyncNotifyProgress(FLAG_SIZE_AVAILABLE | FLAG_HAS_TRANSPARENCY | FLAG_FRAME_COMPLETE | FLAG_DECODE_COMPLETE | FLAG_ONLOAD_UNBLOCKED, GetMaxSizedIntRect()); } EvaluateAnimation(); }
void VectorImage::OnSVGDocumentLoaded() { MOZ_ASSERT(mSVGDocumentWrapper->GetRootSVGElem(), "Should have parsed successfully"); MOZ_ASSERT(!mIsFullyLoaded && !mHaveAnimations, "These flags shouldn't get set until OnSVGDocumentLoaded. " "Duplicate calls to OnSVGDocumentLoaded?"); CancelAllListeners(); // XXX Flushing is wasteful if embedding frame hasn't had initial reflow. mSVGDocumentWrapper->FlushLayout(); mIsFullyLoaded = true; mHaveAnimations = mSVGDocumentWrapper->IsAnimated(); // Start listening to our image for rendering updates. mRenderingObserver = new SVGRootRenderingObserver(mSVGDocumentWrapper, this); // ProgressTracker::SyncNotifyProgress may release us, so ensure we // stick around long enough to complete our work. RefPtr<VectorImage> kungFuDeathGrip(this); // Tell *our* observers that we're done loading. if (mProgressTracker) { Progress progress = FLAG_SIZE_AVAILABLE | FLAG_HAS_TRANSPARENCY | FLAG_FRAME_COMPLETE | FLAG_DECODE_COMPLETE | FLAG_ONLOAD_UNBLOCKED; if (mHaveAnimations) { progress |= FLAG_IS_ANIMATED; } // Merge in any saved progress from OnImageDataComplete. if (mLoadProgress) { progress |= *mLoadProgress; mLoadProgress = Nothing(); } mProgressTracker->SyncNotifyProgress(progress, GetMaxSizedIntRect()); } EvaluateAnimation(); }
void VectorImage::SendInvalidationNotifications() { // Animated images don't send out invalidation notifications as soon as // they're generated. Instead, InvalidateObserversOnNextRefreshDriverTick // records that there are pending invalidations and then returns immediately. // The notifications are actually sent from RequestRefresh(). We send these // notifications there to ensure that there is actually a document observing // us. Otherwise, the notifications are just wasted effort. // // Non-animated images call this method directly from // InvalidateObserversOnNextRefreshDriverTick, because RequestRefresh is never // called for them. Ordinarily this isn't needed, since we send out // invalidation notifications in OnSVGDocumentLoaded, but in rare cases the // SVG document may not be 100% ready to render at that time. In those cases // we would miss the subsequent invalidations if we didn't send out the // notifications directly in |InvalidateObservers...|. if (mProgressTracker) { SurfaceCache::RemoveImage(ImageKey(this)); mProgressTracker->SyncNotifyProgress(FLAG_FRAME_COMPLETE, GetMaxSizedIntRect()); } }
void VectorImage::CreateSurfaceAndShow(const SVGDrawingParameters& aParams) { mSVGDocumentWrapper->UpdateViewportBounds(aParams.viewportSize); mSVGDocumentWrapper->FlushImageTransformInvalidation(); RefPtr<gfxDrawingCallback> cb = new SVGDrawingCallback(mSVGDocumentWrapper, IntRect(IntPoint(0, 0), aParams.viewportSize), aParams.size, aParams.flags); RefPtr<gfxDrawable> svgDrawable = new gfxCallbackDrawable(cb, aParams.size); bool bypassCache = bool(aParams.flags & FLAG_BYPASS_SURFACE_CACHE) || // Refuse to cache animated images: // XXX(seth): We may remove this restriction in bug 922893. mHaveAnimations || // The image is too big to fit in the cache: !SurfaceCache::CanHold(aParams.size); if (bypassCache) { return Show(svgDrawable, aParams); } // We're about to rerasterize, which may mean that some of the previous // surfaces we've rasterized aren't useful anymore. We can allow them to // expire from the cache by unlocking them here, and then sending out an // invalidation. If this image is locked, any surfaces that are still useful // will become locked again when Draw touches them, and the remainder will // eventually expire. SurfaceCache::UnlockSurfaces(ImageKey(this)); // Try to create an imgFrame, initializing the surface it contains by drawing // our gfxDrawable into it. (We use FILTER_NEAREST since we never scale here.) RefPtr<imgFrame> frame = new imgFrame; nsresult rv = frame->InitWithDrawable(svgDrawable, aParams.size, SurfaceFormat::B8G8R8A8, Filter::POINT, aParams.flags); // If we couldn't create the frame, it was probably because it would end // up way too big. Generally it also wouldn't fit in the cache, but the prefs // could be set such that the cache isn't the limiting factor. if (NS_FAILED(rv)) { return Show(svgDrawable, aParams); } // Take a strong reference to the frame's surface and make sure it hasn't // already been purged by the operating system. RefPtr<SourceSurface> surface = frame->GetSurface(); if (!surface) { return Show(svgDrawable, aParams); } // Attempt to cache the frame. SurfaceCache::Insert(frame, ImageKey(this), VectorSurfaceKey(aParams.size, aParams.svgContext, aParams.animationTime)); // Draw. RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(surface, aParams.size); Show(drawable, aParams); // Send out an invalidation so that surfaces that are still in use get // re-locked. See the discussion of the UnlockSurfaces call above. mProgressTracker->SyncNotifyProgress(FLAG_FRAME_COMPLETE, GetMaxSizedIntRect()); }