1use api::{NormalBorder, PremultipliedColorF, Shadow, RasterSpace};
6use api::units::*;
7use crate::border::create_border_segments;
8use crate::border::NormalBorderAu;
9use crate::scene_building::{CreateShadow, IsVisible};
10use crate::frame_builder::FrameBuildingState;
11use crate::gpu_cache::GpuDataRequest;
12use crate::intern;
13use crate::internal_types::{LayoutPrimitiveInfo, FrameId};
14use crate::prim_store::{
15 BorderSegmentInfo, BrushSegment, NinePatchDescriptor, PrimKey,
16 PrimTemplate, PrimTemplateCommonData,
17 PrimitiveInstanceKind, PrimitiveOpacity,
18 PrimitiveStore, InternablePrimitive,
19};
20use crate::resource_cache::ImageRequest;
21use crate::render_task::RenderTask;
22use crate::render_task_graph::RenderTaskId;
23
24use super::storage;
25
26#[cfg_attr(feature = "capture", derive(Serialize))]
27#[cfg_attr(feature = "replay", derive(Deserialize))]
28#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
29pub struct NormalBorderPrim {
30 pub border: NormalBorderAu,
31 pub widths: LayoutSideOffsetsAu,
32}
33
34pub type NormalBorderKey = PrimKey<NormalBorderPrim>;
35
36impl NormalBorderKey {
37 pub fn new(
38 info: &LayoutPrimitiveInfo,
39 normal_border: NormalBorderPrim,
40 ) -> Self {
41 NormalBorderKey {
42 common: info.into(),
43 kind: normal_border,
44 }
45 }
46}
47
48impl intern::InternDebug for NormalBorderKey {}
49
50#[cfg_attr(feature = "capture", derive(Serialize))]
51#[cfg_attr(feature = "replay", derive(Deserialize))]
52#[derive(MallocSizeOf)]
53pub struct NormalBorderData {
54 pub brush_segments: Vec<BrushSegment>,
55 pub border_segments: Vec<BorderSegmentInfo>,
56 pub border: NormalBorder,
57 pub widths: LayoutSideOffsets,
58}
59
60impl NormalBorderData {
61 pub fn update(
66 &mut self,
67 common: &mut PrimTemplateCommonData,
68 frame_state: &mut FrameBuildingState,
69 ) {
70 if let Some(ref mut request) = frame_state.gpu_cache.request(&mut common.gpu_cache_handle) {
71 self.write_prim_gpu_blocks(request, common.prim_rect.size());
72 self.write_segment_gpu_blocks(request);
73 }
74
75 common.opacity = PrimitiveOpacity::translucent();
76 }
77
78 fn write_prim_gpu_blocks(
79 &self,
80 request: &mut GpuDataRequest,
81 prim_size: LayoutSize
82 ) {
83 request.push(PremultipliedColorF::WHITE);
87 request.push(PremultipliedColorF::WHITE);
88 request.push([
89 prim_size.width,
90 prim_size.height,
91 0.0,
92 0.0,
93 ]);
94 }
95
96 fn write_segment_gpu_blocks(
97 &self,
98 request: &mut GpuDataRequest,
99 ) {
100 for segment in &self.brush_segments {
101 request.write_segment(
103 segment.local_rect,
104 segment.extra_data,
105 );
106 }
107 }
108}
109
110pub type NormalBorderTemplate = PrimTemplate<NormalBorderData>;
111
112impl From<NormalBorderKey> for NormalBorderTemplate {
113 fn from(key: NormalBorderKey) -> Self {
114 let common = PrimTemplateCommonData::with_key_common(key.common);
115
116 let mut border: NormalBorder = key.kind.border.into();
117 let widths = LayoutSideOffsets::from_au(key.kind.widths);
118
119 border.normalize(&widths);
121
122 let mut brush_segments = Vec::new();
123 let mut border_segments = Vec::new();
124
125 create_border_segments(
126 common.prim_rect.size(),
127 &border,
128 &widths,
129 &mut border_segments,
130 &mut brush_segments,
131 );
132
133 NormalBorderTemplate {
134 common,
135 kind: NormalBorderData {
136 brush_segments,
137 border_segments,
138 border,
139 widths,
140 }
141 }
142 }
143}
144
145pub type NormalBorderDataHandle = intern::Handle<NormalBorderPrim>;
146
147impl intern::Internable for NormalBorderPrim {
148 type Key = NormalBorderKey;
149 type StoreData = NormalBorderTemplate;
150 type InternData = ();
151 const PROFILE_COUNTER: usize = crate::profiler::INTERNED_NORMAL_BORDERS;
152}
153
154impl InternablePrimitive for NormalBorderPrim {
155 fn into_key(
156 self,
157 info: &LayoutPrimitiveInfo,
158 ) -> NormalBorderKey {
159 NormalBorderKey::new(
160 info,
161 self,
162 )
163 }
164
165 fn make_instance_kind(
166 _key: NormalBorderKey,
167 data_handle: NormalBorderDataHandle,
168 _: &mut PrimitiveStore,
169 ) -> PrimitiveInstanceKind {
170 PrimitiveInstanceKind::NormalBorder {
171 data_handle,
172 render_task_ids: storage::Range::empty(),
173 }
174 }
175}
176
177impl CreateShadow for NormalBorderPrim {
178 fn create_shadow(
179 &self,
180 shadow: &Shadow,
181 _: bool,
182 _: RasterSpace,
183 ) -> Self {
184 let border = self.border.with_color(shadow.color.into());
185 NormalBorderPrim {
186 border,
187 widths: self.widths,
188 }
189 }
190}
191
192impl IsVisible for NormalBorderPrim {
193 fn is_visible(&self) -> bool {
194 true
195 }
196}
197
198#[cfg_attr(feature = "capture", derive(Serialize))]
201#[cfg_attr(feature = "replay", derive(Deserialize))]
202#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
203pub struct ImageBorder {
204 #[ignore_malloc_size_of = "Arc"]
205 pub request: ImageRequest,
206 pub nine_patch: NinePatchDescriptor,
207}
208
209pub type ImageBorderKey = PrimKey<ImageBorder>;
210
211impl ImageBorderKey {
212 pub fn new(
213 info: &LayoutPrimitiveInfo,
214 image_border: ImageBorder,
215 ) -> Self {
216 ImageBorderKey {
217 common: info.into(),
218 kind: image_border,
219 }
220 }
221}
222
223impl intern::InternDebug for ImageBorderKey {}
224
225
226#[cfg_attr(feature = "capture", derive(Serialize))]
227#[cfg_attr(feature = "replay", derive(Deserialize))]
228#[derive(MallocSizeOf)]
229pub struct ImageBorderData {
230 #[ignore_malloc_size_of = "Arc"]
231 pub request: ImageRequest,
232 pub brush_segments: Vec<BrushSegment>,
233 pub src_color: Option<RenderTaskId>,
234 pub frame_id: FrameId,
235 pub is_opaque: bool,
236}
237
238impl ImageBorderData {
239 pub fn update(
244 &mut self,
245 common: &mut PrimTemplateCommonData,
246 frame_state: &mut FrameBuildingState,
247 ) {
248 if let Some(ref mut request) = frame_state.gpu_cache.request(&mut common.gpu_cache_handle) {
249 self.write_prim_gpu_blocks(request, &common.prim_rect.size());
250 self.write_segment_gpu_blocks(request);
251 }
252
253 let frame_id = frame_state.rg_builder.frame_id();
254 if self.frame_id != frame_id {
255 self.frame_id = frame_id;
256
257 let size = frame_state.resource_cache.request_image(
258 self.request,
259 frame_state.gpu_cache,
260 );
261
262 let task_id = frame_state.rg_builder.add().init(
263 RenderTask::new_image(size, self.request)
264 );
265
266 self.src_color = Some(task_id);
267
268 let image_properties = frame_state
269 .resource_cache
270 .get_image_properties(self.request.key);
271
272 self.is_opaque = image_properties
273 .map(|properties| properties.descriptor.is_opaque())
274 .unwrap_or(true);
275 }
276
277 common.opacity = PrimitiveOpacity { is_opaque: self.is_opaque };
278 }
279
280 fn write_prim_gpu_blocks(
281 &self,
282 request: &mut GpuDataRequest,
283 prim_size: &LayoutSize,
284 ) {
285 request.push(PremultipliedColorF::WHITE);
289 request.push(PremultipliedColorF::WHITE);
290 request.push([
291 prim_size.width,
292 prim_size.height,
293 0.0,
294 0.0,
295 ]);
296 }
297
298 fn write_segment_gpu_blocks(
299 &self,
300 request: &mut GpuDataRequest,
301 ) {
302 for segment in &self.brush_segments {
303 request.write_segment(
305 segment.local_rect,
306 segment.extra_data,
307 );
308 }
309 }
310}
311
312pub type ImageBorderTemplate = PrimTemplate<ImageBorderData>;
313
314impl From<ImageBorderKey> for ImageBorderTemplate {
315 fn from(key: ImageBorderKey) -> Self {
316 let common = PrimTemplateCommonData::with_key_common(key.common);
317
318 let brush_segments = key.kind.nine_patch.create_segments(common.prim_rect.size());
319 ImageBorderTemplate {
320 common,
321 kind: ImageBorderData {
322 request: key.kind.request,
323 brush_segments,
324 src_color: None,
325 frame_id: FrameId::INVALID,
326 is_opaque: false,
327 }
328 }
329 }
330}
331
332pub type ImageBorderDataHandle = intern::Handle<ImageBorder>;
333
334impl intern::Internable for ImageBorder {
335 type Key = ImageBorderKey;
336 type StoreData = ImageBorderTemplate;
337 type InternData = ();
338 const PROFILE_COUNTER: usize = crate::profiler::INTERNED_IMAGE_BORDERS;
339}
340
341impl InternablePrimitive for ImageBorder {
342 fn into_key(
343 self,
344 info: &LayoutPrimitiveInfo,
345 ) -> ImageBorderKey {
346 ImageBorderKey::new(
347 info,
348 self,
349 )
350 }
351
352 fn make_instance_kind(
353 _key: ImageBorderKey,
354 data_handle: ImageBorderDataHandle,
355 _: &mut PrimitiveStore,
356 ) -> PrimitiveInstanceKind {
357 PrimitiveInstanceKind::ImageBorder {
358 data_handle
359 }
360 }
361}
362
363impl IsVisible for ImageBorder {
364 fn is_visible(&self) -> bool {
365 true
366 }
367}
368
369#[test]
370#[cfg(target_pointer_width = "64")]
371fn test_struct_sizes() {
372 use std::mem;
373 assert_eq!(mem::size_of::<NormalBorderPrim>(), 84, "NormalBorderPrim size changed");
380 assert_eq!(mem::size_of::<NormalBorderTemplate>(), 216, "NormalBorderTemplate size changed");
381 assert_eq!(mem::size_of::<NormalBorderKey>(), 104, "NormalBorderKey size changed");
382 assert_eq!(mem::size_of::<ImageBorder>(), 68, "ImageBorder size changed");
383 assert_eq!(mem::size_of::<ImageBorderTemplate>(), 104, "ImageBorderTemplate size changed");
384 assert_eq!(mem::size_of::<ImageBorderKey>(), 88, "ImageBorderKey size changed");
385}