aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/main/layout/incremental.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/main/layout/incremental.rs')
-rw-r--r--src/components/main/layout/incremental.rs198
1 files changed, 198 insertions, 0 deletions
diff --git a/src/components/main/layout/incremental.rs b/src/components/main/layout/incremental.rs
new file mode 100644
index 00000000000..da26ddcfc2e
--- /dev/null
+++ b/src/components/main/layout/incremental.rs
@@ -0,0 +1,198 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+use newcss::complete::CompleteSelectResults;
+
+use script::dom::node::{AbstractNode, LayoutView};
+
+/// Individual layout actions that may be necessary after restyling.
+///
+/// If you add to this enum, also add the value to RestyleDamage::all below.
+/// (FIXME: do this automatically)
+pub enum RestyleEffect {
+ /// Repaint the node itself.
+ /// Currently unused; need to decide how this propagates.
+ Repaint = 0x01,
+
+ /// Recompute intrinsic widths (minimum and preferred).
+ /// Propagates down the flow tree because the computation is
+ /// bottom-up.
+ BubbleWidths = 0x02,
+
+ /// Recompute actual widths and heights.
+ /// Propagates up the flow tree because the computation is
+ /// top-down.
+ Reflow = 0x04,
+}
+
+/// A set of RestyleEffects.
+// FIXME: Switch to librustc/util/enum_set.rs if that gets moved into
+// libextra (Rust #8054)
+pub struct RestyleDamage {
+ priv bits: int
+}
+
+// Provide literal syntax of the form restyle_damage!(Repaint, Reflow)
+macro_rules! restyle_damage(
+ ( $($damage:ident),* ) => (
+ RestyleDamage::none() $( .add($damage) )*
+ )
+)
+
+impl RestyleDamage {
+ pub fn none() -> RestyleDamage {
+ RestyleDamage { bits: 0 }
+ }
+
+ pub fn all() -> RestyleDamage {
+ restyle_damage!(Repaint, BubbleWidths, Reflow)
+ }
+
+ /// Effects of resizing the window.
+ pub fn for_resize() -> RestyleDamage {
+ RestyleDamage::all()
+ }
+
+ pub fn is_empty(self) -> bool {
+ self.bits == 0
+ }
+
+ pub fn is_nonempty(self) -> bool {
+ self.bits != 0
+ }
+
+ pub fn add(self, effect: RestyleEffect) -> RestyleDamage {
+ RestyleDamage { bits: self.bits | (effect as int) }
+ }
+
+ pub fn has(self, effect: RestyleEffect) -> bool {
+ (self.bits & (effect as int)) != 0
+ }
+
+ pub fn lacks(self, effect: RestyleEffect) -> bool {
+ (self.bits & (effect as int)) == 0
+ }
+
+ pub fn union(self, other: RestyleDamage) -> RestyleDamage {
+ RestyleDamage { bits: self.bits | other.bits }
+ }
+
+ pub fn union_in_place(&mut self, other: RestyleDamage) {
+ self.bits = self.bits | other.bits;
+ }
+
+ pub fn intersect(self, other: RestyleDamage) -> RestyleDamage {
+ RestyleDamage { bits: self.bits & other.bits }
+ }
+
+ /// Elements of self which should also get set on any ancestor flow.
+ pub fn propagate_up(self) -> RestyleDamage {
+ self.intersect(restyle_damage!(Reflow))
+ }
+
+ /// Elements of self which should also get set on any child flows.
+ pub fn propagate_down(self) -> RestyleDamage {
+ self.intersect(restyle_damage!(BubbleWidths))
+ }
+}
+
+// NB: We need the braces inside the RHS due to Rust #8012. This particular
+// version of this macro might be safe anyway, but we want to avoid silent
+// breakage on modifications.
+macro_rules! add_if_not_equal(
+ ([ $($effect:ident),* ], [ $($getter:ident),* ]) => ({
+ if $( (old.$getter() != new.$getter()) )||* {
+ damage.union_in_place( restyle_damage!( $($effect),* ) );
+ }
+ })
+)
+
+pub fn compute_damage(node: &AbstractNode<LayoutView>,
+ old_results: &CompleteSelectResults, new_results: &CompleteSelectResults)
+ -> RestyleDamage {
+ let old = old_results.computed_style();
+ let new = new_results.computed_style();
+ let mut damage = RestyleDamage::none();
+
+ // This checks every CSS property, as enumerated in
+ // impl<'self> CssComputedStyle<'self>
+ // in src/support/netsurfcss/rust-netsurfcss/netsurfcss.rc.
+
+ // FIXME: We can short-circuit more of this.
+
+ add_if_not_equal!([ Repaint ],
+ [ color, background_color, border_top_color, border_right_color,
+ border_bottom_color, border_left_color ]);
+
+ add_if_not_equal!([ Repaint, BubbleWidths, Reflow ],
+ [ border_top_width, border_right_width, border_bottom_width,
+ border_left_width, margin_top, margin_right, margin_bottom, margin_left,
+ padding_top, padding_right, padding_bottom, padding_left, position,
+ width, height, float, font_family, font_size, font_style, font_weight,
+ text_align, text_decoration, line_height ]);
+
+ // Handle 'display' specially because it has this 'is_root' parameter.
+ let is_root = node.is_root();
+ if old.display(is_root) != new.display(is_root) {
+ damage.union_in_place(restyle_damage!(Repaint, BubbleWidths, Reflow));
+ }
+
+ // FIXME: test somehow that we checked every CSS property
+
+ damage
+}
+
+
+#[cfg(test)]
+mod restyle_damage_tests {
+ use super::*;
+
+ #[test]
+ fn none_is_empty() {
+ let d = RestyleDamage::none();
+ assert!(!d.has(Repaint));
+ assert!(!d.has(BubbleWidths));
+ assert!(d.lacks(Repaint));
+ assert!(d.lacks(BubbleWidths));
+ }
+
+ #[test]
+ fn all_is_full() {
+ let d = RestyleDamage::all();
+ assert!(d.has(Repaint));
+ assert!(d.has(BubbleWidths));
+ assert!(!d.lacks(Repaint));
+ assert!(!d.lacks(BubbleWidths));
+ }
+
+ #[test]
+ fn can_add() {
+ assert!(RestyleDamage::none().add(BubbleWidths).has(BubbleWidths));
+ }
+
+ #[test]
+ fn can_union() {
+ let d = restyle_damage!(Repaint).union(restyle_damage!(BubbleWidths));
+ assert!(d.has(Repaint));
+ assert!(d.has(BubbleWidths));
+ }
+
+ #[test]
+ fn can_union_in_place() {
+ let mut d = restyle_damage!(Repaint);
+ d.union_in_place(restyle_damage!(BubbleWidths));
+ assert!(d.has(Repaint));
+ assert!(d.has(BubbleWidths));
+ }
+
+ #[test]
+ fn can_intersect() {
+ let x = restyle_damage!(Repaint, BubbleWidths);
+ let y = restyle_damage!(Repaint, Reflow);
+ let d = x.intersect(y);
+ assert!(d.has(Repaint));
+ assert!(d.lacks(BubbleWidths));
+ assert!(d.lacks(Reflow));
+ }
+}