1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef nsCSSRenderingGradients_h__
8 #define nsCSSRenderingGradients_h__
12 #include "nsStyleStruct.h"
14 #include "mozilla/Maybe.h"
15 #include "mozilla/gfx/2D.h"
16 #include "mozilla/webrender/webrender_ffi.h"
23 class StackingContextHelper
;
27 class DisplayListBuilder
;
30 // A resolved color stop, with a specific position along the gradient line and
33 ColorStop() : mPosition(0), mIsMidpoint(false) {}
34 ColorStop(double aPosition
, bool aIsMidPoint
,
35 const StyleAbsoluteColor
& aColor
)
36 : mPosition(aPosition
), mIsMidpoint(aIsMidPoint
), mColor(aColor
) {}
37 double mPosition
; // along the gradient line; 0=start, 1=end
39 StyleAbsoluteColor mColor
;
43 class MOZ_STACK_CLASS ColorStopInterpolator
{
45 ColorStopInterpolator(
46 const nsTArray
<ColorStop
>& aStops
,
47 const StyleColorInterpolationMethod
& aStyleColorInterpolationMethod
)
48 : mStyleColorInterpolationMethod(aStyleColorInterpolationMethod
),
52 for (uint32_t i
= 0; i
< mStops
.Length() - 1; i
++) {
53 const auto& start
= mStops
[i
];
54 const auto& end
= mStops
[i
+ 1];
56 (uint32_t)(floor(end
.mPosition
* kFullRangeExtraStops
) -
57 floor(start
.mPosition
* kFullRangeExtraStops
));
58 extraStops
= clamped(extraStops
, 1U, kFullRangeExtraStops
);
59 float step
= 1.0f
/ (float)extraStops
;
60 for (uint32_t extraStop
= 0; extraStop
<= extraStops
; extraStop
++) {
61 auto progress
= (float)extraStop
* step
;
63 start
.mPosition
+ progress
* (end
.mPosition
- start
.mPosition
);
64 StyleAbsoluteColor color
=
65 Servo_InterpolateColor(mStyleColorInterpolationMethod
, &end
.mColor
,
66 &start
.mColor
, progress
);
67 static_cast<T
*>(this)->CreateStop(float(position
),
68 gfx::ToDeviceColor(color
));
74 StyleColorInterpolationMethod mStyleColorInterpolationMethod
;
75 const nsTArray
<ColorStop
>& mStops
;
77 // this could be made tunable, but at 1.0/128 the error is largely
78 // irrelevant, as WebRender re-encodes it to 128 pairs of stops.
80 // note that we don't attempt to place the positions of these stops
81 // precisely at intervals, we just add this many extra stops across the
82 // range where it is convenient.
83 inline static const uint32_t kFullRangeExtraStops
= 128;
86 class nsCSSGradientRenderer final
{
89 * Prepare a nsCSSGradientRenderer for a gradient for an element.
90 * aIntrinsicSize - the size of the source gradient.
92 static nsCSSGradientRenderer
Create(nsPresContext
* aPresContext
,
93 ComputedStyle
* aComputedStyle
,
94 const StyleGradient
& aGradient
,
95 const nsSize
& aIntrinsiceSize
);
98 * Draw the gradient to aContext
99 * aDest - where the first tile of gradient is
100 * aFill - the area to be filled with tiles of aDest
101 * aSrc - the area of the gradient that will fill aDest
102 * aRepeatSize - the distance from the origin of a tile
103 * to the next origin of a tile
104 * aDirtyRect - pixels outside of this area may be skipped
106 void Paint(gfxContext
& aContext
, const nsRect
& aDest
, const nsRect
& aFill
,
107 const nsSize
& aRepeatSize
, const mozilla::CSSIntRect
& aSrc
,
108 const nsRect
& aDirtyRect
, float aOpacity
= 1.0);
111 * Collect the gradient parameters
113 void BuildWebRenderParameters(float aOpacity
, wr::ExtendMode
& aMode
,
114 nsTArray
<wr::GradientStop
>& aStops
,
115 LayoutDevicePoint
& aLineStart
,
116 LayoutDevicePoint
& aLineEnd
,
117 LayoutDeviceSize
& aGradientRadius
,
118 LayoutDevicePoint
& aGradientCenter
,
119 float& aGradientAngle
);
122 * Build display items for the gradient
123 * aLayer - the layer to make this display item relative to
124 * aDest - where the first tile of gradient is
125 * aFill - the area to be filled with tiles of aDest
126 * aRepeatSize - the distance from the origin of a tile
127 * to the next origin of a tile
128 * aSrc - the area of the gradient that will fill aDest
130 void BuildWebRenderDisplayItems(wr::DisplayListBuilder
& aBuilder
,
131 const layers::StackingContextHelper
& aSc
,
132 const nsRect
& aDest
, const nsRect
& aFill
,
133 const nsSize
& aRepeatSize
,
134 const mozilla::CSSIntRect
& aSrc
,
135 bool aIsBackfaceVisible
,
136 float aOpacity
= 1.0);
139 nsCSSGradientRenderer()
140 : mPresContext(nullptr),
147 * Attempts to paint the tiles for a gradient by painting it once to an
148 * offscreen surface and then painting that offscreen surface with
149 * ExtendMode::Repeat to cover all tiles.
151 * Returns false if the optimization wasn't able to be used, in which case
152 * a fallback should be used.
154 bool TryPaintTilesWithExtendMode(
155 gfxContext
& aContext
, gfxPattern
* aGradientPattern
, nscoord aXStart
,
156 nscoord aYStart
, const gfxRect
& aDirtyAreaToFill
, const nsRect
& aDest
,
157 const nsSize
& aRepeatSize
, bool aForceRepeatToCoverTiles
);
159 nsPresContext
* mPresContext
;
160 const StyleGradient
* mGradient
;
161 nsTArray
<ColorStop
> mStops
;
162 gfxPoint mLineStart
, mLineEnd
; // only for linear/radial gradients
163 double mRadiusX
, mRadiusY
; // only for radial gradients
164 gfxPoint mCenter
; // only for conic gradients
165 float mAngle
; // only for conic gradients
168 } // namespace mozilla
170 #endif /* nsCSSRenderingGradients_h__ */