1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "gfxPattern.h"
10 #include "gfxPlatform.h"
11 #include "gfx2DGlue.h"
12 #include "gfxGradientCache.h"
13 #include "mozilla/gfx/2D.h"
19 using namespace mozilla::gfx
;
21 gfxPattern::gfxPattern(const DeviceColor
& aColor
) : mExtend(ExtendMode::CLAMP
) {
22 mGfxPattern
.InitColorPattern(aColor
);
26 gfxPattern::gfxPattern(gfxFloat x0
, gfxFloat y0
, gfxFloat x1
, gfxFloat y1
)
27 : mExtend(ExtendMode::CLAMP
) {
28 mGfxPattern
.InitLinearGradientPattern(Point(x0
, y0
), Point(x1
, y1
), nullptr);
32 gfxPattern::gfxPattern(gfxFloat cx0
, gfxFloat cy0
, gfxFloat radius0
,
33 gfxFloat cx1
, gfxFloat cy1
, gfxFloat radius1
)
34 : mExtend(ExtendMode::CLAMP
) {
35 mGfxPattern
.InitRadialGradientPattern(Point(cx0
, cy0
), Point(cx1
, cy1
),
36 radius0
, radius1
, nullptr);
40 gfxPattern::gfxPattern(gfxFloat cx
, gfxFloat cy
, gfxFloat angle
,
41 gfxFloat startOffset
, gfxFloat endOffset
)
42 : mExtend(ExtendMode::CLAMP
) {
43 mGfxPattern
.InitConicGradientPattern(Point(cx
, cy
), angle
, startOffset
,
48 gfxPattern::gfxPattern(SourceSurface
* aSurface
,
49 const Matrix
& aPatternToUserSpace
)
50 : mPatternToUserSpace(aPatternToUserSpace
), mExtend(ExtendMode::CLAMP
) {
51 mGfxPattern
.InitSurfacePattern(
52 aSurface
, mExtend
, Matrix(), // matrix is overridden in GetPattern()
53 mozilla::gfx::SamplingFilter::GOOD
);
56 void gfxPattern::AddColorStop(gfxFloat offset
, const DeviceColor
& c
) {
57 if (mGfxPattern
.GetPattern()->GetType() != PatternType::LINEAR_GRADIENT
&&
58 mGfxPattern
.GetPattern()->GetType() != PatternType::RADIAL_GRADIENT
&&
59 mGfxPattern
.GetPattern()->GetType() != PatternType::CONIC_GRADIENT
) {
68 mStopsList
.AppendElement(stop
);
71 void gfxPattern::SetColorStops(GradientStops
* aStops
) { mStops
= aStops
; }
73 void gfxPattern::CacheColorStops(const DrawTarget
* aDT
) {
74 mStops
= gfxGradientCache::GetOrCreateGradientStops(aDT
, mStopsList
, mExtend
);
77 void gfxPattern::SetMatrix(const gfxMatrix
& aPatternToUserSpace
) {
78 mPatternToUserSpace
= ToMatrix(aPatternToUserSpace
);
79 // Cairo-pattern matrices specify the conversion from DrawTarget to pattern
80 // space. Azure pattern matrices specify the conversion from pattern to
82 mPatternToUserSpace
.Invert();
85 gfxMatrix
gfxPattern::GetMatrix() const {
86 // invert at the higher precision of gfxMatrix
87 // cause we need to convert at some point anyways
88 gfxMatrix mat
= ThebesMatrix(mPatternToUserSpace
);
93 gfxMatrix
gfxPattern::GetInverseMatrix() const {
94 return ThebesMatrix(mPatternToUserSpace
);
97 Pattern
* gfxPattern::GetPattern(const DrawTarget
* aTarget
,
98 const Matrix
* aOriginalUserToDevice
) {
99 Matrix patternToUser
= mPatternToUserSpace
;
101 if (aOriginalUserToDevice
&&
102 !aOriginalUserToDevice
->FuzzyEquals(aTarget
->GetTransform())) {
103 // mPatternToUserSpace maps from pattern space to the original user space,
104 // but aTarget now has a transform to a different user space. In order for
105 // the Pattern* that we return to be usable in aTarget's new user space we
106 // need the Pattern's mMatrix to be the transform from pattern space to
107 // aTarget's -new- user space. That transform is equivalent to the
108 // transform from pattern space to original user space (patternToUser),
109 // multiplied by the transform from original user space to device space,
110 // multiplied by the transform from device space to current user space.
112 Matrix deviceToCurrentUser
= aTarget
->GetTransform();
113 deviceToCurrentUser
.Invert();
116 patternToUser
* *aOriginalUserToDevice
* deviceToCurrentUser
;
118 patternToUser
.NudgeToIntegers();
120 if (!mStops
&& !mStopsList
.IsEmpty()) {
121 mStops
= aTarget
->CreateGradientStops(mStopsList
.Elements(),
122 mStopsList
.Length(), mExtend
);
125 switch (mGfxPattern
.GetPattern()->GetType()) {
126 case PatternType::SURFACE
: {
127 SurfacePattern
* surfacePattern
=
128 static_cast<SurfacePattern
*>(mGfxPattern
.GetPattern());
129 surfacePattern
->mMatrix
= patternToUser
;
130 surfacePattern
->mExtendMode
= mExtend
;
133 case PatternType::LINEAR_GRADIENT
: {
134 LinearGradientPattern
* linearGradientPattern
=
135 static_cast<LinearGradientPattern
*>(mGfxPattern
.GetPattern());
136 linearGradientPattern
->mMatrix
= patternToUser
;
137 linearGradientPattern
->mStops
= mStops
;
140 case PatternType::RADIAL_GRADIENT
: {
141 RadialGradientPattern
* radialGradientPattern
=
142 static_cast<RadialGradientPattern
*>(mGfxPattern
.GetPattern());
143 radialGradientPattern
->mMatrix
= patternToUser
;
144 radialGradientPattern
->mStops
= mStops
;
147 case PatternType::CONIC_GRADIENT
: {
148 ConicGradientPattern
* conicGradientPattern
=
149 static_cast<ConicGradientPattern
*>(mGfxPattern
.GetPattern());
150 conicGradientPattern
->mMatrix
= patternToUser
;
151 conicGradientPattern
->mStops
= mStops
;
155 /* Reassure the compiler we are handling all the enum values. */
159 return mGfxPattern
.GetPattern();
162 void gfxPattern::SetExtend(ExtendMode aExtend
) {
167 bool gfxPattern::IsOpaque() {
168 if (mGfxPattern
.GetPattern()->GetType() != PatternType::SURFACE
) {
172 if (static_cast<SurfacePattern
*>(mGfxPattern
.GetPattern())
173 ->mSurface
->GetFormat() == SurfaceFormat::B8G8R8X8
) {
179 void gfxPattern::SetSamplingFilter(mozilla::gfx::SamplingFilter filter
) {
180 if (mGfxPattern
.GetPattern()->GetType() != PatternType::SURFACE
) {
184 static_cast<SurfacePattern
*>(mGfxPattern
.GetPattern())->mSamplingFilter
=
188 SamplingFilter
gfxPattern::SamplingFilter() const {
189 if (mGfxPattern
.GetPattern()->GetType() != PatternType::SURFACE
) {
190 return mozilla::gfx::SamplingFilter::GOOD
;
192 return static_cast<const SurfacePattern
*>(mGfxPattern
.GetPattern())
196 bool gfxPattern::GetSolidColor(DeviceColor
& aColorOut
) {
197 if (mGfxPattern
.GetPattern()->GetType() == PatternType::COLOR
) {
198 aColorOut
= static_cast<ColorPattern
*>(mGfxPattern
.GetPattern())->mColor
;