Line data Source code
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/. */
5 :
6 : #include "gfxPattern.h"
7 :
8 : #include "gfxUtils.h"
9 : #include "gfxTypes.h"
10 : #include "gfxASurface.h"
11 : #include "gfxPlatform.h"
12 : #include "gfx2DGlue.h"
13 : #include "gfxGradientCache.h"
14 : #include "mozilla/gfx/2D.h"
15 :
16 : #include "cairo.h"
17 :
18 : #include <vector>
19 :
20 : using namespace mozilla::gfx;
21 :
22 14 : gfxPattern::gfxPattern(const Color& aColor)
23 14 : : mExtend(ExtendMode::CLAMP)
24 : {
25 14 : mGfxPattern.InitColorPattern(ToDeviceColor(aColor));
26 14 : }
27 :
28 : // linear
29 26 : gfxPattern::gfxPattern(gfxFloat x0, gfxFloat y0, gfxFloat x1, gfxFloat y1)
30 26 : : mExtend(ExtendMode::CLAMP)
31 : {
32 26 : mGfxPattern.InitLinearGradientPattern(Point(x0, y0), Point(x1, y1), nullptr);
33 26 : }
34 :
35 : // radial
36 0 : gfxPattern::gfxPattern(gfxFloat cx0, gfxFloat cy0, gfxFloat radius0,
37 0 : gfxFloat cx1, gfxFloat cy1, gfxFloat radius1)
38 0 : : mExtend(ExtendMode::CLAMP)
39 : {
40 0 : mGfxPattern.InitRadialGradientPattern(Point(cx0, cy0), Point(cx1, cy1),
41 0 : radius0, radius1, nullptr);
42 0 : }
43 :
44 : // Azure
45 0 : gfxPattern::gfxPattern(SourceSurface *aSurface, const Matrix &aPatternToUserSpace)
46 : : mPatternToUserSpace(aPatternToUserSpace)
47 0 : , mExtend(ExtendMode::CLAMP)
48 : {
49 0 : mGfxPattern.InitSurfacePattern(aSurface, mExtend, Matrix(), // matrix is overridden in GetPattern()
50 0 : mozilla::gfx::SamplingFilter::GOOD);
51 0 : }
52 :
53 : void
54 0 : gfxPattern::AddColorStop(gfxFloat offset, const Color& c)
55 : {
56 0 : if (mGfxPattern.GetPattern()->GetType() != PatternType::LINEAR_GRADIENT &&
57 0 : mGfxPattern.GetPattern()->GetType() != PatternType::RADIAL_GRADIENT) {
58 0 : return;
59 : }
60 :
61 0 : mStops = nullptr;
62 :
63 0 : GradientStop stop;
64 0 : stop.offset = offset;
65 0 : stop.color = ToDeviceColor(c);
66 0 : mStopsList.AppendElement(stop);
67 : }
68 :
69 : void
70 26 : gfxPattern::SetColorStops(GradientStops* aStops)
71 : {
72 26 : mStops = aStops;
73 26 : }
74 :
75 : void
76 0 : gfxPattern::CacheColorStops(const DrawTarget *aDT)
77 : {
78 0 : mStops = gfxGradientCache::GetOrCreateGradientStops(aDT, mStopsList, mExtend);
79 0 : }
80 :
81 : void
82 26 : gfxPattern::SetMatrix(const gfxMatrix& aPatternToUserSpace)
83 : {
84 26 : 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
87 : // DrawTarget space.
88 26 : mPatternToUserSpace.Invert();
89 26 : }
90 :
91 : gfxMatrix
92 0 : gfxPattern::GetMatrix() const
93 : {
94 : // invert at the higher precision of gfxMatrix
95 : // cause we need to convert at some point anyways
96 0 : gfxMatrix mat = ThebesMatrix(mPatternToUserSpace);
97 0 : mat.Invert();
98 0 : return mat;
99 : }
100 :
101 : gfxMatrix
102 0 : gfxPattern::GetInverseMatrix() const
103 : {
104 0 : return ThebesMatrix(mPatternToUserSpace);
105 : }
106 :
107 : Pattern*
108 39 : gfxPattern::GetPattern(const DrawTarget *aTarget,
109 : const Matrix *aOriginalUserToDevice)
110 : {
111 39 : Matrix patternToUser = mPatternToUserSpace;
112 :
113 117 : if (aOriginalUserToDevice &&
114 39 : *aOriginalUserToDevice != 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.
123 :
124 0 : Matrix deviceToCurrentUser = aTarget->GetTransform();
125 0 : deviceToCurrentUser.Invert();
126 :
127 0 : patternToUser = patternToUser * *aOriginalUserToDevice * deviceToCurrentUser;
128 : }
129 39 : patternToUser.NudgeToIntegers();
130 :
131 53 : if (!mStops &&
132 14 : !mStopsList.IsEmpty()) {
133 0 : mStops = aTarget->CreateGradientStops(mStopsList.Elements(),
134 0 : mStopsList.Length(), mExtend);
135 : }
136 :
137 39 : switch (mGfxPattern.GetPattern()->GetType()) {
138 : case PatternType::SURFACE: {
139 0 : SurfacePattern* surfacePattern = static_cast<SurfacePattern*>(mGfxPattern.GetPattern());
140 0 : surfacePattern->mMatrix = patternToUser;
141 0 : surfacePattern->mExtendMode = mExtend;
142 0 : break;
143 : }
144 : case PatternType::LINEAR_GRADIENT: {
145 25 : LinearGradientPattern* linearGradientPattern = static_cast<LinearGradientPattern*>(mGfxPattern.GetPattern());
146 25 : linearGradientPattern->mMatrix = patternToUser;
147 25 : linearGradientPattern->mStops = mStops;
148 25 : break;
149 : }
150 : case PatternType::RADIAL_GRADIENT: {
151 0 : RadialGradientPattern* radialGradientPattern = static_cast<RadialGradientPattern*>(mGfxPattern.GetPattern());
152 0 : radialGradientPattern->mMatrix = patternToUser;
153 0 : radialGradientPattern->mStops = mStops;
154 0 : break;
155 : }
156 : default:
157 : /* Reassure the compiler we are handling all the enum values. */
158 14 : break;
159 : }
160 :
161 39 : return mGfxPattern.GetPattern();
162 : }
163 :
164 : void
165 0 : gfxPattern::SetExtend(ExtendMode aExtend)
166 : {
167 0 : mExtend = aExtend;
168 0 : mStops = nullptr;
169 0 : }
170 :
171 : bool
172 0 : gfxPattern::IsOpaque()
173 : {
174 0 : if (mGfxPattern.GetPattern()->GetType() != PatternType::SURFACE) {
175 0 : return false;
176 : }
177 :
178 0 : if (static_cast<SurfacePattern*>(mGfxPattern.GetPattern())->mSurface->GetFormat() == SurfaceFormat::B8G8R8X8) {
179 0 : return true;
180 : }
181 0 : return false;
182 : }
183 :
184 : void
185 0 : gfxPattern::SetSamplingFilter(gfx::SamplingFilter filter)
186 : {
187 0 : if (mGfxPattern.GetPattern()->GetType() != PatternType::SURFACE) {
188 0 : return;
189 : }
190 :
191 0 : static_cast<SurfacePattern*>(mGfxPattern.GetPattern())->mSamplingFilter = filter;
192 : }
193 :
194 : SamplingFilter
195 0 : gfxPattern::SamplingFilter() const
196 : {
197 0 : if (mGfxPattern.GetPattern()->GetType() != PatternType::SURFACE) {
198 0 : return gfx::SamplingFilter::GOOD;
199 : }
200 0 : return static_cast<const SurfacePattern*>(mGfxPattern.GetPattern())->mSamplingFilter;
201 : }
202 :
203 : bool
204 0 : gfxPattern::GetSolidColor(Color& aColorOut)
205 : {
206 0 : if (mGfxPattern.GetPattern()->GetType() == PatternType::COLOR) {
207 0 : aColorOut = static_cast<ColorPattern*>(mGfxPattern.GetPattern())->mColor;
208 0 : return true;
209 : }
210 :
211 0 : return false;
212 : }
|