diff options
Diffstat (limited to 'gfx/thebes/gfxPattern.cpp')
-rw-r--r-- | gfx/thebes/gfxPattern.cpp | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/gfx/thebes/gfxPattern.cpp b/gfx/thebes/gfxPattern.cpp new file mode 100644 index 000000000..d937b992f --- /dev/null +++ b/gfx/thebes/gfxPattern.cpp @@ -0,0 +1,218 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gfxPattern.h" + +#include "gfxUtils.h" +#include "gfxTypes.h" +#include "gfxASurface.h" +#include "gfxPlatform.h" +#include "gfx2DGlue.h" +#include "gfxGradientCache.h" +#include "mozilla/gfx/2D.h" + +#include "cairo.h" + +#include <vector> + +using namespace mozilla::gfx; + +gfxPattern::gfxPattern(const Color& aColor) + : mExtend(ExtendMode::CLAMP) +{ + mGfxPattern.InitColorPattern(ToDeviceColor(aColor)); +} + +// linear +gfxPattern::gfxPattern(gfxFloat x0, gfxFloat y0, gfxFloat x1, gfxFloat y1) + : mExtend(ExtendMode::CLAMP) +{ + mGfxPattern.InitLinearGradientPattern(Point(x0, y0), Point(x1, y1), nullptr); +} + +// radial +gfxPattern::gfxPattern(gfxFloat cx0, gfxFloat cy0, gfxFloat radius0, + gfxFloat cx1, gfxFloat cy1, gfxFloat radius1) + : mExtend(ExtendMode::CLAMP) +{ + mGfxPattern.InitRadialGradientPattern(Point(cx0, cy0), Point(cx1, cy1), + radius0, radius1, nullptr); +} + +// Azure +gfxPattern::gfxPattern(SourceSurface *aSurface, const Matrix &aPatternToUserSpace) + : mPatternToUserSpace(aPatternToUserSpace) + , mExtend(ExtendMode::CLAMP) +{ + mGfxPattern.InitSurfacePattern(aSurface, mExtend, Matrix(), // matrix is overridden in GetPattern() + mozilla::gfx::SamplingFilter::GOOD); +} + +void +gfxPattern::AddColorStop(gfxFloat offset, const Color& c) +{ + if (mGfxPattern.GetPattern()->GetType() != PatternType::LINEAR_GRADIENT && + mGfxPattern.GetPattern()->GetType() != PatternType::RADIAL_GRADIENT) { + return; + } + + mStops = nullptr; + + GradientStop stop; + stop.offset = offset; + stop.color = ToDeviceColor(c); + mStopsList.AppendElement(stop); +} + +void +gfxPattern::SetColorStops(GradientStops* aStops) +{ + mStops = aStops; +} + +void +gfxPattern::CacheColorStops(const DrawTarget *aDT) +{ + mStops = gfxGradientCache::GetOrCreateGradientStops(aDT, mStopsList, mExtend); +} + +void +gfxPattern::SetMatrix(const gfxMatrix& aPatternToUserSpace) +{ + mPatternToUserSpace = ToMatrix(aPatternToUserSpace); + // Cairo-pattern matrices specify the conversion from DrawTarget to pattern + // space. Azure pattern matrices specify the conversion from pattern to + // DrawTarget space. + mPatternToUserSpace.Invert(); +} + +gfxMatrix +gfxPattern::GetMatrix() const +{ + // invert at the higher precision of gfxMatrix + // cause we need to convert at some point anyways + gfxMatrix mat = ThebesMatrix(mPatternToUserSpace); + mat.Invert(); + return mat; +} + +gfxMatrix +gfxPattern::GetInverseMatrix() const +{ + return ThebesMatrix(mPatternToUserSpace); +} + +Pattern* +gfxPattern::GetPattern(const DrawTarget *aTarget, + Matrix *aOriginalUserToDevice) +{ + Matrix patternToUser = mPatternToUserSpace; + + if (aOriginalUserToDevice && + *aOriginalUserToDevice != aTarget->GetTransform()) { + // mPatternToUserSpace maps from pattern space to the original user space, + // but aTarget now has a transform to a different user space. In order for + // the Pattern* that we return to be usable in aTarget's new user space we + // need the Pattern's mMatrix to be the transform from pattern space to + // aTarget's -new- user space. That transform is equivalent to the + // transform from pattern space to original user space (patternToUser), + // multiplied by the transform from original user space to device space, + // multiplied by the transform from device space to current user space. + + Matrix deviceToCurrentUser = aTarget->GetTransform(); + deviceToCurrentUser.Invert(); + + patternToUser = patternToUser * *aOriginalUserToDevice * deviceToCurrentUser; + } + patternToUser.NudgeToIntegers(); + + if (!mStops && + !mStopsList.IsEmpty()) { + mStops = aTarget->CreateGradientStops(mStopsList.Elements(), + mStopsList.Length(), mExtend); + } + + switch (mGfxPattern.GetPattern()->GetType()) { + case PatternType::SURFACE: { + SurfacePattern* surfacePattern = static_cast<SurfacePattern*>(mGfxPattern.GetPattern()); + surfacePattern->mMatrix = patternToUser; + surfacePattern->mExtendMode = mExtend; + break; + } + case PatternType::LINEAR_GRADIENT: { + LinearGradientPattern* linearGradientPattern = static_cast<LinearGradientPattern*>(mGfxPattern.GetPattern()); + linearGradientPattern->mMatrix = patternToUser; + linearGradientPattern->mStops = mStops; + break; + } + case PatternType::RADIAL_GRADIENT: { + RadialGradientPattern* radialGradientPattern = static_cast<RadialGradientPattern*>(mGfxPattern.GetPattern()); + radialGradientPattern->mMatrix = patternToUser; + radialGradientPattern->mStops = mStops; + break; + } + default: + /* Reassure the compiler we are handling all the enum values. */ + break; + } + + return mGfxPattern.GetPattern(); +} + +void +gfxPattern::SetExtend(ExtendMode aExtend) +{ + mExtend = aExtend; + mStops = nullptr; +} + +bool +gfxPattern::IsOpaque() +{ + if (mGfxPattern.GetPattern()->GetType() != PatternType::SURFACE) { + return false; + } + + if (static_cast<SurfacePattern*>(mGfxPattern.GetPattern())->mSurface->GetFormat() == SurfaceFormat::B8G8R8X8) { + return true; + } + return false; +} + +void +gfxPattern::SetSamplingFilter(gfx::SamplingFilter filter) +{ + if (mGfxPattern.GetPattern()->GetType() != PatternType::SURFACE) { + return; + } + + static_cast<SurfacePattern*>(mGfxPattern.GetPattern())->mSamplingFilter = filter; +} + +SamplingFilter +gfxPattern::SamplingFilter() const +{ + if (mGfxPattern.GetPattern()->GetType() != PatternType::SURFACE) { + return gfx::SamplingFilter::GOOD; + } + return static_cast<const SurfacePattern*>(mGfxPattern.GetPattern())->mSamplingFilter; +} + +bool +gfxPattern::GetSolidColor(Color& aColorOut) +{ + if (mGfxPattern.GetPattern()->GetType() == PatternType::COLOR) { + aColorOut = static_cast<ColorPattern*>(mGfxPattern.GetPattern())->mColor; + return true; + } + + return false; +} + +int +gfxPattern::CairoStatus() +{ + return CAIRO_STATUS_SUCCESS; +} |