Bug 1220629 - Part 3: Implement PushLayer/PopLayer API in cairo. r=jrmuizel

--HG--
extra : rebase_source : 058ed10659456f59761535f7538ced6df5425aec
This commit is contained in:
Bas Schouten 2016-01-06 00:04:38 +01:00
parent fd6c57413d
commit 6b108bc5cb
3 changed files with 119 additions and 3 deletions

View File

@ -1234,6 +1234,18 @@ DrawTargetCairo::Fill(const Path *aPath,
DrawPattern(aPattern, StrokeOptions(), aOptions, DRAW_FILL);
}
bool
DrawTargetCairo::IsCurrentGroupOpaque()
{
cairo_surface_t* surf = cairo_get_group_target(mContext);
if (!surf) {
return false;
}
return cairo_surface_get_content(surf) == CAIRO_CONTENT_COLOR;
}
void
DrawTargetCairo::SetPermitSubpixelAA(bool aPermitSubpixelAA)
{
@ -1455,6 +1467,87 @@ DrawTargetCairo::PopClip()
cairo_set_matrix(mContext, &mat);
}
void
DrawTargetCairo::PushLayer(bool aOpaque, Float aOpacity, SourceSurface* aMask,
const Matrix& aMaskTransform, const IntRect& aBounds,
bool aCopyBackground)
{
cairo_content_t content = CAIRO_CONTENT_COLOR_ALPHA;
if (mFormat == SurfaceFormat::A8) {
content = CAIRO_CONTENT_ALPHA;
} else if (aOpaque) {
content = CAIRO_CONTENT_COLOR;
}
if (aCopyBackground) {
cairo_surface_t* source = cairo_get_group_target(mContext);
cairo_push_group_with_content(mContext, content);
cairo_surface_t* dest = cairo_get_group_target(mContext);
cairo_t* ctx = cairo_create(dest);
cairo_set_source_surface(ctx, source, 0, 0);
cairo_set_operator(ctx, CAIRO_OPERATOR_SOURCE);
cairo_paint(ctx);
cairo_destroy(ctx);
} else {
cairo_push_group_with_content(mContext, content);
}
PushedLayer layer(aOpacity, mPermitSubpixelAA);
if (aMask) {
cairo_surface_t* surf = GetCairoSurfaceForSourceSurface(aMask);
if (surf) {
layer.mMaskPattern = cairo_pattern_create_for_surface(surf);
cairo_matrix_t mat;
GfxMatrixToCairoMatrix(aMaskTransform, mat);
cairo_matrix_invert(&mat);
cairo_pattern_set_matrix(layer.mMaskPattern, &mat);
cairo_surface_destroy(surf);
} else {
gfxCriticalError() << "Failed to get cairo surface for mask surface!";
}
}
mPushedLayers.push_back(layer);
SetPermitSubpixelAA(aOpaque);
}
void
DrawTargetCairo::PopLayer()
{
MOZ_ASSERT(mPushedLayers.size());
cairo_set_operator(mContext, CAIRO_OPERATOR_OVER);
cairo_pop_group_to_source(mContext);
PushedLayer layer = mPushedLayers.back();
mPushedLayers.pop_back();
if (!layer.mMaskPattern) {
cairo_paint_with_alpha(mContext, layer.mOpacity);
} else {
if (layer.mOpacity != Float(1.0)) {
cairo_push_group_with_content(mContext, CAIRO_CONTENT_COLOR_ALPHA);
// Now draw the content using the desired operator
cairo_paint_with_alpha(mContext, layer.mOpacity);
cairo_pop_group_to_source(mContext);
}
cairo_mask(mContext, layer.mMaskPattern);
}
cairo_matrix_t mat;
GfxMatrixToCairoMatrix(mTransform, mat);
cairo_set_matrix(mContext, &mat);
cairo_pattern_destroy(layer.mMaskPattern);
SetPermitSubpixelAA(layer.mWasPermittingSubpixelAA);
}
already_AddRefed<PathBuilder>
DrawTargetCairo::CreatePathBuilder(FillRule aFillRule /* = FillRule::FILL_WINDING */) const
@ -1772,7 +1865,7 @@ void *
DrawTargetCairo::GetNativeSurface(NativeSurfaceType aType)
{
if (aType == NativeSurfaceType::CAIRO_SURFACE) {
return cairo_get_target(mContext);
return cairo_get_group_target(mContext);
}
if (aType == NativeSurfaceType::CAIRO_CONTEXT) {
return mContext;

View File

@ -65,6 +65,8 @@ public:
virtual already_AddRefed<SourceSurface> Snapshot() override;
virtual IntSize GetSize() override;
virtual bool IsCurrentGroupOpaque() override;
virtual void SetPermitSubpixelAA(bool aPermitSubpixelAA) override;
virtual bool LockBits(uint8_t** aData, IntSize* aSize,
@ -134,6 +136,12 @@ public:
virtual void PushClip(const Path *aPath) override;
virtual void PushClipRect(const Rect &aRect) override;
virtual void PopClip() override;
virtual void PushLayer(bool aOpaque, Float aOpacity,
SourceSurface* aMask,
const Matrix& aMaskTransform,
const IntRect& aBounds = IntRect(),
bool aCopyBackground = false) override;
virtual void PopLayer() override;
virtual already_AddRefed<PathBuilder> CreatePathBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const override;
@ -214,6 +222,19 @@ private: // data
uint8_t* mLockedBits;
struct PushedLayer
{
PushedLayer(Float aOpacity, bool aWasPermittingSubpixelAA)
: mOpacity(aOpacity)
, mMaskPattern(nullptr)
, mWasPermittingSubpixelAA(aWasPermittingSubpixelAA)
{}
Float mOpacity;
cairo_pattern_t* mMaskPattern;
bool mWasPermittingSubpixelAA;
};
std::vector<PushedLayer> mPushedLayers;
// The latest snapshot of this surface. This needs to be told when this
// target is modified. We keep it alive as a cache.
RefPtr<SourceSurfaceCairo> mSnapshot;

View File

@ -115,8 +115,10 @@ gfxContext::CurrentSurface(gfxFloat *dx, gfxFloat *dy)
(cairo_surface_t*)mDT->GetNativeSurface(NativeSurfaceType::CAIRO_SURFACE);
if (s) {
if (dx && dy) {
*dx = -CurrentState().deviceOffset.x;
*dy = -CurrentState().deviceOffset.y;
double sdx, sdy;
cairo_surface_get_device_offset(s, &sdx, &sdy);
*dx = -CurrentState().deviceOffset.x + sdx;
*dy = -CurrentState().deviceOffset.y + sdy;
}
return gfxASurface::Wrap(s);
}