1#![deny(unsafe_code)]
10
11mod layout_damage;
12pub mod wrapper_traits;
13
14use std::any::Any;
15use std::collections::HashMap;
16use std::sync::Arc;
17use std::sync::atomic::{AtomicIsize, AtomicU64, Ordering};
18use std::thread::JoinHandle;
19use std::time::Duration;
20
21use app_units::Au;
22use atomic_refcell::AtomicRefCell;
23use base::Epoch;
24use base::generic_channel::GenericSender;
25use base::id::{BrowsingContextId, PipelineId, WebViewId};
26use bitflags::bitflags;
27use compositing_traits::CrossProcessCompositorApi;
28use constellation_traits::LoadData;
29use embedder_traits::{Cursor, Theme, UntrustedNodeAddress, ViewportDetails};
30use euclid::Point2D;
31use euclid::default::{Point2D as UntypedPoint2D, Rect};
32use fnv::FnvHashMap;
33use fonts::{FontContext, SystemFontServiceProxy};
34use fxhash::FxHashMap;
35pub use layout_damage::LayoutDamage;
36use libc::c_void;
37use malloc_size_of::{MallocSizeOf as MallocSizeOfTrait, MallocSizeOfOps, malloc_size_of_is_0};
38use malloc_size_of_derive::MallocSizeOf;
39use net_traits::image_cache::{ImageCache, PendingImageId};
40use parking_lot::RwLock;
41use pixels::RasterImage;
42use profile_traits::mem::Report;
43use profile_traits::time;
44use script_traits::{InitialScriptState, Painter, ScriptThreadMessage};
45use serde::{Deserialize, Serialize};
46use servo_arc::Arc as ServoArc;
47use servo_url::{ImmutableOrigin, ServoUrl};
48use style::Atom;
49use style::animation::DocumentAnimationSet;
50use style::context::QuirksMode;
51use style::data::ElementData;
52use style::dom::OpaqueNode;
53use style::invalidation::element::restyle_hints::RestyleHint;
54use style::media_queries::Device;
55use style::properties::PropertyId;
56use style::properties::style_structs::Font;
57use style::selector_parser::{PseudoElement, RestyleDamage, Snapshot};
58use style::stylesheets::{Stylesheet, UrlExtraData};
59use style_traits::CSSPixel;
60use webrender_api::units::{DeviceIntSize, LayoutPoint, LayoutVector2D};
61use webrender_api::{ExternalScrollId, ImageKey};
62
63pub trait GenericLayoutDataTrait: Any + MallocSizeOfTrait {
64 fn as_any(&self) -> &dyn Any;
65}
66
67pub type GenericLayoutData = dyn GenericLayoutDataTrait + Send + Sync;
68
69#[derive(MallocSizeOf)]
70pub struct StyleData {
71 pub element_data: AtomicRefCell<ElementData>,
76
77 pub parallel: DomParallelInfo,
79}
80
81impl Default for StyleData {
82 fn default() -> Self {
83 Self {
84 element_data: AtomicRefCell::new(ElementData::default()),
85 parallel: DomParallelInfo::default(),
86 }
87 }
88}
89
90#[derive(Default, MallocSizeOf)]
92pub struct DomParallelInfo {
93 pub children_to_process: AtomicIsize,
95}
96
97#[derive(Clone, Copy, Debug, Eq, PartialEq)]
98pub enum LayoutNodeType {
99 Element(LayoutElementType),
100 Text,
101}
102
103#[derive(Clone, Copy, Debug, Eq, PartialEq)]
104pub enum LayoutElementType {
105 Element,
106 HTMLBodyElement,
107 HTMLBRElement,
108 HTMLCanvasElement,
109 HTMLHtmlElement,
110 HTMLIFrameElement,
111 HTMLImageElement,
112 HTMLInputElement,
113 HTMLMediaElement,
114 HTMLObjectElement,
115 HTMLOptGroupElement,
116 HTMLOptionElement,
117 HTMLParagraphElement,
118 HTMLPreElement,
119 HTMLSelectElement,
120 HTMLTableCellElement,
121 HTMLTableColElement,
122 HTMLTableElement,
123 HTMLTableRowElement,
124 HTMLTableSectionElement,
125 HTMLTextAreaElement,
126 SVGImageElement,
127 SVGSVGElement,
128}
129
130pub struct HTMLCanvasData {
131 pub source: Option<ImageKey>,
132 pub width: u32,
133 pub height: u32,
134}
135
136pub struct SVGElementData {
137 pub source: Option<Result<ServoUrl, ()>>,
139 pub width: Option<i32>,
140 pub height: Option<i32>,
141 pub ratio: Option<f32>,
142}
143
144#[derive(Clone, Copy, Debug, Eq, PartialEq)]
146pub struct TrustedNodeAddress(pub *const c_void);
147
148#[allow(unsafe_code)]
149unsafe impl Send for TrustedNodeAddress {}
150
151#[derive(Debug)]
153pub enum PendingImageState {
154 Unrequested(ServoUrl),
155 PendingResponse,
156}
157
158#[derive(Debug)]
162pub struct PendingImage {
163 pub state: PendingImageState,
164 pub node: UntrustedNodeAddress,
165 pub id: PendingImageId,
166 pub origin: ImmutableOrigin,
167}
168
169#[derive(Debug)]
173pub struct PendingRasterizationImage {
174 pub node: UntrustedNodeAddress,
175 pub id: PendingImageId,
176 pub size: DeviceIntSize,
177}
178
179#[derive(Clone, Copy, Debug, MallocSizeOf)]
180pub struct MediaFrame {
181 pub image_key: webrender_api::ImageKey,
182 pub width: i32,
183 pub height: i32,
184}
185
186pub struct MediaMetadata {
187 pub width: u32,
188 pub height: u32,
189}
190
191pub struct HTMLMediaData {
192 pub current_frame: Option<MediaFrame>,
193 pub metadata: Option<MediaMetadata>,
194}
195
196pub struct LayoutConfig {
197 pub id: PipelineId,
198 pub webview_id: WebViewId,
199 pub url: ServoUrl,
200 pub is_iframe: bool,
201 pub script_chan: GenericSender<ScriptThreadMessage>,
202 pub image_cache: Arc<dyn ImageCache>,
203 pub font_context: Arc<FontContext>,
204 pub time_profiler_chan: time::ProfilerChan,
205 pub compositor_api: CrossProcessCompositorApi,
206 pub viewport_details: ViewportDetails,
207 pub theme: Theme,
208}
209
210pub struct PropertyRegistration {
211 pub name: String,
212 pub syntax: String,
213 pub initial_value: Option<String>,
214 pub inherits: bool,
215 pub url_data: UrlExtraData,
216}
217
218#[derive(Debug)]
219pub enum RegisterPropertyError {
220 InvalidName,
221 AlreadyRegistered,
222 InvalidSyntax,
223 InvalidInitialValue,
224 InitialValueNotComputationallyIndependent,
225 NoInitialValue,
226}
227
228pub trait LayoutFactory: Send + Sync {
229 fn create(&self, config: LayoutConfig) -> Box<dyn Layout>;
230}
231
232pub trait Layout {
233 fn device(&self) -> &Device;
236
237 fn current_epoch(&self) -> Epoch;
239
240 fn load_web_fonts_from_stylesheet(&self, stylesheet: ServoArc<Stylesheet>);
243
244 fn add_stylesheet(
248 &mut self,
249 stylesheet: ServoArc<Stylesheet>,
250 before_stylsheet: Option<ServoArc<Stylesheet>>,
251 );
252
253 fn exit_now(&mut self);
255
256 fn collect_reports(&self, reports: &mut Vec<Report>, ops: &mut MallocSizeOfOps);
259
260 fn set_quirks_mode(&mut self, quirks_mode: QuirksMode);
262
263 fn remove_stylesheet(&mut self, stylesheet: ServoArc<Stylesheet>);
265
266 fn reflow(&mut self, reflow_request: ReflowRequest) -> Option<ReflowResult>;
268
269 fn ensure_stacking_context_tree(&self, viewport_details: ViewportDetails);
272
273 fn register_paint_worklet_modules(
275 &mut self,
276 name: Atom,
277 properties: Vec<Atom>,
278 painter: Box<dyn Painter>,
279 );
280
281 fn set_scroll_offsets_from_renderer(
283 &mut self,
284 scroll_states: &HashMap<ExternalScrollId, LayoutVector2D>,
285 );
286
287 fn scroll_offset(&self, id: ExternalScrollId) -> Option<LayoutVector2D>;
290
291 fn needs_new_display_list(&self) -> bool;
293
294 fn query_box_area(&self, node: TrustedNodeAddress, area: BoxAreaType) -> Option<Rect<Au>>;
295 fn query_box_areas(&self, node: TrustedNodeAddress, area: BoxAreaType) -> Vec<Rect<Au>>;
296 fn query_client_rect(&self, node: TrustedNodeAddress) -> Rect<i32>;
297 fn query_element_inner_outer_text(&self, node: TrustedNodeAddress) -> String;
298 fn query_offset_parent(&self, node: TrustedNodeAddress) -> OffsetParentResponse;
299 fn query_resolved_style(
300 &self,
301 node: TrustedNodeAddress,
302 pseudo: Option<PseudoElement>,
303 property_id: PropertyId,
304 animations: DocumentAnimationSet,
305 animation_timeline_value: f64,
306 ) -> String;
307 fn query_resolved_font_style(
308 &self,
309 node: TrustedNodeAddress,
310 value: &str,
311 animations: DocumentAnimationSet,
312 animation_timeline_value: f64,
313 ) -> Option<ServoArc<Font>>;
314 fn query_scrolling_area(&self, node: Option<TrustedNodeAddress>) -> Rect<i32>;
315 fn query_text_indext(&self, node: OpaqueNode, point: UntypedPoint2D<f32>) -> Option<usize>;
316 fn query_elements_from_point(
317 &self,
318 point: LayoutPoint,
319 flags: ElementsFromPointFlags,
320 ) -> Vec<ElementsFromPointResult>;
321 fn register_custom_property(
322 &mut self,
323 property_registration: PropertyRegistration,
324 ) -> Result<(), RegisterPropertyError>;
325}
326
327pub trait ScriptThreadFactory {
331 fn create(
333 state: InitialScriptState,
334 layout_factory: Arc<dyn LayoutFactory>,
335 system_font_service: Arc<SystemFontServiceProxy>,
336 load_data: LoadData,
337 ) -> JoinHandle<()>;
338}
339
340#[derive(Copy, Clone)]
343pub enum BoxAreaType {
344 Content,
345 Padding,
346 Border,
347}
348
349#[derive(Clone, Default)]
350pub struct OffsetParentResponse {
351 pub node_address: Option<UntrustedNodeAddress>,
352 pub rect: Rect<Au>,
353}
354
355#[derive(Debug, PartialEq)]
356pub enum QueryMsg {
357 BoxArea,
358 BoxAreas,
359 ClientRectQuery,
360 ElementInnerOuterTextQuery,
361 ElementsFromPoint,
362 InnerWindowDimensionsQuery,
363 NodesFromPointQuery,
364 OffsetParentQuery,
365 ResolvedFontStyleQuery,
366 ResolvedStyleQuery,
367 ScrollingAreaOrOffsetQuery,
368 StyleQuery,
369 TextIndexQuery,
370}
371
372#[derive(Debug, PartialEq)]
378pub enum ReflowGoal {
379 UpdateTheRendering,
382
383 LayoutQuery(QueryMsg),
386
387 UpdateScrollNode(ExternalScrollId, LayoutVector2D),
391}
392
393#[derive(Clone, Debug, MallocSizeOf)]
394pub struct IFrameSize {
395 pub browsing_context_id: BrowsingContextId,
396 pub pipeline_id: PipelineId,
397 pub viewport_details: ViewportDetails,
398}
399
400pub type IFrameSizes = FnvHashMap<BrowsingContextId, IFrameSize>;
401
402bitflags! {
403 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
406 pub struct RestyleReason: u16 {
407 const StylesheetsChanged = 1 << 0;
408 const DOMChanged = 1 << 1;
409 const PendingRestyles = 1 << 2;
410 const HighlightedDOMNodeChanged = 1 << 3;
411 const ThemeChanged = 1 << 4;
412 const ViewportSizeChanged = 1 << 5;
413 const PaintWorkletLoaded = 1 << 6;
414 }
415}
416
417malloc_size_of_is_0!(RestyleReason);
418
419impl RestyleReason {
420 pub fn needs_restyle(&self) -> bool {
421 !self.is_empty()
422 }
423}
424
425#[derive(Debug, Default)]
427pub struct ReflowResult {
428 pub reflow_phases_run: ReflowPhasesRun,
430 pub pending_images: Vec<PendingImage>,
432 pub pending_rasterization_images: Vec<PendingRasterizationImage>,
434 pub pending_svg_elements_for_serialization: Vec<UntrustedNodeAddress>,
438 pub iframe_sizes: Option<IFrameSizes>,
444}
445
446bitflags! {
447 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
449 pub struct ReflowPhasesRun: u8 {
450 const RanLayout = 1 << 0;
451 const CalculatedOverflow = 1 << 1;
452 const BuiltStackingContextTree = 1 << 2;
453 const BuiltDisplayList = 1 << 3;
454 const UpdatedScrollNodeOffset = 1 << 4;
455 const UpdatedCanvasContents = 1 << 5;
456 }
457}
458
459impl ReflowPhasesRun {
460 pub fn needs_frame(&self) -> bool {
461 self.intersects(
462 Self::BuiltDisplayList | Self::UpdatedScrollNodeOffset | Self::UpdatedCanvasContents,
463 )
464 }
465}
466
467#[derive(Debug)]
470pub struct ReflowRequestRestyle {
471 pub reason: RestyleReason,
473 pub dirty_root: Option<TrustedNodeAddress>,
475 pub stylesheets_changed: bool,
477 pub pending_restyles: Vec<(TrustedNodeAddress, PendingRestyle)>,
479}
480
481#[derive(Debug)]
483pub struct ReflowRequest {
484 pub document: TrustedNodeAddress,
486 pub restyle: Option<ReflowRequestRestyle>,
488 pub viewport_details: ViewportDetails,
490 pub reflow_goal: ReflowGoal,
492 pub dom_count: u32,
494 pub origin: ImmutableOrigin,
496 pub animation_timeline_value: f64,
498 pub animations: DocumentAnimationSet,
500 pub node_to_animating_image_map: Arc<RwLock<FxHashMap<OpaqueNode, ImageAnimationState>>>,
502 pub theme: Theme,
504 pub highlighted_dom_node: Option<OpaqueNode>,
506}
507
508impl ReflowRequest {
509 pub fn stylesheets_changed(&self) -> bool {
510 self.restyle
511 .as_ref()
512 .is_some_and(|restyle| restyle.stylesheets_changed)
513 }
514}
515
516#[derive(Debug, Default, MallocSizeOf)]
518pub struct PendingRestyle {
519 pub snapshot: Option<Snapshot>,
522
523 pub hint: RestyleHint,
525
526 pub damage: RestyleDamage,
528}
529
530#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
536pub enum FragmentType {
537 FragmentBody,
539 BeforePseudoContent,
541 AfterPseudoContent,
543}
544
545impl From<Option<PseudoElement>> for FragmentType {
546 fn from(value: Option<PseudoElement>) -> Self {
547 match value {
548 Some(PseudoElement::After) => FragmentType::AfterPseudoContent,
549 Some(PseudoElement::Before) => FragmentType::BeforePseudoContent,
550 _ => FragmentType::FragmentBody,
551 }
552 }
553}
554
555static NEXT_SPECIAL_SCROLL_ROOT_ID: AtomicU64 = AtomicU64::new(0);
559
560const SPECIAL_SCROLL_ROOT_ID_MASK: u64 = 0xffff;
563
564fn next_special_id() -> u64 {
566 ((NEXT_SPECIAL_SCROLL_ROOT_ID.fetch_add(1, Ordering::SeqCst) + 1) << 2) &
568 SPECIAL_SCROLL_ROOT_ID_MASK
569}
570
571pub fn combine_id_with_fragment_type(id: usize, fragment_type: FragmentType) -> u64 {
572 debug_assert_eq!(id & (fragment_type as usize), 0);
573 if fragment_type == FragmentType::FragmentBody {
574 id as u64
575 } else {
576 next_special_id() | (fragment_type as u64)
577 }
578}
579
580pub fn node_id_from_scroll_id(id: usize) -> Option<usize> {
581 if (id as u64 & !SPECIAL_SCROLL_ROOT_ID_MASK) != 0 {
582 return Some(id & !3);
583 }
584 None
585}
586
587#[derive(Clone, Debug, MallocSizeOf)]
588pub struct ImageAnimationState {
589 #[ignore_malloc_size_of = "Arc is hard"]
590 pub image: Arc<RasterImage>,
591 pub active_frame: usize,
592 frame_start_time: f64,
593}
594
595impl ImageAnimationState {
596 pub fn new(image: Arc<RasterImage>, last_update_time: f64) -> Self {
597 Self {
598 image,
599 active_frame: 0,
600 frame_start_time: last_update_time,
601 }
602 }
603
604 pub fn image_key(&self) -> Option<ImageKey> {
605 self.image.id
606 }
607
608 pub fn duration_to_next_frame(&self, now: f64) -> Duration {
609 let frame_delay = self
610 .image
611 .frames
612 .get(self.active_frame)
613 .expect("Image frame should always be valid")
614 .delay
615 .unwrap_or_default();
616
617 let time_since_frame_start = (now - self.frame_start_time).max(0.0) * 1000.0;
618 let time_since_frame_start = Duration::from_secs_f64(time_since_frame_start);
619 frame_delay - time_since_frame_start.min(frame_delay)
620 }
621
622 pub fn update_frame_for_animation_timeline_value(&mut self, now: f64) -> bool {
626 if self.image.frames.len() <= 1 {
627 return false;
628 }
629 let image = &self.image;
630 let time_interval_since_last_update = now - self.frame_start_time;
631 let mut remain_time_interval = time_interval_since_last_update -
632 image
633 .frames
634 .get(self.active_frame)
635 .unwrap()
636 .delay
637 .unwrap()
638 .as_secs_f64();
639 let mut next_active_frame_id = self.active_frame;
640 while remain_time_interval > 0.0 {
641 next_active_frame_id = (next_active_frame_id + 1) % image.frames.len();
642 remain_time_interval -= image
643 .frames
644 .get(next_active_frame_id)
645 .unwrap()
646 .delay
647 .unwrap()
648 .as_secs_f64();
649 }
650 if self.active_frame == next_active_frame_id {
651 return false;
652 }
653 self.active_frame = next_active_frame_id;
654 self.frame_start_time = now;
655 true
656 }
657}
658
659#[derive(Debug)]
661pub struct ElementsFromPointResult {
662 pub node: OpaqueNode,
665 pub point_in_target: Point2D<f32, CSSPixel>,
668 pub cursor: Cursor,
671}
672
673bitflags! {
674 pub struct ElementsFromPointFlags: u8 {
675 const FindAll = 0b00000001;
678 }
679}
680
681#[cfg(test)]
682mod test {
683 use std::sync::Arc;
684 use std::time::Duration;
685
686 use ipc_channel::ipc::IpcSharedMemory;
687 use pixels::{CorsStatus, ImageFrame, ImageMetadata, PixelFormat, RasterImage};
688
689 use crate::ImageAnimationState;
690
691 #[test]
692 fn test() {
693 let image_frames: Vec<ImageFrame> = std::iter::repeat_with(|| ImageFrame {
694 delay: Some(Duration::from_millis(100)),
695 byte_range: 0..1,
696 width: 100,
697 height: 100,
698 })
699 .take(10)
700 .collect();
701 let image = RasterImage {
702 metadata: ImageMetadata {
703 width: 100,
704 height: 100,
705 },
706 format: PixelFormat::BGRA8,
707 id: None,
708 bytes: IpcSharedMemory::from_byte(1, 1),
709 frames: image_frames,
710 cors_status: CorsStatus::Unsafe,
711 };
712 let mut image_animation_state = ImageAnimationState::new(Arc::new(image), 0.0);
713
714 assert_eq!(image_animation_state.active_frame, 0);
715 assert_eq!(image_animation_state.frame_start_time, 0.0);
716 assert_eq!(
717 image_animation_state.update_frame_for_animation_timeline_value(0.101),
718 true
719 );
720 assert_eq!(image_animation_state.active_frame, 1);
721 assert_eq!(image_animation_state.frame_start_time, 0.101);
722 assert_eq!(
723 image_animation_state.update_frame_for_animation_timeline_value(0.116),
724 false
725 );
726 assert_eq!(image_animation_state.active_frame, 1);
727 assert_eq!(image_animation_state.frame_start_time, 0.101);
728 }
729}