void
BasicTextureImage::EndUpdate()
{
    NS_ASSERTION(!!mUpdateDrawTarget, "EndUpdate() without BeginUpdate()?");

    // FIXME: this is the slow boat.  Make me fast (with GLXPixmap?).

    RefPtr<gfx::SourceSurface> updateSnapshot = mUpdateDrawTarget->Snapshot();
    RefPtr<gfx::DataSourceSurface> updateData = updateSnapshot->GetDataSurface();

    bool relative = FinishedSurfaceUpdate();

    mTextureFormat =
        UploadSurfaceToTexture(mGLContext,
                               updateData,
                               mUpdateRegion,
                               mTexture,
                               mTextureState == Created,
                               mUpdateOffset,
                               relative);
    FinishedSurfaceUpload();

    mUpdateDrawTarget = nullptr;
    mTextureState = Valid;
}
Example #2
0
/* static */ already_AddRefed<ImageBitmap>
ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvasEl,
                            const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
{
  if (aCanvasEl.Width() == 0 || aCanvasEl.Height() == 0) {
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    return nullptr;
  }

  RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aCanvasEl, aRv);

  if (NS_WARN_IF(aRv.Failed())) {
    return nullptr;
  }

  // Crop the source surface if needed.
  RefPtr<SourceSurface> croppedSurface;
  IntRect cropRect = aCropRect.valueOr(IntRect());

  // If the HTMLCanvasElement's rendering context is WebGL, then the snapshot
  // we got from the HTMLCanvasElement is a DataSourceSurface which is a copy
  // of the rendering context. We handle cropping in this case.
  if ((aCanvasEl.GetCurrentContextType() == CanvasContextType::WebGL1 ||
       aCanvasEl.GetCurrentContextType() == CanvasContextType::WebGL2) &&
      aCropRect.isSome()) {
    // The _surface_ must be a DataSourceSurface.
    MOZ_ASSERT(surface->GetType() == SurfaceType::DATA,
               "The snapshot SourceSurface from WebGL rendering contest is not \
               DataSourceSurface.");
    RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
    croppedSurface = CropAndCopyDataSourceSurface(dataSurface, cropRect);
    cropRect.MoveTo(0, 0);
  }
Example #3
0
NS_IMETHODIMP
imgTools::EncodeImage(imgIContainer* aContainer,
                      const nsACString& aMimeType,
                      const nsAString& aOutputOptions,
                      nsIInputStream** aStream)
{
  // Use frame 0 from the image container.
  RefPtr<SourceSurface> frame =
    aContainer->GetFrame(imgIContainer::FRAME_FIRST,
                         imgIContainer::FLAG_SYNC_DECODE);
  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);

  RefPtr<DataSourceSurface> dataSurface;

  if (frame->GetFormat() == SurfaceFormat::B8G8R8A8) {
    dataSurface = frame->GetDataSurface();
  } else {
    // Convert format to SurfaceFormat::B8G8R8A8
    dataSurface = gfxUtils::
      CopySurfaceToDataSourceSurfaceWithFormat(frame,
                                               SurfaceFormat::B8G8R8A8);
  }

  NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);

  return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
}
void
TextureImageEGL::EndUpdate()
{
    NS_ASSERTION(!!mUpdateDrawTarget, "EndUpdate() without BeginUpdate()?");

    //printf_stderr("EndUpdate: slow path");

    // This is the slower path -- we didn't have any way to set up
    // a fast mapping between our cairo target surface and the GL
    // texture, so we have to upload data.

    RefPtr<gfx::SourceSurface> updateSurface = nullptr;
    RefPtr<gfx::DataSourceSurface> uploadImage = nullptr;
    gfx::IntSize updateSize(mUpdateRect.width, mUpdateRect.height);

    NS_ASSERTION(mUpdateDrawTarget->GetSize() == updateSize,
                  "Upload image is the wrong size!");

    updateSurface = mUpdateDrawTarget->Snapshot();
    uploadImage = updateSurface->GetDataSurface();

    if (!uploadImage) {
        return;
    }

    mGLContext->MakeCurrent();
    mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);

    if (mTextureState != Valid) {
        NS_ASSERTION(mUpdateRect.x == 0 && mUpdateRect.y == 0 &&
                      mUpdateRect.Size() == mSize,
                      "Bad initial update on non-created texture!");

        mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
                                0,
                                GLFormatForImage(mUpdateFormat),
                                mUpdateRect.width,
                                mUpdateRect.height,
                                0,
                                GLFormatForImage(uploadImage->GetFormat()),
                                GLTypeForImage(uploadImage->GetFormat()),
                                uploadImage->GetData());
    } else {
        mGLContext->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
                                    0,
                                    mUpdateRect.x,
                                    mUpdateRect.y,
                                    mUpdateRect.width,
                                    mUpdateRect.height,
                                    GLFormatForImage(uploadImage->GetFormat()),
                                    GLTypeForImage(uploadImage->GetFormat()),
                                    uploadImage->GetData());
    }

    mUpdateDrawTarget = nullptr;
    mTextureState = Valid;
    return;         // mTexture is bound
}
static nsresult
ConvertSourceSurfaceToNV12(const RefPtr<SourceSurface>& aSurface, uint8_t* aDestination)
{
  if (!aSurface) {
    CODEC_ERROR("Getting surface from image failed");
    return NS_ERROR_FAILURE;
  }

  uint32_t width = aSurface->GetSize().width;
  uint32_t height = aSurface->GetSize().height;

  uint8_t* y = aDestination;
  int yStride = width;

  uint8_t* uv = y + (yStride * height);
  int uvStride = width / 2;

  RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
  if (!data) {
    CODEC_ERROR("Getting data surface from %s image with %s surface failed",
                Stringify(aSurface->GetFormat()).c_str(),
                Stringify(aSurface->GetType()).c_str());
    return NS_ERROR_FAILURE;
  }

  DataSourceSurface::ScopedMap map(data, DataSourceSurface::READ);
  if (!map.IsMapped()) {
    CODEC_ERROR("Reading DataSourceSurface from %s image with %s surface failed",
                Stringify(aSurface->GetFormat()).c_str(),
                Stringify(aSurface->GetType()).c_str());
    return NS_ERROR_FAILURE;
  }

  int rv;
  switch (aSurface->GetFormat()) {
    case SurfaceFormat::B8G8R8A8:
    case SurfaceFormat::B8G8R8X8:
      rv = libyuv::ARGBToNV12(static_cast<uint8*>(map.GetData()),
                              map.GetStride(),
                              y, yStride,
                              uv, uvStride,
                              width, height);
      break;
    default:
      CODEC_ERROR("Unsupported SourceSurface format %s",
                  Stringify(aSurface->GetFormat()).c_str());
      NS_ASSERTION(false, "Unsupported SourceSurface format");
      return NS_ERROR_NOT_IMPLEMENTED;
  }

  if (rv != 0) {
    CODEC_ERROR("%s to I420 conversion failed",
                Stringify(aSurface->GetFormat()).c_str());
    return NS_ERROR_FAILURE;
  }

  return NS_OK;
}
Example #6
0
ImageBitmapCloneData*
ImageBitmap::ToCloneData()
{
  ImageBitmapCloneData* result = new ImageBitmapCloneData();
  result->mPictureRect = mPictureRect;
  RefPtr<SourceSurface> surface = mData->GetAsSourceSurface();
  result->mSurface = surface->GetDataSurface();
  MOZ_ASSERT(result->mSurface);

  return result;
}
nsresult
nsDragServiceProxy::InvokeDragSessionImpl(nsIArray* aArrayTransferables,
                                          nsIScriptableRegion* aRegion,
                                          uint32_t aActionType)
{
  nsCOMPtr<nsIDocument> doc = do_QueryInterface(mSourceDocument);
  NS_ENSURE_STATE(doc->GetDocShell());
  TabChild* child = TabChild::GetFrom(doc->GetDocShell());
  NS_ENSURE_STATE(child);
  nsTArray<mozilla::dom::IPCDataTransfer> dataTransfers;
  nsContentUtils::TransferablesToIPCTransferables(aArrayTransferables,
                                                  dataTransfers,
                                                  false,
                                                  child->Manager(),
                                                  nullptr);

  LayoutDeviceIntRect dragRect;
  if (mHasImage || mSelection) {
    nsPresContext* pc;
    RefPtr<mozilla::gfx::SourceSurface> surface;
    DrawDrag(mSourceNode, aRegion, mScreenPosition, &dragRect, &surface, &pc);

    if (surface) {
      RefPtr<mozilla::gfx::DataSourceSurface> dataSurface =
        surface->GetDataSurface();
      if (dataSurface) {
        size_t length;
        int32_t stride;
        Shmem surfaceData;
        nsContentUtils::GetSurfaceData(dataSurface, &length, &stride, child,
                                       &surfaceData);
        // Save the surface data to shared memory.
        if (!surfaceData.IsReadable() || !surfaceData.get<char>()) {
          NS_WARNING("Failed to create shared memory for drag session.");
          return NS_ERROR_FAILURE;
        }

        mozilla::Unused <<
          child->SendInvokeDragSession(dataTransfers, aActionType, surfaceData,
                                       stride, static_cast<uint8_t>(dataSurface->GetFormat()),
                                       dragRect);
        StartDragSession();
        return NS_OK;
      }
    }
  }

  mozilla::Unused << child->SendInvokeDragSession(dataTransfers, aActionType,
                                                  mozilla::void_t(), 0, 0, dragRect);
  StartDragSession();
  return NS_OK;
}
Example #8
0
static already_AddRefed<layers::Image>
CreateImageFromRawData(const gfx::IntSize& aSize,
                       uint32_t aStride,
                       gfx::SurfaceFormat aFormat,
                       uint8_t* aBuffer,
                       uint32_t aBufferLength,
                       const Maybe<IntRect>& aCropRect)
{
  MOZ_ASSERT(NS_IsMainThread());

  // Copy and crop the source buffer into a SourceSurface.
  RefPtr<SourceSurface> rgbaSurface =
    CreateSurfaceFromRawData(aSize, aStride, aFormat,
                             aBuffer, aBufferLength,
                             aCropRect);

  if (NS_WARN_IF(!rgbaSurface)) {
    return nullptr;
  }

  // Convert RGBA to BGRA
  RefPtr<DataSourceSurface> rgbaDataSurface = rgbaSurface->GetDataSurface();
  RefPtr<DataSourceSurface> bgraDataSurface =
    Factory::CreateDataSourceSurfaceWithStride(rgbaDataSurface->GetSize(),
                                               SurfaceFormat::B8G8R8A8,
                                               rgbaDataSurface->Stride());

  DataSourceSurface::MappedSurface rgbaMap;
  DataSourceSurface::MappedSurface bgraMap;

  if (NS_WARN_IF(!rgbaDataSurface->Map(DataSourceSurface::MapType::READ, &rgbaMap)) ||
      NS_WARN_IF(!bgraDataSurface->Map(DataSourceSurface::MapType::WRITE, &bgraMap))) {
    return nullptr;
  }

  libyuv::ABGRToARGB(rgbaMap.mData, rgbaMap.mStride,
                     bgraMap.mData, bgraMap.mStride,
                     bgraDataSurface->GetSize().width,
                     bgraDataSurface->GetSize().height);

  rgbaDataSurface->Unmap();
  bgraDataSurface->Unmap();

  // Create an Image from the BGRA SourceSurface.
  RefPtr<layers::Image> image = CreateImageFromSurface(bgraDataSurface);

  if (NS_WARN_IF(!image)) {
    return nullptr;
  }

  return image.forget();
}
Example #9
0
NS_IMETHODIMP
PuppetWidget::SetCursor(imgIContainer* aCursor,
                        uint32_t aHotspotX, uint32_t aHotspotY)
{
  if (!aCursor || !mTabChild) {
    return NS_OK;
  }

#if !defined(XP_WIN)
  if (mCustomCursor == aCursor &&
      mCursorHotspotX == aHotspotX &&
      mCursorHotspotY == aHotspotY &&
      !mUpdateCursor) {
    return NS_OK;
  }
#endif

  RefPtr<mozilla::gfx::SourceSurface> surface =
    aCursor->GetFrame(imgIContainer::FRAME_CURRENT,
                      imgIContainer::FLAG_SYNC_DECODE);
  if (!surface) {
    return NS_ERROR_FAILURE;
  }

  RefPtr<mozilla::gfx::DataSourceSurface> dataSurface =
    surface->GetDataSurface();
  if (!dataSurface) {
    return NS_ERROR_FAILURE;
  }

  size_t length;
  int32_t stride;
  mozilla::UniquePtr<char[]> surfaceData =
    nsContentUtils::GetSurfaceData(WrapNotNull(dataSurface), &length, &stride);

  nsDependentCString cursorData(surfaceData.get(), length);
  mozilla::gfx::IntSize size = dataSurface->GetSize();
  if (!mTabChild->SendSetCustomCursor(cursorData, size.width, size.height, stride,
                                      static_cast<uint8_t>(dataSurface->GetFormat()),
                                      aHotspotX, aHotspotY, mUpdateCursor)) {
    return NS_ERROR_FAILURE;
  }

  mCursor = nsCursor(-1);
  mCustomCursor = aCursor;
  mCursorHotspotX = aHotspotX;
  mCursorHotspotY = aHotspotY;
  mUpdateCursor = false;

  return NS_OK;
}
nsresult
nsDragServiceProxy::InvokeDragSessionImpl(nsISupportsArray* aArrayTransferables,
                                          nsIScriptableRegion* aRegion,
                                          uint32_t aActionType)
{
  nsCOMPtr<nsIDocument> doc = do_QueryInterface(mSourceDocument);
  NS_ENSURE_STATE(doc->GetDocShell());
  mozilla::dom::TabChild* child =
    mozilla::dom::TabChild::GetFrom(doc->GetDocShell());
  NS_ENSURE_STATE(child);
  nsTArray<mozilla::dom::IPCDataTransfer> dataTransfers;
  nsContentUtils::TransferablesToIPCTransferables(aArrayTransferables,
                                                  dataTransfers,
                                                  false,
                                                  child->Manager(),
                                                  nullptr);

  if (mHasImage || mSelection) {
    nsIntRect dragRect;
    nsPresContext* pc;
    RefPtr<mozilla::gfx::SourceSurface> surface;
    DrawDrag(mSourceNode, aRegion, mScreenX, mScreenY,
             &dragRect, &surface, &pc);

    if (surface) {
      RefPtr<mozilla::gfx::DataSourceSurface> dataSurface =
        surface->GetDataSurface();
      mozilla::gfx::IntSize size = dataSurface->GetSize();

      size_t length;
      int32_t stride;
      mozilla::UniquePtr<char[]> surfaceData =
        nsContentUtils::GetSurfaceData(dataSurface, &length, &stride);
      nsDependentCString dragImage(surfaceData.get(), length);

      mozilla::unused <<
        child->SendInvokeDragSession(dataTransfers, aActionType, dragImage,
                                     size.width, size.height, stride,
                                     static_cast<uint8_t>(dataSurface->GetFormat()),
                                     dragRect.x, dragRect.y);
      StartDragSession();
      return NS_OK;
    }
  }

  mozilla::unused << child->SendInvokeDragSession(dataTransfers, aActionType,
                                                  nsCString(),
                                                  0, 0, 0, 0, 0, 0);
  StartDragSession();
  return NS_OK;
}
void
TiledTextureImage::EndUpdate()
{
    NS_ASSERTION(mInUpdate, "EndUpdate not in update");
    if (!mUpdateDrawTarget) { // update was to a single TextureImage
        mImages[mCurrentImage]->EndUpdate();
        mInUpdate = false;
        mTextureState = Valid;
        mTextureFormat = mImages[mCurrentImage]->GetTextureFormat();
        return;
    }

    RefPtr<gfx::SourceSurface> updateSnapshot = mUpdateDrawTarget->Snapshot();
    RefPtr<gfx::DataSourceSurface> updateData = updateSnapshot->GetDataSurface();

    // upload tiles from temp surface
    for (unsigned i = 0; i < mImages.Length(); i++) {
        int xPos = (i % mColumns) * mTileSize;
        int yPos = (i / mColumns) * mTileSize;
        IntRect imageRect = IntRect(IntPoint(xPos,yPos), mImages[i]->GetSize());

        nsIntRegion subregion;
        subregion.And(mUpdateRegion, imageRect);
        if (subregion.IsEmpty())
            continue;
        subregion.MoveBy(-xPos, -yPos); // Tile-local space
        // copy tile from temp target
        gfx::DrawTarget* drawTarget = mImages[i]->BeginUpdate(subregion);
        MOZ_ASSERT(drawTarget->GetBackendType() == BackendType::CAIRO,
                   "updateSnapshot should not have been converted to data");
        gfxUtils::ClipToRegion(drawTarget, subregion);
        Size size(updateData->GetSize().width,
                  updateData->GetSize().height);
        drawTarget->DrawSurface(updateData,
                                Rect(Point(-xPos, -yPos), size),
                                Rect(Point(0, 0), size),
                                DrawSurfaceOptions(),
                                DrawOptions(1.0, CompositionOp::OP_SOURCE,
                                            AntialiasMode::NONE));
        drawTarget->PopClip();
        mImages[i]->EndUpdate();
    }

    mUpdateDrawTarget = nullptr;
    mInUpdate = false;
    mTextureFormat = mImages[0]->GetTextureFormat();
    mTextureState = Valid;
}
Example #12
0
already_AddRefed<gfxASurface>
gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
{
  // If we have already created a thebes surface, we can just return it.
  void *surface = aTarget->GetUserData(&kThebesSurfaceKey);
  if (surface) {
    nsRefPtr<gfxASurface> surf = static_cast<gfxASurface*>(surface);
    return surf.forget();
  }

  nsRefPtr<gfxASurface> surf;
  if (aTarget->GetType() == BACKEND_CAIRO) {
    cairo_surface_t* csurf =
      static_cast<cairo_surface_t*>(aTarget->GetNativeSurface(NATIVE_SURFACE_CAIRO_SURFACE));
    surf = gfxASurface::Wrap(csurf);
  } else {
    // The semantics of this part of the function are sort of weird. If we
    // don't have direct support for the backend, we snapshot the first time
    // and then return the snapshotted surface for the lifetime of the draw
    // target. Sometimes it seems like this works out, but it seems like it
    // might result in no updates ever.
    RefPtr<SourceSurface> source = aTarget->Snapshot();
    RefPtr<DataSourceSurface> data = source->GetDataSurface();

    if (!data) {
      return NULL;
    }

    IntSize size = data->GetSize();
    gfxASurface::gfxImageFormat format = gfxASurface::FormatFromContent(ContentForFormat(data->GetFormat()));


    // We need to make a copy here because data might change its data under us
    nsRefPtr<gfxImageSurface> imageSurf = new gfxImageSurface(gfxIntSize(size.width, size.height), format, false);
 
    bool resultOfCopy = imageSurf->CopyFrom(source);
    NS_ASSERTION(resultOfCopy, "Failed to copy surface.");
    surf = imageSurf;
  }

  // add a reference to be held by the drawTarget
  // careful, the reference graph is getting complicated here
  surf->AddRef();
  aTarget->AddUserData(&kThebesSurfaceKey, surf.get(), DestroyThebesSurface);

  return surf.forget();
}
Example #13
0
void
WebGLContext::GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat)
{
    *aImageBuffer = nullptr;
    *aFormat = 0;

    // Use GetSurfaceSnapshot() to make sure that appropriate y-flip gets applied
    bool premult;
    RefPtr<SourceSurface> snapshot =
      GetSurfaceSnapshot(mOptions.premultipliedAlpha ? nullptr : &premult);
    if (!snapshot) {
        return;
    }
    MOZ_ASSERT(mOptions.premultipliedAlpha || !premult, "We must get unpremult when we ask for it!");

    RefPtr<DataSourceSurface> dataSurface = snapshot->GetDataSurface();

    DataSourceSurface::MappedSurface map;
    if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) {
        return;
    }

    static const fallible_t fallible = fallible_t();
    uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4];
    if (!imageBuffer) {
        dataSurface->Unmap();
        return;
    }
    memcpy(imageBuffer, map.mData, mWidth * mHeight * 4);

    dataSurface->Unmap();

    int32_t format = imgIEncoder::INPUT_FORMAT_HOSTARGB;
    if (!mOptions.premultipliedAlpha) {
        // We need to convert to INPUT_FORMAT_RGBA, otherwise
        // we are automatically considered premult, and unpremult'd.
        // Yes, it is THAT silly.
        // Except for different lossy conversions by color,
        // we could probably just change the label, and not change the data.
        gfxUtils::ConvertBGRAtoRGBA(imageBuffer, mWidth * mHeight * 4);
        format = imgIEncoder::INPUT_FORMAT_RGBA;
    }

    *aImageBuffer = imageBuffer;
    *aFormat = format;
}
Example #14
0
void
DIBTextureClient::Unlock()
{
  MOZ_ASSERT(mIsLocked, "Unlocked called while the texture is not locked!");
  if (mDrawTarget) {
    if (mReadbackSink) {
      RefPtr<SourceSurface> snapshot = mDrawTarget->Snapshot();
      RefPtr<DataSourceSurface> dataSurf = snapshot->GetDataSurface();
      mReadbackSink->ProcessReadback(dataSurf);
    }

    mDrawTarget->Flush();
    mDrawTarget = nullptr;
  }

  mIsLocked = false;
}
Example #15
0
already_AddRefed<gfx::DataSourceSurface>
X11TextureHost::GetAsSurface()
{
  if (!mTextureSource || !mTextureSource->AsSourceBasic()) {
    return nullptr;
  }
  RefPtr<DrawTarget> tempDT =
    gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
      GetSize(), GetFormat());
  if (!tempDT) {
    return nullptr;
  }
  RefPtr<SourceSurface> surf = mTextureSource->AsSourceBasic()->GetSurface(tempDT);
  if (!surf) {
    return nullptr;
  }
  return surf->GetDataSurface();
}
already_AddRefed<gfxASurface>
gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
{
  RefPtr<SourceSurface> source = aTarget->Snapshot();
  RefPtr<DataSourceSurface> data = source->GetDataSurface();

  if (!data) {
    return NULL;
  }

  IntSize size = data->GetSize();
  gfxASurface::gfxImageFormat format = gfxASurface::FormatFromContent(ContentForFormat(data->GetFormat()));
  
  nsRefPtr<gfxImageSurface> image =
    new gfxImageSurface(data->GetData(), gfxIntSize(size.width, size.height),
                        data->Stride(), format);

  image->SetData(&kDrawSourceSurface, data.forget().drop(), DataSourceSurfaceDestroy);
  return image.forget();
}
mozilla::UniquePtr<uint8_t[]>
ImageBitmapRenderingContext::GetImageBuffer(int32_t* aFormat)
{
  *aFormat = 0;

  if (!mImage) {
    return nullptr;
  }

  RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface();
  RefPtr<DataSourceSurface> data = surface->GetDataSurface();
  if (!data) {
    return nullptr;
  }

  if (data->GetSize() != IntSize(mWidth, mHeight)) {
    data = MatchWithIntrinsicSize();
  }

  *aFormat = imgIEncoder::INPUT_FORMAT_HOSTARGB;
  return SurfaceToPackedBGRA(data);
}
Example #18
0
void WriteSnapshotToDumpFile(Compositor* aCompositor, DrawTarget* aTarget)
{
  RefPtr<SourceSurface> surf = aTarget->Snapshot();
  RefPtr<DataSourceSurface> dSurf = surf->GetDataSurface();
  WriteSnapshotToDumpFile_internal(aCompositor, dSurf);
}
Example #19
0
NS_IMETHODIMP
nsClipboard::SetData(nsITransferable *aTransferable,
                     nsIClipboardOwner *anOwner,
                     int32_t aWhichClipboard)
{
  if (aWhichClipboard != kGlobalClipboard) {
    return NS_ERROR_NOT_IMPLEMENTED;
  }

  if (!XRE_IsParentProcess()) {
    // Re-direct to the clipboard proxy.
    RefPtr<nsClipboardProxy> clipboardProxy = new nsClipboardProxy();
    return clipboardProxy->SetData(aTransferable, anOwner, aWhichClipboard);
  }

  // Clear out the clipboard in order to set the new data.
  EmptyClipboard(aWhichClipboard);

  // Use a pref to toggle rich text/non-text support.
  if (Preferences::GetBool("clipboard.plainTextOnly")) {
    nsCOMPtr<nsISupports> clip;
    uint32_t len;
    nsresult rv = aTransferable->GetTransferData(kUnicodeMime,
                                                 getter_AddRefs(clip),
                                                 &len);
    if (NS_FAILED(rv)) {
      return rv;
    }
    nsCOMPtr<nsISupportsString> wideString = do_QueryInterface(clip);
    if (!wideString) {
      return NS_ERROR_NOT_IMPLEMENTED;
    }
    nsAutoString utf16string;
    wideString->GetData(utf16string);
    mClipboard->SetText(utf16string);
    return NS_OK;
  }

  // Get the types of supported flavors.
  nsCOMPtr<nsISupportsArray> flavorList;
  nsresult rv = aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
  if (!flavorList || NS_FAILED(rv)) {
    return NS_ERROR_FAILURE;
  }

  uint32_t flavorCount = 0;
  flavorList->Count(&flavorCount);
  bool imageAdded = false;
  for (uint32_t i = 0; i < flavorCount; ++i) {
    nsCOMPtr<nsISupportsCString> currentFlavor = do_QueryElementAt(flavorList, i);

    if (currentFlavor) {
      // MIME type
      nsXPIDLCString flavorStr;
      currentFlavor->ToString(getter_Copies(flavorStr));

      // Clip is the data which will be sent to the clipboard.
      nsCOMPtr<nsISupports> clip;
      uint32_t len;

      if (flavorStr.EqualsLiteral(kUnicodeMime)) {
        // text/plain
        rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(clip), &len);
        nsCOMPtr<nsISupportsString> wideString = do_QueryInterface(clip);
        if (!wideString || NS_FAILED(rv)) {
          continue;
        }

        nsAutoString utf16string;
        wideString->GetData(utf16string);
        mClipboard->SetText(utf16string);
      } else if (flavorStr.EqualsLiteral(kHTMLMime)) {
        // text/html
        rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(clip), &len);
        nsCOMPtr<nsISupportsString> wideString = do_QueryInterface(clip);
        if (!wideString || NS_FAILED(rv)) {
          continue;
        }

        nsAutoString utf16string;
        wideString->GetData(utf16string);
        mClipboard->SetHTML(utf16string);
      } else if (!imageAdded && // image is added only once to the clipboard.
                 (flavorStr.EqualsLiteral(kNativeImageMime) ||
                  flavorStr.EqualsLiteral(kPNGImageMime) ||
                  flavorStr.EqualsLiteral(kJPEGImageMime) ||
                  flavorStr.EqualsLiteral(kJPGImageMime))) {
        // image/[png|jpeg|jpg] or application/x-moz-nativeimage

        // Look through our transfer data for the image.
        static const char* const imageMimeTypes[] = {
          kNativeImageMime, kPNGImageMime, kJPEGImageMime, kJPGImageMime };

        nsCOMPtr<nsISupportsInterfacePointer> imgPtr;
        for (uint32_t i = 0; !imgPtr && i < ArrayLength(imageMimeTypes); ++i) {
          aTransferable->GetTransferData(imageMimeTypes[i], getter_AddRefs(clip), &len);
          imgPtr = do_QueryInterface(clip);
        }
        if (!imgPtr) {
          continue;
        }

        nsCOMPtr<nsISupports> imageData;
        imgPtr->GetData(getter_AddRefs(imageData));
        nsCOMPtr<imgIContainer> image(do_QueryInterface(imageData));
        if (!image) {
          continue;
        }

        RefPtr<gfx::SourceSurface> surface =
          image->GetFrame(imgIContainer::FRAME_CURRENT,
                          imgIContainer::FLAG_SYNC_DECODE);
        if (!surface) {
          continue;
        }

        RefPtr<gfx::DataSourceSurface> dataSurface;
        if (surface->GetFormat() == gfx::SurfaceFormat::B8G8R8A8) {
          dataSurface = surface->GetDataSurface();
        } else {
          // Convert format to SurfaceFormat::B8G8R8A8.
          dataSurface = gfxUtils::CopySurfaceToDataSourceSurfaceWithFormat(surface, gfx::SurfaceFormat::B8G8R8A8);
        }

        mClipboard->SetImage(dataSurface);
        imageAdded = true;
      }
    }
  }

  return NS_OK;
}
Example #20
0
NS_IMETHODIMP
AsyncFaviconDataReady::OnComplete(nsIURI *aFaviconURI,
                                  uint32_t aDataLen,
                                  const uint8_t *aData, 
                                  const nsACString &aMimeType)
{
  if (!aDataLen || !aData) {
    if (mURLShortcut) {
      OnFaviconDataNotAvailable();
    }
    
    return NS_OK;
  }

  nsCOMPtr<nsIFile> icoFile;
  nsresult rv = FaviconHelper::GetOutputIconPath(mNewURI, icoFile, mURLShortcut);
  NS_ENSURE_SUCCESS(rv, rv);
  
  nsAutoString path;
  rv = icoFile->GetPath(path);
  NS_ENSURE_SUCCESS(rv, rv);

  // Convert the obtained favicon data to an input stream
  nsCOMPtr<nsIInputStream> stream;
  rv = NS_NewByteInputStream(getter_AddRefs(stream),
                             reinterpret_cast<const char*>(aData),
                             aDataLen,
                             NS_ASSIGNMENT_DEPEND);
  NS_ENSURE_SUCCESS(rv, rv);

  // Decode the image from the format it was returned to us in (probably PNG)
  nsAutoCString mimeTypeOfInputData;
  mimeTypeOfInputData.AssignLiteral("image/vnd.microsoft.icon");
  nsCOMPtr<imgIContainer> container;
  nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1");
  rv = imgtool->DecodeImageData(stream, aMimeType,
                                getter_AddRefs(container));
  NS_ENSURE_SUCCESS(rv, rv);

  nsRefPtr<gfxASurface> imgFrame =
    container->GetFrame(imgIContainer::FRAME_FIRST, 0);
  NS_ENSURE_TRUE(imgFrame, NS_ERROR_FAILURE);

  RefPtr<SourceSurface> surface =
    gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(nullptr, imgFrame);
  NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE);

  RefPtr<DataSourceSurface> dataSurface;
  IntSize size;

  if (mURLShortcut) {
    // Create a 48x48 surface and paint the icon into the central 16x16 rect.
    size.width = 48;
    size.height = 48;
    dataSurface =
      Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8);
    NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);

    DataSourceSurface::MappedSurface map;
    if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) {
      return NS_ERROR_FAILURE;
    }

    RefPtr<DrawTarget> dt =
      Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                       map.mData,
                                       dataSurface->GetSize(),
                                       map.mStride,
                                       dataSurface->GetFormat());
    dt->FillRect(Rect(0, 0, size.width, size.height),
                 ColorPattern(Color(1.0f, 1.0f, 1.0f, 1.0f)));
    dt->DrawSurface(surface,
                    Rect(16, 16, 16, 16),
                    Rect(Point(0, 0),
                         Size(surface->GetSize().width, surface->GetSize().height)));

    dataSurface->Unmap();
  } else {
    size.width = GetSystemMetrics(SM_CXSMICON);
    size.height = GetSystemMetrics(SM_CYSMICON);
    if (!size.width || !size.height) {
      size.width = 16;
      size.height = 16;
    }
    dataSurface = surface->GetDataSurface();
  }

  // Allocate a new buffer that we own and can use out of line in
  // another thread.
  uint8_t *data = SurfaceToPackedBGRA(dataSurface);
  if (!data) {
    return NS_ERROR_OUT_OF_MEMORY;
  }
  int32_t stride = 4 * size.width;
  int32_t dataLength = stride * size.height;

  // AsyncEncodeAndWriteIcon takes ownership of the heap allocated buffer
  nsCOMPtr<nsIRunnable> event = new AsyncEncodeAndWriteIcon(path, data,
                                                            dataLength,
                                                            stride,
                                                            size.width,
                                                            size.height,
                                                            mURLShortcut);
  mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);

  return NS_OK;
}
Example #21
0
nsresult VP8TrackEncoder::PrepareRawFrame(VideoChunk &aChunk)
{
  RefPtr<Image> img;
  if (aChunk.mFrame.GetForceBlack() || aChunk.IsNull()) {
    if (!mMuteFrame) {
      mMuteFrame = VideoFrame::CreateBlackImage(gfx::IntSize(mFrameWidth, mFrameHeight));
      MOZ_ASSERT(mMuteFrame);
    }
    img = mMuteFrame;
  } else {
    img = aChunk.mFrame.GetImage();
  }

  if (img->GetSize() != IntSize(mFrameWidth, mFrameHeight)) {
    VP8LOG("Dynamic resolution changes (was %dx%d, now %dx%d) are unsupported\n",
           mFrameWidth, mFrameHeight, img->GetSize().width, img->GetSize().height);
    return NS_ERROR_FAILURE;
  }

  ImageFormat format = img->GetFormat();
  if (format == ImageFormat::PLANAR_YCBCR) {
    PlanarYCbCrImage* yuv = static_cast<PlanarYCbCrImage *>(img.get());

    MOZ_RELEASE_ASSERT(yuv);
    if (!yuv->IsValid()) {
      NS_WARNING("PlanarYCbCrImage is not valid");
      return NS_ERROR_FAILURE;
    }
    const PlanarYCbCrImage::Data *data = yuv->GetData();

    if (isYUV420(data) && !data->mCbSkip) {
      // 420 planar, no need for conversions
      mVPXImageWrapper->planes[VPX_PLANE_Y] = data->mYChannel;
      mVPXImageWrapper->planes[VPX_PLANE_U] = data->mCbChannel;
      mVPXImageWrapper->planes[VPX_PLANE_V] = data->mCrChannel;
      mVPXImageWrapper->stride[VPX_PLANE_Y] = data->mYStride;
      mVPXImageWrapper->stride[VPX_PLANE_U] = data->mCbCrStride;
      mVPXImageWrapper->stride[VPX_PLANE_V] = data->mCbCrStride;

      return NS_OK;
    }
  }

  // Not 420 planar, have to convert
  uint32_t yPlaneSize = mFrameWidth * mFrameHeight;
  uint32_t halfWidth = (mFrameWidth + 1) / 2;
  uint32_t halfHeight = (mFrameHeight + 1) / 2;
  uint32_t uvPlaneSize = halfWidth * halfHeight;

  if (mI420Frame.IsEmpty()) {
    mI420Frame.SetLength(yPlaneSize + uvPlaneSize * 2);
  }

  uint8_t *y = mI420Frame.Elements();
  uint8_t *cb = mI420Frame.Elements() + yPlaneSize;
  uint8_t *cr = mI420Frame.Elements() + yPlaneSize + uvPlaneSize;

  if (format == ImageFormat::PLANAR_YCBCR) {
    PlanarYCbCrImage* yuv = static_cast<PlanarYCbCrImage *>(img.get());

    MOZ_RELEASE_ASSERT(yuv);
    if (!yuv->IsValid()) {
      NS_WARNING("PlanarYCbCrImage is not valid");
      return NS_ERROR_FAILURE;
    }
    const PlanarYCbCrImage::Data *data = yuv->GetData();

    int rv;
    std::string yuvFormat;
    if (isYUV420(data) && data->mCbSkip) {
      // If mCbSkip is set, we assume it's nv12 or nv21.
      if (data->mCbChannel < data->mCrChannel) { // nv12
        rv = libyuv::NV12ToI420(data->mYChannel, data->mYStride,
                                data->mCbChannel, data->mCbCrStride,
                                y, mFrameWidth,
                                cb, halfWidth,
                                cr, halfWidth,
                                mFrameWidth, mFrameHeight);
        yuvFormat = "NV12";
      } else { // nv21
        rv = libyuv::NV21ToI420(data->mYChannel, data->mYStride,
                                data->mCrChannel, data->mCbCrStride,
                                y, mFrameWidth,
                                cb, halfWidth,
                                cr, halfWidth,
                                mFrameWidth, mFrameHeight);
        yuvFormat = "NV21";
      }
    } else if (isYUV444(data) && !data->mCbSkip) {
      rv = libyuv::I444ToI420(data->mYChannel, data->mYStride,
                              data->mCbChannel, data->mCbCrStride,
                              data->mCrChannel, data->mCbCrStride,
                              y, mFrameWidth,
                              cb, halfWidth,
                              cr, halfWidth,
                              mFrameWidth, mFrameHeight);
      yuvFormat = "I444";
    } else if (isYUV422(data) && !data->mCbSkip) {
      rv = libyuv::I422ToI420(data->mYChannel, data->mYStride,
                              data->mCbChannel, data->mCbCrStride,
                              data->mCrChannel, data->mCbCrStride,
                              y, mFrameWidth,
                              cb, halfWidth,
                              cr, halfWidth,
                              mFrameWidth, mFrameHeight);
      yuvFormat = "I422";
    } else {
      VP8LOG("Unsupported planar format\n");
      NS_ASSERTION(false, "Unsupported planar format");
      return NS_ERROR_NOT_IMPLEMENTED;
    }

    if (rv != 0) {
      VP8LOG("Converting an %s frame to I420 failed\n", yuvFormat.c_str());
      return NS_ERROR_FAILURE;
    }

    VP8LOG("Converted an %s frame to I420\n");
  } else {
    // Not YCbCr at all. Try to get access to the raw data and convert.

    RefPtr<SourceSurface> surf = img->GetAsSourceSurface();
    if (!surf) {
      VP8LOG("Getting surface from %s image failed\n", Stringify(format).c_str());
      return NS_ERROR_FAILURE;
    }

    RefPtr<DataSourceSurface> data = surf->GetDataSurface();
    if (!data) {
      VP8LOG("Getting data surface from %s image with %s (%s) surface failed\n",
             Stringify(format).c_str(), Stringify(surf->GetType()).c_str(),
             Stringify(surf->GetFormat()).c_str());
      return NS_ERROR_FAILURE;
    }

    DataSourceSurface::ScopedMap map(data, DataSourceSurface::READ);
    if (!map.IsMapped()) {
      VP8LOG("Reading DataSourceSurface from %s image with %s (%s) surface failed\n",
             Stringify(format).c_str(), Stringify(surf->GetType()).c_str(),
             Stringify(surf->GetFormat()).c_str());
      return NS_ERROR_FAILURE;
    }

    int rv;
    switch (surf->GetFormat()) {
      case SurfaceFormat::B8G8R8A8:
      case SurfaceFormat::B8G8R8X8:
        rv = libyuv::ARGBToI420(static_cast<uint8*>(map.GetData()),
                                map.GetStride(),
                                y, mFrameWidth,
                                cb, halfWidth,
                                cr, halfWidth,
                                mFrameWidth, mFrameHeight);
        break;
      case SurfaceFormat::R5G6B5_UINT16:
        rv = libyuv::RGB565ToI420(static_cast<uint8*>(map.GetData()),
                                  map.GetStride(),
                                  y, mFrameWidth,
                                  cb, halfWidth,
                                  cr, halfWidth,
                                  mFrameWidth, mFrameHeight);
        break;
      default:
        VP8LOG("Unsupported SourceSurface format %s\n",
               Stringify(surf->GetFormat()).c_str());
        NS_ASSERTION(false, "Unsupported SourceSurface format");
        return NS_ERROR_NOT_IMPLEMENTED;
    }

    if (rv != 0) {
      VP8LOG("%s to I420 conversion failed\n",
             Stringify(surf->GetFormat()).c_str());
      return NS_ERROR_FAILURE;
    }

    VP8LOG("Converted a %s frame to I420\n",
           Stringify(surf->GetFormat()).c_str());
  }

  mVPXImageWrapper->planes[VPX_PLANE_Y] = y;
  mVPXImageWrapper->planes[VPX_PLANE_U] = cb;
  mVPXImageWrapper->planes[VPX_PLANE_V] = cr;
  mVPXImageWrapper->stride[VPX_PLANE_Y] = mFrameWidth;
  mVPXImageWrapper->stride[VPX_PLANE_U] = halfWidth;
  mVPXImageWrapper->stride[VPX_PLANE_V] = halfWidth;

  return NS_OK;
}
Example #22
0
NS_IMETHODIMP
AsyncFaviconDataReady::OnComplete(nsIURI *aFaviconURI,
                                  uint32_t aDataLen,
                                  const uint8_t *aData, 
                                  const nsACString &aMimeType)
{
  if (!aDataLen || !aData) {
    if (mURLShortcut) {
      OnFaviconDataNotAvailable();
    }
    
    return NS_OK;
  }

  nsCOMPtr<nsIFile> icoFile;
  nsresult rv = FaviconHelper::GetOutputIconPath(mNewURI, icoFile, mURLShortcut);
  NS_ENSURE_SUCCESS(rv, rv);
  
  nsAutoString path;
  rv = icoFile->GetPath(path);
  NS_ENSURE_SUCCESS(rv, rv);

  // Convert the obtained favicon data to an input stream
  nsCOMPtr<nsIInputStream> stream;
  rv = NS_NewByteInputStream(getter_AddRefs(stream),
                             reinterpret_cast<const char*>(aData),
                             aDataLen,
                             NS_ASSIGNMENT_DEPEND);
  NS_ENSURE_SUCCESS(rv, rv);

  // Decode the image from the format it was returned to us in (probably PNG)
  nsCOMPtr<imgIContainer> container;
  nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1");
  rv = imgtool->DecodeImageData(stream, aMimeType,
                                getter_AddRefs(container));
  NS_ENSURE_SUCCESS(rv, rv);

  RefPtr<SourceSurface> surface =
    container->GetFrame(imgIContainer::FRAME_FIRST, 0);
  NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE);

  RefPtr<DataSourceSurface> dataSurface;
  IntSize size;

  if (mURLShortcut) {
    // Create a 48x48 surface and paint the icon into the central 16x16 rect.
    size.width = 48;
    size.height = 48;
    dataSurface =
      Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8);
    NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);

    DataSourceSurface::MappedSurface map;
    if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) {
      return NS_ERROR_FAILURE;
    }

    RefPtr<DrawTarget> dt =
      Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                       map.mData,
                                       dataSurface->GetSize(),
                                       map.mStride,
                                       dataSurface->GetFormat());
    if (!dt) {
      gfxWarning() << "AsyncFaviconDataReady::OnComplete failed in CreateDrawTargetForData";
      return NS_ERROR_OUT_OF_MEMORY;
    }
    dt->FillRect(Rect(0, 0, size.width, size.height),
                 ColorPattern(Color(1.0f, 1.0f, 1.0f, 1.0f)));
    dt->DrawSurface(surface,
                    Rect(16, 16, 16, 16),
                    Rect(Point(0, 0),
                         Size(surface->GetSize().width, surface->GetSize().height)));

    dataSurface->Unmap();
  } else {
    // By using the input image surface's size, we may end up encoding
    // to a different size than a 16x16 (or bigger for higher DPI) ICO, but
    // Windows will resize appropriately for us. If we want to encode ourselves
    // one day because we like our resizing better, we'd have to manually
    // resize the image here and use GetSystemMetrics w/ SM_CXSMICON and
    // SM_CYSMICON. We don't support resizing images asynchronously at the
    // moment anyway so getting the DPI aware icon size won't help.
    size.width = surface->GetSize().width;
    size.height = surface->GetSize().height;
    dataSurface = surface->GetDataSurface();
    NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
  }

  // Allocate a new buffer that we own and can use out of line in
  // another thread.
  uint8_t *data = SurfaceToPackedBGRA(dataSurface);
  if (!data) {
    return NS_ERROR_OUT_OF_MEMORY;
  }
  int32_t stride = 4 * size.width;
  int32_t dataLength = stride * size.height;

  // AsyncEncodeAndWriteIcon takes ownership of the heap allocated buffer
  nsCOMPtr<nsIRunnable> event = new AsyncEncodeAndWriteIcon(path, data,
                                                            dataLength,
                                                            stride,
                                                            size.width,
                                                            size.height,
                                                            mURLShortcut);
  mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);

  return NS_OK;
}
already_AddRefed<DataSourceSurface> MacIOSurfaceTextureData::GetAsSurface() {
  RefPtr<SourceSurface> surf = CreateSourceSurfaceFromMacIOSurface(mSurface);
  return surf->GetDataSurface();
}
Example #24
0
NS_IMETHODIMP
nsClipboard::SetNativeClipboardData( nsITransferable *aTransferable,
                                     QClipboard::Mode clipboardMode )
{
    if (nullptr == aTransferable)
    {
        NS_WARNING("nsClipboard::SetNativeClipboardData(): no transferable!");
        return NS_ERROR_FAILURE;
    }

    // get flavor list that includes all flavors that can be written (including
    // ones obtained through conversion)
    nsCOMPtr<nsISupportsArray> flavorList;
    nsresult rv = aTransferable->FlavorsTransferableCanExport( getter_AddRefs(flavorList) );

    if (NS_FAILED(rv))
    {
        NS_WARNING("nsClipboard::SetNativeClipboardData(): no FlavorsTransferable !");
        return NS_ERROR_FAILURE;
    }

    QClipboard *cb = QGuiApplication::clipboard();
    QMimeData *mimeData = new QMimeData;

    uint32_t flavorCount = 0;
    flavorList->Count(&flavorCount);
    bool imageAdded = false;

    for (uint32_t i = 0; i < flavorCount; ++i)
    {
        nsCOMPtr<nsISupports> genericFlavor;
        flavorList->GetElementAt(i,getter_AddRefs(genericFlavor));
        nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor));
        
        if (currentFlavor)
        {
            // flavorStr is the mime type
            nsXPIDLCString flavorStr;
            currentFlavor->ToString(getter_Copies(flavorStr));

            // Clip is the data which will be sent to the clipboard
            nsCOMPtr<nsISupports> clip;
            // len is the length of the data
            uint32_t len;

            // Unicode text?
            if (!strcmp(flavorStr.get(), kUnicodeMime))
            {
                rv = aTransferable->GetTransferData(flavorStr,getter_AddRefs(clip),&len);
                nsCOMPtr<nsISupportsString> wideString;
                wideString = do_QueryInterface(clip);
                if (!wideString || NS_FAILED(rv))
                    continue;

                nsAutoString utf16string;
                wideString->GetData(utf16string);
                QString str = QString::fromUtf16((const ushort*)utf16string.get());

                // Add text to the mimeData
                mimeData->setText(str);
            }

            // html?
            else if (!strcmp(flavorStr.get(), kHTMLMime))
            {
                rv = aTransferable->GetTransferData(flavorStr,getter_AddRefs(clip),&len);
                nsCOMPtr<nsISupportsString> wideString;
                wideString = do_QueryInterface(clip);
                if (!wideString || NS_FAILED(rv))
                    continue;

                nsAutoString utf16string;
                wideString->GetData(utf16string);
                QString str = QString::fromUtf16((const ushort*)utf16string.get());

                // Add html to the mimeData
                mimeData->setHtml(str);
            }

            // image?
            else if (!imageAdded // image is added only once to the clipboard
                     && (!strcmp(flavorStr.get(), kNativeImageMime)
                     ||  !strcmp(flavorStr.get(), kPNGImageMime)
                     ||  !strcmp(flavorStr.get(), kJPEGImageMime)
                     ||  !strcmp(flavorStr.get(), kJPGImageMime)
                     ||  !strcmp(flavorStr.get(), kGIFImageMime))
                    )
            {
                // Look through our transfer data for the image
                static const char* const imageMimeTypes[] = {
                    kNativeImageMime, kPNGImageMime, kJPEGImageMime, kJPGImageMime, kGIFImageMime };
                nsCOMPtr<nsISupportsInterfacePointer> ptrPrimitive;
                for (uint32_t i = 0; !ptrPrimitive && i < ArrayLength(imageMimeTypes); i++)
                {
                    aTransferable->GetTransferData(imageMimeTypes[i], getter_AddRefs(clip), &len);
                    ptrPrimitive = do_QueryInterface(clip);
                }

                if (!ptrPrimitive)
                    continue;

                nsCOMPtr<nsISupports> primitiveData;
                ptrPrimitive->GetData(getter_AddRefs(primitiveData));
                nsCOMPtr<imgIContainer> image(do_QueryInterface(primitiveData));
                if (!image)  // Not getting an image for an image mime type!?
                   continue;

                RefPtr<SourceSurface> surface =
                  image->GetFrame(imgIContainer::FRAME_CURRENT,
                                  imgIContainer::FLAG_SYNC_DECODE);
                if (!surface)
                  continue;

                RefPtr<DataSourceSurface> dataSurface =
                  surface->GetDataSurface();
                if (!dataSurface)
                  continue;

                DataSourceSurface::MappedSurface map;
                if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map))
                  continue;

                QImage qImage(map.mData,
                              dataSurface->GetSize().width,
                              dataSurface->GetSize().height,
                              map.mStride,
                              _moz2dformat_to_qformat(dataSurface->GetFormat()));

                dataSurface->Unmap();

                // Add image to the mimeData
                mimeData->setImageData(qImage);
                imageAdded = true;
            }

            // Other flavors, adding data to clipboard "as is"
            else
            {
                rv = aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(clip), &len);
                // nothing found?
                if (!clip || NS_FAILED(rv))
                    continue;

                void *primitive_data = nullptr;
                nsPrimitiveHelpers::CreateDataFromPrimitive(flavorStr.get(), clip,
                                                            &primitive_data, len);

                if (primitive_data)
                {
                    QByteArray data ((const char *)primitive_data, len);
                    // Add data to the mimeData
                    mimeData->setData(flavorStr.get(), data);
                    nsMemory::Free(primitive_data);
                }
            }
        }
    }

    // If we have some mime data, add it to the clipboard
    if(!mimeData->formats().isEmpty())
        cb->setMimeData(mimeData, clipboardMode);
    else
        delete mimeData;

    return NS_OK;
}
Example #25
0
bool
TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
                              WebGLTexture* tex, TexImageTarget target, GLint level,
                              const webgl::DriverUnpackInfo* dui, GLint xOffset,
                              GLint yOffset, GLint zOffset, GLenum* const out_error) const
{
    MOZ_ASSERT_IF(needsRespec, !isSubImage);

    WebGLContext* webgl = tex->mContext;

    gl::GLContext* gl = webgl->GL();
    gl->MakeCurrent();

    if (needsRespec) {
        *out_error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset,
                                     yOffset, zOffset, mWidth, mHeight, mDepth,
                                     nullptr);
        if (*out_error)
            return false;
    }

    do {
        if (mDepth != 1)
            break;

        const bool isDstPremult = webgl->mPixelStore_PremultiplyAlpha;
        if (mIsSrcPremult != isDstPremult)
            break;

        if (dui->unpackFormat != LOCAL_GL_RGB && dui->unpackFormat != LOCAL_GL_RGBA)
            break;

        if (dui->unpackType != LOCAL_GL_UNSIGNED_BYTE)
            break;

        gl::ScopedFramebuffer scopedFB(gl);
        gl::ScopedBindFramebuffer bindFB(gl, scopedFB.FB());

        {
            gl::GLContext::LocalErrorScope errorScope(*gl);

            gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
                                      target.get(), tex->mGLName, level);

            if (errorScope.GetError())
                break;
        }

        const GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
        if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE)
            break;

        const gfx::IntSize destSize(mWidth, mHeight);
        const auto dstOrigin = (webgl->mPixelStore_FlipY ? gl::OriginPos::TopLeft
                                                         : gl::OriginPos::BottomLeft);
        if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, destSize, scopedFB.FB(),
                                                      dstOrigin))
        {
            break;
        }

        // Blitting was successful, so we're done!
        *out_error = 0;
        return true;
    } while (false);

    webgl->GenerateWarning("%s: Failed to hit GPU-copy fast-path. Falling back to CPU"
                           " upload.",
                           funcName);

    const RefPtr<gfx::SourceSurface> surf = mImage->GetAsSourceSurface();

    RefPtr<gfx::DataSourceSurface> dataSurf;
    if (surf) {
        // WARNING: OSX can lose our MakeCurrent here.
        dataSurf = surf->GetDataSurface();
    }
    if (!dataSurf) {
        webgl->ErrorOutOfMemory("%s: GetAsSourceSurface or GetDataSurface failed after"
                                " blit failed for TexUnpackImage.",
                                funcName);
        return false;
    }

    const TexUnpackSurface surfBlob(webgl, target, mWidth, mHeight, mDepth, dataSurf,
                                    mIsSrcPremult);

    return surfBlob.TexOrSubImage(isSubImage, needsRespec, funcName, tex, target, level,
                                  dui, xOffset, yOffset, zOffset, out_error);
}
Example #26
0
void
BasicCompositor::DrawQuad(const gfx::Rect& aRect,
                          const gfx::Rect& aClipRect,
                          const EffectChain &aEffectChain,
                          gfx::Float aOpacity,
                          const gfx::Matrix4x4& aTransform,
                          const gfx::Rect& aVisibleRect)
{
  RefPtr<DrawTarget> buffer = mRenderTarget->mDrawTarget;

  // For 2D drawing, |dest| and |buffer| are the same surface. For 3D drawing,
  // |dest| is a temporary surface.
  RefPtr<DrawTarget> dest = buffer;

  buffer->PushClipRect(aClipRect);
  AutoRestoreTransform autoRestoreTransform(dest);

  Matrix newTransform;
  Rect transformBounds;
  gfx3DMatrix new3DTransform;
  IntPoint offset = mRenderTarget->GetOrigin();

  if (aTransform.Is2D()) {
    newTransform = aTransform.As2D();
  } else {
    // Create a temporary surface for the transform.
    dest = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(RoundOut(aRect).Size(), SurfaceFormat::B8G8R8A8);
    if (!dest) {
      return;
    }

    dest->SetTransform(Matrix::Translation(-aRect.x, -aRect.y));

    // Get the bounds post-transform.
    new3DTransform = To3DMatrix(aTransform);
    gfxRect bounds = new3DTransform.TransformBounds(ThebesRect(aRect));
    bounds.IntersectRect(bounds, gfxRect(offset.x, offset.y, buffer->GetSize().width, buffer->GetSize().height));

    transformBounds = ToRect(bounds);
    transformBounds.RoundOut();

    // Propagate the coordinate offset to our 2D draw target.
    newTransform = Matrix::Translation(transformBounds.x, transformBounds.y);

    // When we apply the 3D transformation, we do it against a temporary
    // surface, so undo the coordinate offset.
    new3DTransform = gfx3DMatrix::Translation(aRect.x, aRect.y, 0) * new3DTransform;
  }

  newTransform.PostTranslate(-offset.x, -offset.y);
  buffer->SetTransform(newTransform);

  RefPtr<SourceSurface> sourceMask;
  Matrix maskTransform;
  if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
    EffectMask *effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get());
    sourceMask = effectMask->mMaskTexture->AsSourceBasic()->GetSurface(dest);
    MOZ_ASSERT(effectMask->mMaskTransform.Is2D(), "How did we end up with a 3D transform here?!");
    MOZ_ASSERT(!effectMask->mIs3D);
    maskTransform = effectMask->mMaskTransform.As2D();
    maskTransform.PreTranslate(-offset.x, -offset.y);
  }

  switch (aEffectChain.mPrimaryEffect->mType) {
    case EffectTypes::SOLID_COLOR: {
      EffectSolidColor* effectSolidColor =
        static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get());

      FillRectWithMask(dest, aRect, effectSolidColor->mColor,
                       DrawOptions(aOpacity), sourceMask, &maskTransform);
      break;
    }
    case EffectTypes::RGB: {
      TexturedEffect* texturedEffect =
          static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
      TextureSourceBasic* source = texturedEffect->mTexture->AsSourceBasic();

      if (texturedEffect->mPremultiplied) {
          DrawSurfaceWithTextureCoords(dest, aRect,
                                       source->GetSurface(dest),
                                       texturedEffect->mTextureCoords,
                                       texturedEffect->mFilter,
                                       aOpacity, sourceMask, &maskTransform);
      } else {
          RefPtr<DataSourceSurface> srcData = source->GetSurface(dest)->GetDataSurface();

          // Yes, we re-create the premultiplied data every time.
          // This might be better with a cache, eventually.
          RefPtr<DataSourceSurface> premultData = gfxUtils::CreatePremultipliedDataSurface(srcData);

          DrawSurfaceWithTextureCoords(dest, aRect,
                                       premultData,
                                       texturedEffect->mTextureCoords,
                                       texturedEffect->mFilter,
                                       aOpacity, sourceMask, &maskTransform);
      }
      break;
    }
    case EffectTypes::YCBCR: {
      NS_RUNTIMEABORT("Can't (easily) support component alpha with BasicCompositor!");
      break;
    }
    case EffectTypes::RENDER_TARGET: {
      EffectRenderTarget* effectRenderTarget =
        static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get());
      RefPtr<BasicCompositingRenderTarget> surface
        = static_cast<BasicCompositingRenderTarget*>(effectRenderTarget->mRenderTarget.get());
      RefPtr<SourceSurface> sourceSurf = surface->mDrawTarget->Snapshot();

      DrawSurfaceWithTextureCoords(dest, aRect,
                                   sourceSurf,
                                   effectRenderTarget->mTextureCoords,
                                   effectRenderTarget->mFilter,
                                   aOpacity, sourceMask, &maskTransform);
      break;
    }
    case EffectTypes::COMPONENT_ALPHA: {
      NS_RUNTIMEABORT("Can't (easily) support component alpha with BasicCompositor!");
      break;
    }
    default: {
      NS_RUNTIMEABORT("Invalid effect type!");
      break;
    }
  }

  if (!aTransform.Is2D()) {
    dest->Flush();

    RefPtr<SourceSurface> snapshot = dest->Snapshot();
    RefPtr<DataSourceSurface> source = snapshot->GetDataSurface();
    RefPtr<DataSourceSurface> temp =
      Factory::CreateDataSourceSurface(RoundOut(transformBounds).Size(), SurfaceFormat::B8G8R8A8
#ifdef MOZ_ENABLE_SKIA
        , true
#endif
        );
    if (NS_WARN_IF(!temp)) {
      buffer->PopClip();
      return;
    }

    Transform(temp, source, new3DTransform, transformBounds.TopLeft());

    transformBounds.MoveTo(0, 0);
    buffer->DrawSurface(temp, transformBounds, transformBounds);
  }

  buffer->PopClip();
}
Example #27
0
nsresult nsWindowGfx::CreateIcon(imgIContainer *aContainer,
                                  bool aIsCursor,
                                  uint32_t aHotspotX,
                                  uint32_t aHotspotY,
                                  IntSize aScaledSize,
                                  HICON *aIcon) {

  MOZ_ASSERT((aScaledSize.width > 0 && aScaledSize.height > 0) ||
             (aScaledSize.width == 0 && aScaledSize.height == 0));

  // Get the image data
  RefPtr<SourceSurface> surface =
    aContainer->GetFrame(imgIContainer::FRAME_CURRENT,
                         imgIContainer::FLAG_SYNC_DECODE);
  NS_ENSURE_TRUE(surface, NS_ERROR_NOT_AVAILABLE);

  IntSize frameSize = surface->GetSize();
  if (frameSize.IsEmpty()) {
    return NS_ERROR_FAILURE;
  }

  IntSize iconSize(aScaledSize.width, aScaledSize.height);
  if (iconSize == IntSize(0, 0)) { // use frame's intrinsic size
    iconSize = frameSize;
  }

  RefPtr<DataSourceSurface> dataSurface;
  bool mappedOK;
  DataSourceSurface::MappedSurface map;

  if (iconSize != frameSize) {
    // Scale the surface
    dataSurface = Factory::CreateDataSourceSurface(iconSize,
                                                   SurfaceFormat::B8G8R8A8);
    NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
    mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map);
    NS_ENSURE_TRUE(mappedOK, NS_ERROR_FAILURE);

    RefPtr<DrawTarget> dt =
      Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                       map.mData,
                                       dataSurface->GetSize(),
                                       map.mStride,
                                       SurfaceFormat::B8G8R8A8);
    if (!dt) {
      gfxWarning() << "nsWindowGfx::CreatesIcon failed in CreateDrawTargetForData";
      return NS_ERROR_OUT_OF_MEMORY;
    }
    dt->DrawSurface(surface,
                    Rect(0, 0, iconSize.width, iconSize.height),
                    Rect(0, 0, frameSize.width, frameSize.height),
                    DrawSurfaceOptions(),
                    DrawOptions(1.0f, CompositionOp::OP_SOURCE));
  } else if (surface->GetFormat() != SurfaceFormat::B8G8R8A8) {
    // Convert format to SurfaceFormat::B8G8R8A8
    dataSurface = gfxUtils::
      CopySurfaceToDataSourceSurfaceWithFormat(surface,
                                               SurfaceFormat::B8G8R8A8);
    NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
    mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ, &map);
  } else {
    dataSurface = surface->GetDataSurface();
    NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
    mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ, &map);
  }
  NS_ENSURE_TRUE(dataSurface && mappedOK, NS_ERROR_FAILURE);
  MOZ_ASSERT(dataSurface->GetFormat() == SurfaceFormat::B8G8R8A8);

  uint8_t* data = nullptr;
  UniquePtr<uint8_t[]> autoDeleteArray;
  if (map.mStride == BytesPerPixel(dataSurface->GetFormat()) * iconSize.width) {
    // Mapped data is already packed
    data = map.mData;
  } else {
    // We can't use map.mData since the pixels are not packed (as required by
    // CreateDIBitmap, which is called under the DataToBitmap call below).
    //
    // We must unmap before calling SurfaceToPackedBGRA because it needs access
    // to the pixel data.
    dataSurface->Unmap();
    map.mData = nullptr;

    autoDeleteArray = SurfaceToPackedBGRA(dataSurface);
    data = autoDeleteArray.get();
    NS_ENSURE_TRUE(data, NS_ERROR_FAILURE);
  }

  HBITMAP bmp = DataToBitmap(data, iconSize.width, -iconSize.height, 32);
  uint8_t* a1data = Data32BitTo1Bit(data, iconSize.width, iconSize.height);
  if (map.mData) {
    dataSurface->Unmap();
  }
  if (!a1data) {
    return NS_ERROR_FAILURE;
  }

  HBITMAP mbmp = DataToBitmap(a1data, iconSize.width, -iconSize.height, 1);
  PR_Free(a1data);

  ICONINFO info = {0};
  info.fIcon = !aIsCursor;
  info.xHotspot = aHotspotX;
  info.yHotspot = aHotspotY;
  info.hbmMask = mbmp;
  info.hbmColor = bmp;

  HCURSOR icon = ::CreateIconIndirect(&info);
  ::DeleteObject(mbmp);
  ::DeleteObject(bmp);
  if (!icon)
    return NS_ERROR_FAILURE;
  *aIcon = icon;
  return NS_OK;
}
Example #28
0
void
TestDrawTargetBase::RefreshSnapshot()
{
  RefPtr<SourceSurface> snapshot = mDT->Snapshot();
  mDataSnapshot = snapshot->GetDataSurface();
}
Example #29
0
bool
TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
                              WebGLTexture* tex, TexImageTarget target, GLint level,
                              const webgl::DriverUnpackInfo* dui, GLint xOffset,
                              GLint yOffset, GLint zOffset, const webgl::PackingInfo& pi,
                              GLenum* const out_error) const
{
    MOZ_ASSERT_IF(needsRespec, !isSubImage);

    WebGLContext* webgl = tex->mContext;

    gl::GLContext* gl = webgl->GL();
    gl->MakeCurrent();

    if (needsRespec) {
        *out_error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset,
                                     yOffset, zOffset, mWidth, mHeight, mDepth,
                                     nullptr);
        if (*out_error)
            return true;
    }

    const char* fallbackReason;
    do {
        if (mDepth != 1) {
            fallbackReason = "depth is not 1";
            break;
        }

        if (webgl->mPixelStore_UnpackSkipPixels ||
            webgl->mPixelStore_UnpackSkipRows ||
            webgl->mPixelStore_UnpackSkipImages)
        {
            fallbackReason = "non-zero UNPACK_SKIP_* not yet supported";
            break;
        }

        const auto fnHasPremultMismatch = [&]() {
            if (mSrcAlphaType == gfxAlphaType::Opaque)
                return false;

            const bool srcIsPremult = (mSrcAlphaType == gfxAlphaType::Premult);
            const auto& dstIsPremult = webgl->mPixelStore_PremultiplyAlpha;
            if (srcIsPremult == dstIsPremult)
                return false;

            if (dstIsPremult) {
                fallbackReason = "UNPACK_PREMULTIPLY_ALPHA_WEBGL is not true";
            } else {
                fallbackReason = "UNPACK_PREMULTIPLY_ALPHA_WEBGL is not false";
            }
            return true;
        };
        if (fnHasPremultMismatch())
            break;

        if (dui->unpackFormat != LOCAL_GL_RGB && dui->unpackFormat != LOCAL_GL_RGBA) {
            fallbackReason = "`format` is not RGB or RGBA";
            break;
        }

        if (dui->unpackType != LOCAL_GL_UNSIGNED_BYTE) {
            fallbackReason = "`type` is not UNSIGNED_BYTE";
            break;
        }

        gl::ScopedFramebuffer scopedFB(gl);
        gl::ScopedBindFramebuffer bindFB(gl, scopedFB.FB());

        {
            gl::GLContext::LocalErrorScope errorScope(*gl);

            gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
                                      target.get(), tex->mGLName, level);

            if (errorScope.GetError()) {
                fallbackReason = "bug: failed to attach to FB for blit";
                break;
            }
        }

        const GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
        if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
            fallbackReason = "bug: failed to confirm FB for blit";
            break;
        }

        const gfx::IntSize destSize(mWidth, mHeight);
        const auto dstOrigin = (webgl->mPixelStore_FlipY ? gl::OriginPos::TopLeft
                                                         : gl::OriginPos::BottomLeft);
        if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, destSize, scopedFB.FB(),
                                                      dstOrigin))
        {
            fallbackReason = "likely bug: failed to blit";
            break;
        }

        // Blitting was successful, so we're done!
        *out_error = 0;
        return true;
    } while (false);

    const nsPrintfCString perfMsg("%s: Failed to hit GPU-copy fast-path: %s (src type %u)",
                                  funcName, fallbackReason, uint32_t(mImage->GetFormat()));

    if (webgl->mPixelStore_RequireFastPath) {
        webgl->ErrorInvalidOperation("%s", perfMsg.BeginReading());
        return false;
    }

    webgl->GeneratePerfWarning("%s Falling back to CPU upload.",
                               perfMsg.BeginReading());

    const RefPtr<gfx::SourceSurface> surf = mImage->GetAsSourceSurface();

    RefPtr<gfx::DataSourceSurface> dataSurf;
    if (surf) {
        // WARNING: OSX can lose our MakeCurrent here.
        dataSurf = surf->GetDataSurface();
    }
    if (!dataSurf) {
        webgl->ErrorOutOfMemory("%s: GetAsSourceSurface or GetDataSurface failed after"
                                " blit failed for TexUnpackImage.",
                                funcName);
        return false;
    }

    const TexUnpackSurface surfBlob(webgl, target, mWidth, mHeight, mDepth, dataSurf,
                                    mSrcAlphaType);

    return surfBlob.TexOrSubImage(isSubImage, needsRespec, funcName, tex, target, level,
                                  dui, xOffset, yOffset, zOffset, pi, out_error);
}
static void DrawVelGraph(const nsIntRect& aClipRect,
                         LayerManagerComposite* aManager,
                         Layer* aLayer) {
  Compositor* compositor = aManager->GetCompositor();
  gfx::Rect clipRect(aClipRect.x, aClipRect.y,
                     aClipRect.width, aClipRect.height);

  TimeStamp now = TimeStamp::Now();
  LayerVelocityUserData* velocityData = GetVelocityData(aLayer);

  if (velocityData->mData.size() >= 1 &&
    now > velocityData->mData[velocityData->mData.size() - 1].mFrameTime +
      TimeDuration::FromMilliseconds(200)) {
    // clear stale data
    velocityData->mData.clear();
  }

  const gfx::Point layerTransform = GetScrollData(aLayer);
  velocityData->mData.push_back(
    LayerVelocityUserData::VelocityData(now,
      static_cast<int>(layerTransform.x), static_cast<int>(layerTransform.y)));

  // TODO: dump to file
  // XXX: Uncomment these lines to enable ScrollGraph logging. This is
  //      useful for HVGA phones or to output the data to accurate
  //      graphing software.
  // printf_stderr("ScrollGraph (%p): %f, %f\n",
  // aLayer, layerTransform.x, layerTransform.y);

  // Keep a circular buffer of 100.
  size_t circularBufferSize = 100;
  if (velocityData->mData.size() > circularBufferSize) {
    velocityData->mData.erase(velocityData->mData.begin());
  }

  if (velocityData->mData.size() == 1) {
    return;
  }

  // Clear and disable the graph when it's flat
  for (size_t i = 1; i < velocityData->mData.size(); i++) {
    if (velocityData->mData[i - 1].mPoint != velocityData->mData[i].mPoint) {
      break;
    }
    if (i == velocityData->mData.size() - 1) {
      velocityData->mData.clear();
      return;
    }
  }

  if (aLayer->GetEffectiveVisibleRegion().GetBounds().width < 300 ||
      aLayer->GetEffectiveVisibleRegion().GetBounds().height < 300) {
    // Don't want a graph for smaller layers
    return;
  }

  aManager->SetDebugOverlayWantsNextFrame(true);

  const Matrix4x4& transform = aLayer->GetEffectiveTransform();
  nsIntRect bounds = aLayer->GetEffectiveVisibleRegion().GetBounds();
  IntSize graphSize = IntSize(200, 100);
  Rect graphRect = Rect(bounds.x, bounds.y, graphSize.width, graphSize.height);

  RefPtr<DrawTarget> dt = aManager->CreateDrawTarget(graphSize, SurfaceFormat::B8G8R8A8);
  dt->FillRect(Rect(0, 0, graphSize.width, graphSize.height),
               ColorPattern(Color(0.2f,0,0,1)));

  int yScaleFactor = 3;
  Point prev = Point(0,0);
  bool first = true;
  for (int32_t i = (int32_t)velocityData->mData.size() - 2; i >= 0; i--) {
    const gfx::Point& p1 = velocityData->mData[i+1].mPoint;
    const gfx::Point& p2 = velocityData->mData[i].mPoint;
    int vel = sqrt((p1.x - p2.x) * (p1.x - p2.x) +
                   (p1.y - p2.y) * (p1.y - p2.y));
    Point next = Point(graphRect.width / circularBufferSize * i,
                       graphRect.height - vel/yScaleFactor);
    if (first) {
      first = false;
    } else {
      dt->StrokeLine(prev, next, ColorPattern(Color(0,1,0,1)));
    }
    prev = next;
  }

  RefPtr<DataTextureSource> textureSource = compositor->CreateDataTextureSource();
  RefPtr<SourceSurface> snapshot = dt->Snapshot();
  RefPtr<DataSourceSurface> data = snapshot->GetDataSurface();
  textureSource->Update(data);

  EffectChain effectChain;
  effectChain.mPrimaryEffect = CreateTexturedEffect(SurfaceFormat::B8G8R8A8,
                                                    textureSource,
                                                    Filter::POINT,
                                                    true);

  compositor->DrawQuad(graphRect,
                       clipRect,
                       effectChain,
                       1.0f,
                       transform);
}