Bug 1616587 - Implement conic-gradient for Skia graphics backend. r=lsalzman

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Tim Nguyen 2020-02-20 22:58:59 +00:00
Родитель e5b5796a47
Коммит 41df136301
10 изменённых файлов: 150 добавлений и 7 удалений

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

@ -290,6 +290,29 @@ class RadialGradientPattern : public Pattern {
Matrix mMatrix; //!< A matrix that transforms the pattern into user space
};
/**
* This class is used for Conic Gradient Patterns, the gradient stops are
* stored in a separate object and are backend dependent. This class itself
* may be used on the stack.
*/
class ConicGradientPattern : public Pattern {
public:
/// For constructor parameter description, see member data documentation.
ConicGradientPattern(const Point& aCenter, Float aAngle,
GradientStops* aStops, const Matrix& aMatrix = Matrix())
: mCenter(aCenter), mAngle(aAngle), mStops(aStops), mMatrix(aMatrix) {}
PatternType GetType() const override { return PatternType::CONIC_GRADIENT; }
Point mCenter; //!< Center of the gradient
Float mAngle; //!< Start angle of gradient
RefPtr<GradientStops>
mStops; /**< GradientStops object for this gradient, this
should match the backend type of the draw target
this pattern will be used with. */
Matrix mMatrix; //!< A matrix that transforms the pattern into user space
};
/**
* This class is used for Surface Patterns, they wrap a surface and a
* repetition mode for the surface. This may be used on the stack.

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

@ -68,6 +68,10 @@ class StoredPattern {
new (mRadial) RadialGradientPattern(
*static_cast<const RadialGradientPattern*>(&aPattern));
return;
case PatternType::CONIC_GRADIENT:
new (mConic) ConicGradientPattern(
*static_cast<const ConicGradientPattern*>(&aPattern));
return;
}
}
@ -98,6 +102,7 @@ class StoredPattern {
char mColor[sizeof(ColorPattern)];
char mLinear[sizeof(LinearGradientPattern)];
char mRadial[sizeof(RadialGradientPattern)];
char mConic[sizeof(ConicGradientPattern)];
char mSurface[sizeof(SurfacePattern)];
};
};

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

@ -494,6 +494,42 @@ static void SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern,
}
break;
}
case PatternType::CONIC_GRADIENT: {
const ConicGradientPattern& pat =
static_cast<const ConicGradientPattern&>(aPattern);
GradientStopsSkia* stops =
static_cast<GradientStopsSkia*>(pat.mStops.get());
if (!stops || stops->mCount < 2 || !pat.mCenter.IsFinite() ||
!IsFinite(pat.mAngle)) {
aPaint.setColor(SK_ColorTRANSPARENT);
} else {
SkMatrix mat;
GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
if (aMatrix) {
mat.postConcat(*aMatrix);
}
SkScalar cx = SkFloatToScalar(pat.mCenter.x);
SkScalar cy = SkFloatToScalar(pat.mCenter.y);
// Skia's sweep gradient angles are relative to the x-axis, not the
// y-axis.
Float angle = (pat.mAngle * 180.0 / M_PI) - 90.0;
if (angle != 0.0) {
mat.preRotate(angle, cx, cy);
}
sk_sp<SkShader> shader = SkGradientShader::MakeSweep(
cx, cy, &stops->mColors.front(), &stops->mPositions.front(),
stops->mCount, 0, &mat);
if (shader) {
aPaint.setShader(shader);
} else {
aPaint.setColor(SK_ColorTRANSPARENT);
}
}
break;
}
case PatternType::SURFACE: {
const SurfacePattern& pat = static_cast<const SurfacePattern&>(aPattern);
sk_sp<SkImage> image =

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

@ -52,6 +52,10 @@ class GeneralPattern final {
mPattern = new (mRadialGradientPattern.addr()) RadialGradientPattern(
static_cast<const RadialGradientPattern&>(aPattern));
break;
case PatternType::CONIC_GRADIENT:
mPattern = new (mConicGradientPattern.addr()) ConicGradientPattern(
static_cast<const ConicGradientPattern&>(aPattern));
break;
case PatternType::SURFACE:
mPattern = new (mSurfacePattern.addr())
SurfacePattern(static_cast<const SurfacePattern&>(aPattern));
@ -86,6 +90,15 @@ class GeneralPattern final {
return mRadialGradientPattern.addr();
}
ConicGradientPattern* InitConicGradientPattern(
const Point& aCenter, Float aAngle, GradientStops* aStops,
const Matrix& aMatrix = Matrix()) {
MOZ_ASSERT(!mPattern);
mPattern = new (mConicGradientPattern.addr())
ConicGradientPattern(aCenter, aAngle, aStops, aMatrix);
return mConicGradientPattern.addr();
}
SurfacePattern* InitSurfacePattern(
SourceSurface* aSourceSurface, ExtendMode aExtendMode,
const Matrix& aMatrix = Matrix(),
@ -113,6 +126,7 @@ class GeneralPattern final {
AlignedStorage2<ColorPattern> mColorPattern;
AlignedStorage2<LinearGradientPattern> mLinearGradientPattern;
AlignedStorage2<RadialGradientPattern> mRadialGradientPattern;
AlignedStorage2<ConicGradientPattern> mConicGradientPattern;
AlignedStorage2<SurfacePattern> mSurfacePattern;
};
Pattern* mPattern = nullptr;

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

@ -129,6 +129,13 @@ struct RadialGradientPatternStorage {
Matrix mMatrix;
};
struct ConicGradientPatternStorage {
Point mCenter;
Float mAngle;
ReferencePtr mStops;
Matrix mMatrix;
};
struct SurfacePatternStorage {
ExtendMode mExtend;
SamplingFilter mSamplingFilter;
@ -144,6 +151,7 @@ struct PatternStorage {
char mColor[sizeof(ColorPatternStorage)];
char mLinear[sizeof(LinearGradientPatternStorage)];
char mRadial[sizeof(RadialGradientPatternStorage)];
char mConic[sizeof(ConicGradientPatternStorage)];
char mSurface[sizeof(SurfacePatternStorage)];
};
};

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

@ -1564,6 +1564,12 @@ void RecordedEvent::RecordPatternData(S& aStream,
&aPattern.mStorage));
return;
}
case PatternType::CONIC_GRADIENT: {
WriteElement(aStream,
*reinterpret_cast<const ConicGradientPatternStorage*>(
&aPattern.mStorage));
return;
}
case PatternType::SURFACE: {
WriteElement(aStream, *reinterpret_cast<const SurfacePatternStorage*>(
&aPattern.mStorage));
@ -1596,6 +1602,11 @@ void RecordedEvent::ReadPatternData(S& aStream,
&aPattern.mStorage));
return;
}
case PatternType::CONIC_GRADIENT: {
ReadElement(aStream, *reinterpret_cast<ConicGradientPatternStorage*>(
&aPattern.mStorage));
return;
}
case PatternType::SURFACE: {
SurfacePatternStorage* sps =
reinterpret_cast<SurfacePatternStorage*>(&aPattern.mStorage);
@ -1661,6 +1672,18 @@ inline void RecordedEvent::StorePattern(PatternStorage& aDestination,
store->mStops = pat->mStops.get();
return;
}
case PatternType::CONIC_GRADIENT: {
ConicGradientPatternStorage* store =
reinterpret_cast<ConicGradientPatternStorage*>(
&aDestination.mStorage);
const ConicGradientPattern* pat =
static_cast<const ConicGradientPattern*>(&aSource);
store->mCenter = pat->mCenter;
store->mAngle = pat->mAngle;
store->mMatrix = pat->mMatrix;
store->mStops = pat->mStops.get();
return;
}
case PatternType::SURFACE: {
SurfacePatternStorage* store =
reinterpret_cast<SurfacePatternStorage*>(&aDestination.mStorage);
@ -1804,6 +1827,14 @@ inline void RecordedEvent::OutputSimplePatternInfo(
<< store->mCenter2.y << ") Radius 2: " << store->mRadius2;
return;
}
case PatternType::CONIC_GRADIENT: {
const ConicGradientPatternStorage* store =
reinterpret_cast<const ConicGradientPatternStorage*>(
&aStorage.mStorage);
aOutput << "ConicGradient (Center: (" << store->mCenter.x << ", "
<< store->mCenter.y << ") Angle: " << store->mAngle;
return;
}
case PatternType::SURFACE: {
const SurfacePatternStorage* store =
reinterpret_cast<const SurfacePatternStorage*>(&aStorage.mStorage);
@ -2139,6 +2170,16 @@ struct GenericPattern {
storage->mMatrix);
return mPattern;
}
case PatternType::CONIC_GRADIENT: {
ConicGradientPatternStorage* storage =
reinterpret_cast<ConicGradientPatternStorage*>(&mStorage->mStorage);
mPattern = new (mConGradPat) ConicGradientPattern(
storage->mCenter, storage->mAngle,
storage->mStops ? mTranslator->LookupGradientStops(storage->mStops)
: nullptr,
storage->mMatrix);
return mPattern;
}
default:
return new (mColPat) ColorPattern(Color());
}
@ -2150,6 +2191,7 @@ struct GenericPattern {
char mColPat[sizeof(ColorPattern)];
char mLinGradPat[sizeof(LinearGradientPattern)];
char mRadGradPat[sizeof(RadialGradientPattern)];
char mConGradPat[sizeof(ConicGradientPattern)];
char mSurfPat[sizeof(SurfacePattern)];
};

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

@ -414,7 +414,8 @@ enum class PatternType : int8_t {
COLOR,
SURFACE,
LINEAR_GRADIENT,
RADIAL_GRADIENT
RADIAL_GRADIENT,
CONIC_GRADIENT
};
enum class JoinStyle : int8_t {

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

@ -37,6 +37,12 @@ gfxPattern::gfxPattern(gfxFloat cx0, gfxFloat cy0, gfxFloat radius0,
radius0, radius1, nullptr);
}
// conic
gfxPattern::gfxPattern(gfxFloat cx, gfxFloat cy, gfxFloat angle)
: mExtend(ExtendMode::CLAMP) {
mGfxPattern.InitConicGradientPattern(Point(cx, cy), angle, nullptr);
}
// Azure
gfxPattern::gfxPattern(SourceSurface* aSurface,
const Matrix& aPatternToUserSpace)
@ -48,7 +54,8 @@ gfxPattern::gfxPattern(SourceSurface* aSurface,
void gfxPattern::AddColorStop(gfxFloat offset, const Color& c) {
if (mGfxPattern.GetPattern()->GetType() != PatternType::LINEAR_GRADIENT &&
mGfxPattern.GetPattern()->GetType() != PatternType::RADIAL_GRADIENT) {
mGfxPattern.GetPattern()->GetType() != PatternType::RADIAL_GRADIENT &&
mGfxPattern.GetPattern()->GetType() != PatternType::CONIC_GRADIENT) {
return;
}
@ -136,6 +143,13 @@ Pattern* gfxPattern::GetPattern(const DrawTarget* aTarget,
radialGradientPattern->mStops = mStops;
break;
}
case PatternType::CONIC_GRADIENT: {
ConicGradientPattern* conicGradientPattern =
static_cast<ConicGradientPattern*>(mGfxPattern.GetPattern());
conicGradientPattern->mMatrix = patternToUser;
conicGradientPattern->mStops = mStops;
break;
}
default:
/* Reassure the compiler we are handling all the enum values. */
break;

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

@ -22,10 +22,11 @@ class gfxPattern final {
public:
explicit gfxPattern(const mozilla::gfx::Color& aColor);
// linear
// gradients
gfxPattern(gfxFloat x0, gfxFloat y0, gfxFloat x1, gfxFloat y1); // linear
gfxPattern(gfxFloat cx0, gfxFloat cy0, gfxFloat radius0, gfxFloat cx1,
gfxFloat cy1, gfxFloat radius1); // radial
gfxFloat cy1, gfxFloat radius1); // radial
gfxPattern(gfxFloat cx, gfxFloat cy, gfxFloat angle); // conic
gfxPattern(mozilla::gfx::SourceSurface* aSurface,
const mozilla::gfx::Matrix& aPatternToUserSpace);

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

@ -951,8 +951,7 @@ void nsCSSGradientRenderer::Paint(gfxContext& aContext, const nsRect& aDest,
matrix.PreTranslate(-mLineStart);
}
} else {
// conic-gradient is only implemented for WebRender
return;
gradientPattern = new gfxPattern(mCenter.x, mCenter.y, mAngle);
}
// Use a pattern transform to take account of source and dest rects
matrix.PreTranslate(gfxPoint(mPresContext->CSSPixelsToDevPixels(aSrc.x),
@ -962,7 +961,7 @@ void nsCSSGradientRenderer::Paint(gfxContext& aContext, const nsRect& aDest,
gfxFloat(nsPresContext::CSSPixelsToAppUnits(aSrc.height)) / aDest.height);
gradientPattern->SetMatrix(matrix);
if (stopDelta == 0.0) {
if (!mGradient->IsConic() && stopDelta == 0.0) {
// Non-repeating gradient with all stops in same place -> just add
// first stop and last stop, both at position 0.
// Repeating gradient with all stops in the same place, or radial