1#![deny(unsafe_code)]
10
11mod layout_damage;
12pub mod wrapper_traits;
13
14use std::any::Any;
15use std::sync::Arc;
16use std::sync::atomic::{AtomicIsize, AtomicU64, Ordering};
17use std::thread::JoinHandle;
18use std::time::Duration;
19
20use app_units::Au;
21use atomic_refcell::AtomicRefCell;
22use base::Epoch;
23use base::generic_channel::GenericSender;
24use base::id::{BrowsingContextId, PipelineId, WebViewId};
25use bitflags::bitflags;
26use compositing_traits::CrossProcessCompositorApi;
27use constellation_traits::LoadData;
28use embedder_traits::{Cursor, Theme, UntrustedNodeAddress, ViewportDetails};
29use euclid::Point2D;
30use euclid::default::{Point2D as UntypedPoint2D, Rect};
31use fonts::{FontContext, SystemFontServiceProxy};
32pub use layout_damage::LayoutDamage;
33use libc::c_void;
34use malloc_size_of::{MallocSizeOf as MallocSizeOfTrait, MallocSizeOfOps, malloc_size_of_is_0};
35use malloc_size_of_derive::MallocSizeOf;
36use net_traits::image_cache::{ImageCache, PendingImageId};
37use parking_lot::RwLock;
38use pixels::RasterImage;
39use profile_traits::mem::Report;
40use profile_traits::time;
41use rustc_hash::FxHashMap;
42use script_traits::{InitialScriptState, Painter, ScriptThreadMessage};
43use serde::{Deserialize, Serialize};
44use servo_arc::Arc as ServoArc;
45use servo_url::{ImmutableOrigin, ServoUrl};
46use style::Atom;
47use style::animation::DocumentAnimationSet;
48use style::context::QuirksMode;
49use style::data::ElementData;
50use style::dom::OpaqueNode;
51use style::invalidation::element::restyle_hints::RestyleHint;
52use style::media_queries::Device;
53use style::properties::style_structs::Font;
54use style::properties::{ComputedValues, PropertyId};
55use style::selector_parser::{PseudoElement, RestyleDamage, Snapshot};
56use style::stylesheets::{Stylesheet, UrlExtraData};
57use style::values::computed::Overflow;
58use style_traits::CSSPixel;
59use webrender_api::units::{DeviceIntSize, LayoutPoint, LayoutVector2D};
60use webrender_api::{ExternalScrollId, ImageKey};
61
62pub trait GenericLayoutDataTrait: Any + MallocSizeOfTrait {
63 fn as_any(&self) -> &dyn Any;
64}
65
66pub type GenericLayoutData = dyn GenericLayoutDataTrait + Send + Sync;
67
68#[derive(MallocSizeOf)]
69pub struct StyleData {
70 pub element_data: AtomicRefCell<ElementData>,
75
76 pub parallel: DomParallelInfo,
78}
79
80impl Default for StyleData {
81 fn default() -> Self {
82 Self {
83 element_data: AtomicRefCell::new(ElementData::default()),
84 parallel: DomParallelInfo::default(),
85 }
86 }
87}
88
89#[derive(Default, MallocSizeOf)]
91pub struct DomParallelInfo {
92 pub children_to_process: AtomicIsize,
94}
95
96#[derive(Clone, Copy, Debug, Eq, PartialEq)]
97pub enum LayoutNodeType {
98 Element(LayoutElementType),
99 Text,
100}
101
102#[derive(Clone, Copy, Debug, Eq, PartialEq)]
103pub enum LayoutElementType {
104 Element,
105 HTMLBodyElement,
106 HTMLBRElement,
107 HTMLCanvasElement,
108 HTMLHtmlElement,
109 HTMLIFrameElement,
110 HTMLImageElement,
111 HTMLInputElement,
112 HTMLMediaElement,
113 HTMLObjectElement,
114 HTMLOptGroupElement,
115 HTMLOptionElement,
116 HTMLParagraphElement,
117 HTMLPreElement,
118 HTMLSelectElement,
119 HTMLTableCellElement,
120 HTMLTableColElement,
121 HTMLTableElement,
122 HTMLTableRowElement,
123 HTMLTableSectionElement,
124 HTMLTextAreaElement,
125 SVGImageElement,
126 SVGSVGElement,
127}
128
129pub struct HTMLCanvasData {
130 pub source: Option<ImageKey>,
131 pub width: u32,
132 pub height: u32,
133}
134
135pub struct SVGElementData {
136 pub source: Option<Result<ServoUrl, ()>>,
138 pub width: Option<i32>,
139 pub height: Option<i32>,
140 pub ratio: Option<f32>,
141}
142
143#[derive(Clone, Copy, Debug, Eq, PartialEq)]
145pub struct TrustedNodeAddress(pub *const c_void);
146
147#[allow(unsafe_code)]
148unsafe impl Send for TrustedNodeAddress {}
149
150#[derive(Debug)]
152pub enum PendingImageState {
153 Unrequested(ServoUrl),
154 PendingResponse,
155}
156
157#[derive(Debug, MallocSizeOf)]
159pub enum LayoutImageDestination {
160 BoxTreeConstruction,
161 DisplayListBuilding,
162}
163
164#[derive(Debug)]
168pub struct PendingImage {
169 pub state: PendingImageState,
170 pub node: UntrustedNodeAddress,
171 pub id: PendingImageId,
172 pub origin: ImmutableOrigin,
173 pub destination: LayoutImageDestination,
174}
175
176#[derive(Debug)]
180pub struct PendingRasterizationImage {
181 pub node: UntrustedNodeAddress,
182 pub id: PendingImageId,
183 pub size: DeviceIntSize,
184}
185
186#[derive(Clone, Copy, Debug, MallocSizeOf)]
187pub struct MediaFrame {
188 pub image_key: webrender_api::ImageKey,
189 pub width: i32,
190 pub height: i32,
191}
192
193pub struct MediaMetadata {
194 pub width: u32,
195 pub height: u32,
196}
197
198pub struct HTMLMediaData {
199 pub current_frame: Option<MediaFrame>,
200 pub metadata: Option<MediaMetadata>,
201}
202
203pub struct LayoutConfig {
204 pub id: PipelineId,
205 pub webview_id: WebViewId,
206 pub url: ServoUrl,
207 pub is_iframe: bool,
208 pub script_chan: GenericSender<ScriptThreadMessage>,
209 pub image_cache: Arc<dyn ImageCache>,
210 pub font_context: Arc<FontContext>,
211 pub time_profiler_chan: time::ProfilerChan,
212 pub compositor_api: CrossProcessCompositorApi,
213 pub viewport_details: ViewportDetails,
214 pub theme: Theme,
215}
216
217pub struct PropertyRegistration {
218 pub name: String,
219 pub syntax: String,
220 pub initial_value: Option<String>,
221 pub inherits: bool,
222 pub url_data: UrlExtraData,
223}
224
225#[derive(Debug)]
226pub enum RegisterPropertyError {
227 InvalidName,
228 AlreadyRegistered,
229 InvalidSyntax,
230 InvalidInitialValue,
231 InitialValueNotComputationallyIndependent,
232 NoInitialValue,
233}
234
235pub trait LayoutFactory: Send + Sync {
236 fn create(&self, config: LayoutConfig) -> Box<dyn Layout>;
237}
238
239pub trait Layout {
240 fn device(&self) -> &Device;
243
244 fn load_web_fonts_from_stylesheet(&self, stylesheet: &ServoArc<Stylesheet>);
247
248 fn add_stylesheet(
252 &mut self,
253 stylesheet: ServoArc<Stylesheet>,
254 before_stylsheet: Option<ServoArc<Stylesheet>>,
255 );
256
257 fn exit_now(&mut self);
259
260 fn collect_reports(&self, reports: &mut Vec<Report>, ops: &mut MallocSizeOfOps);
263
264 fn set_quirks_mode(&mut self, quirks_mode: QuirksMode);
266
267 fn remove_stylesheet(&mut self, stylesheet: ServoArc<Stylesheet>);
269
270 fn reflow(&mut self, reflow_request: ReflowRequest) -> Option<ReflowResult>;
272
273 fn ensure_stacking_context_tree(&self, viewport_details: ViewportDetails);
276
277 fn register_paint_worklet_modules(
279 &mut self,
280 name: Atom,
281 properties: Vec<Atom>,
282 painter: Box<dyn Painter>,
283 );
284
285 fn set_scroll_offsets_from_renderer(
287 &mut self,
288 scroll_states: &FxHashMap<ExternalScrollId, LayoutVector2D>,
289 );
290
291 fn scroll_offset(&self, id: ExternalScrollId) -> Option<LayoutVector2D>;
294
295 fn needs_new_display_list(&self) -> bool;
297
298 fn set_needs_new_display_list(&self);
300
301 fn query_box_area(&self, node: TrustedNodeAddress, area: BoxAreaType) -> Option<Rect<Au>>;
302 fn query_box_areas(&self, node: TrustedNodeAddress, area: BoxAreaType) -> Vec<Rect<Au>>;
303 fn query_client_rect(&self, node: TrustedNodeAddress) -> Rect<i32>;
304 fn query_element_inner_outer_text(&self, node: TrustedNodeAddress) -> String;
305 fn query_offset_parent(&self, node: TrustedNodeAddress) -> OffsetParentResponse;
306 fn query_scroll_container(
309 &self,
310 node: Option<TrustedNodeAddress>,
311 flags: ScrollContainerQueryFlags,
312 ) -> Option<ScrollContainerResponse>;
313 fn query_resolved_style(
314 &self,
315 node: TrustedNodeAddress,
316 pseudo: Option<PseudoElement>,
317 property_id: PropertyId,
318 animations: DocumentAnimationSet,
319 animation_timeline_value: f64,
320 ) -> String;
321 fn query_resolved_font_style(
322 &self,
323 node: TrustedNodeAddress,
324 value: &str,
325 animations: DocumentAnimationSet,
326 animation_timeline_value: f64,
327 ) -> Option<ServoArc<Font>>;
328 fn query_scrolling_area(&self, node: Option<TrustedNodeAddress>) -> Rect<i32>;
329 fn query_text_indext(&self, node: OpaqueNode, point: UntypedPoint2D<f32>) -> Option<usize>;
330 fn query_elements_from_point(
331 &self,
332 point: LayoutPoint,
333 flags: ElementsFromPointFlags,
334 ) -> Vec<ElementsFromPointResult>;
335 fn register_custom_property(
336 &mut self,
337 property_registration: PropertyRegistration,
338 ) -> Result<(), RegisterPropertyError>;
339}
340
341pub trait ScriptThreadFactory {
345 fn create(
347 state: InitialScriptState,
348 layout_factory: Arc<dyn LayoutFactory>,
349 system_font_service: Arc<SystemFontServiceProxy>,
350 load_data: LoadData,
351 ) -> JoinHandle<()>;
352}
353
354#[derive(Copy, Clone)]
357pub enum BoxAreaType {
358 Content,
359 Padding,
360 Border,
361}
362
363#[derive(Clone, Default)]
364pub struct OffsetParentResponse {
365 pub node_address: Option<UntrustedNodeAddress>,
366 pub rect: Rect<Au>,
367}
368
369bitflags! {
370 #[derive(PartialEq)]
371 pub struct ScrollContainerQueryFlags: u8 {
372 const ForScrollParent = 1 << 0;
374 const Inclusive = 1 << 1;
376 }
377}
378
379#[derive(Clone, Copy, Debug, MallocSizeOf)]
380pub struct AxesOverflow {
381 pub x: Overflow,
382 pub y: Overflow,
383}
384
385impl Default for AxesOverflow {
386 fn default() -> Self {
387 Self {
388 x: Overflow::Visible,
389 y: Overflow::Visible,
390 }
391 }
392}
393
394impl From<&ComputedValues> for AxesOverflow {
395 fn from(style: &ComputedValues) -> Self {
396 Self {
397 x: style.clone_overflow_x(),
398 y: style.clone_overflow_y(),
399 }
400 }
401}
402
403impl AxesOverflow {
404 pub fn to_scrollable(&self) -> Self {
405 Self {
406 x: self.x.to_scrollable(),
407 y: self.y.to_scrollable(),
408 }
409 }
410}
411
412#[derive(Clone)]
413pub enum ScrollContainerResponse {
414 Viewport(AxesOverflow),
415 Element(UntrustedNodeAddress, AxesOverflow),
416}
417
418#[derive(Debug, PartialEq)]
419pub enum QueryMsg {
420 BoxArea,
421 BoxAreas,
422 ClientRectQuery,
423 ElementInnerOuterTextQuery,
424 ElementsFromPoint,
425 InnerWindowDimensionsQuery,
426 NodesFromPointQuery,
427 OffsetParentQuery,
428 ScrollParentQuery,
429 ResolvedFontStyleQuery,
430 ResolvedStyleQuery,
431 ScrollingAreaOrOffsetQuery,
432 StyleQuery,
433 TextIndexQuery,
434}
435
436#[derive(Debug, PartialEq)]
442pub enum ReflowGoal {
443 UpdateTheRendering,
446
447 LayoutQuery(QueryMsg),
450
451 UpdateScrollNode(ExternalScrollId, LayoutVector2D),
455}
456
457#[derive(Clone, Debug, MallocSizeOf)]
458pub struct IFrameSize {
459 pub browsing_context_id: BrowsingContextId,
460 pub pipeline_id: PipelineId,
461 pub viewport_details: ViewportDetails,
462}
463
464pub type IFrameSizes = FxHashMap<BrowsingContextId, IFrameSize>;
465
466bitflags! {
467 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
470 pub struct RestyleReason: u16 {
471 const StylesheetsChanged = 1 << 0;
472 const DOMChanged = 1 << 1;
473 const PendingRestyles = 1 << 2;
474 const HighlightedDOMNodeChanged = 1 << 3;
475 const ThemeChanged = 1 << 4;
476 const ViewportSizeChanged = 1 << 5;
477 const PaintWorkletLoaded = 1 << 6;
478 }
479}
480
481malloc_size_of_is_0!(RestyleReason);
482
483impl RestyleReason {
484 pub fn needs_restyle(&self) -> bool {
485 !self.is_empty()
486 }
487}
488
489#[derive(Debug, Default)]
491pub struct ReflowResult {
492 pub reflow_phases_run: ReflowPhasesRun,
494 pub pending_images: Vec<PendingImage>,
496 pub pending_rasterization_images: Vec<PendingRasterizationImage>,
498 pub pending_svg_elements_for_serialization: Vec<UntrustedNodeAddress>,
502 pub iframe_sizes: Option<IFrameSizes>,
508}
509
510bitflags! {
511 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
513 pub struct ReflowPhasesRun: u8 {
514 const RanLayout = 1 << 0;
515 const CalculatedOverflow = 1 << 1;
516 const BuiltStackingContextTree = 1 << 2;
517 const BuiltDisplayList = 1 << 3;
518 const UpdatedScrollNodeOffset = 1 << 4;
519 const UpdatedImageData = 1 << 5;
523 }
524}
525
526impl ReflowPhasesRun {
527 pub fn needs_frame(&self) -> bool {
528 self.intersects(
529 Self::BuiltDisplayList | Self::UpdatedScrollNodeOffset | Self::UpdatedImageData,
530 )
531 }
532}
533
534#[derive(Debug)]
537pub struct ReflowRequestRestyle {
538 pub reason: RestyleReason,
540 pub dirty_root: Option<TrustedNodeAddress>,
542 pub stylesheets_changed: bool,
544 pub pending_restyles: Vec<(TrustedNodeAddress, PendingRestyle)>,
546}
547
548#[derive(Debug)]
550pub struct ReflowRequest {
551 pub document: TrustedNodeAddress,
553 pub epoch: Epoch,
555 pub restyle: Option<ReflowRequestRestyle>,
557 pub viewport_details: ViewportDetails,
559 pub reflow_goal: ReflowGoal,
561 pub dom_count: u32,
563 pub origin: ImmutableOrigin,
565 pub animation_timeline_value: f64,
567 pub animations: DocumentAnimationSet,
569 pub animating_images: Arc<RwLock<AnimatingImages>>,
571 pub theme: Theme,
573 pub highlighted_dom_node: Option<OpaqueNode>,
575}
576
577impl ReflowRequest {
578 pub fn stylesheets_changed(&self) -> bool {
579 self.restyle
580 .as_ref()
581 .is_some_and(|restyle| restyle.stylesheets_changed)
582 }
583}
584
585#[derive(Debug, Default, MallocSizeOf)]
587pub struct PendingRestyle {
588 pub snapshot: Option<Snapshot>,
591
592 pub hint: RestyleHint,
594
595 pub damage: RestyleDamage,
597}
598
599#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
605pub enum FragmentType {
606 FragmentBody,
608 BeforePseudoContent,
610 AfterPseudoContent,
612}
613
614impl From<Option<PseudoElement>> for FragmentType {
615 fn from(value: Option<PseudoElement>) -> Self {
616 match value {
617 Some(PseudoElement::After) => FragmentType::AfterPseudoContent,
618 Some(PseudoElement::Before) => FragmentType::BeforePseudoContent,
619 _ => FragmentType::FragmentBody,
620 }
621 }
622}
623
624static NEXT_SPECIAL_SCROLL_ROOT_ID: AtomicU64 = AtomicU64::new(0);
628
629const SPECIAL_SCROLL_ROOT_ID_MASK: u64 = 0xffff;
632
633fn next_special_id() -> u64 {
635 ((NEXT_SPECIAL_SCROLL_ROOT_ID.fetch_add(1, Ordering::SeqCst) + 1) << 2) &
637 SPECIAL_SCROLL_ROOT_ID_MASK
638}
639
640pub fn combine_id_with_fragment_type(id: usize, fragment_type: FragmentType) -> u64 {
641 debug_assert_eq!(id & (fragment_type as usize), 0);
642 if fragment_type == FragmentType::FragmentBody {
643 id as u64
644 } else {
645 next_special_id() | (fragment_type as u64)
646 }
647}
648
649pub fn node_id_from_scroll_id(id: usize) -> Option<usize> {
650 if (id as u64 & !SPECIAL_SCROLL_ROOT_ID_MASK) != 0 {
651 return Some(id & !3);
652 }
653 None
654}
655
656#[derive(Clone, Debug, MallocSizeOf)]
657pub struct ImageAnimationState {
658 #[ignore_malloc_size_of = "RasterImage"]
659 pub image: Arc<RasterImage>,
660 pub active_frame: usize,
661 frame_start_time: f64,
662}
663
664impl ImageAnimationState {
665 pub fn new(image: Arc<RasterImage>, last_update_time: f64) -> Self {
666 Self {
667 image,
668 active_frame: 0,
669 frame_start_time: last_update_time,
670 }
671 }
672
673 pub fn image_key(&self) -> Option<ImageKey> {
674 self.image.id
675 }
676
677 pub fn duration_to_next_frame(&self, now: f64) -> Duration {
678 let frame_delay = self
679 .image
680 .frames
681 .get(self.active_frame)
682 .expect("Image frame should always be valid")
683 .delay
684 .unwrap_or_default();
685
686 let time_since_frame_start = (now - self.frame_start_time).max(0.0) * 1000.0;
687 let time_since_frame_start = Duration::from_secs_f64(time_since_frame_start);
688 frame_delay - time_since_frame_start.min(frame_delay)
689 }
690
691 pub fn update_frame_for_animation_timeline_value(&mut self, now: f64) -> bool {
695 if self.image.frames.len() <= 1 {
696 return false;
697 }
698 let image = &self.image;
699 let time_interval_since_last_update = now - self.frame_start_time;
700 let mut remain_time_interval = time_interval_since_last_update -
701 image
702 .frames
703 .get(self.active_frame)
704 .unwrap()
705 .delay()
706 .unwrap()
707 .as_secs_f64();
708 let mut next_active_frame_id = self.active_frame;
709 while remain_time_interval > 0.0 {
710 next_active_frame_id = (next_active_frame_id + 1) % image.frames.len();
711 remain_time_interval -= image
712 .frames
713 .get(next_active_frame_id)
714 .unwrap()
715 .delay()
716 .unwrap()
717 .as_secs_f64();
718 }
719 if self.active_frame == next_active_frame_id {
720 return false;
721 }
722 self.active_frame = next_active_frame_id;
723 self.frame_start_time = now;
724 true
725 }
726}
727
728#[derive(Debug)]
730pub struct ElementsFromPointResult {
731 pub node: OpaqueNode,
734 pub point_in_target: Point2D<f32, CSSPixel>,
737 pub cursor: Cursor,
740}
741
742bitflags! {
743 pub struct ElementsFromPointFlags: u8 {
744 const FindAll = 0b00000001;
747 }
748}
749
750#[derive(Debug, Default, MallocSizeOf)]
751pub struct AnimatingImages {
752 pub node_to_state_map: FxHashMap<OpaqueNode, ImageAnimationState>,
755 pub dirty: bool,
758}
759
760impl AnimatingImages {
761 pub fn maybe_insert_or_update(
762 &mut self,
763 node: OpaqueNode,
764 image: Arc<RasterImage>,
765 current_timeline_value: f64,
766 ) {
767 let entry = self.node_to_state_map.entry(node).or_insert_with(|| {
768 self.dirty = true;
769 ImageAnimationState::new(image.clone(), current_timeline_value)
770 });
771
772 if entry.image.id != image.id {
775 self.dirty = true;
776 *entry = ImageAnimationState::new(image.clone(), current_timeline_value);
777 }
778 }
779
780 pub fn remove(&mut self, node: OpaqueNode) {
781 if self.node_to_state_map.remove(&node).is_some() {
782 self.dirty = true;
783 }
784 }
785
786 pub fn clear_dirty(&mut self) -> bool {
788 std::mem::take(&mut self.dirty)
789 }
790
791 pub fn is_empty(&self) -> bool {
792 self.node_to_state_map.is_empty()
793 }
794}
795
796#[cfg(test)]
797mod test {
798 use std::sync::Arc;
799 use std::time::Duration;
800
801 use ipc_channel::ipc::IpcSharedMemory;
802 use pixels::{CorsStatus, ImageFrame, ImageMetadata, PixelFormat, RasterImage};
803
804 use crate::ImageAnimationState;
805
806 #[test]
807 fn test() {
808 let image_frames: Vec<ImageFrame> = std::iter::repeat_with(|| ImageFrame {
809 delay: Some(Duration::from_millis(100)),
810 byte_range: 0..1,
811 width: 100,
812 height: 100,
813 })
814 .take(10)
815 .collect();
816 let image = RasterImage {
817 metadata: ImageMetadata {
818 width: 100,
819 height: 100,
820 },
821 format: PixelFormat::BGRA8,
822 id: None,
823 bytes: IpcSharedMemory::from_byte(1, 1),
824 frames: image_frames,
825 cors_status: CorsStatus::Unsafe,
826 };
827 let mut image_animation_state = ImageAnimationState::new(Arc::new(image), 0.0);
828
829 assert_eq!(image_animation_state.active_frame, 0);
830 assert_eq!(image_animation_state.frame_start_time, 0.0);
831 assert_eq!(
832 image_animation_state.update_frame_for_animation_timeline_value(0.101),
833 true
834 );
835 assert_eq!(image_animation_state.active_frame, 1);
836 assert_eq!(image_animation_state.frame_start_time, 0.101);
837 assert_eq!(
838 image_animation_state.update_frame_for_animation_timeline_value(0.116),
839 false
840 );
841 assert_eq!(image_animation_state.active_frame, 1);
842 assert_eq!(image_animation_state.frame_start_time, 0.101);
843 }
844}