summaryrefslogtreecommitdiffstats
path: root/gfx/2d/PatternHelpers.h
blob: 09b4cd4d935752ea03dc892918fdbe58f4af8ecb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */

#ifndef _MOZILLA_GFX_PATTERNHELPERS_H
#define _MOZILLA_GFX_PATTERNHELPERS_H

#include "mozilla/Alignment.h"
#include "mozilla/gfx/2D.h"

namespace mozilla {
namespace gfx {

/**
 * This class is used to allow general pattern creation functions to return
 * any type of pattern via an out-paramater without allocating a pattern
 * instance on the free-store (an instance of this class being created on the
 * stack before passing it in to the creation function). Without this class
 * writing pattern creation functions would be a pain since Pattern objects are
 * not reference counted, making lifetime management of instances created on
 * the free-store and returned from a creation function hazardous. Besides
 * that, in the case that ColorPattern's are expected to be common, it is
 * particularly desirable to avoid the overhead of allocating on the
 * free-store.
 */
class GeneralPattern final {
 public:
  explicit GeneralPattern() = default;

  GeneralPattern(const GeneralPattern& aOther) {}

  ~GeneralPattern() {
    if (mPattern) {
      mPattern->~Pattern();
    }
  }

  Pattern* Init(const Pattern& aPattern) {
    MOZ_ASSERT(!mPattern);
    switch (aPattern.GetType()) {
      case PatternType::COLOR:
        mPattern = new (mColorPattern.addr())
            ColorPattern(static_cast<const ColorPattern&>(aPattern));
        break;
      case PatternType::LINEAR_GRADIENT:
        mPattern = new (mLinearGradientPattern.addr()) LinearGradientPattern(
            static_cast<const LinearGradientPattern&>(aPattern));
        break;
      case PatternType::RADIAL_GRADIENT:
        mPattern = new (mRadialGradientPattern.addr()) RadialGradientPattern(
            static_cast<const RadialGradientPattern&>(aPattern));
        break;
      case PatternType::CONIC_GRADIENT:
        mPattern = new (mConicGradientPattern.addr()) ConicGradientPattern(
            static_cast<const ConicGradientPattern&>(aPattern));
        break;
      case PatternType::SURFACE:
        mPattern = new (mSurfacePattern.addr())
            SurfacePattern(static_cast<const SurfacePattern&>(aPattern));
        break;
      default:
        MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unknown pattern type");
    }
    return mPattern;
  }

  ColorPattern* InitColorPattern(const DeviceColor& aColor) {
    MOZ_ASSERT(!mPattern);
    mPattern = new (mColorPattern.addr()) ColorPattern(aColor);
    return mColorPattern.addr();
  }

  LinearGradientPattern* InitLinearGradientPattern(
      const Point& aBegin, const Point& aEnd,
      already_AddRefed<GradientStops> aStops,
      const Matrix& aMatrix = Matrix()) {
    MOZ_ASSERT(!mPattern);
    mPattern = new (mLinearGradientPattern.addr())
        LinearGradientPattern(aBegin, aEnd, std::move(aStops), aMatrix);
    return mLinearGradientPattern.addr();
  }

  RadialGradientPattern* InitRadialGradientPattern(
      const Point& aCenter1, const Point& aCenter2, Float aRadius1,
      Float aRadius2, already_AddRefed<GradientStops> aStops,
      const Matrix& aMatrix = Matrix()) {
    MOZ_ASSERT(!mPattern);
    mPattern = new (mRadialGradientPattern.addr()) RadialGradientPattern(
        aCenter1, aCenter2, aRadius1, aRadius2, std::move(aStops), aMatrix);
    return mRadialGradientPattern.addr();
  }

  ConicGradientPattern* InitConicGradientPattern(
      const Point& aCenter, Float aAngle, Float aStartOffset, Float aEndOffset,
      already_AddRefed<GradientStops> aStops,
      const Matrix& aMatrix = Matrix()) {
    MOZ_ASSERT(!mPattern);
    mPattern = new (mConicGradientPattern.addr()) ConicGradientPattern(
        aCenter, aAngle, aStartOffset, aEndOffset, std::move(aStops), aMatrix);
    return mConicGradientPattern.addr();
  }

  SurfacePattern* InitSurfacePattern(
      SourceSurface* aSourceSurface, ExtendMode aExtendMode,
      const Matrix& aMatrix = Matrix(),
      SamplingFilter aSamplingFilter = SamplingFilter::GOOD,
      const IntRect& aSamplingRect = IntRect()) {
    MOZ_ASSERT(!mPattern);
    mPattern = new (mSurfacePattern.addr()) SurfacePattern(
        aSourceSurface, aExtendMode, aMatrix, aSamplingFilter, aSamplingRect);
    return mSurfacePattern.addr();
  }

  Pattern* GetPattern() { return mPattern; }

  const Pattern* GetPattern() const { return mPattern; }

  operator Pattern&() {
    if (!mPattern) {
      MOZ_CRASH("GFX: GeneralPattern not initialized");
    }
    return *mPattern;
  }

 private:
  union {
    AlignedStorage2<ColorPattern> mColorPattern;
    AlignedStorage2<LinearGradientPattern> mLinearGradientPattern;
    AlignedStorage2<RadialGradientPattern> mRadialGradientPattern;
    AlignedStorage2<ConicGradientPattern> mConicGradientPattern;
    AlignedStorage2<SurfacePattern> mSurfacePattern;
  };
  Pattern* mPattern = nullptr;
};

}  // namespace gfx
}  // namespace mozilla

#endif  //  _MOZILLA_GFX_PATTERNHELPERS_H