Exemple #1
0
bool
X11DataTextureSourceBasic::Update(gfx::DataSourceSurface* aSurface,
                                  nsIntRegion* aDestRegion,
                                  gfx::IntPoint* aSrcOffset)
{
  // Reallocate our internal X11 surface if we don't have a DrawTarget yet,
  // or if we changed surface size or format since last update.
  if (!mBufferDrawTarget ||
      (aSurface->GetSize() != mBufferDrawTarget->GetSize()) ||
      (aSurface->GetFormat() != mBufferDrawTarget->GetFormat())) {

    nsRefPtr<gfxASurface> surf;
    gfxImageFormat imageFormat = SurfaceFormatToImageFormat(aSurface->GetFormat());
    Display *display = DefaultXDisplay();
    Screen *screen = DefaultScreenOfDisplay(display);
    XRenderPictFormat *xrenderFormat =
      gfxXlibSurface::FindRenderFormat(display, imageFormat);

    if (xrenderFormat) {
      surf = gfxXlibSurface::Create(screen, xrenderFormat,
                                    ThebesIntSize(aSurface->GetSize()));
    }

    if (!surf) {
      NS_WARNING("Couldn't create native surface, fallback to image surface");
      surf = new gfxImageSurface(ThebesIntSize(aSurface->GetSize()), imageFormat);
    }

    mBufferDrawTarget = gfxPlatform::GetPlatform()->
      CreateDrawTargetForSurface(surf, aSurface->GetSize());
  }

  // Image contents have changed, upload to our DrawTarget
  // If aDestRegion is null, means we're updating the whole surface
  // Note : Incremental update with a source offset is only used on Mac.
  NS_ASSERTION(!aSrcOffset, "SrcOffset should not be used with linux OMTC basic");

  if (aDestRegion) {
    nsIntRegionRectIterator iter(*aDestRegion);
    while (const nsIntRect* iterRect = iter.Next()) {
      IntRect srcRect(iterRect->x, iterRect->y, iterRect->width, iterRect->height);
      IntPoint dstPoint(iterRect->x, iterRect->y);

      // We're uploading regions to our buffer, so let's just copy contents over
      mBufferDrawTarget->CopySurface(aSurface, srcRect, dstPoint);
    }
  } else {
    // We're uploading the whole buffer, so let's just copy the full surface
    IntSize size = aSurface->GetSize();
    mBufferDrawTarget->CopySurface(aSurface, IntRect(0, 0, size.width, size.height),
                                   IntPoint(0, 0));
  }

  return true;
}
static TemporaryRef<DataSourceSurface> YInvertImageSurface(DataSourceSurface* aSurf)
{
  RefPtr<DataSourceSurface> temp =
    Factory::CreateDataSourceSurfaceWithStride(aSurf->GetSize(),
                                               aSurf->GetFormat(),
                                               aSurf->Stride());
  RefPtr<DrawTarget> dt =
    Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                     temp->GetData(),
                                     temp->GetSize(),
                                     temp->Stride(),
                                     temp->GetFormat());
  nsRefPtr<gfxContext> ctx = new gfxContext(dt);
  ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
  ctx->Scale(1.0, -1.0);
  ctx->Translate(-gfxPoint(0.0, aSurf->GetSize().height));

  nsRefPtr<gfxImageSurface> thebesSurf =
    new gfxImageSurface(aSurf->GetData(),
                        ThebesIntSize(aSurf->GetSize()),
                        aSurf->Stride(),
                        SurfaceFormatToImageFormat(aSurf->GetFormat()));
  ctx->SetSource(thebesSurf);
  ctx->Paint();
  return temp.forget();
}
void
SharedSurface_EGLImage::Fence()
{
    MutexAutoLock lock(mMutex);
    mGL->MakeCurrent();

    if (!mPipeActive) {
        MOZ_ASSERT(!mSync);
        MOZ_ASSERT(!mPipeComplete);

        if (!mPipeFailed) {
            if (!CreateTexturePipe(mEGL, mGL, mFormats, Size(),
                                   &mProdTexForPipe, &mImage))
            {
                mPipeFailed = true;
            }
        }

        if (!mPixels) {
            SurfaceFormat format =
                  HasAlpha() ? SurfaceFormat::B8G8R8A8
                             : SurfaceFormat::B8G8R8X8;
            mPixels = Factory::CreateDataSourceSurface(Size(), format);
        }

        nsRefPtr<gfxImageSurface> wrappedData =
            new gfxImageSurface(mPixels->GetData(),
                                ThebesIntSize(mPixels->GetSize()),
                                mPixels->Stride(),
                                SurfaceFormatToImageFormat(mPixels->GetFormat()));
        ReadScreenIntoImageSurface(mGL, wrappedData);
        mPixels->MarkDirty();
        return;
    }
    MOZ_ASSERT(mPipeActive);
    MOZ_ASSERT(mCurConsGL);

    if (mEGL->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync) &&
        mGL->IsExtensionSupported(GLContext::OES_EGL_sync))
    {
        if (mSync) {
            MOZ_ALWAYS_TRUE( mEGL->fDestroySync(Display(), mSync) );
            mSync = 0;
        }

        mSync = mEGL->fCreateSync(Display(),
                                  LOCAL_EGL_SYNC_FENCE,
                                  nullptr);
        if (mSync) {
            mGL->fFlush();
            return;
        }
    }

    MOZ_ASSERT(!mSync);
    mGL->fFinish();
}
void
VectorImage::Show(gfxDrawable* aDrawable, const SVGDrawingParameters& aParams)
{
  MOZ_ASSERT(aDrawable, "Should have a gfxDrawable by now");
  gfxUtils::DrawPixelSnapped(aParams.context, aDrawable,
                             ThebesIntSize(aParams.size),
                             aParams.region,
                             SurfaceFormat::B8G8R8A8,
                             aParams.filter, aParams.flags, aParams.opacity);

  MOZ_ASSERT(mRenderingObserver, "Should have a rendering observer by now");
  mRenderingObserver->ResumeHonoringInvalidations();
}
Exemple #5
0
already_AddRefed<gfxASurface>
gfxOS2Platform::CreateOffscreenSurface(const IntSize & aSize,
                                       gfxContentType contentType)
{
    gfxImageFormat format =
        OptimalFormatForContent(contentType);
    int stride =
        cairo_format_stride_for_width(static_cast<cairo_format_t>(format),
                                      aSize.width);

    // To avoid memory fragmentation, return a standard image surface
    // for small images (32x32x4 or 64x64x1).  Their bitmaps will be
    // be allocated from libc's heap rather than system memory.

    nsRefPtr<gfxASurface> surf;
    if (stride * aSize.height <= 4096) {
        surf = new gfxImageSurface(ThebesIntSize(aSize), format);
    } else {
        surf = new gfxOS2Surface(ThebesIntSize(aSize), format);
    }

    return surf.forget();
}
void
GLScreenBuffer::Readback(SharedSurface_GL* src, DataSourceSurface* dest)
{
  MOZ_ASSERT(src && dest);
  DataSourceSurface::MappedSurface ms;
  dest->Map(DataSourceSurface::MapType::READ, &ms);
  nsRefPtr<gfxImageSurface> wrappedDest =
    new gfxImageSurface(ms.mData,
                        ThebesIntSize(dest->GetSize()),
                        ms.mStride,
                        SurfaceFormatToImageFormat(dest->GetFormat()));
  DeprecatedReadback(src, wrappedDest);
  dest->Unmap();
}
Exemple #7
0
gfxImageSurface*
CopyableCanvasLayer::GetTempSurface(const IntSize& aSize, const gfxImageFormat aFormat)
{
  if (!mCachedTempSurface ||
      aSize.width != mCachedSize.width ||
      aSize.height != mCachedSize.height ||
      aFormat != mCachedFormat)
  {
    mCachedTempSurface = new gfxImageSurface(ThebesIntSize(aSize), aFormat);
    mCachedSize = aSize;
    mCachedFormat = aFormat;
  }

  MOZ_ASSERT(mCachedTempSurface->Stride() == mCachedTempSurface->Width() * 4);
  return mCachedTempSurface;
}
void
SharedSurface_Basic::Fence()
{
    mGL->MakeCurrent();

    ScopedBindFramebuffer autoFB(mGL, mFB);

    DataSourceSurface::MappedSurface map;
    mData->Map(DataSourceSurface::MapType::WRITE, &map);
    nsRefPtr<gfxImageSurface> wrappedData =
      new gfxImageSurface(map.mData,
                          ThebesIntSize(mData->GetSize()),
                          map.mStride,
                          SurfaceFormatToImageFormat(mData->GetFormat()));
    ReadPixelsIntoImageSurface(mGL, wrappedData);
    mData->Unmap();
}
// Run the test for a texture client and a surface
void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface) {

    // client allocation
    ASSERT_TRUE(texture->CanExposeDrawTarget());
    texture->AllocateForSurface(ToIntSize(surface->GetSize()));
    ASSERT_TRUE(texture->IsAllocated());

    ASSERT_TRUE(texture->Lock(OPEN_READ_WRITE));
    // client painting
    RefPtr<DrawTarget> dt = texture->GetAsDrawTarget();
    RefPtr<SourceSurface> source =
        gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, surface);
    dt->CopySurface(source, IntRect(IntPoint(), source->GetSize()), IntPoint());

    RefPtr<SourceSurface> snapshot = dt->Snapshot();

    AssertSurfacesEqual(snapshot, source);

    dt = nullptr; // drop reference before calling Unlock()
    texture->Unlock();

    // client serialization
    SurfaceDescriptor descriptor;
    ASSERT_TRUE(texture->ToSurfaceDescriptor(descriptor));

    ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t);

    // host deserialization
    RefPtr<TextureHost> host = CreateBackendIndependentTextureHost(descriptor, nullptr,
                               texture->GetFlags());

    ASSERT_TRUE(host.get() != nullptr);
    ASSERT_EQ(host->GetFlags(), texture->GetFlags());

    // host read
    ASSERT_TRUE(host->Lock());
    RefPtr<mozilla::gfx::DataSourceSurface> hostDataSurface = host->GetAsSurface();
    host->Unlock();

    nsRefPtr<gfxImageSurface> hostSurface =
        new gfxImageSurface(hostDataSurface->GetData(),
                            ThebesIntSize(hostDataSurface->GetSize()),
                            hostDataSurface->Stride(),
                            SurfaceFormatToImageFormat(hostDataSurface->GetFormat()));
    AssertSurfacesEqual(surface, hostSurface.get());
}
Exemple #10
0
void WriteSnapshotToDumpFile_internal(T* aObj, DataSourceSurface* aSurf)
{
  nsRefPtr<gfxImageSurface> deprecatedSurf =
    new gfxImageSurface(aSurf->GetData(),
                        ThebesIntSize(aSurf->GetSize()),
                        aSurf->Stride(),
                        SurfaceFormatToImageFormat(aSurf->GetFormat()));
  nsCString string(aObj->Name());
  string.Append('-');
  string.AppendInt((uint64_t)aObj);
  if (gfxUtils::sDumpPaintFile) {
    fprintf_stderr(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading());
  }
  deprecatedSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile);
  if (gfxUtils::sDumpPaintFile) {
    fprintf_stderr(gfxUtils::sDumpPaintFile, "\";");
  }
}
Exemple #11
0
void GStreamerReader::VideoPreroll()
{
  /* The first video buffer has reached the video sink. Get width and height */
  LOG(PR_LOG_DEBUG, "Video preroll");
  GstPad* sinkpad = gst_element_get_static_pad(GST_ELEMENT(mVideoAppSink), "sink");
  int PARNumerator, PARDenominator;
#if GST_VERSION_MAJOR >= 1
  GstCaps* caps = gst_pad_get_current_caps(sinkpad);
  memset (&mVideoInfo, 0, sizeof (mVideoInfo));
  gst_video_info_from_caps(&mVideoInfo, caps);
  mFormat = mVideoInfo.finfo->format;
  mPicture.width = mVideoInfo.width;
  mPicture.height = mVideoInfo.height;
  PARNumerator = GST_VIDEO_INFO_PAR_N(&mVideoInfo);
  PARDenominator = GST_VIDEO_INFO_PAR_D(&mVideoInfo);
#else
  GstCaps* caps = gst_pad_get_negotiated_caps(sinkpad);
  gst_video_format_parse_caps(caps, &mFormat, &mPicture.width, &mPicture.height);
  if (!gst_video_parse_caps_pixel_aspect_ratio(caps, &PARNumerator, &PARDenominator)) {
    PARNumerator = 1;
    PARDenominator = 1;
  }
#endif
  NS_ASSERTION(mPicture.width && mPicture.height, "invalid video resolution");

  // Calculate display size according to pixel aspect ratio.
  nsIntRect pictureRect(0, 0, mPicture.width, mPicture.height);
  nsIntSize frameSize = nsIntSize(mPicture.width, mPicture.height);
  nsIntSize displaySize = nsIntSize(mPicture.width, mPicture.height);
  ScaleDisplayByAspectRatio(displaySize, float(PARNumerator) / float(PARDenominator));

  // If video frame size is overflow, stop playing.
  if (IsValidVideoRegion(frameSize, pictureRect, displaySize)) {
    GstStructure* structure = gst_caps_get_structure(caps, 0);
    gst_structure_get_fraction(structure, "framerate", &fpsNum, &fpsDen);
    mInfo.mVideo.mDisplay = ThebesIntSize(displaySize.ToIntSize());
    mInfo.mVideo.mHasVideo = true;
  } else {
    LOG(PR_LOG_DEBUG, "invalid video region");
    Eos();
  }
  gst_caps_unref(caps);
  gst_object_unref(sinkpad);
}
bool
TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
                                     TextureFlags aFlags,
                                     nsIntRegion* aDestRegion,
                                     gfx::IntPoint* aSrcOffset)
{
  MOZ_ASSERT(mGL);
  if (!mGL) {
    NS_WARNING("trying to update TextureImageTextureSourceOGL without a GLContext");
    return false;
  }
  MOZ_ASSERT(aSurface);

  nsIntSize size = ThebesIntSize(aSurface->GetSize());
  if (!mTexImage ||
      mTexImage->GetSize() != size ||
      mTexImage->GetContentType() != gfx::ContentForFormat(aSurface->GetFormat())) {
    if (mAllowBigImage) {
      // XXX - clarify which size we want to use. IncrementalContentHost will
      // require the size of the destination surface to be different from
      // the size of aSurface.
      // See bug 893300 (tracks the implementation of ContentHost for new textures).
      mTexImage = mGL->CreateTextureImage(size,
                                          gfx::ContentForFormat(aSurface->GetFormat()),
                                          WrapMode(mGL, aFlags & TEXTURE_ALLOW_REPEAT),
                                          FlagsToGLFlags(aFlags));
    } else {
      mTexImage = CreateBasicTextureImage(mGL,
                                          size,
                                          gfx::ContentForFormat(aSurface->GetFormat()),
                                          WrapMode(mGL, aFlags & TEXTURE_ALLOW_REPEAT),
                                          FlagsToGLFlags(aFlags));
    }
  }

  mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset);

  if (mTexImage->InUpdate()) {
    mTexImage->EndUpdate();
  }
  return true;
}
Exemple #13
0
void GStreamerReader::VideoPreroll()
{
  /* The first video buffer has reached the video sink. Get width and height */
  LOG(PR_LOG_DEBUG, ("Video preroll"));
  GstPad* sinkpad = gst_element_get_static_pad(GST_ELEMENT(mVideoAppSink), "sink");
#if GST_VERSION_MAJOR >= 1
  GstCaps* caps = gst_pad_get_current_caps(sinkpad);
  memset (&mVideoInfo, 0, sizeof (mVideoInfo));
  gst_video_info_from_caps(&mVideoInfo, caps);
  mFormat = mVideoInfo.finfo->format;
  mPicture.width = mVideoInfo.width;
  mPicture.height = mVideoInfo.height;
#else
  GstCaps* caps = gst_pad_get_negotiated_caps(sinkpad);
  gst_video_format_parse_caps(caps, &mFormat, &mPicture.width, &mPicture.height);
#endif
  GstStructure* structure = gst_caps_get_structure(caps, 0);
  gst_structure_get_fraction(structure, "framerate", &fpsNum, &fpsDen);
  NS_ASSERTION(mPicture.width && mPicture.height, "invalid video resolution");
  mInfo.mVideo.mDisplay = ThebesIntSize(mPicture.Size());
  mInfo.mVideo.mHasVideo = true;
  gst_caps_unref(caps);
  gst_object_unref(sinkpad);
}
void
CanvasLayerD3D9::UpdateSurface()
{
  if (!IsDirty() && mTexture)
    return;
  Painted();

  if (!mTexture) {
    CreateTexture();

    if (!mTexture) {
      NS_WARNING("CanvasLayerD3D9::Updated called but no texture present and creation failed!");
      return;
    }
  }

  if (mGLContext) {
    SharedSurface* surf = mGLContext->RequestFrame();
    if (!surf)
        return;

    SharedSurface_Basic* shareSurf = SharedSurface_Basic::Cast(surf);

    // WebGL reads entire surface.
    LockTextureRectD3D9 textureLock(mTexture);
    if (!textureLock.HasLock()) {
      NS_WARNING("Failed to lock CanvasLayer texture.");
      return;
    }

    D3DLOCKED_RECT rect = textureLock.GetLockRect();
    
    DataSourceSurface* frameData = shareSurf->GetData();
    // Scope for gfxContext, so it's destroyed early.
    {
      RefPtr<DrawTarget> mapDt = Factory::CreateDrawTargetForData(BACKEND_CAIRO,
                                                                  (uint8_t*)rect.pBits,
                                                                  shareSurf->Size(),
                                                                  rect.Pitch,
                                                                  FORMAT_B8G8R8A8);

      nsRefPtr<gfxImageSurface> thebesFrameData =
          new gfxImageSurface(frameData->GetData(),
                              ThebesIntSize(frameData->GetSize()),
                              frameData->Stride(),
                              SurfaceFormatToImageFormat(frameData->GetFormat()));

      nsRefPtr<gfxContext> ctx = new gfxContext(mapDt);
      ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
      ctx->SetSource(thebesFrameData);
      ctx->Paint();

      mapDt->Flush();
    }
  } else {
    RECT r;
    r.left = mBounds.x;
    r.top = mBounds.y;
    r.right = mBounds.XMost();
    r.bottom = mBounds.YMost();

    LockTextureRectD3D9 textureLock(mTexture);
    if (!textureLock.HasLock()) {
      NS_WARNING("Failed to lock CanvasLayer texture.");
      return;
    }

    D3DLOCKED_RECT lockedRect = textureLock.GetLockRect();

    nsRefPtr<gfxImageSurface> sourceSurface;

    if (mSurface->GetType() == gfxSurfaceTypeWin32) {
      sourceSurface = mSurface->GetAsImageSurface();
    } else if (mSurface->GetType() == gfxSurfaceTypeImage) {
      sourceSurface = static_cast<gfxImageSurface*>(mSurface.get());
      if (sourceSurface->Format() != gfxImageFormatARGB32 &&
          sourceSurface->Format() != gfxImageFormatRGB24)
      {
        return;
      }
    } else {
      sourceSurface = new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height),
                                          gfxImageFormatARGB32);
      nsRefPtr<gfxContext> ctx = new gfxContext(sourceSurface);
      ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
      ctx->SetSource(mSurface);
      ctx->Paint();
    }

    uint8_t *startBits = sourceSurface->Data();
    uint32_t sourceStride = sourceSurface->Stride();

    if (sourceSurface->Format() != gfxImageFormatARGB32) {
      mHasAlpha = false;
    } else {
      mHasAlpha = true;
    }

    for (int y = 0; y < mBounds.height; y++) {
      memcpy((uint8_t*)lockedRect.pBits + lockedRect.Pitch * y,
             startBits + sourceStride * y,
             mBounds.width * 4);
    }

  }
}
gfxIntSize
SharedRGBImage::GetSize()
{
  return ThebesIntSize(mSize);
}
Exemple #16
0
bool
StreamTextureSourceOGL::RetrieveTextureFromStream()
{
    gl()->MakeCurrent();

    SharedSurface* sharedSurf = mStream->SwapConsumer();
    if (!sharedSurf) {
        // We don't have a valid surf to show yet.
        return false;
    }

    gl()->MakeCurrent();

    mSize = IntSize(sharedSurf->Size().width, sharedSurf->Size().height);

    DataSourceSurface* toUpload = nullptr;
    switch (sharedSurf->Type()) {
    case SharedSurfaceType::GLTextureShare: {
        SharedSurface_GLTexture* glTexSurf = SharedSurface_GLTexture::Cast(sharedSurf);
        mTextureHandle = glTexSurf->ConsTexture(gl());
        mTextureTarget = glTexSurf->ConsTextureTarget();
        MOZ_ASSERT(mTextureHandle);
        mFormat = sharedSurf->HasAlpha() ? SurfaceFormat::R8G8B8A8
                  : SurfaceFormat::R8G8B8X8;
        break;
    }
    case SharedSurfaceType::EGLImageShare: {
        SharedSurface_EGLImage* eglImageSurf =
            SharedSurface_EGLImage::Cast(sharedSurf);

        eglImageSurf->AcquireConsumerTexture(gl(), &mTextureHandle, &mTextureTarget);
        MOZ_ASSERT(mTextureHandle);
        mFormat = sharedSurf->HasAlpha() ? SurfaceFormat::R8G8B8A8
                  : SurfaceFormat::R8G8B8X8;
        break;
    }
#ifdef XP_MACOSX
    case SharedSurfaceType::IOSurface: {
        SharedSurface_IOSurface* glTexSurf = SharedSurface_IOSurface::Cast(sharedSurf);
        mTextureHandle = glTexSurf->ConsTexture(gl());
        mTextureTarget = glTexSurf->ConsTextureTarget();
        MOZ_ASSERT(mTextureHandle);
        mFormat = sharedSurf->HasAlpha() ? SurfaceFormat::R8G8B8A8
                  : SurfaceFormat::R8G8B8X8;
        break;
    }
#endif
    case SharedSurfaceType::Basic: {
        toUpload = SharedSurface_Basic::Cast(sharedSurf)->GetData();
        MOZ_ASSERT(toUpload);
        break;
    }
    default:
        MOZ_CRASH("Invalid SharedSurface type.");
    }

    if (toUpload) {
        // mBounds seems to end up as (0,0,0,0) a lot, so don't use it?
        nsIntSize size(ThebesIntSize(toUpload->GetSize()));
        nsIntRect rect(nsIntPoint(0,0), size);
        nsIntRegion bounds(rect);
        mFormat = UploadSurfaceToTexture(gl(),
                                         toUpload,
                                         bounds,
                                         mUploadTexture,
                                         true);
        mTextureHandle = mUploadTexture;
        mTextureTarget = LOCAL_GL_TEXTURE_2D;
    }

    MOZ_ASSERT(mTextureHandle);
    gl()->fBindTexture(mTextureTarget, mTextureHandle);
    gl()->fTexParameteri(mTextureTarget,
                         LOCAL_GL_TEXTURE_WRAP_S,
                         LOCAL_GL_CLAMP_TO_EDGE);
    gl()->fTexParameteri(mTextureTarget,
                         LOCAL_GL_TEXTURE_WRAP_T,
                         LOCAL_GL_CLAMP_TO_EDGE);

    ClearCachedFilter();

    return true;
}
void
CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer)
{
  if (!IsDirty())
    return;
  Painted();

  if (mDrawTarget) {
    mDrawTarget->Flush();
    mSurface =
      gfxPlatform::GetPlatform()->CreateThebesSurfaceAliasForDrawTarget_hack(mDrawTarget);
  }

  if (!mGLContext && aDestSurface) {
    nsRefPtr<gfxContext> tmpCtx = new gfxContext(aDestSurface);
    tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
    CopyableCanvasLayer::PaintWithOpacity(tmpCtx, 1.0f, aMaskLayer);
    return;
  }

  if (mGLContext) {
    nsRefPtr<gfxImageSurface> readSurf;
    RefPtr<DataSourceSurface> readDSurf;
    nsRefPtr<gfxASurface> resultSurf;

    SharedSurface* sharedSurf = mGLContext->RequestFrame();
    if (!sharedSurf) {
      NS_WARNING("Null frame received.");
      return;
    }

    IntSize readSize(sharedSurf->Size());
    gfxImageFormat format = (GetContentFlags() & CONTENT_OPAQUE)
                            ? gfxImageFormat::RGB24
                            : gfxImageFormat::ARGB32;

    if (aDestSurface) {
      resultSurf = aDestSurface;
    } else {
      resultSurf = GetTempSurface(readSize, format);
    }
    MOZ_ASSERT(resultSurf);
    if (resultSurf->CairoStatus() != 0) {
      MOZ_ASSERT(false, "Bad resultSurf->CairoStatus().");
      return;
    }

    MOZ_ASSERT(sharedSurf->APIType() == APITypeT::OpenGL);
    SharedSurface_GL* surfGL = SharedSurface_GL::Cast(sharedSurf);

    if (surfGL->Type() == SharedSurfaceType::Basic) {
      // sharedSurf_Basic->mData must outlive readSurf and readDSurf. Alas,
      // readSurf and readDSurf may not leave the scope they were declared in.
      SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL);
      readDSurf = sharedSurf_Basic->GetData();
      readSurf = new gfxImageSurface(readDSurf->GetData(),
                                     ThebesIntSize(readDSurf->GetSize()),
                                     readDSurf->Stride(),
                                     SurfaceFormatToImageFormat(readDSurf->GetFormat()));
    } else {
      if (ToIntSize(resultSurf->GetSize()) != readSize ||
          !(readSurf = resultSurf->GetAsImageSurface()) ||
          readSurf->Format() != format)
      {
        readSurf = GetTempSurface(readSize, format);
      }

      // Readback handles Flush/MarkDirty.
      mGLContext->Screen()->Readback(surfGL, readSurf);
    }
    MOZ_ASSERT(readSurf);

    bool needsPremult = surfGL->HasAlpha() && !mIsGLAlphaPremult;
    if (needsPremult) {
      readSurf->Flush();
      gfxUtils::PremultiplyImageSurface(readSurf);
      readSurf->MarkDirty();
    }
    
    if (readSurf != resultSurf) {
      readSurf->Flush();
      nsRefPtr<gfxContext> ctx = new gfxContext(resultSurf);
      ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
      ctx->SetSource(readSurf);
      ctx->Paint();
    }

    // If !aDestSurface then we will end up painting using mSurface, so
    // stick our surface into mSurface, so that the Paint() path is the same.
    if (!aDestSurface) {
      mSurface = resultSurf;
    }
  }
}
VectorImage::Draw(gfxContext* aContext,
                  const nsIntSize& aSize,
                  const ImageRegion& aRegion,
                  uint32_t aWhichFrame,
                  GraphicsFilter aFilter,
                  const Maybe<SVGImageContext>& aSVGContext,
                  uint32_t aFlags)
{
  if (aWhichFrame > FRAME_MAX_VALUE) {
    return DrawResult::BAD_ARGS;
  }

  if (!aContext) {
    return DrawResult::BAD_ARGS;
  }

  if (mError) {
    return DrawResult::BAD_IMAGE;
  }

  if (!mIsFullyLoaded) {
    return DrawResult::NOT_READY;
  }

  if (mIsDrawing) {
    NS_WARNING("Refusing to make re-entrant call to VectorImage::Draw");
    return DrawResult::TEMPORARY_ERROR;
  }

  if (mAnimationConsumers == 0 && mProgressTracker) {
    mProgressTracker->OnUnlockedDraw();
  }

  AutoRestore<bool> autoRestoreIsDrawing(mIsDrawing);
  mIsDrawing = true;

  float animTime = (aWhichFrame == FRAME_FIRST) ? 0.0f
                                                : mSVGDocumentWrapper->GetCurrentTime();
  AutoSVGRenderingState autoSVGState(aSVGContext, animTime,
                                     mSVGDocumentWrapper->GetRootSVGElem());

  // Pack up the drawing parameters.
  SVGDrawingParameters params(aContext, aSize, aRegion, aFilter,
                              aSVGContext, animTime, aFlags);

  if (aFlags & FLAG_BYPASS_SURFACE_CACHE) {
    CreateSurfaceAndShow(params);
    return DrawResult::SUCCESS;
  }

  DrawableFrameRef frameRef =
    SurfaceCache::Lookup(ImageKey(this),
                         VectorSurfaceKey(params.size,
                                          params.svgContext,
                                          params.animationTime));

  // Draw.
  if (frameRef) {
    RefPtr<SourceSurface> surface = frameRef->GetSurface();
    if (surface) {
      nsRefPtr<gfxDrawable> svgDrawable =
        new gfxSurfaceDrawable(surface, ThebesIntSize(frameRef->GetSize()));
      Show(svgDrawable, params);
      return DrawResult::SUCCESS;
    }

    // We lost our surface due to some catastrophic event.
    RecoverFromLossOfSurfaces();
  }

  CreateSurfaceAndShow(params);

  return DrawResult::SUCCESS;
}
void
VectorImage::CreateSurfaceAndShow(const SVGDrawingParameters& aParams)
{
  mSVGDocumentWrapper->UpdateViewportBounds(aParams.viewportSize);
  mSVGDocumentWrapper->FlushImageTransformInvalidation();

  nsRefPtr<gfxDrawingCallback> cb =
    new SVGDrawingCallback(mSVGDocumentWrapper,
                           nsIntRect(nsIntPoint(0, 0), aParams.viewportSize),
                           aParams.size,
                           aParams.flags);

  nsRefPtr<gfxDrawable> svgDrawable =
    new gfxCallbackDrawable(cb, ThebesIntSize(aParams.size));

  // We take an early exit without using the surface cache if too large,
  // because for vector images this can cause bad perf issues if large sizes
  // are scaled repeatedly (a rather common scenario) that can quickly exhaust
  // the cache.
  // Similar to max image size calculations, this has a max cap and size check.
  // max cap = 8000 (pixels); size check = 5% of cache
  int32_t maxDimension = 8000;
  int32_t maxCacheElemSize = (gfxPrefs::ImageMemSurfaceCacheMaxSizeKB() * 1024) / 20;
  
  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) ||
                     // Image x or y is larger than our cache cap:
                     aParams.size.width > maxDimension ||
                     aParams.size.height > maxDimension;
  if (!bypassCache) {
    // This is separated out to make sure width and height are sane at this point
    // and the result can't overflow. Note: keep maxDimension low enough so that
    // (maxDimension)^2 x 4 < INT32_MAX.
    // Assuming surface size for any rendered vector image is RGBA, so 4Bpp.
    bypassCache = (aParams.size.width * aParams.size.height * 4) > maxCacheElemSize;
  }

  if (bypassCache)
    return Show(svgDrawable, aParams);

  // 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.)
  nsRefPtr<imgFrame> frame = new imgFrame;
  nsresult rv =
    frame->InitWithDrawable(svgDrawable, ThebesIntSize(aParams.size),
                            SurfaceFormat::B8G8R8A8,
                            GraphicsFilter::FILTER_NEAREST, 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),
                       Lifetime::Transient);

  // Draw.
  nsRefPtr<gfxDrawable> drawable =
    new gfxSurfaceDrawable(surface, ThebesIntSize(aParams.size));
  Show(drawable, aParams);
}