Skip to main content

webrender/prim_store/gradient/
conic.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5//! Conic gradients
6//!
7//! Specification: https://drafts.csswg.org/css-images-4/#conic-gradients
8//!
9//! Conic gradients are rendered via cached render tasks and composited with the image brush.
10
11use api::{ExtendMode, GradientStop};
12use api::units::*;
13use crate::pattern::gradient::{conic_gradient_pattern};
14use crate::pattern::{Pattern, PatternBuilder, PatternBuilderContext, PatternBuilderState};
15use crate::scene_building::IsVisible;
16use crate::intern::{Internable, InternDebug, Handle as InternHandle};
17use crate::internal_types::LayoutPrimitiveInfo;
18use crate::prim_store::{PrimitiveKind, PrimitiveOpacity};
19use crate::prim_store::{PrimKeyCommonData, PrimTemplateCommonData, PrimitiveStore};
20use crate::prim_store::{NinePatchDescriptor, PointKey, SizeKey, InternablePrimitive};
21
22use std::{hash, ops::{Deref, DerefMut}};
23use super::{stops_and_min_alpha, GradientStopKey};
24
25/// Hashable conic gradient parameters, for use during prim interning.
26#[cfg_attr(feature = "capture", derive(Serialize))]
27#[cfg_attr(feature = "replay", derive(Deserialize))]
28#[derive(Debug, Clone, MallocSizeOf, PartialEq)]
29pub struct ConicGradientParams {
30    pub angle: f32, // in radians
31    pub start_offset: f32,
32    pub end_offset: f32,
33}
34
35impl Eq for ConicGradientParams {}
36
37impl hash::Hash for ConicGradientParams {
38    fn hash<H: hash::Hasher>(&self, state: &mut H) {
39        self.angle.to_bits().hash(state);
40        self.start_offset.to_bits().hash(state);
41        self.end_offset.to_bits().hash(state);
42    }
43}
44
45/// Identifying key for a line decoration.
46#[cfg_attr(feature = "capture", derive(Serialize))]
47#[cfg_attr(feature = "replay", derive(Deserialize))]
48#[derive(Debug, Clone, Eq, PartialEq, Hash, MallocSizeOf)]
49pub struct ConicGradientKey {
50    pub common: PrimKeyCommonData,
51    pub extend_mode: ExtendMode,
52    pub center: PointKey,
53    pub params: ConicGradientParams,
54    /// Per-axis tile size encoded as a fraction of `common.prim_size`. The
55    /// runtime `stretch_size` is `stretch_ratio * common.prim_size`.
56    pub stretch_ratio: SizeKey,
57    pub stops: Vec<GradientStopKey>,
58    pub tile_spacing: SizeKey,
59    pub nine_patch: Option<Box<NinePatchDescriptor>>,
60}
61
62impl ConicGradientKey {
63    pub fn new(
64        info: &LayoutPrimitiveInfo,
65        conic_grad: ConicGradient,
66    ) -> Self {
67        ConicGradientKey {
68            common: info.into(),
69            extend_mode: conic_grad.extend_mode,
70            center: conic_grad.center,
71            params: conic_grad.params,
72            stretch_ratio: conic_grad.stretch_ratio,
73            stops: conic_grad.stops,
74            tile_spacing: conic_grad.tile_spacing,
75            nine_patch: conic_grad.nine_patch,
76        }
77    }
78}
79
80impl InternDebug for ConicGradientKey {}
81
82#[cfg_attr(feature = "capture", derive(Serialize))]
83#[cfg_attr(feature = "replay", derive(Deserialize))]
84#[derive(MallocSizeOf)]
85pub struct ConicGradientTemplate {
86    pub common: PrimTemplateCommonData,
87    pub extend_mode: ExtendMode,
88    pub center: LayoutPoint,
89    pub params: ConicGradientParams,
90    /// Per-axis fraction of `common.prim_size` covered by one tile of the
91    /// gradient pattern. Multiply by `common.prim_size` at use to recover the
92    /// absolute stretch_size.
93    pub stretch_ratio: LayoutSize,
94    pub tile_spacing: LayoutSize,
95    pub border_nine_patch: Option<Box<NinePatchDescriptor>>,
96    pub stops_opacity: PrimitiveOpacity,
97    pub stops: Vec<GradientStop>,
98}
99
100impl PatternBuilder for ConicGradientTemplate {
101    fn build(
102        &self,
103        _sub_rect: Option<DeviceRect>,
104        offset: LayoutVector2D,
105        ctx: &PatternBuilderContext,
106        state: &mut PatternBuilderState,
107    ) -> Pattern {
108        // The scaling parameter is used to compensate for when we reduce the size
109        // of the render task for cached gradients. Here we aren't applying any.
110        let no_scale = DeviceVector2D::one();
111
112        // ConicGradientTemplate stores the center point relative to the primitive
113        // origin, but the shader works with start/end points in "proper" layout
114        // coordinates (relative to the primitive's spatial node).
115        let center = self.center + ctx.prim_origin.to_vector() + offset;
116
117        conic_gradient_pattern(
118            center,
119            no_scale,
120            self.params.angle,
121            self.params.start_offset,
122            self.params.end_offset,
123            self.extend_mode,
124            &self.stops,
125            state.frame_gpu_data,
126        )
127    }
128}
129
130impl Deref for ConicGradientTemplate {
131    type Target = PrimTemplateCommonData;
132    fn deref(&self) -> &Self::Target {
133        &self.common
134    }
135}
136
137impl DerefMut for ConicGradientTemplate {
138    fn deref_mut(&mut self) -> &mut Self::Target {
139        &mut self.common
140    }
141}
142
143impl From<ConicGradientKey> for ConicGradientTemplate {
144    fn from(item: ConicGradientKey) -> Self {
145        let common = PrimTemplateCommonData::with_key_common(item.common);
146
147        let (stops, min_alpha) = stops_and_min_alpha(&item.stops);
148
149        // Save opacity of the stops for use in
150        // selecting which pass this gradient
151        // should be drawn in.
152        let stops_opacity = PrimitiveOpacity::from_alpha(min_alpha);
153
154        ConicGradientTemplate {
155            common,
156            center: item.center.into(),
157            extend_mode: item.extend_mode,
158            params: item.params,
159            stretch_ratio: item.stretch_ratio.into(),
160            tile_spacing: item.tile_spacing.into(),
161            border_nine_patch: item.nine_patch,
162            stops_opacity,
163            stops,
164        }
165    }
166}
167
168pub type ConicGradientDataHandle = InternHandle<ConicGradient>;
169
170#[derive(Debug, MallocSizeOf)]
171#[cfg_attr(feature = "capture", derive(Serialize))]
172#[cfg_attr(feature = "replay", derive(Deserialize))]
173pub struct ConicGradient {
174    pub extend_mode: ExtendMode,
175    pub center: PointKey,
176    pub params: ConicGradientParams,
177    /// Per-axis tile size encoded as a fraction of the prim's size. See
178    /// [`ConicGradientKey::stretch_ratio`].
179    pub stretch_ratio: SizeKey,
180    pub stops: Vec<GradientStopKey>,
181    pub tile_spacing: SizeKey,
182    pub nine_patch: Option<Box<NinePatchDescriptor>>,
183}
184
185impl Internable for ConicGradient {
186    type Key = ConicGradientKey;
187    type StoreData = ConicGradientTemplate;
188    type InternData = ();
189    const PROFILE_COUNTER: usize = crate::profiler::INTERNED_CONIC_GRADIENTS;
190}
191
192impl InternablePrimitive for ConicGradient {
193    fn into_key(
194        self,
195        info: &LayoutPrimitiveInfo,
196    ) -> ConicGradientKey {
197        ConicGradientKey::new(info, self)
198    }
199
200    fn make_instance_kind(
201        _key: ConicGradientKey,
202        data_handle: ConicGradientDataHandle,
203        _prim_store: &mut PrimitiveStore,
204    ) -> PrimitiveKind {
205        PrimitiveKind::ConicGradient {
206            data_handle,
207        }
208    }
209}
210
211impl IsVisible for ConicGradient {
212    fn is_visible(&self) -> bool {
213        true
214    }
215}
216