Bug 880836. Add MaskSurface() to Azure. r=bas

This gives a substantial performance improvement over the more general Mask():

Test (MaskSurface10x10):  1.93042ms +/- 0.305028
Test (MaskSurface100x100):  2.33435ms +/- 1.00807
Test (MaskSurface500x500):  28.0472ms +/- 0.820744
Test (MaskSurface1000x1000):  107.656ms +/- 6.44615
Test (Mask10x10):  13.5237ms +/- 0.0932034
Test (Mask100x100):  14.0742ms +/- 1.21005
Test (Mask500x500):  96.5596ms +/- 1.81415
Test (Mask1000x1000):  356.891ms +/- 9.30592

--HG--
rename : layout/reftests/svg/text/dynamic-non-scaling-stroke-ref.svg => layout/reftests/svg/non-scaling-stroke-03-ref.svg
rename : layout/reftests/svg/text/dynamic-non-scaling-stroke.svg => layout/reftests/svg/non-scaling-stroke-03.svg
extra : rebase_source : a1218b8bc5cdcec7d4dd94561d841fb6e2a8ce5d
This commit is contained in:
Jeff Muizelaar 2013-06-12 23:57:51 -04:00
Родитель f810a607cb
Коммит 32dbe991d6
8 изменённых файлов: 202 добавлений и 57 удалений

Просмотреть файл

@ -706,6 +706,21 @@ public:
const Pattern &aMask,
const DrawOptions &aOptions = DrawOptions()) = 0;
/*
* This takes a source pattern and a mask, and composites the source pattern
* onto the destination surface using the alpha channel of the mask source.
* The operation is bound by the extents of the mask.
*
* aSource Source pattern
* aMask Mask surface
* aOffset a transformed offset that the surface is masked at
* aOptions Drawing options
*/
virtual void MaskSurface(const Pattern &aSource,
SourceSurface *aMask,
Point aOffset,
const DrawOptions &aOptions = DrawOptions()) { MOZ_ASSERT(0); };
/*
* Push a clip to the DrawTarget.
*

Просмотреть файл

@ -300,6 +300,38 @@ DrawTargetCG::DrawSurface(SourceSurface *aSurface,
CGImageRelease(subimage);
}
void
DrawTargetCG::MaskSurface(const Pattern &aSource,
SourceSurface *aMask,
Point aOffset,
const DrawOptions &aDrawOptions)
{
MarkChanged();
CGImageRef image;
CGContextSaveGState(mCg);
CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp));
UnboundnessFixer fixer;
CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp);
CGContextSetAlpha(cg, aDrawOptions.mAlpha);
CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform));
image = GetImageFromSourceSurface(aMask);
CGContextScaleCTM(cg, 1, -1);
IntSize size = aMask->GetSize();
CGContextClipToMask(cg, CGRectMake(aOffset.x, aOffset.y, size.width, size.height), image);
FillRect(Rect(0, 0, size.width, size.height), aSource, aDrawOptions);
fixer.Fix(mCg);
CGContextRestoreGState(mCg);
}
static CGColorRef ColorToCGColor(CGColorSpaceRef aColorSpace, const Color& aColor)
{
CGFloat components[4] = {aColor.r, aColor.g, aColor.b, aColor.a};

Просмотреть файл

@ -96,6 +96,10 @@ public:
const Rect &aSource,
const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(),
const DrawOptions &aOptions = DrawOptions());
virtual void MaskSurface(const Pattern &aSource,
SourceSurface *aMask,
Point aOffset,
const DrawOptions &aOptions = DrawOptions());
virtual void FillRect(const Rect &aRect,
const Pattern &aPattern,

Просмотреть файл

@ -676,6 +676,55 @@ DrawTargetCairo::Mask(const Pattern &aSource,
cairo_pattern_destroy(mask);
cairo_pattern_destroy(source);
}
#if 0
DrawTargetCairo::MaskSurface(SourceSurface *aSurface,
const Rect &aDest,
const Rect &aSource,
const DrawSurfaceOptions &aSurfOptions,
const DrawOptions &aOptions)
{
AutoPrepareForDrawing prep(this, mContext);
float sx = aSource.Width() / aDest.Width();
float sy = aSource.Height() / aDest.Height();
cairo_matrix_t src_mat;
cairo_matrix_init_translate(&src_mat, aSource.X(), aSource.Y());
cairo_matrix_scale(&src_mat, sx, sy);
cairo_surface_t* surf = GetCairoSurfaceForSourceSurface(aSurface);
cairo_pattern_t* pat = cairo_pattern_create_for_surface(surf);
cairo_surface_destroy(surf);
cairo_pattern_set_matrix(pat, &src_mat);
cairo_pattern_set_filter(pat, GfxFilterToCairoFilter(aSurfOptions.mFilter));
cairo_pattern_set_extend(pat, CAIRO_EXTEND_PAD);
cairo_translate(mContext, aDest.X(), aDest.Y());
if (IsOperatorBoundByMask(aOptions.mCompositionOp)) {
cairo_new_path(mContext);
cairo_rectangle(mContext, 0, 0, aDest.Width(), aDest.Height());
cairo_clip(mContext);
cairo_set_source(mContext, pat);
} else {
cairo_push_group(mContext);
cairo_new_path(mContext);
cairo_rectangle(mContext, 0, 0, aDest.Width(), aDest.Height());
cairo_set_source(mContext, pat);
cairo_fill(mContext);
cairo_pop_group_to_source(mContext);
}
cairo_set_operator(mContext, GfxOpToCairoOp(aOptions.mCompositionOp));
DrawPattern(aPattern, StrokeOptions(), aOptions, DRAW_FILL);
cairo_paint_with_alpha(mContext, aOptions.mAlpha);
cairo_pattern_destroy(pat);
}
#endif
void
DrawTargetCairo::PushClip(const Path *aPath)

Просмотреть файл

@ -257,6 +257,63 @@ DrawTargetD2D::AddDependencyOnSource(SourceSurfaceD2DTarget* aSource)
}
}
TemporaryRef<ID2D1Bitmap>
DrawTargetD2D::GetBitmapForSurface(SourceSurface *aSurface,
Rect &aSource)
{
RefPtr<ID2D1Bitmap> bitmap;
switch (aSurface->GetType()) {
case SURFACE_D2D1_BITMAP:
{
SourceSurfaceD2D *srcSurf = static_cast<SourceSurfaceD2D*>(aSurface);
bitmap = srcSurf->GetBitmap();
}
break;
case SURFACE_D2D1_DRAWTARGET:
{
SourceSurfaceD2DTarget *srcSurf = static_cast<SourceSurfaceD2DTarget*>(aSurface);
bitmap = srcSurf->GetBitmap(mRT);
AddDependencyOnSource(srcSurf);
}
break;
default:
{
RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface();
if (!srcSurf) {
gfxDebug() << "Not able to deal with non-data source surface.";
return nullptr;
}
if (aSource.width > mRT->GetMaximumBitmapSize() ||
aSource.height > mRT->GetMaximumBitmapSize()) {
gfxDebug() << "Bitmap source larger than texture size specified. DrawBitmap will silently fail.";
// Don't know how to deal with this yet.
return nullptr;
}
int stride = srcSurf->Stride();
unsigned char *data = srcSurf->GetData() +
(uint32_t)aSource.y * stride +
(uint32_t)aSource.x * BytesPerPixel(srcSurf->GetFormat());
D2D1_BITMAP_PROPERTIES props =
D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(srcSurf->GetFormat()), AlphaMode(srcSurf->GetFormat())));
mRT->CreateBitmap(D2D1::SizeU(UINT32(aSource.width), UINT32(aSource.height)), data, stride, props, byRef(bitmap));
// subtract the integer part leaving the fractional part
aSource.x -= (uint32_t)aSource.x;
aSource.y -= (uint32_t)aSource.y;
}
break;
}
return bitmap;
}
void
DrawTargetD2D::DrawSurface(SourceSurface *aSurface,
const Rect &aDest,
@ -274,62 +331,45 @@ DrawTargetD2D::DrawSurface(SourceSurface *aSurface,
Rect srcRect = aSource;
switch (aSurface->GetType()) {
case SURFACE_D2D1_BITMAP:
{
SourceSurfaceD2D *srcSurf = static_cast<SourceSurfaceD2D*>(aSurface);
bitmap = srcSurf->GetBitmap();
if (!bitmap) {
return;
}
}
break;
case SURFACE_D2D1_DRAWTARGET:
{
SourceSurfaceD2DTarget *srcSurf = static_cast<SourceSurfaceD2DTarget*>(aSurface);
bitmap = srcSurf->GetBitmap(mRT);
AddDependencyOnSource(srcSurf);
}
break;
default:
{
RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface();
if (!srcSurf) {
gfxDebug() << "Not able to deal with non-data source surface.";
return;
}
if (aSource.width > rt->GetMaximumBitmapSize() ||
aSource.height > rt->GetMaximumBitmapSize()) {
gfxDebug() << "Bitmap source larger than texture size specified. DrawBitmap will silently fail.";
// Don't know how to deal with this yet.
return;
}
int stride = srcSurf->Stride();
unsigned char *data = srcSurf->GetData() +
(uint32_t)aSource.y * stride +
(uint32_t)aSource.x * BytesPerPixel(srcSurf->GetFormat());
D2D1_BITMAP_PROPERTIES props =
D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(srcSurf->GetFormat()), AlphaMode(srcSurf->GetFormat())));
mRT->CreateBitmap(D2D1::SizeU(UINT32(aSource.width), UINT32(aSource.height)), data, stride, props, byRef(bitmap));
srcRect.x -= (uint32_t)aSource.x;
srcRect.y -= (uint32_t)aSource.y;
}
break;
bitmap = GetBitmapForSurface(aSurface, srcRect);
if (!bitmap) {
return;
}
rt->DrawBitmap(bitmap, D2DRect(aDest), aOptions.mAlpha, D2DFilter(aSurfOptions.mFilter), D2DRect(srcRect));
FinalizeRTForOperation(aOptions.mCompositionOp, ColorPattern(Color()), aDest);
}
void
DrawTargetD2D::MaskSurface(const Pattern &aSource,
SourceSurface *aMask,
Point aOffset,
const DrawOptions &aOptions)
{
RefPtr<ID2D1Bitmap> bitmap;
ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, ColorPattern(Color()));
PrepareForDrawing(rt);
// FillOpacityMask only works if the antialias mode is MODE_ALIASED
rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
IntSize size = aMask->GetSize();
Rect maskRect = Rect(0.f, 0.f, size.width, size.height);
bitmap = GetBitmapForSurface(aMask, maskRect);
if (!bitmap) {
return;
}
Rect dest = Rect(aOffset.x, aOffset.y, size.width, size.height);
RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aSource, aOptions.mAlpha);
rt->FillOpacityMask(bitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS, D2DRect(dest), D2DRect(maskRect));
FinalizeRTForOperation(aOptions.mCompositionOp, ColorPattern(Color()), dest);
}
void
DrawTargetD2D::DrawSurfaceWithShadow(SourceSurface *aSurface,
const Point &aDest,

Просмотреть файл

@ -63,6 +63,11 @@ public:
Float aSigma,
CompositionOp aOperator);
virtual void ClearRect(const Rect &aRect);
virtual void MaskSurface(const Pattern &aSource,
SourceSurface *aMask,
Point aOffset,
const DrawOptions &aOptions = DrawOptions());
virtual void CopySurface(SourceSurface *aSurface,
const IntRect &aSourceRect,
@ -142,6 +147,9 @@ public:
static uint64_t mVRAMUsageSS;
private:
TemporaryRef<ID2D1Bitmap>
DrawTargetD2D::GetBitmapForSurface(SourceSurface *aSurface,
Rect &aSource);
friend class AutoSaveRestoreClippedOut;
friend class SourceSurfaceD2DTarget;

Просмотреть файл

@ -1397,7 +1397,6 @@ gfxContext::GetPattern()
// masking
void
gfxContext::Mask(gfxPattern *pattern)
{
@ -1463,12 +1462,10 @@ gfxContext::Mask(gfxASurface *surface, const gfxPoint& offset)
gfxPoint pt = surface->GetDeviceOffset();
// We clip here to bind to the mask surface bounds, see above.
mDT->PushClipRect(Rect(offset.x - pt.x, offset.y - pt.y, sourceSurf->GetSize().width, sourceSurf->GetSize().height));
mDT->Mask(GeneralPattern(this),
SurfacePattern(sourceSurf, EXTEND_CLAMP,
Matrix(1.0f, 0, 0, 1.0f, Float(offset.x - pt.x), Float(offset.y - pt.y))),
mDT->MaskSurface(GeneralPattern(this),
sourceSurf,
Point(offset.x - pt.x, offset.y - pt.y),
DrawOptions(1.0f, CurrentState().op, CurrentState().aaMode));
mDT->PopClip();
}
}

Просмотреть файл

@ -1716,7 +1716,7 @@ skip-if(B2G) == 751012-1b.html 751012-1-ref.html
random-if(Android) == 753329-1.html about:blank
== 758561-1.html 758561-1-ref.html
fuzzy-if(true,1,19) fails-if(d2d) == 759036-1.html 759036-1-ref.html
fuzzy-if(true,17,5859) == 759036-2.html 759036-2-ref.html
fuzzy-if(true,17,5860) == 759036-2.html 759036-2-ref.html
== 776265-1a.html 776265-1-ref.html
== 776265-1b.html 776265-1-ref.html
== 776265-1c.html 776265-1-ref.html