gecko-dev/gfx/2d/DrawTargetDual.cpp
Jeff Muizelaar 0b68652b49 Bug 1539702. Improve CreateClippedDrawTarget API r=jwatt,rhunt
This changes CreateClippedDrawTarget so that instead of taking
a max size and a transform it just takes a user space rect of
the desired bounds.

This change allows the caller to not worry about the computing
a max size based on the current clip. Instead this responsibility
is lowered into the specific backends.

The main motivation for this work is to allow blob recoordination
to create recordings that don't depend on the current clip.

Some additional benefits are that the API is easier to use and
as can be seen simplifies the SVG masking code because it doesn't
need to track surface offsets manually.

It's also an important step towards removing all the uses of
gfxContext::GetClipExtents which will let us get rid of the separate
clipping stack in gfxContext and help us move off of gfxContext
completely.

Most backend implementations of CreateClippedDrawTarget are relatively
simple. DrawTargetCapture is modified to track the current clip rect
so that it can create a new DrawTargetCapture of the appropriate size
without needing to worry about lazy resolution.

Differential Revision: https://phabricator.services.mozilla.com/D33363

--HG--
extra : moz-landing-system : lando
2019-06-21 09:51:00 +00:00

216 lines
7.7 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DrawTargetDual.h"
#include "Tools.h"
#include "Logging.h"
namespace mozilla {
namespace gfx {
class DualSurface {
public:
inline explicit DualSurface(SourceSurface* aSurface) {
if (!aSurface) {
mA = mB = nullptr;
return;
}
if (aSurface->GetType() != SurfaceType::DUAL_DT) {
mA = mB = aSurface;
return;
}
SourceSurfaceDual* ssDual = static_cast<SourceSurfaceDual*>(aSurface);
mA = ssDual->mA;
mB = ssDual->mB;
}
SourceSurface* mA;
SourceSurface* mB;
};
/* This only needs to split patterns up for SurfacePatterns. Only in that
* case can we be dealing with a 'dual' source (SourceSurfaceDual) and do
* we need to pass separate patterns into our destination DrawTargets.
*/
class DualPattern final {
public:
inline explicit DualPattern(const Pattern& aPattern)
: mPatternsInitialized(false) {
if (aPattern.GetType() != PatternType::SURFACE) {
mA = mB = &aPattern;
return;
}
const SurfacePattern* surfPat =
static_cast<const SurfacePattern*>(&aPattern);
if (surfPat->mSurface->GetType() != SurfaceType::DUAL_DT) {
mA = mB = &aPattern;
return;
}
const SourceSurfaceDual* ssDual =
static_cast<const SourceSurfaceDual*>(surfPat->mSurface.get());
mA = new (mSurfPatA.addr())
SurfacePattern(ssDual->mA, surfPat->mExtendMode, surfPat->mMatrix,
surfPat->mSamplingFilter);
mB = new (mSurfPatB.addr())
SurfacePattern(ssDual->mB, surfPat->mExtendMode, surfPat->mMatrix,
surfPat->mSamplingFilter);
mPatternsInitialized = true;
}
inline ~DualPattern() {
if (mPatternsInitialized) {
mA->~Pattern();
mB->~Pattern();
}
}
ClassStorage<SurfacePattern> mSurfPatA;
ClassStorage<SurfacePattern> mSurfPatB;
const Pattern* mA;
const Pattern* mB;
bool mPatternsInitialized;
};
void DrawTargetDual::DetachAllSnapshots() {
mA->DetachAllSnapshots();
mB->DetachAllSnapshots();
}
void DrawTargetDual::DrawSurface(SourceSurface* aSurface, const Rect& aDest,
const Rect& aSource,
const DrawSurfaceOptions& aSurfOptions,
const DrawOptions& aOptions) {
DualSurface surface(aSurface);
mA->DrawSurface(surface.mA, aDest, aSource, aSurfOptions, aOptions);
mB->DrawSurface(surface.mB, aDest, aSource, aSurfOptions, aOptions);
}
void DrawTargetDual::DrawSurfaceWithShadow(SourceSurface* aSurface,
const Point& aDest,
const Color& aColor,
const Point& aOffset, Float aSigma,
CompositionOp aOp) {
DualSurface surface(aSurface);
mA->DrawSurfaceWithShadow(surface.mA, aDest, aColor, aOffset, aSigma, aOp);
mB->DrawSurfaceWithShadow(surface.mB, aDest, aColor, aOffset, aSigma, aOp);
}
void DrawTargetDual::MaskSurface(const Pattern& aSource, SourceSurface* aMask,
Point aOffset, const DrawOptions& aOptions) {
DualPattern source(aSource);
DualSurface mask(aMask);
mA->MaskSurface(*source.mA, mask.mA, aOffset, aOptions);
mB->MaskSurface(*source.mB, mask.mB, aOffset, aOptions);
}
void DrawTargetDual::ClearRect(const Rect& aRect) {
mA->FillRect(aRect, ColorPattern(Color(0.0, 0.0, 0.0, 1.0)));
mB->FillRect(aRect, ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
}
void DrawTargetDual::CopySurface(SourceSurface* aSurface,
const IntRect& aSourceRect,
const IntPoint& aDestination) {
DualSurface surface(aSurface);
mA->CopySurface(surface.mA, aSourceRect, aDestination);
mB->CopySurface(surface.mB, aSourceRect, aDestination);
}
void DrawTargetDual::FillRect(const Rect& aRect, const Pattern& aPattern,
const DrawOptions& aOptions) {
DualPattern pattern(aPattern);
mA->FillRect(aRect, *pattern.mA, aOptions);
mB->FillRect(aRect, *pattern.mB, aOptions);
}
void DrawTargetDual::StrokeRect(const Rect& aRect, const Pattern& aPattern,
const StrokeOptions& aStrokeOptions,
const DrawOptions& aOptions) {
DualPattern pattern(aPattern);
mA->StrokeRect(aRect, *pattern.mA, aStrokeOptions, aOptions);
mB->StrokeRect(aRect, *pattern.mB, aStrokeOptions, aOptions);
}
void DrawTargetDual::StrokeLine(const Point& aStart, const Point& aEnd,
const Pattern& aPattern,
const StrokeOptions& aStrokeOptions,
const DrawOptions& aOptions) {
DualPattern pattern(aPattern);
mA->StrokeLine(aStart, aEnd, *pattern.mA, aStrokeOptions, aOptions);
mB->StrokeLine(aStart, aEnd, *pattern.mB, aStrokeOptions, aOptions);
}
void DrawTargetDual::Stroke(const Path* aPath, const Pattern& aPattern,
const StrokeOptions& aStrokeOptions,
const DrawOptions& aOptions) {
DualPattern pattern(aPattern);
mA->Stroke(aPath, *pattern.mA, aStrokeOptions, aOptions);
mB->Stroke(aPath, *pattern.mB, aStrokeOptions, aOptions);
}
void DrawTargetDual::Fill(const Path* aPath, const Pattern& aPattern,
const DrawOptions& aOptions) {
DualPattern pattern(aPattern);
mA->Fill(aPath, *pattern.mA, aOptions);
mB->Fill(aPath, *pattern.mB, aOptions);
}
void DrawTargetDual::FillGlyphs(ScaledFont* aScaledFont,
const GlyphBuffer& aBuffer,
const Pattern& aPattern,
const DrawOptions& aOptions) {
DualPattern pattern(aPattern);
mA->FillGlyphs(aScaledFont, aBuffer, *pattern.mA, aOptions);
mB->FillGlyphs(aScaledFont, aBuffer, *pattern.mB, aOptions);
}
void DrawTargetDual::Mask(const Pattern& aSource, const Pattern& aMask,
const DrawOptions& aOptions) {
DualPattern source(aSource);
DualPattern mask(aMask);
mA->Mask(*source.mA, *mask.mA, aOptions);
mB->Mask(*source.mB, *mask.mB, aOptions);
}
void DrawTargetDual::PushLayer(bool aOpaque, Float aOpacity,
SourceSurface* aMask,
const Matrix& aMaskTransform,
const IntRect& aBounds, bool aCopyBackground) {
DualSurface mask(aMask);
mA->PushLayer(aOpaque, aOpacity, mask.mA, aMaskTransform, aBounds,
aCopyBackground);
mB->PushLayer(aOpaque, aOpacity, mask.mB, aMaskTransform, aBounds,
aCopyBackground);
}
already_AddRefed<DrawTarget> DrawTargetDual::CreateSimilarDrawTarget(
const IntSize& aSize, SurfaceFormat aFormat) const {
/* Now that we have PushLayer there a very few cases where a user of
* DrawTargetDual wants to have a DualTarget when creating a similar one. */
return mA->CreateSimilarDrawTarget(aSize, aFormat);
}
RefPtr<DrawTarget> DrawTargetDual::CreateClippedDrawTarget(
const Rect& aBounds, SurfaceFormat aFormat) {
/* The user probably doesn't want a DualDrawTarget here. */
return mA->CreateClippedDrawTarget(aBounds, aFormat);
}
bool DrawTargetDual::CanCreateSimilarDrawTarget(const IntSize& aSize,
SurfaceFormat aFormat) const {
return mA->CanCreateSimilarDrawTarget(aSize, aFormat);
}
} // namespace gfx
} // namespace mozilla