示例#1
0
nsresult
nsSVGFilterInstance::BuildSourcePaint(PrimitiveInfo *aPrimitive)
{
  NS_ASSERTION(aPrimitive->mImageUsers > 0, "Some user must have needed this");

  nsRefPtr<gfxImageSurface> image = CreateImage();
  if (!image)
    return NS_ERROR_OUT_OF_MEMORY;

  nsRefPtr<gfxASurface> offscreen =
    gfxPlatform::GetPlatform()->CreateOffscreenSurface(
            gfxIntSize(mSurfaceRect.width, mSurfaceRect.height),
            gfxASurface::CONTENT_COLOR_ALPHA);
  if (!offscreen || offscreen->CairoStatus())
    return NS_ERROR_OUT_OF_MEMORY;
  offscreen->SetDeviceOffset(gfxPoint(-mSurfaceRect.x, -mSurfaceRect.y));

  nsRenderingContext tmpCtx;
  tmpCtx.Init(mTargetFrame->PresContext()->DeviceContext(), offscreen);

  gfxRect r = aPrimitive->mImage.mFilterPrimitiveSubregion;
  gfxMatrix m = GetUserSpaceToFilterSpaceTransform();
  m.Invert();
  r = m.TransformBounds(r);

  gfxMatrix deviceToFilterSpace = GetFilterSpaceToDeviceSpaceTransform().Invert();
  gfxContext *gfx = tmpCtx.ThebesContext();
  gfx->Multiply(deviceToFilterSpace);

  gfx->Save();

  gfxMatrix matrix =
    nsSVGUtils::GetCanvasTM(mTargetFrame, nsISVGChildFrame::FOR_PAINTING,
                            mTransformRoot);
  if (!matrix.IsSingular()) {
    gfx->Multiply(matrix);
    gfx->Rectangle(r);
    if ((aPrimitive == &mFillPaint && 
         nsSVGUtils::SetupCairoFillPaint(mTargetFrame, gfx)) ||
        (aPrimitive == &mStrokePaint &&
         nsSVGUtils::SetupCairoStrokePaint(mTargetFrame, gfx))) {
      gfx->Fill();
    }
  }
  gfx->Restore();

  gfxContext copyContext(image);
  copyContext.SetSource(offscreen);
  copyContext.Paint();

  aPrimitive->mImage.mImage = image;
  // color model is PREMULTIPLIED SRGB by default.

  return NS_OK;
}
nsresult
nsSVGFilterInstance::BuildSourceImages()
{
  nsIntRect neededRect;
  neededRect.UnionRect(mSourceColorAlpha.mResultNeededBox,
                       mSourceAlpha.mResultNeededBox);
  if (neededRect.IsEmpty())
    return NS_OK;

  nsRefPtr<gfxImageSurface> sourceColorAlpha = CreateImage();
  if (!sourceColorAlpha)
    return NS_ERROR_OUT_OF_MEMORY;

  {
    // Paint to an offscreen surface first, then copy it to an image
    // surface. This can be faster especially when the stuff we're painting
    // contains native themes.
    nsRefPtr<gfxASurface> offscreen =
      gfxPlatform::GetPlatform()->CreateOffscreenSurface(
              gfxIntSize(mSurfaceRect.width, mSurfaceRect.height),
              gfxASurface::CONTENT_COLOR_ALPHA);
    if (!offscreen || offscreen->CairoStatus())
      return NS_ERROR_OUT_OF_MEMORY;
    offscreen->SetDeviceOffset(gfxPoint(-mSurfaceRect.x, -mSurfaceRect.y));
  
    nsSVGRenderState tmpState(offscreen);
    gfxMatrix userSpaceToFilterSpace = GetUserSpaceToFilterSpaceTransform();

    gfxRect r(neededRect.x, neededRect.y, neededRect.width, neededRect.height);
    gfxMatrix m = userSpaceToFilterSpace;
    m.Invert();
    r = m.TransformBounds(r);
    r.RoundOut();
    nsIntRect dirty;
    if (!gfxUtils::GfxRectToIntRect(r, &dirty))
      return NS_ERROR_FAILURE;

    // SVG graphics paint to device space, so we need to set an initial device
    // space to filter space transform on the gfxContext that SourceGraphic
    // and SourceAlpha will paint to.
    //
    // (In theory it would be better to minimize error by having filtered SVG
    // graphics temporarily paint to user space when painting the sources and
    // only set a user space to filter space transform on the gfxContext
    // (since that would eliminate the transform multiplications from user
    // space to device space and back again). However, that would make the
    // code more complex while being hard to get right without introducing
    // subtle bugs, and in practice it probably makes no real difference.)
    gfxMatrix deviceToFilterSpace = GetFilterSpaceToDeviceSpaceTransform().Invert();
    tmpState.GetGfxContext()->Multiply(deviceToFilterSpace);
    mPaintCallback->Paint(&tmpState, mTargetFrame, &dirty);

    gfxContext copyContext(sourceColorAlpha);
    copyContext.SetSource(offscreen);
    copyContext.Paint();
  }

  if (!mSourceColorAlpha.mResultNeededBox.IsEmpty()) {
    NS_ASSERTION(mSourceColorAlpha.mImageUsers > 0, "Some user must have needed this");
    mSourceColorAlpha.mImage.mImage = sourceColorAlpha;
    // color model is PREMULTIPLIED SRGB by default.
  }

  if (!mSourceAlpha.mResultNeededBox.IsEmpty()) {
    NS_ASSERTION(mSourceAlpha.mImageUsers > 0, "Some user must have needed this");

    mSourceAlpha.mImage.mImage = CreateImage();
    if (!mSourceAlpha.mImage.mImage)
      return NS_ERROR_OUT_OF_MEMORY;
    // color model is PREMULTIPLIED SRGB by default.

    // Clear the color channel
    const PRUint32* src = reinterpret_cast<PRUint32*>(sourceColorAlpha->Data());
    PRUint32* dest = reinterpret_cast<PRUint32*>(mSourceAlpha.mImage.mImage->Data());
    for (PRInt32 y = 0; y < mSurfaceRect.height; y++) {
      PRUint32 rowOffset = (mSourceAlpha.mImage.mImage->Stride()*y) >> 2;
      for (PRInt32 x = 0; x < mSurfaceRect.width; x++) {
        dest[rowOffset + x] = src[rowOffset + x] & 0xFF000000U;
      }
    }
    mSourceAlpha.mImage.mConstantColorChannels = true;
  }