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 "gfxASurface.h"
11 #include "gfxPlatform.h"
12 #include "gfx2DGlue.h"
13 #include "gfxGradientCache.h"
14 #include "mozilla/gfx/2D.h"
20 using namespace mozilla::gfx
;
22 gfxPattern::gfxPattern(const Color
& aColor
)
23 : mExtend(ExtendMode::CLAMP
)
25 mGfxPattern
.InitColorPattern(ToDeviceColor(aColor
));
29 gfxPattern::gfxPattern(gfxFloat x0
, gfxFloat y0
, gfxFloat x1
, gfxFloat y1
)
30 : mExtend(ExtendMode::CLAMP
)
32 mGfxPattern
.InitLinearGradientPattern(Point(x0
, y0
), Point(x1
, y1
), nullptr);
36 gfxPattern::gfxPattern(gfxFloat cx0
, gfxFloat cy0
, gfxFloat radius0
,
37 gfxFloat cx1
, gfxFloat cy1
, gfxFloat radius1
)
38 : mExtend(ExtendMode::CLAMP
)
40 mGfxPattern
.InitRadialGradientPattern(Point(cx0
, cy0
), Point(cx1
, cy1
),
41 radius0
, radius1
, nullptr);
45 gfxPattern::gfxPattern(SourceSurface
*aSurface
, const Matrix
&aPatternToUserSpace
)
46 : mPatternToUserSpace(aPatternToUserSpace
)
47 , mExtend(ExtendMode::CLAMP
)
49 mGfxPattern
.InitSurfacePattern(aSurface
, mExtend
, Matrix(), // matrix is overridden in GetPattern()
50 mozilla::gfx::SamplingFilter::GOOD
);
54 gfxPattern::AddColorStop(gfxFloat offset
, const Color
& c
)
56 if (mGfxPattern
.GetPattern()->GetType() != PatternType::LINEAR_GRADIENT
&&
57 mGfxPattern
.GetPattern()->GetType() != PatternType::RADIAL_GRADIENT
) {
65 stop
.color
= ToDeviceColor(c
);
66 mStopsList
.AppendElement(stop
);
70 gfxPattern::SetColorStops(GradientStops
* aStops
)
76 gfxPattern::CacheColorStops(const DrawTarget
*aDT
)
78 mStops
= gfxGradientCache::GetOrCreateGradientStops(aDT
, mStopsList
, mExtend
);
82 gfxPattern::SetMatrix(const gfxMatrix
& aPatternToUserSpace
)
84 mPatternToUserSpace
= ToMatrix(aPatternToUserSpace
);
85 // Cairo-pattern matrices specify the conversion from DrawTarget to pattern
86 // space. Azure pattern matrices specify the conversion from pattern to
88 mPatternToUserSpace
.Invert();
92 gfxPattern::GetMatrix() const
94 // invert at the higher precision of gfxMatrix
95 // cause we need to convert at some point anyways
96 gfxMatrix mat
= ThebesMatrix(mPatternToUserSpace
);
102 gfxPattern::GetInverseMatrix() const
104 return ThebesMatrix(mPatternToUserSpace
);
108 gfxPattern::GetPattern(const DrawTarget
*aTarget
,
109 const Matrix
*aOriginalUserToDevice
)
111 Matrix patternToUser
= mPatternToUserSpace
;
113 if (aOriginalUserToDevice
&&
114 !aOriginalUserToDevice
->FuzzyEquals(aTarget
->GetTransform())) {
115 // mPatternToUserSpace maps from pattern space to the original user space,
116 // but aTarget now has a transform to a different user space. In order for
117 // the Pattern* that we return to be usable in aTarget's new user space we
118 // need the Pattern's mMatrix to be the transform from pattern space to
119 // aTarget's -new- user space. That transform is equivalent to the
120 // transform from pattern space to original user space (patternToUser),
121 // multiplied by the transform from original user space to device space,
122 // multiplied by the transform from device space to current user space.
124 Matrix deviceToCurrentUser
= aTarget
->GetTransform();
125 deviceToCurrentUser
.Invert();
127 patternToUser
= patternToUser
* *aOriginalUserToDevice
* deviceToCurrentUser
;
129 patternToUser
.NudgeToIntegers();
132 !mStopsList
.IsEmpty()) {
133 mStops
= aTarget
->CreateGradientStops(mStopsList
.Elements(),
134 mStopsList
.Length(), mExtend
);
137 switch (mGfxPattern
.GetPattern()->GetType()) {
138 case PatternType::SURFACE
: {
139 SurfacePattern
* surfacePattern
= static_cast<SurfacePattern
*>(mGfxPattern
.GetPattern());
140 surfacePattern
->mMatrix
= patternToUser
;
141 surfacePattern
->mExtendMode
= mExtend
;
144 case PatternType::LINEAR_GRADIENT
: {
145 LinearGradientPattern
* linearGradientPattern
= static_cast<LinearGradientPattern
*>(mGfxPattern
.GetPattern());
146 linearGradientPattern
->mMatrix
= patternToUser
;
147 linearGradientPattern
->mStops
= mStops
;
150 case PatternType::RADIAL_GRADIENT
: {
151 RadialGradientPattern
* radialGradientPattern
= static_cast<RadialGradientPattern
*>(mGfxPattern
.GetPattern());
152 radialGradientPattern
->mMatrix
= patternToUser
;
153 radialGradientPattern
->mStops
= mStops
;
157 /* Reassure the compiler we are handling all the enum values. */
161 return mGfxPattern
.GetPattern();
165 gfxPattern::SetExtend(ExtendMode aExtend
)
172 gfxPattern::IsOpaque()
174 if (mGfxPattern
.GetPattern()->GetType() != PatternType::SURFACE
) {
178 if (static_cast<SurfacePattern
*>(mGfxPattern
.GetPattern())->mSurface
->GetFormat() == SurfaceFormat::B8G8R8X8
) {
185 gfxPattern::SetSamplingFilter(gfx::SamplingFilter filter
)
187 if (mGfxPattern
.GetPattern()->GetType() != PatternType::SURFACE
) {
191 static_cast<SurfacePattern
*>(mGfxPattern
.GetPattern())->mSamplingFilter
= filter
;
195 gfxPattern::SamplingFilter() const
197 if (mGfxPattern
.GetPattern()->GetType() != PatternType::SURFACE
) {
198 return gfx::SamplingFilter::GOOD
;
200 return static_cast<const SurfacePattern
*>(mGfxPattern
.GetPattern())->mSamplingFilter
;
204 gfxPattern::GetSolidColor(Color
& aColorOut
)
206 if (mGfxPattern
.GetPattern()->GetType() == PatternType::COLOR
) {
207 aColorOut
= static_cast<ColorPattern
*>(mGfxPattern
.GetPattern())->mColor
;