Bug 1444940 [wpt PR 9917] - Writable streams: test changes to abort() under error...
[gecko.git] / gfx / thebes / gfxPattern.cpp
blob429645f402e46ec574cc80684748938a0d2e793c
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"
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"
16 #include "cairo.h"
18 #include <vector>
20 using namespace mozilla::gfx;
22 gfxPattern::gfxPattern(const Color& aColor)
23 : mExtend(ExtendMode::CLAMP)
25 mGfxPattern.InitColorPattern(ToDeviceColor(aColor));
28 // linear
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);
35 // radial
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);
44 // Azure
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);
53 void
54 gfxPattern::AddColorStop(gfxFloat offset, const Color& c)
56 if (mGfxPattern.GetPattern()->GetType() != PatternType::LINEAR_GRADIENT &&
57 mGfxPattern.GetPattern()->GetType() != PatternType::RADIAL_GRADIENT) {
58 return;
61 mStops = nullptr;
63 GradientStop stop;
64 stop.offset = offset;
65 stop.color = ToDeviceColor(c);
66 mStopsList.AppendElement(stop);
69 void
70 gfxPattern::SetColorStops(GradientStops* aStops)
72 mStops = aStops;
75 void
76 gfxPattern::CacheColorStops(const DrawTarget *aDT)
78 mStops = gfxGradientCache::GetOrCreateGradientStops(aDT, mStopsList, mExtend);
81 void
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
87 // DrawTarget space.
88 mPatternToUserSpace.Invert();
91 gfxMatrix
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);
97 mat.Invert();
98 return mat;
101 gfxMatrix
102 gfxPattern::GetInverseMatrix() const
104 return ThebesMatrix(mPatternToUserSpace);
107 Pattern*
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();
131 if (!mStops &&
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;
142 break;
144 case PatternType::LINEAR_GRADIENT: {
145 LinearGradientPattern* linearGradientPattern = static_cast<LinearGradientPattern*>(mGfxPattern.GetPattern());
146 linearGradientPattern->mMatrix = patternToUser;
147 linearGradientPattern->mStops = mStops;
148 break;
150 case PatternType::RADIAL_GRADIENT: {
151 RadialGradientPattern* radialGradientPattern = static_cast<RadialGradientPattern*>(mGfxPattern.GetPattern());
152 radialGradientPattern->mMatrix = patternToUser;
153 radialGradientPattern->mStops = mStops;
154 break;
156 default:
157 /* Reassure the compiler we are handling all the enum values. */
158 break;
161 return mGfxPattern.GetPattern();
164 void
165 gfxPattern::SetExtend(ExtendMode aExtend)
167 mExtend = aExtend;
168 mStops = nullptr;
171 bool
172 gfxPattern::IsOpaque()
174 if (mGfxPattern.GetPattern()->GetType() != PatternType::SURFACE) {
175 return false;
178 if (static_cast<SurfacePattern*>(mGfxPattern.GetPattern())->mSurface->GetFormat() == SurfaceFormat::B8G8R8X8) {
179 return true;
181 return false;
184 void
185 gfxPattern::SetSamplingFilter(gfx::SamplingFilter filter)
187 if (mGfxPattern.GetPattern()->GetType() != PatternType::SURFACE) {
188 return;
191 static_cast<SurfacePattern*>(mGfxPattern.GetPattern())->mSamplingFilter = filter;
194 SamplingFilter
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;
203 bool
204 gfxPattern::GetSolidColor(Color& aColorOut)
206 if (mGfxPattern.GetPattern()->GetType() == PatternType::COLOR) {
207 aColorOut = static_cast<ColorPattern*>(mGfxPattern.GetPattern())->mColor;
208 return true;
211 return false;