Bug 1083672 - Avoid copying more than needed when drawing a canvas onto itself. r=jrmuizel

This commit is contained in:
Markus Stange 2014-10-24 18:32:17 +02:00
Родитель 28bf55dae8
Коммит 1874a2749b
1 изменённых файлов: 36 добавлений и 1 удалений

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

@ -3854,6 +3854,32 @@ bool CanvasRenderingContext2D::IsPointInStroke(const CanvasPath& mPath, double x
return tempPath->StrokeContainsPoint(strokeOptions, Point(x, y), mTarget->GetTransform());
}
// Returns a surface that contains only the part needed to draw aSourceRect.
// On entry, aSourceRect is relative to aSurface, and on return aSourceRect is
// relative to the returned surface.
static TemporaryRef<SourceSurface>
ExtractSubrect(SourceSurface* aSurface, mgfx::Rect* aSourceRect, DrawTarget* aTargetDT)
{
mgfx::Rect roundedOutSourceRect = *aSourceRect;
roundedOutSourceRect.RoundOut();
mgfx::IntRect roundedOutSourceRectInt;
if (!roundedOutSourceRect.ToIntRect(&roundedOutSourceRectInt)) {
return aSurface;
}
RefPtr<DrawTarget> subrectDT =
aTargetDT->CreateSimilarDrawTarget(roundedOutSourceRectInt.Size(), SurfaceFormat::B8G8R8A8);
if (!subrectDT) {
return aSurface;
}
*aSourceRect -= roundedOutSourceRect.TopLeft();
subrectDT->CopySurface(aSurface, roundedOutSourceRectInt, IntPoint());
return subrectDT->Snapshot();
}
//
// image
//
@ -3999,10 +4025,19 @@ CanvasRenderingContext2D::DrawImage(const HTMLImageOrCanvasOrVideoElement& image
}
if (srcSurf) {
mgfx::Rect sourceRect(sx, sy, sw, sh);
if (element == mCanvasElement) {
// srcSurf is a snapshot of mTarget. If we draw to mTarget now, we'll
// trigger a COW copy of the whole canvas into srcSurf. That's a huge
// waste if sourceRect doesn't cover the whole canvas.
// We avoid copying the whole canvas by manually copying just the part
// that we need.
srcSurf = ExtractSubrect(srcSurf, &sourceRect, mTarget);
}
AdjustedTarget(this, bounds.IsEmpty() ? nullptr : &bounds)->
DrawSurface(srcSurf,
mgfx::Rect(dx, dy, dw, dh),
mgfx::Rect(sx, sy, sw, sh),
sourceRect,
DrawSurfaceOptions(filter),
DrawOptions(CurrentState().globalAlpha, UsedOperation()));
} else {