summaryrefslogtreecommitdiffstats
path: root/gfx/thebes/gfxPattern.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/thebes/gfxPattern.cpp')
-rw-r--r--gfx/thebes/gfxPattern.cpp204
1 files changed, 204 insertions, 0 deletions
diff --git a/gfx/thebes/gfxPattern.cpp b/gfx/thebes/gfxPattern.cpp
new file mode 100644
index 0000000000..5f063fc484
--- /dev/null
+++ b/gfx/thebes/gfxPattern.cpp
@@ -0,0 +1,204 @@
+/* -*- 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 DeviceColor& aColor) : mExtend(ExtendMode::CLAMP) {
+ mGfxPattern.InitColorPattern(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);
+}
+
+// conic
+gfxPattern::gfxPattern(gfxFloat cx, gfxFloat cy, gfxFloat angle,
+ gfxFloat startOffset, gfxFloat endOffset)
+ : mExtend(ExtendMode::CLAMP) {
+ mGfxPattern.InitConicGradientPattern(Point(cx, cy), angle, startOffset,
+ endOffset, 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 DeviceColor& c) {
+ if (mGfxPattern.GetPattern()->GetType() != PatternType::LINEAR_GRADIENT &&
+ mGfxPattern.GetPattern()->GetType() != PatternType::RADIAL_GRADIENT &&
+ mGfxPattern.GetPattern()->GetType() != PatternType::CONIC_GRADIENT) {
+ return;
+ }
+
+ mStops = nullptr;
+
+ GradientStop stop;
+ stop.offset = offset;
+ stop.color = 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,
+ const Matrix* aOriginalUserToDevice) {
+ Matrix patternToUser = mPatternToUserSpace;
+
+ if (aOriginalUserToDevice &&
+ !aOriginalUserToDevice->FuzzyEquals(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;
+ }
+ case PatternType::CONIC_GRADIENT: {
+ ConicGradientPattern* conicGradientPattern =
+ static_cast<ConicGradientPattern*>(mGfxPattern.GetPattern());
+ conicGradientPattern->mMatrix = patternToUser;
+ conicGradientPattern->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(mozilla::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 mozilla::gfx::SamplingFilter::GOOD;
+ }
+ return static_cast<const SurfacePattern*>(mGfxPattern.GetPattern())
+ ->mSamplingFilter;
+}
+
+bool gfxPattern::GetSolidColor(DeviceColor& aColorOut) {
+ if (mGfxPattern.GetPattern()->GetType() == PatternType::COLOR) {
+ aColorOut = static_cast<ColorPattern*>(mGfxPattern.GetPattern())->mColor;
+ return true;
+ }
+
+ return false;
+}