CGContextRef
gfxQuartzNativeDrawing::BeginNativeDrawing()
{
  NS_ASSERTION(!mCGContext, "BeginNativeDrawing called when drawing already in progress");

  DrawTarget *dt = mDrawTarget;
  if (dt->IsDualDrawTarget() || dt->IsTiledDrawTarget() ||
      dt->GetBackendType() != BackendType::SKIA || dt->IsRecording()) {
    // We need a DrawTarget that we can get a CGContextRef from:
    Matrix transform = dt->GetTransform();

    mNativeRect = transform.TransformBounds(mNativeRect);
    mNativeRect.RoundOut();
    if (mNativeRect.IsEmpty()) {
      return nullptr;
    }

    mTempDrawTarget =
      Factory::CreateDrawTarget(BackendType::SKIA,
                                IntSize::Truncate(mNativeRect.width, mNativeRect.height),
                                SurfaceFormat::B8G8R8A8);
    if (!mTempDrawTarget) {
      return nullptr;
    }

    transform.PostTranslate(-mNativeRect.x, -mNativeRect.y);
    mTempDrawTarget->SetTransform(transform);

    dt = mTempDrawTarget;
  } else {
    // Clip the DT in case BorrowedCGContext needs to create a new layer.
    // This prevents it from creating a new layer the size of the window.
    // But make sure that this clip is device pixel aligned.
    Matrix transform = dt->GetTransform();

    Rect deviceRect = transform.TransformBounds(mNativeRect);
    deviceRect.RoundOut();
    mNativeRect = transform.Inverse().TransformBounds(deviceRect);
    mDrawTarget->PushClipRect(mNativeRect);
  }

  MOZ_ASSERT(dt->GetBackendType() == BackendType::SKIA);
  mCGContext = mBorrowedContext.Init(dt);

  if (NS_WARN_IF(!mCGContext)) {
    // Failed borrowing CG context, so we need to clean up.
    if (!mTempDrawTarget) {
      mDrawTarget->PopClip();
    }
    return nullptr;
  }

  return mCGContext;
}
Example #2
0
void
DrawBlur(gfxContext* aDestinationCtx,
         SourceSurface* aBlur,
         const IntPoint& aTopLeft,
         const Rect* aDirtyRect)
{
    DrawTarget *dest = aDestinationCtx->GetDrawTarget();

    nsRefPtr<gfxPattern> thebesPat = aDestinationCtx->GetPattern();
    Pattern* pat = thebesPat->GetPattern(dest, nullptr);

    Matrix oldTransform = dest->GetTransform();
    Matrix newTransform = oldTransform;
    newTransform.Translate(aTopLeft.x, aTopLeft.y);

    // Avoid a semi-expensive clip operation if we can, otherwise
    // clip to the dirty rect
    if (aDirtyRect) {
        dest->PushClipRect(*aDirtyRect);
    }

    dest->SetTransform(newTransform);
    dest->MaskSurface(*pat, aBlur, Point(0, 0));
    dest->SetTransform(oldTransform);

    if (aDirtyRect) {
        dest->PopClip();
    }
}
Example #3
0
bool
SnapLineToDevicePixelsForStroking(Point& aP1, Point& aP2,
                                  const DrawTarget& aDrawTarget)
{
  Matrix mat = aDrawTarget.GetTransform();
  if (mat.HasNonTranslation()) {
    return false;
  }
  if (aP1.x != aP2.x && aP1.y != aP2.y) {
    return false; // not a horizontal or vertical line
  }
  Point p1 = aP1 + mat.GetTranslation(); // into device space
  Point p2 = aP2 + mat.GetTranslation();
  p1.Round();
  p2.Round();
  p1 -= mat.GetTranslation(); // back into user space
  p2 -= mat.GetTranslation();
  if (aP1.x == aP2.x) {
    // snap vertical line, adding 0.5 to align it to be mid-pixel:
    aP1 = p1 + Point(0.5, 0);
    aP2 = p2 + Point(0.5, 0);
  } else {
    // snap horizontal line, adding 0.5 to align it to be mid-pixel:
    aP1 = p1 + Point(0, 0.5);
    aP2 = p2 + Point(0, 0.5);
  }
  return true;
}
Example #4
0
static void
RepeatOrStretchSurface(DrawTarget& aDT, SourceSurface* aSurface,
                       const Rect& aDest, const Rect& aSrc, Rect& aSkipRect)
{
  if (aSkipRect.Contains(aDest)) {
    return;
  }

  if ((!aDT.GetTransform().IsRectilinear() &&
       aDT.GetBackendType() != BackendType::CAIRO) ||
      (aDT.GetBackendType() == BackendType::DIRECT2D)) {
    // Use stretching if possible, since it leads to less seams when the
    // destination is transformed. However, don't do this if we're using cairo,
    // because if cairo is using pixman it won't render anything for large
    // stretch factors because pixman's internal fixed point precision is not
    // high enough to handle those scale factors.
    // Calling FillRect on a D2D backend with a repeating pattern is much slower
    // than DrawSurface, so special case the D2D backend here.
    aDT.DrawSurface(aSurface, aDest, aSrc);
    return;
  }

  SurfacePattern pattern(aSurface, ExtendMode::REPEAT,
                         Matrix::Translation(aDest.TopLeft() - aSrc.TopLeft()),
                         Filter::GOOD, RoundedToInt(aSrc));
  aDT.FillRect(aDest, pattern);
}
void
gfxQuartzNativeDrawing::EndNativeDrawing()
{
  NS_ASSERTION(mCGContext, "EndNativeDrawing called without BeginNativeDrawing");
  MOZ_ASSERT(!mContext->IsCairo(), "BeginNativeDrawing succeeded with cairo context?");

  mBorrowedContext.Finish();
  if (mDrawTarget) {
    DrawTarget *dest = mContext->GetDrawTarget();
    RefPtr<SourceSurface> source = mDrawTarget->Snapshot();

    IntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale),
                        NSToIntFloor(mNativeRect.height * mBackingScale));

    Matrix oldTransform = dest->GetTransform();
    Matrix newTransform = oldTransform;
    newTransform.Translate(mNativeRect.x, mNativeRect.y);
    newTransform.Scale(1.0f / mBackingScale, 1.0f / mBackingScale);

    dest->SetTransform(newTransform);

    dest->DrawSurface(source,
                      gfx::Rect(0, 0, backingSize.width, backingSize.height),
                      gfx::Rect(0, 0, backingSize.width, backingSize.height));


    dest->SetTransform(oldTransform);
  }
}
void
ClientLayerManager::MakeSnapshotIfRequired()
{
  if (!mShadowTarget) {
    return;
  }
  if (mWidget) {
    if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) {
      // The compositor doesn't draw to a different sized surface
      // when there's a rotation. Instead we rotate the result
      // when drawing into dt
      LayoutDeviceIntRect outerBounds;
      mWidget->GetBounds(outerBounds);

      IntRect bounds = ToOutsideIntRect(mShadowTarget->GetClipExtents());
      if (mTargetRotation) {
        bounds =
          RotateRect(bounds, outerBounds.ToUnknownRect(), mTargetRotation);
      }

      SurfaceDescriptor inSnapshot;
      if (!bounds.IsEmpty() &&
          mForwarder->AllocSurfaceDescriptor(bounds.Size(),
                                             gfxContentType::COLOR_ALPHA,
                                             &inSnapshot)) {

        // Make a copy of |inSnapshot| because the call to send it over IPC
        // will call forget() on the Shmem inside, and zero it out.
        SurfaceDescriptor outSnapshot = inSnapshot;

        if (remoteRenderer->SendMakeSnapshot(inSnapshot, bounds)) {
          RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(outSnapshot);
          DrawTarget* dt = mShadowTarget->GetDrawTarget();

          Rect dstRect(bounds.x, bounds.y, bounds.width, bounds.height);
          Rect srcRect(0, 0, bounds.width, bounds.height);

          gfx::Matrix rotate =
            ComputeTransformForUnRotation(outerBounds.ToUnknownRect(),
                                          mTargetRotation);

          gfx::Matrix oldMatrix = dt->GetTransform();
          dt->SetTransform(rotate * oldMatrix);
          dt->DrawSurface(surf, dstRect, srcRect,
                          DrawSurfaceOptions(),
                          DrawOptions(1.0f, CompositionOp::OP_OVER));
          dt->SetTransform(oldMatrix);
        }
        mForwarder->DestroySurfaceDescriptor(&outSnapshot);
      }
    }
  }
  mShadowTarget = nullptr;
}
Example #7
0
void
gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx)
{
    if (!mContext)
        return;

    mBlur->Blur(mData);

    mozilla::gfx::Rect* dirtyRect = mBlur->GetDirtyRect();

    DrawTarget *dest = aDestinationCtx->GetDrawTarget();
    if (!dest) {
      NS_ERROR("Blurring not supported for Thebes contexts!");
      return;
    }

    mozilla::RefPtr<SourceSurface> mask
      = dest->CreateSourceSurfaceFromData(mData,
                                          mBlur->GetSize(),
                                          mBlur->GetStride(),
                                          FORMAT_A8);
    if (!mask) {
      NS_ERROR("Failed to create mask!");
      return;
    }

    nsRefPtr<gfxPattern> thebesPat = aDestinationCtx->GetPattern();
    Pattern* pat = thebesPat->GetPattern(dest, nullptr);

    Matrix oldTransform = dest->GetTransform();
    Matrix newTransform = oldTransform;
    newTransform.Translate(mBlur->GetRect().x, mBlur->GetRect().y);

    // Avoid a semi-expensive clip operation if we can, otherwise
    // clip to the dirty rect
    if (dirtyRect) {
        dest->PushClipRect(*dirtyRect);
    }

    dest->SetTransform(newTransform);
    dest->MaskSurface(*pat, mask, Point(0, 0));
    dest->SetTransform(oldTransform);

    if (dirtyRect) {
        dest->PopClip();
    }
}
Example #8
0
void
gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx)
{
  if (!mAccelerated && !mData) {
    return;
  }

  DrawTarget *dest = aDestinationCtx->GetDrawTarget();
  if (!dest) {
    NS_WARNING("Blurring not supported for Thebes contexts!");
    return;
  }

  RefPtr<gfxPattern> thebesPat = aDestinationCtx->GetPattern();
  Pattern* pat = thebesPat->GetPattern(dest, nullptr);
  if (!pat) {
    NS_WARNING("Failed to get pattern for blur!");
    return;
  }

  IntPoint topLeft;
  RefPtr<SourceSurface> mask = DoBlur(nullptr, &topLeft);
  if (!mask) {
    NS_ERROR("Failed to create mask!");
    return;
  }

  // Avoid a semi-expensive clip operation if we can, otherwise
  // clip to the dirty rect
  Rect* dirtyRect = mBlur.GetDirtyRect();
  if (dirtyRect) {
    dest->PushClipRect(*dirtyRect);
  }

  Matrix oldTransform = dest->GetTransform();
  Matrix newTransform = oldTransform;
  newTransform.PreTranslate(topLeft);
  dest->SetTransform(newTransform);

  dest->MaskSurface(*pat, mask, Point(0, 0));

  dest->SetTransform(oldTransform);

  if (dirtyRect) {
    dest->PopClip();
  }
}
void
ClientLayerManager::MakeSnapshotIfRequired()
{
  if (!mShadowTarget) {
    return;
  }
  if (mWidget) {
    if (CompositorChild* remoteRenderer = GetRemoteRenderer()) {
      // The compositor doesn't draw to a different sized surface
      // when there's a rotation. Instead we rotate the result
      // when drawing into dt
      nsIntRect outerBounds;
      mWidget->GetBounds(outerBounds);

      nsIntRect bounds = ToOutsideIntRect(mShadowTarget->GetClipExtents());
      if (mTargetRotation) {
        bounds = RotateRect(bounds, outerBounds, mTargetRotation);
      }

      SurfaceDescriptor inSnapshot;
      if (!bounds.IsEmpty() &&
          mForwarder->AllocSurfaceDescriptor(bounds.Size().ToIntSize(),
                                             gfxContentType::COLOR_ALPHA,
                                             &inSnapshot) &&
          remoteRenderer->SendMakeSnapshot(inSnapshot, bounds)) {
        RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(inSnapshot);
        DrawTarget* dt = mShadowTarget->GetDrawTarget();

        Rect dstRect(bounds.x, bounds.y, bounds.width, bounds.height);
        Rect srcRect(0, 0, bounds.width, bounds.height);

        gfx::Matrix rotate = ComputeTransformForUnRotation(outerBounds, mTargetRotation);

        gfx::Matrix oldMatrix = dt->GetTransform();
        dt->SetTransform(oldMatrix * rotate);
        dt->DrawSurface(surf, dstRect, srcRect,
                        DrawSurfaceOptions(),
                        DrawOptions(1.0f, CompositionOp::OP_OVER));
        dt->SetTransform(oldMatrix);
      }
      mForwarder->DestroySharedSurface(&inSnapshot);
    }
  }
  mShadowTarget = nullptr;
}
void
gfxQuartzNativeDrawing::EndNativeDrawing()
{
    NS_ASSERTION(mCGContext, "EndNativeDrawing called without BeginNativeDrawing");

    if (mBorrowedContext.cg) {
        MOZ_ASSERT(!mContext->IsCairo());
        mBorrowedContext.Finish();
        if (mDrawTarget) {
          DrawTarget *dest = mContext->GetDrawTarget();
          RefPtr<SourceSurface> source = mDrawTarget->Snapshot();

          IntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale),
                              NSToIntFloor(mNativeRect.height * mBackingScale));

          Matrix oldTransform = dest->GetTransform();
          Matrix newTransform = oldTransform;
          newTransform.Translate(mNativeRect.x, mNativeRect.y);
          newTransform.Scale(1.0f / mBackingScale, 1.0f / mBackingScale);

          dest->SetTransform(newTransform);

          dest->DrawSurface(source,
                            gfx::Rect(0, 0, backingSize.width, backingSize.height),
                            gfx::Rect(0, 0, backingSize.width, backingSize.height));


          dest->SetTransform(oldTransform);
        }
        return;
    }

    cairo_quartz_finish_cg_context_with_clip(mSurfaceContext->GetCairo());
    mQuartzSurface->MarkDirty();
    if (mSurfaceContext != mContext) {
        gfxContextMatrixAutoSaveRestore save(mContext);

        // Copy back to destination
        mContext->Translate(mNativeRect.TopLeft());
        mContext->Scale(1.0f / mBackingScale, 1.0f / mBackingScale);
        mContext->DrawSurface(mQuartzSurface, mQuartzSurface->GetSize());
    }
}
void
gfxWindowsNativeDrawing::PaintToContext()
{
    if (mRenderState == RENDER_STATE_NATIVE_DRAWING_DONE) {
        // nothing to do, it already went to the context
        mRenderState = RENDER_STATE_DONE;
    } else if (mRenderState == RENDER_STATE_ALPHA_RECOVERY_WHITE_DONE) {
        RefPtr<gfxImageSurface> black = mBlackSurface->GetAsImageSurface();
        RefPtr<gfxImageSurface> white = mWhiteSurface->GetAsImageSurface();
        if (!gfxAlphaRecovery::RecoverAlpha(black, white)) {
            NS_ERROR("Alpha recovery failure");
            return;
        }
        RefPtr<DataSourceSurface> source =
            Factory::CreateWrappingDataSourceSurface(black->Data(),
                                                     black->Stride(),
                                                     black->GetSize(),
                                                     SurfaceFormat::B8G8R8A8);
        {
            DrawTarget* dt = mContext->GetDrawTarget();
            AutoRestoreTransform autoRestoreTransform(dt);

            Matrix newTransform = dt->GetTransform();
            newTransform.PreTranslate(ToPoint(mNativeRect.TopLeft()));
            dt->SetTransform(newTransform);

            Rect rect(Point(0.0, 0.0), ToSize(mNativeRect.Size()));
            Matrix m = Matrix::Scaling(1.0 / mScale.width, 1.0 / mScale.height);
            Filter filter = (mNativeDrawFlags & DO_NEAREST_NEIGHBOR_FILTERING)
                          ? Filter::LINEAR
                          : Filter::GOOD;
            SurfacePattern pat(source, ExtendMode::CLAMP, m, filter);
            dt->FillRect(rect, pat);
        }

        mRenderState = RENDER_STATE_DONE;
    } else {
        NS_ERROR("Invalid RenderState in gfxWindowsNativeDrawing::PaintToContext");
    }
}
Example #12
0
void
nsTableCellFrame::DecorateForSelection(nsRenderingContext& aRenderingContext,
                                       nsPoint aPt)
{
  NS_ASSERTION(IsSelected(), "Should only be called for selected cells");
  int16_t displaySelection;
  nsPresContext* presContext = PresContext();
  displaySelection = DisplaySelection(presContext);
  if (displaySelection) {
    RefPtr<nsFrameSelection> frameSelection =
      presContext->PresShell()->FrameSelection();

    if (frameSelection->GetTableCellSelection()) {
      nscolor       bordercolor;
      if (displaySelection == nsISelectionController::SELECTION_DISABLED) {
        bordercolor = NS_RGB(176,176,176);// disabled color
      }
      else {
        bordercolor =
          LookAndFeel::GetColor(LookAndFeel::eColorID_TextSelectBackground);
      }
      nscoord threePx = nsPresContext::CSSPixelsToAppUnits(3);
      if ((mRect.width > threePx) && (mRect.height > threePx))
      {
        //compare bordercolor to ((nsStyleColor *)myColor)->mBackgroundColor)
        bordercolor = EnsureDifferentColors(bordercolor,
                                            StyleBackground()->mBackgroundColor);

        int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
        Point devPixelOffset = NSPointToPoint(aPt, appUnitsPerDevPixel);

        DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
        AutoRestoreTransform autoRestoreTransform(drawTarget);
        drawTarget->SetTransform(
          drawTarget->GetTransform().PreTranslate(devPixelOffset));

        ColorPattern color(ToDeviceColor(bordercolor));

        nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);

        StrokeLineWithSnapping(nsPoint(onePixel, 0), nsPoint(mRect.width, 0),
                               appUnitsPerDevPixel, *drawTarget, color);
        StrokeLineWithSnapping(nsPoint(0, onePixel), nsPoint(0, mRect.height),
                               appUnitsPerDevPixel, *drawTarget, color);
        StrokeLineWithSnapping(nsPoint(onePixel, mRect.height),
                               nsPoint(mRect.width, mRect.height),
                               appUnitsPerDevPixel, *drawTarget, color);
        StrokeLineWithSnapping(nsPoint(mRect.width, onePixel),
                               nsPoint(mRect.width, mRect.height),
                               appUnitsPerDevPixel, *drawTarget, color);
        //middle
        nsRect r(onePixel, onePixel,
                 mRect.width - onePixel, mRect.height - onePixel);
        Rect devPixelRect =
          NSRectToSnappedRect(r, appUnitsPerDevPixel, *drawTarget);
        drawTarget->StrokeRect(devPixelRect, color);
        //shading
        StrokeLineWithSnapping(nsPoint(2*onePixel, mRect.height-2*onePixel),
                               nsPoint(mRect.width-onePixel, mRect.height- (2*onePixel)),
                               appUnitsPerDevPixel, *drawTarget, color);
        StrokeLineWithSnapping(nsPoint(mRect.width - (2*onePixel), 2*onePixel),
                               nsPoint(mRect.width - (2*onePixel), mRect.height-onePixel),
                               appUnitsPerDevPixel, *drawTarget, color);
      }
    }
  }
}
void
gfxXlibNativeRenderer::Draw(gfxContext* ctx, nsIntSize size,
                            uint32_t flags, Screen *screen, Visual *visual)
{
    gfxMatrix matrix = ctx->CurrentMatrix();

    // We can only draw direct or onto a copied background if pixels align and
    // native drawing is compatible with the current operator.  (The matrix is
    // actually also pixel-exact for flips and right-angle rotations, which
    // would permit copying the background but not drawing direct.)
    bool matrixIsIntegerTranslation = !matrix.HasNonIntegerTranslation();
    bool canDrawOverBackground = matrixIsIntegerTranslation &&
        ctx->CurrentOperator() == gfxContext::OPERATOR_OVER;

    // The padding of 0.5 for non-pixel-exact transformations used here is
    // the same as what _cairo_pattern_analyze_filter uses.
    const gfxFloat filterRadius = 0.5;
    gfxRect affectedRect(0.0, 0.0, size.width, size.height);
    if (!matrixIsIntegerTranslation) {
        // The filter footprint means that the affected rectangle is a
        // little larger than the drawingRect;
        affectedRect.Inflate(filterRadius);

        NATIVE_DRAWING_NOTE("FALLBACK: matrix not integer translation");
    } else if (!canDrawOverBackground) {
        NATIVE_DRAWING_NOTE("FALLBACK: unsupported operator");
    }

    // Clipping to the region affected by drawing allows us to consider only
    // the portions of the clip region that will be affected by drawing.
    gfxRect clipExtents;
    {
        gfxContextAutoSaveRestore autoSR(ctx);
        ctx->Clip(affectedRect);

        clipExtents = ctx->GetClipExtents();
        if (clipExtents.IsEmpty())
            return; // nothing to do

        if (canDrawOverBackground &&
            DrawDirect(ctx, size, flags, screen, visual))
          return;
    }

    IntRect drawingRect(IntPoint(0, 0), size);
    // Drawing need only be performed within the clip extents
    // (and padding for the filter).
    if (!matrixIsIntegerTranslation) {
        // The source surface may need to be a little larger than the clip
        // extents due to the filter footprint.
        clipExtents.Inflate(filterRadius);
    }
    clipExtents.RoundOut();

    IntRect intExtents(int32_t(clipExtents.X()),
                         int32_t(clipExtents.Y()),
                         int32_t(clipExtents.Width()),
                         int32_t(clipExtents.Height()));
    drawingRect.IntersectRect(drawingRect, intExtents);

    gfxPoint offset(drawingRect.x, drawingRect.y);

    DrawingMethod method;
    DrawTarget* drawTarget = ctx->GetDrawTarget();
    Matrix dtTransform = drawTarget->GetTransform();
    gfxPoint deviceTranslation = gfxPoint(dtTransform._31, dtTransform._32);
    cairo_surface_t* cairoTarget = static_cast<cairo_surface_t*>
            (drawTarget->GetNativeSurface(NativeSurfaceType::CAIRO_SURFACE));

    cairo_surface_t* tempXlibSurface =
        CreateTempXlibSurface(cairoTarget, drawTarget, size,
                              canDrawOverBackground, flags, screen, visual,
                              &method);
    if (!tempXlibSurface)
        return;

    bool drawIsOpaque = (flags & DRAW_IS_OPAQUE) != 0;
    if (!drawIsOpaque) {
        cairo_t* tmpCtx = cairo_create(tempXlibSurface);
        if (method == eCopyBackground) {
            NS_ASSERTION(cairoTarget, "eCopyBackground only used when there's a cairoTarget");
            cairo_set_operator(tmpCtx, CAIRO_OPERATOR_SOURCE);
            gfxPoint pt = -(offset + deviceTranslation);
            cairo_set_source_surface(tmpCtx, cairoTarget, pt.x, pt.y);
            // The copy from the tempXlibSurface to the target context should
            // use operator SOURCE, but that would need a mask to bound the
            // operation.  Here we only copy opaque backgrounds so operator
            // OVER will behave like SOURCE masked by the surface.
            NS_ASSERTION(cairo_surface_get_content(tempXlibSurface) == CAIRO_CONTENT_COLOR,
                         "Don't copy background with a transparent surface");
        } else {
            cairo_set_operator(tmpCtx, CAIRO_OPERATOR_CLEAR);
        }
        cairo_paint(tmpCtx);
        cairo_destroy(tmpCtx);
    }

    if (!DrawOntoTempSurface(tempXlibSurface, -drawingRect.TopLeft())) {
        cairo_surface_destroy(tempXlibSurface);
        return;
    }

    SurfaceFormat moz2DFormat =
        cairo_surface_get_content(tempXlibSurface) == CAIRO_CONTENT_COLOR ?
            SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8;
    if (method != eAlphaExtraction) {
        if (drawTarget) {
            NativeSurface native;
            native.mFormat = moz2DFormat;
            native.mType = NativeSurfaceType::CAIRO_SURFACE;
            native.mSurface = tempXlibSurface;
            native.mSize = size;
            RefPtr<SourceSurface> sourceSurface =
                drawTarget->CreateSourceSurfaceFromNativeSurface(native);
            if (sourceSurface) {
                drawTarget->DrawSurface(sourceSurface,
                    Rect(offset.x, offset.y, size.width, size.height),
                    Rect(0, 0, size.width, size.height));
            }
        } else {
            nsRefPtr<gfxASurface> tmpSurf = gfxASurface::Wrap(tempXlibSurface);
            ctx->SetSource(tmpSurf, offset);
            ctx->Paint();
        }
        cairo_surface_destroy(tempXlibSurface);
        return;
    }
    
    nsRefPtr<gfxImageSurface> blackImage =
        CopyXlibSurfaceToImage(tempXlibSurface, size, gfxImageFormat::ARGB32);
    
    cairo_t* tmpCtx = cairo_create(tempXlibSurface);
    cairo_set_source_rgba(tmpCtx, 1.0, 1.0, 1.0, 1.0);
    cairo_set_operator(tmpCtx, CAIRO_OPERATOR_SOURCE);
    cairo_paint(tmpCtx);
    cairo_destroy(tmpCtx);
    DrawOntoTempSurface(tempXlibSurface, -drawingRect.TopLeft());
    nsRefPtr<gfxImageSurface> whiteImage =
        CopyXlibSurfaceToImage(tempXlibSurface, size, gfxImageFormat::RGB24);
  
    if (blackImage->CairoStatus() == CAIRO_STATUS_SUCCESS &&
        whiteImage->CairoStatus() == CAIRO_STATUS_SUCCESS) {
        if (!gfxAlphaRecovery::RecoverAlpha(blackImage, whiteImage)) {
            cairo_surface_destroy(tempXlibSurface);
            return;
        }

        gfxASurface* paintSurface = blackImage;
        if (drawTarget) {
            NativeSurface native;
            native.mFormat = moz2DFormat;
            native.mType = NativeSurfaceType::CAIRO_SURFACE;
            native.mSurface = paintSurface->CairoSurface();
            native.mSize = size;
            RefPtr<SourceSurface> sourceSurface =
                drawTarget->CreateSourceSurfaceFromNativeSurface(native);
            if (sourceSurface) {
                drawTarget->DrawSurface(sourceSurface,
                    Rect(offset.x, offset.y, size.width, size.height),
                    Rect(0, 0, size.width, size.height));
            }
        } else {
            ctx->SetSource(paintSurface, offset);
            ctx->Paint();
        }
    }
    cairo_surface_destroy(tempXlibSurface);
}