Bug 1732219 - Add API for fetching the preview image. r=geckoview-reviewers,agi,mconley
[gecko.git] / gfx / thebes / gfxPattern.cpp
blob709776dbede6bddce2a760ea1773f131b786f772
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 "gfxPlatform.h"
11 #include "gfx2DGlue.h"
12 #include "gfxGradientCache.h"
13 #include "mozilla/gfx/2D.h"
15 #include "cairo.h"
17 #include <vector>
19 using namespace mozilla::gfx;
21 gfxPattern::gfxPattern(const DeviceColor& aColor) : mExtend(ExtendMode::CLAMP) {
22 mGfxPattern.InitColorPattern(aColor);
25 // linear
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);
31 // radial
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);
39 // conic
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,
44 endOffset, nullptr);
47 // Azure
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) {
60 return;
63 mStops = nullptr;
65 GradientStop stop;
66 stop.offset = offset;
67 stop.color = c;
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
81 // DrawTarget space.
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);
89 mat.Invert();
90 return mat;
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();
115 patternToUser =
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;
131 break;
133 case PatternType::LINEAR_GRADIENT: {
134 LinearGradientPattern* linearGradientPattern =
135 static_cast<LinearGradientPattern*>(mGfxPattern.GetPattern());
136 linearGradientPattern->mMatrix = patternToUser;
137 linearGradientPattern->mStops = mStops;
138 break;
140 case PatternType::RADIAL_GRADIENT: {
141 RadialGradientPattern* radialGradientPattern =
142 static_cast<RadialGradientPattern*>(mGfxPattern.GetPattern());
143 radialGradientPattern->mMatrix = patternToUser;
144 radialGradientPattern->mStops = mStops;
145 break;
147 case PatternType::CONIC_GRADIENT: {
148 ConicGradientPattern* conicGradientPattern =
149 static_cast<ConicGradientPattern*>(mGfxPattern.GetPattern());
150 conicGradientPattern->mMatrix = patternToUser;
151 conicGradientPattern->mStops = mStops;
152 break;
154 default:
155 /* Reassure the compiler we are handling all the enum values. */
156 break;
159 return mGfxPattern.GetPattern();
162 void gfxPattern::SetExtend(ExtendMode aExtend) {
163 mExtend = aExtend;
164 mStops = nullptr;
167 bool gfxPattern::IsOpaque() {
168 if (mGfxPattern.GetPattern()->GetType() != PatternType::SURFACE) {
169 return false;
172 if (static_cast<SurfacePattern*>(mGfxPattern.GetPattern())
173 ->mSurface->GetFormat() == SurfaceFormat::B8G8R8X8) {
174 return true;
176 return false;
179 void gfxPattern::SetSamplingFilter(mozilla::gfx::SamplingFilter filter) {
180 if (mGfxPattern.GetPattern()->GetType() != PatternType::SURFACE) {
181 return;
184 static_cast<SurfacePattern*>(mGfxPattern.GetPattern())->mSamplingFilter =
185 filter;
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())
193 ->mSamplingFilter;
196 bool gfxPattern::GetSolidColor(DeviceColor& aColorOut) {
197 if (mGfxPattern.GetPattern()->GetType() == PatternType::COLOR) {
198 aColorOut = static_cast<ColorPattern*>(mGfxPattern.GetPattern())->mColor;
199 return true;
202 return false;