1use api::{
6 ColorF, ColorU, RasterSpace,
7 LineOrientation, LineStyle, PremultipliedColorF, Shadow,
8};
9use api::units::*;
10use crate::scene_building::{CreateShadow, IsVisible};
11use crate::frame_builder::FrameBuildingState;
12use crate::gpu_cache::GpuDataRequest;
13use crate::intern;
14use crate::internal_types::LayoutPrimitiveInfo;
15use crate::prim_store::{
16 PrimKey, PrimTemplate, PrimTemplateCommonData,
17 InternablePrimitive, PrimitiveStore,
18};
19use crate::prim_store::PrimitiveInstanceKind;
20
21pub const MAX_LINE_DECORATION_RESOLUTION: u32 = 4096;
23
24#[derive(Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)]
25#[cfg_attr(feature = "capture", derive(Serialize))]
26#[cfg_attr(feature = "replay", derive(Deserialize))]
27pub struct LineDecorationCacheKey {
28 pub style: LineStyle,
29 pub orientation: LineOrientation,
30 pub wavy_line_thickness: Au,
31 pub size: LayoutSizeAu,
32}
33
34#[derive(Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)]
36#[cfg_attr(feature = "capture", derive(Serialize))]
37#[cfg_attr(feature = "replay", derive(Deserialize))]
38pub struct LineDecoration {
39 pub cache_key: Option<LineDecorationCacheKey>,
44 pub color: ColorU,
45}
46
47pub type LineDecorationKey = PrimKey<LineDecoration>;
48
49impl LineDecorationKey {
50 pub fn new(
51 info: &LayoutPrimitiveInfo,
52 line_dec: LineDecoration,
53 ) -> Self {
54 LineDecorationKey {
55 common: info.into(),
56 kind: line_dec,
57 }
58 }
59}
60
61impl intern::InternDebug for LineDecorationKey {}
62
63#[cfg_attr(feature = "capture", derive(Serialize))]
64#[cfg_attr(feature = "replay", derive(Deserialize))]
65#[derive(MallocSizeOf)]
66pub struct LineDecorationData {
67 pub cache_key: Option<LineDecorationCacheKey>,
68 pub color: ColorF,
69}
70
71impl LineDecorationData {
72 pub fn update(
77 &mut self,
78 common: &mut PrimTemplateCommonData,
79 frame_state: &mut FrameBuildingState,
80 ) {
81 if let Some(ref mut request) = frame_state.gpu_cache.request(&mut common.gpu_cache_handle) {
82 self.write_prim_gpu_blocks(request);
83 }
84 }
85
86 fn write_prim_gpu_blocks(
87 &self,
88 request: &mut GpuDataRequest
89 ) {
90 match self.cache_key.as_ref() {
91 Some(cache_key) => {
92 request.push(self.color.premultiplied());
93 request.push(PremultipliedColorF::WHITE);
94 request.push([
95 cache_key.size.width.to_f32_px(),
96 cache_key.size.height.to_f32_px(),
97 0.0,
98 0.0,
99 ]);
100 }
101 None => {
102 request.push(self.color.premultiplied());
103 }
104 }
105 }
106}
107
108pub type LineDecorationTemplate = PrimTemplate<LineDecorationData>;
109
110impl From<LineDecorationKey> for LineDecorationTemplate {
111 fn from(line_dec: LineDecorationKey) -> Self {
112 let common = PrimTemplateCommonData::with_key_common(line_dec.common);
113 LineDecorationTemplate {
114 common,
115 kind: LineDecorationData {
116 cache_key: line_dec.kind.cache_key,
117 color: line_dec.kind.color.into(),
118 }
119 }
120 }
121}
122
123pub type LineDecorationDataHandle = intern::Handle<LineDecoration>;
124
125impl intern::Internable for LineDecoration {
126 type Key = LineDecorationKey;
127 type StoreData = LineDecorationTemplate;
128 type InternData = ();
129 const PROFILE_COUNTER: usize = crate::profiler::INTERNED_LINE_DECORATIONS;
130}
131
132impl InternablePrimitive for LineDecoration {
133 fn into_key(
134 self,
135 info: &LayoutPrimitiveInfo,
136 ) -> LineDecorationKey {
137 LineDecorationKey::new(
138 info,
139 self,
140 )
141 }
142
143 fn make_instance_kind(
144 _key: LineDecorationKey,
145 data_handle: LineDecorationDataHandle,
146 _: &mut PrimitiveStore,
147 ) -> PrimitiveInstanceKind {
148 PrimitiveInstanceKind::LineDecoration {
149 data_handle,
150 render_task: None,
151 }
152 }
153}
154
155impl CreateShadow for LineDecoration {
156 fn create_shadow(
157 &self,
158 shadow: &Shadow,
159 _: bool,
160 _: RasterSpace,
161 ) -> Self {
162 LineDecoration {
163 color: shadow.color.into(),
164 cache_key: self.cache_key.clone(),
165 }
166 }
167}
168
169impl IsVisible for LineDecoration {
170 fn is_visible(&self) -> bool {
171 self.color.a > 0
172 }
173}
174
175pub fn get_line_decoration_size(
196 rect_size: &LayoutSize,
197 orientation: LineOrientation,
198 style: LineStyle,
199 wavy_line_thickness: f32,
200) -> Option<LayoutSize> {
201 let h = match orientation {
202 LineOrientation::Horizontal => rect_size.height,
203 LineOrientation::Vertical => rect_size.width,
204 };
205
206 let (parallel, perpendicular) = match style {
213 LineStyle::Solid => {
214 return None;
215 }
216 LineStyle::Dashed => {
217 let dash_length = (3.0 * h).min(64.0).max(1.0);
218
219 (2.0 * dash_length, 4.0)
220 }
221 LineStyle::Dotted => {
222 let diameter = h.min(64.0).max(1.0);
223 let period = 2.0 * diameter;
224
225 (period, diameter)
226 }
227 LineStyle::Wavy => {
228 let line_thickness = wavy_line_thickness.max(1.0);
229 let slope_length = h - line_thickness;
230 let flat_length = ((line_thickness - 1.0) * 2.0).max(1.0);
231 let approx_period = 2.0 * (slope_length + flat_length);
232
233 (approx_period, h)
234 }
235 };
236
237 Some(match orientation {
238 LineOrientation::Horizontal => LayoutSize::new(parallel, perpendicular),
239 LineOrientation::Vertical => LayoutSize::new(perpendicular, parallel),
240 })
241}
242
243#[test]
244#[cfg(target_pointer_width = "64")]
245fn test_struct_sizes() {
246 use std::mem;
247 assert_eq!(mem::size_of::<LineDecoration>(), 20, "LineDecoration size changed");
254 assert_eq!(mem::size_of::<LineDecorationTemplate>(), 60, "LineDecorationTemplate size changed");
255 assert_eq!(mem::size_of::<LineDecorationKey>(), 40, "LineDecorationKey size changed");
256}