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