Esempio n. 1
0
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);
}
Esempio n. 2
0
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();
}
Esempio n. 3
0
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();
}
Esempio n. 4
0
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());
  }
}
Esempio n. 5
0
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());
}