aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout_2020/fragment_tree/base_fragment.rs
blob: ac29bcc976d74ff374b944beb2d6bc3a815455f7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use bitflags::bitflags;
use gfx_traits::{combine_id_with_fragment_type, FragmentType};
use serde::Serialize;
use style::dom::OpaqueNode;
use style::selector_parser::PseudoElement;

use crate::layout_debug::DebugId;

/// This data structure stores fields that are common to all non-base
/// Fragment types and should generally be the first member of all
/// concrete fragments.
#[derive(Debug, Serialize)]
pub(crate) struct BaseFragment {
    /// A tag which identifies the DOM node and pseudo element of this
    /// Fragment's content. If this fragment isn't related to any DOM
    /// node at all, the tag will be None.
    pub tag: Option<Tag>,

    /// An id used to uniquely identify this Fragment in debug builds.
    pub debug_id: DebugId,

    /// Flags which various information about this fragment used during
    /// layout.
    pub flags: FragmentFlags,
}

impl BaseFragment {
    pub(crate) fn anonymous() -> Self {
        BaseFragment {
            tag: None,
            debug_id: DebugId::new(),
            flags: FragmentFlags::empty(),
        }
    }

    /// Returns true if this fragment is non-anonymous and it is for the given
    /// OpaqueNode, regardless of the pseudo element.
    pub(crate) fn is_for_node(&self, node: OpaqueNode) -> bool {
        self.tag.map(|tag| tag.node == node).unwrap_or(false)
    }
}

/// Information necessary to construct a new BaseFragment.
#[derive(Clone, Copy, Debug, Serialize)]
pub(crate) struct BaseFragmentInfo {
    /// The tag to use for the new BaseFragment, if it is not an anonymous Fragment.
    pub tag: Option<Tag>,

    /// The flags to use for the new BaseFragment.
    pub flags: FragmentFlags,
}

impl BaseFragmentInfo {
    pub(crate) fn new_for_node(node: OpaqueNode) -> Self {
        Self {
            tag: Some(Tag::new(node)),
            flags: FragmentFlags::empty(),
        }
    }

    pub(crate) fn anonymous() -> Self {
        Self {
            tag: None,
            flags: FragmentFlags::empty(),
        }
    }
}

impl From<BaseFragmentInfo> for BaseFragment {
    fn from(info: BaseFragmentInfo) -> Self {
        Self {
            tag: info.tag,
            debug_id: DebugId::new(),
            flags: info.flags,
        }
    }
}

bitflags! {
    /// Flags used to track various information about a DOM node during layout.
    #[derive(Clone, Copy, Debug, Serialize)]
    pub(crate) struct FragmentFlags: u8 {
        /// Whether or not the node that created this fragment is a `<body>` element on an HTML document.
        const IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT = 0b00000001;
        /// Whether or not the node that created this Fragment is a `<br>` element.
        const IS_BR_ELEMENT = 0b00000010;
    }
}

/// A data structure used to hold DOM and pseudo-element information about
/// a particular layout object.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
pub(crate) struct Tag {
    pub(crate) node: OpaqueNode,
    pub(crate) pseudo: Option<PseudoElement>,
}

impl Tag {
    /// Create a new Tag for a non-pseudo element. This is mainly used for
    /// matching existing tags, since it does not accept an `info` argument.
    pub(crate) fn new(node: OpaqueNode) -> Self {
        Tag { node, pseudo: None }
    }

    /// Create a new Tag for a pseudo element. This is mainly used for
    /// matching existing tags, since it does not accept an `info` argument.
    pub(crate) fn new_pseudo(node: OpaqueNode, pseudo: Option<PseudoElement>) -> Self {
        Tag { node, pseudo }
    }

    /// Returns true if this tag is for a pseudo element.
    pub(crate) fn is_pseudo(&self) -> bool {
        self.pseudo.is_some()
    }

    pub(crate) fn to_display_list_fragment_id(self) -> u64 {
        let fragment_type = match self.pseudo {
            Some(PseudoElement::Before) => FragmentType::BeforePseudoContent,
            Some(PseudoElement::After) => FragmentType::AfterPseudoContent,
            _ => FragmentType::FragmentBody,
        };
        combine_id_with_fragment_type(self.node.id(), fragment_type) as u64
    }
}