Commit 6c267624 authored by Andrew Osmond's avatar Andrew Osmond
Browse files

Bug 1711061 - Part 10. Implement BlobSurfaceProvider for non-rasterized blob recordings. r=tnikkel

This WebRenderImageProvider/ISurfaceProvider subclass provides the
implementation for blob recordings. This is mostly just taking the
functionality that was previously in SourceSurfaceBlobImage.

Differential Revision: https://phabricator.services.mozilla.com/D126602
parent ba2c6dea
Loading
Loading
Loading
Loading
+43 −37
Original line number Diff line number Diff line
@@ -20,23 +20,18 @@ using namespace mozilla::layers;

namespace mozilla::image {

SourceSurfaceBlobImage::SourceSurfaceBlobImage(
    image::SVGDocumentWrapper* aSVGDocumentWrapper,
    const Maybe<SVGImageContext>& aSVGContext,
    const Maybe<ImageIntRegion>& aRegion, const IntSize& aSize,
    uint32_t aWhichFrame, uint32_t aImageFlags)
    : mSVGDocumentWrapper(aSVGDocumentWrapper),
      mSVGContext(aSVGContext),
      mRegion(aRegion),
      mSize(aSize),
      mWhichFrame(aWhichFrame),
BlobSurfaceProvider::BlobSurfaceProvider(
    const ImageKey aImageKey, const SurfaceKey& aSurfaceKey,
    image::SVGDocumentWrapper* aSVGDocumentWrapper, uint32_t aImageFlags)
    : ISurfaceProvider(aImageKey, aSurfaceKey,
                       AvailabilityState::StartAvailable()),
      mSVGDocumentWrapper(aSVGDocumentWrapper),
      mImageFlags(aImageFlags) {
  MOZ_ASSERT(mSVGDocumentWrapper);
  MOZ_ASSERT(aWhichFrame <= imgIContainer::FRAME_MAX_VALUE);
  MOZ_ASSERT(aImageFlags & imgIContainer::FLAG_RECORD_BLOB);
}

SourceSurfaceBlobImage::~SourceSurfaceBlobImage() {
BlobSurfaceProvider::~BlobSurfaceProvider() {
  if (NS_IsMainThread()) {
    DestroyKeys(mKeys);
    return;
@@ -49,7 +44,7 @@ SourceSurfaceBlobImage::~SourceSurfaceBlobImage() {
                             [keys = std::move(mKeys)] { DestroyKeys(keys); }));
}

/* static */ void SourceSurfaceBlobImage::DestroyKeys(
/* static */ void BlobSurfaceProvider::DestroyKeys(
    const AutoTArray<BlobImageKeyData, 1>& aKeys) {
  for (const auto& entry : aKeys) {
    if (!entry.mManager->IsDestroyed()) {
@@ -59,10 +54,14 @@ SourceSurfaceBlobImage::~SourceSurfaceBlobImage() {
  }
}

Maybe<wr::BlobImageKey> SourceSurfaceBlobImage::UpdateKey(
    WebRenderLayerManager* aManager, wr::IpcResourceUpdateQueue& aResources) {
nsresult BlobSurfaceProvider::UpdateKey(
    layers::RenderRootStateManager* aManager,
    wr::IpcResourceUpdateQueue& aResources, wr::ImageKey& aKey) {
  MOZ_ASSERT(NS_IsMainThread());

  layers::WebRenderLayerManager* manager = aManager->LayerManager();
  MOZ_ASSERT(manager);

  Maybe<wr::BlobImageKey> key;
  auto i = mKeys.Length();
  while (i > 0) {
@@ -70,8 +69,8 @@ Maybe<wr::BlobImageKey> SourceSurfaceBlobImage::UpdateKey(
    BlobImageKeyData& entry = mKeys[i];
    if (entry.mManager->IsDestroyed()) {
      mKeys.RemoveElementAt(i);
    } else if (entry.mManager == aManager) {
      WebRenderBridgeChild* wrBridge = aManager->WrBridge();
    } else if (entry.mManager == manager) {
      WebRenderBridgeChild* wrBridge = manager->WrBridge();
      MOZ_ASSERT(wrBridge);

      bool ownsKey = wrBridge->MatchesNamespace(entry.mBlobKey);
@@ -84,12 +83,11 @@ Maybe<wr::BlobImageKey> SourceSurfaceBlobImage::UpdateKey(
      // can change state. Either our namespace differs, and our old key has
      // already been discarded, or the blob has changed. Either way, we need
      // to rerecord it.
      auto newEntry = RecordDrawing(aManager, aResources,
      auto newEntry = RecordDrawing(manager, aResources,
                                    ownsKey ? Some(entry.mBlobKey) : Nothing());
      if (!newEntry) {
        if (ownsKey) {
          aManager->GetRenderRootStateManager()->AddBlobImageKeyForDiscard(
              entry.mBlobKey);
          aManager->AddBlobImageKeyForDiscard(entry.mBlobKey);
        }
        mKeys.RemoveElementAt(i);
        continue;
@@ -103,17 +101,22 @@ Maybe<wr::BlobImageKey> SourceSurfaceBlobImage::UpdateKey(

  // We didn't find an entry. Attempt to record the blob with a new key.
  if (!key) {
    auto newEntry = RecordDrawing(aManager, aResources, Nothing());
    auto newEntry = RecordDrawing(manager, aResources, Nothing());
    if (newEntry) {
      key.emplace(newEntry.ref().mBlobKey);
      mKeys.AppendElement(std::move(newEntry.ref()));
    }
  }

  return key;
  if (key) {
    aKey = wr::AsImageKey(key.value());
    return NS_OK;
  }

void SourceSurfaceBlobImage::MarkDirty() {
  return NS_ERROR_FAILURE;
}

void BlobSurfaceProvider::InvalidateRecording() {
  MOZ_ASSERT(NS_IsMainThread());

  auto i = mKeys.Length();
@@ -128,7 +131,7 @@ void SourceSurfaceBlobImage::MarkDirty() {
  }
}

Maybe<BlobImageKeyData> SourceSurfaceBlobImage::RecordDrawing(
Maybe<BlobImageKeyData> BlobSurfaceProvider::RecordDrawing(
    WebRenderLayerManager* aManager, wr::IpcResourceUpdateQueue& aResources,
    Maybe<wr::BlobImageKey> aBlobKey) {
  MOZ_ASSERT(!aManager->IsDestroyed());
@@ -142,8 +145,11 @@ Maybe<BlobImageKeyData> SourceSurfaceBlobImage::RecordDrawing(
  auto* rootManager = aManager->GetRenderRootStateManager();
  auto* wrBridge = aManager->WrBridge();

  IntRect imageRect =
      mRegion ? mRegion->Rect() : IntRect(IntPoint(0, 0), mSize);
  const auto& size = GetSurfaceKey().Size();
  const auto& region = GetSurfaceKey().Region();
  const auto& svgContext = GetSurfaceKey().SVGContext();

  IntRect imageRect = region ? region->Rect() : IntRect(IntPoint(0, 0), size);
  IntRect imageRectOrigin = imageRect - imageRect.TopLeft();

  std::vector<RefPtr<ScaledFont>> fonts;
@@ -178,15 +184,15 @@ Maybe<BlobImageKeyData> SourceSurfaceBlobImage::RecordDrawing(
    return Nothing();
  }

  bool contextPaint = mSVGContext && mSVGContext->GetContextPaint();
  bool contextPaint = svgContext && svgContext->GetContextPaint();

  float animTime = (mWhichFrame == imgIContainer::FRAME_FIRST)
  float animTime = (GetSurfaceKey().Playback() == PlaybackType::eStatic)
                       ? 0.0f
                       : mSVGDocumentWrapper->GetCurrentTimeAsFloat();

  IntSize viewportSize = mSize;
  if (mSVGContext) {
    auto cssViewportSize = mSVGContext->GetViewportSize();
  IntSize viewportSize = size;
  if (svgContext) {
    auto cssViewportSize = svgContext->GetViewportSize();
    if (cssViewportSize) {
      // XXX losing unit
      viewportSize.SizeTo(cssViewportSize->width, cssViewportSize->height);
@@ -206,11 +212,11 @@ Maybe<BlobImageKeyData> SourceSurfaceBlobImage::RecordDrawing(
    AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(
        "SVG Image recording", GRAPHICS,
        nsPrintfCString("(%d,%d) %dx%d from %dx%d %s", imageRect.x, imageRect.y,
                        imageRect.width, imageRect.height, mSize.width,
                        mSize.height,
                        imageRect.width, imageRect.height, size.width,
                        size.height,
                        uri ? uri->GetSpecOrDefault().get() : "N/A"));

    AutoRestoreSVGState autoRestore(mSVGContext, animTime, mSVGDocumentWrapper,
    AutoRestoreSVGState autoRestore(svgContext, animTime, mSVGDocumentWrapper,
                                    contextPaint);

    mSVGDocumentWrapper->UpdateViewportBounds(viewportSize);
@@ -221,9 +227,9 @@ Maybe<BlobImageKeyData> SourceSurfaceBlobImage::RecordDrawing(

    nsRect svgRect;
    auto auPerDevPixel = presContext->AppUnitsPerDevPixel();
    if (mSize != viewportSize) {
      auto scaleX = double(mSize.width) / viewportSize.width;
      auto scaleY = double(mSize.height) / viewportSize.height;
    if (size != viewportSize) {
      auto scaleX = double(size.width) / viewportSize.width;
      auto scaleY = double(size.height) / viewportSize.height;
      ctx->SetMatrix(Matrix::Scaling(float(scaleX), float(scaleY)));

      auto scaledVisibleRect = IntRectToRect(imageRect);
+40 −32
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include "mozilla/gfx/2D.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "ImageRegion.h"
#include "ISurfaceProvider.h"

#include <vector>

@@ -70,45 +71,56 @@ namespace image {
class SVGDocumentWrapper;

/**
 * This class is used to wrap blob recordings stored in ImageContainers, used
 * by SVG images. Unlike rasterized images stored in SourceSurfaceSharedData,
 * each SourceSurfaceBlobImage can only be used by one WebRenderLayerManager
 * because the recording is tied to a particular instance.
 * An ISurfaceProvider that manages blob recordings of SVG images. Unlike the
 * rasterized ISurfaceProviders, it only provides a recording which may be
 * replayed in the compositor process by WebRender. It may be invalidated
 * directly in order to reuse the resource ids and underlying buffers when the
 * SVG image has changed (e.g. it is animated).
 */
class SourceSurfaceBlobImage final : public gfx::SourceSurface {
class BlobSurfaceProvider final : public ISurfaceProvider {
 public:
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceBlobImage, override)
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BlobSurfaceProvider, override)

  SourceSurfaceBlobImage(SVGDocumentWrapper* aSVGDocumentWrapper,
                         const Maybe<SVGImageContext>& aSVGContext,
                         const Maybe<ImageIntRegion>& aRegion,
                         const gfx::IntSize& aSize, uint32_t aWhichFrame,
  BlobSurfaceProvider(ImageKey aImageKey, const SurfaceKey& aSurfaceKey,
                      SVGDocumentWrapper* aSVGDocumentWrapper,
                      uint32_t aImageFlags);

  Maybe<wr::BlobImageKey> UpdateKey(layers::WebRenderLayerManager* aManager,
                                    wr::IpcResourceUpdateQueue& aResources);
  bool IsFinished() const override { return true; }

  void MarkDirty();

  gfx::SurfaceType GetType() const override {
    return gfx::SurfaceType::BLOB_IMAGE;
  }
  gfx::IntSize GetSize() const override { return mSize; }
  gfx::SurfaceFormat GetFormat() const override {
    return gfx::SurfaceFormat::OS_RGBA;
  size_t LogicalSizeInBytes() const override {
    const gfx::IntSize& size = GetSurfaceKey().Size();
    return size.width * size.height * sizeof(uint32_t);
  }
  already_AddRefed<gfx::DataSourceSurface> GetDataSurface() override {
    return nullptr;

  nsresult UpdateKey(layers::RenderRootStateManager* aManager,
                     wr::IpcResourceUpdateQueue& aResources,
                     wr::ImageKey& aKey) override;

  void InvalidateRecording() override;

  void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
                              const AddSizeOfCb& aCallback) override {
    AddSizeOfCbData metadata;
    metadata.mFinished = true;
    metadata.mHeapBytes += mKeys.ShallowSizeOfExcludingThis(aMallocSizeOf);

    gfx::SourceSurface::SizeOfInfo info;
    info.AddType(gfx::SurfaceType::BLOB_IMAGE);
    metadata.Accumulate(info);

    aCallback(metadata);
  }

  void SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
                           SizeOfInfo& aInfo) const override {
    aInfo.AddType(gfx::SurfaceType::BLOB_IMAGE);
    aInfo.mHeapBytes += mKeys.ShallowSizeOfExcludingThis(aMallocSizeOf);
 protected:
  DrawableFrameRef DrawableRef(size_t aFrame) override {
    MOZ_ASSERT_UNREACHABLE("BlobSurfaceProvider::DrawableRef not supported!");
    return DrawableFrameRef();
  }
  bool IsLocked() const override { return true; }
  void SetLocked(bool) override {}

 private:
  ~SourceSurfaceBlobImage() override;
  ~BlobSurfaceProvider() override;

  Maybe<BlobImageKeyData> RecordDrawing(layers::WebRenderLayerManager* aManager,
                                        wr::IpcResourceUpdateQueue& aResources,
@@ -119,10 +131,6 @@ class SourceSurfaceBlobImage final : public gfx::SourceSurface {
  AutoTArray<BlobImageKeyData, 1> mKeys;

  RefPtr<image::SVGDocumentWrapper> mSVGDocumentWrapper;
  Maybe<SVGImageContext> mSVGContext;
  Maybe<ImageIntRegion> mRegion;
  gfx::IntSize mSize;
  uint32_t mWhichFrame;
  uint32_t mImageFlags;
};