forked from mirrors/gecko-dev
		
	 c90e25dd1b
			
		
	
	
		c90e25dd1b
		
	
	
	
	
		
			
			<!-- Please describe your changes on the following line: --> This PR fixes two different issues: 1) In non-incremental layout mode if the inline node hasn't changes - the style pass was skipped, that leads to the corresponding ConstructionResult was not produced. When the parent was rebuilt, the child without the ConstructionResult was omited. 2) When the opacity was changed (or other style change, causing only repaint) for image (and others, producing only ConstructionItem) the damage is calculated only from children's flows, not from individual fragments. So for now, let's pretend we've newly constructed the ConstructionItem and thus need to rebuild the parent's flow. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #12602 (github issue number if applicable). <!-- Either: --> - [x] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: d5913035ecef35350897c5fad9960615bbb4cec1
		
			
				
	
	
		
			263 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			263 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| /* 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 std::fmt;
 | |
| use std::sync::Arc;
 | |
| use style::computed_values::display;
 | |
| use style::dom::TRestyleDamage;
 | |
| use style::properties::ServoComputedValues;
 | |
| 
 | |
| bitflags! {
 | |
|     #[doc = "Individual layout actions that may be necessary after restyling."]
 | |
|     pub flags RestyleDamage: u8 {
 | |
|         #[doc = "Repaint the node itself."]
 | |
|         #[doc = "Currently unused; need to decide how this propagates."]
 | |
|         const REPAINT = 0x01,
 | |
| 
 | |
|         #[doc = "Recompute the overflow regions (bounding box of object and all descendants)."]
 | |
|         #[doc = "Propagates down the flow tree because the computation is bottom-up."]
 | |
|         const STORE_OVERFLOW = 0x02,
 | |
| 
 | |
|         #[doc = "Recompute intrinsic inline_sizes (minimum and preferred)."]
 | |
|         #[doc = "Propagates down the flow tree because the computation is"]
 | |
|         #[doc = "bottom-up."]
 | |
|         const BUBBLE_ISIZES = 0x04,
 | |
| 
 | |
|         #[doc = "Recompute actual inline-sizes and block-sizes, only taking out-of-flow children \
 | |
|                  into account. \
 | |
|                  Propagates up the flow tree because the computation is top-down."]
 | |
|         const REFLOW_OUT_OF_FLOW = 0x08,
 | |
| 
 | |
|         #[doc = "Recompute actual inline_sizes and block_sizes."]
 | |
|         #[doc = "Propagates up the flow tree because the computation is"]
 | |
|         #[doc = "top-down."]
 | |
|         const REFLOW = 0x10,
 | |
| 
 | |
|         #[doc = "Re-resolve generated content. \
 | |
|                  Propagates up the flow tree because the computation is inorder."]
 | |
|         const RESOLVE_GENERATED_CONTENT = 0x20,
 | |
| 
 | |
|         #[doc = "The entire flow needs to be reconstructed."]
 | |
|         const RECONSTRUCT_FLOW = 0x40
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl TRestyleDamage for RestyleDamage {
 | |
|     /// For Servo the style source is always the computed values.
 | |
|     type PreExistingComputedValues = Arc<ServoComputedValues>;
 | |
| 
 | |
|     fn empty() -> Self {
 | |
|         RestyleDamage::empty()
 | |
|     }
 | |
| 
 | |
|     fn compute(old: &Arc<ServoComputedValues>,
 | |
|                new: &Arc<ServoComputedValues>) -> RestyleDamage {
 | |
|         compute_damage(old, new)
 | |
|     }
 | |
| 
 | |
|     /// Returns a bitmask that represents a flow that needs to be rebuilt and
 | |
|     /// reflowed.
 | |
|     ///
 | |
|     /// Use this instead of `RestyleDamage::all()` because
 | |
|     /// `RestyleDamage::all()` will result in unnecessary sequential resolution
 | |
|     /// of generated content.
 | |
|     fn rebuild_and_reflow() -> RestyleDamage {
 | |
|         REPAINT | STORE_OVERFLOW | BUBBLE_ISIZES | REFLOW_OUT_OF_FLOW | REFLOW | RECONSTRUCT_FLOW
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl RestyleDamage {
 | |
|     /// Supposing a flow has the given `position` property and this damage,
 | |
|     /// returns the damage that we should add to the *parent* of this flow.
 | |
|     pub fn damage_for_parent(self, child_is_absolutely_positioned: bool) -> RestyleDamage {
 | |
|         if child_is_absolutely_positioned {
 | |
|             self & (REPAINT | STORE_OVERFLOW | REFLOW_OUT_OF_FLOW | RESOLVE_GENERATED_CONTENT)
 | |
|         } else {
 | |
|             self & (REPAINT | STORE_OVERFLOW | REFLOW | REFLOW_OUT_OF_FLOW |
 | |
|                     RESOLVE_GENERATED_CONTENT)
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Supposing the *parent* of a flow with the given `position` property has this damage,
 | |
|     /// returns the damage that we should add to this flow.
 | |
|     pub fn damage_for_child(self,
 | |
|                             parent_is_absolutely_positioned: bool,
 | |
|                             child_is_absolutely_positioned: bool)
 | |
|                             -> RestyleDamage {
 | |
|         match (parent_is_absolutely_positioned, child_is_absolutely_positioned) {
 | |
|             (false, true) => {
 | |
|                 // Absolute children are out-of-flow and therefore insulated from changes.
 | |
|                 //
 | |
|                 // FIXME(pcwalton): Au contraire, if the containing block dimensions change!
 | |
|                 self & REPAINT
 | |
|             }
 | |
|             (true, false) => {
 | |
|                 // Changing the position of an absolutely-positioned block requires us to reflow
 | |
|                 // its kids.
 | |
|                 if self.contains(REFLOW_OUT_OF_FLOW) {
 | |
|                     self | REFLOW
 | |
|                 } else {
 | |
|                     self
 | |
|                 }
 | |
|             }
 | |
|             _ => {
 | |
|                 // TODO(pcwalton): Take floatedness into account.
 | |
|                 self & (REPAINT | REFLOW)
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl fmt::Display for RestyleDamage {
 | |
|     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
 | |
|         let mut first_elem = true;
 | |
| 
 | |
|         let to_iter =
 | |
|             [ (REPAINT, "Repaint")
 | |
|             , (STORE_OVERFLOW, "StoreOverflow")
 | |
|             , (BUBBLE_ISIZES, "BubbleISizes")
 | |
|             , (REFLOW_OUT_OF_FLOW, "ReflowOutOfFlow")
 | |
|             , (REFLOW, "Reflow")
 | |
|             , (RESOLVE_GENERATED_CONTENT, "ResolveGeneratedContent")
 | |
|             , (RECONSTRUCT_FLOW, "ReconstructFlow")
 | |
|             ];
 | |
| 
 | |
|         for &(damage, damage_str) in &to_iter {
 | |
|             if self.contains(damage) {
 | |
|                 if !first_elem { try!(write!(f, " | ")); }
 | |
|                 try!(write!(f, "{}", damage_str));
 | |
|                 first_elem = false;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if first_elem {
 | |
|             try!(write!(f, "NoDamage"));
 | |
|         }
 | |
| 
 | |
|         Ok(())
 | |
|     }
 | |
| }
 | |
| 
 | |
| // 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(
 | |
|     ($old:ident, $new:ident, $damage:ident,
 | |
|      [ $($effect:ident),* ], [ $($style_struct_getter:ident.$name:ident),* ]) => ({
 | |
|         if $( ($old.$style_struct_getter().$name != $new.$style_struct_getter().$name) )||* {
 | |
|             $damage.insert($($effect)|*);
 | |
|             true
 | |
|         } else {
 | |
|             false
 | |
|         }
 | |
|     })
 | |
| );
 | |
| 
 | |
| fn compute_damage(old: &ServoComputedValues, new: &ServoComputedValues) -> RestyleDamage {
 | |
|     let mut damage = RestyleDamage::empty();
 | |
| 
 | |
|     // This should check every CSS property, as enumerated in the fields of
 | |
|     // http://doc.servo.org/style/properties/struct.ServoComputedValues.html
 | |
| 
 | |
|     // FIXME: Test somehow that every property is included.
 | |
| 
 | |
|     add_if_not_equal!(old, new, damage,
 | |
|                       [
 | |
|                           REPAINT,
 | |
|                           STORE_OVERFLOW,
 | |
|                           BUBBLE_ISIZES,
 | |
|                           REFLOW_OUT_OF_FLOW,
 | |
|                           REFLOW,
 | |
|                           RECONSTRUCT_FLOW
 | |
|                       ], [
 | |
|         get_box.float, get_box.display, get_box.position, get_counters.content,
 | |
|         get_counters.counter_reset, get_counters.counter_increment,
 | |
|         get_inheritedbox._servo_under_display_none,
 | |
|         get_list.quotes, get_list.list_style_type,
 | |
| 
 | |
|         // If these text or font properties change, we need to reconstruct the flow so that
 | |
|         // text shaping is re-run.
 | |
|         get_inheritedtext.letter_spacing, get_inheritedtext.text_rendering,
 | |
|         get_inheritedtext.text_transform, get_inheritedtext.word_spacing,
 | |
|         get_inheritedtext.overflow_wrap, get_inheritedtext.text_justify,
 | |
|         get_inheritedtext.white_space, get_inheritedtext.word_break, get_text.text_overflow,
 | |
|         get_font.font_family, get_font.font_style, get_font.font_variant, get_font.font_weight,
 | |
|         get_font.font_size, get_font.font_stretch,
 | |
|         get_inheritedbox.direction, get_inheritedbox.writing_mode,
 | |
|         get_inheritedbox.text_orientation,
 | |
|         get_text.text_decoration, get_text.unicode_bidi,
 | |
|         get_inheritedtable.empty_cells, get_inheritedtable.caption_side,
 | |
|         get_column.column_width, get_column.column_count
 | |
|     ]) || (new.get_box().display == display::T::inline &&
 | |
|            add_if_not_equal!(old, new, damage,
 | |
|                              [REPAINT, STORE_OVERFLOW, BUBBLE_ISIZES, REFLOW_OUT_OF_FLOW, REFLOW,
 | |
|                               RECONSTRUCT_FLOW], [
 | |
|         // For inline boxes only, border/padding styles are used in flow construction (to decide
 | |
|         // whether to create fragments for empty flows).
 | |
|         get_border.border_top_width, get_border.border_right_width,
 | |
|         get_border.border_bottom_width, get_border.border_left_width,
 | |
|         get_padding.padding_top, get_padding.padding_right,
 | |
|         get_padding.padding_bottom, get_padding.padding_left
 | |
|     ])) || add_if_not_equal!(old, new, damage,
 | |
|                             [ REPAINT, STORE_OVERFLOW, BUBBLE_ISIZES, REFLOW_OUT_OF_FLOW, REFLOW ],
 | |
|         [get_border.border_top_width, get_border.border_right_width,
 | |
|         get_border.border_bottom_width, get_border.border_left_width,
 | |
|         get_margin.margin_top, get_margin.margin_right,
 | |
|         get_margin.margin_bottom, get_margin.margin_left,
 | |
|         get_padding.padding_top, get_padding.padding_right,
 | |
|         get_padding.padding_bottom, get_padding.padding_left,
 | |
|         get_position.width, get_position.height,
 | |
|         get_inheritedtext.line_height,
 | |
|         get_inheritedtext.text_align, get_inheritedtext.text_indent,
 | |
|         get_table.table_layout,
 | |
|         get_inheritedtable.border_collapse,
 | |
|         get_inheritedtable.border_spacing,
 | |
|         get_column.column_gap,
 | |
|         get_position.flex_direction,
 | |
|         get_position.flex_wrap,
 | |
|         get_position.justify_content,
 | |
|         get_position.align_items,
 | |
|         get_position.align_content,
 | |
|         get_position.order,
 | |
|         get_position.flex_basis,
 | |
|         get_position.flex_grow,
 | |
|         get_position.flex_shrink,
 | |
|         get_position.align_self
 | |
|     ]) || add_if_not_equal!(old, new, damage,
 | |
|                             [ REPAINT, STORE_OVERFLOW, REFLOW_OUT_OF_FLOW ], [
 | |
|         get_position.top, get_position.left,
 | |
|         get_position.right, get_position.bottom
 | |
|     ]) || add_if_not_equal!(old, new, damage,
 | |
|                             [ REPAINT ], [
 | |
|         get_color.color, get_background.background_color,
 | |
|         get_background.background_image, get_background.background_position,
 | |
|         get_background.background_repeat, get_background.background_attachment,
 | |
|         get_background.background_clip, get_background.background_origin,
 | |
|         get_background.background_size,
 | |
|         get_border.border_top_color, get_border.border_right_color,
 | |
|         get_border.border_bottom_color, get_border.border_left_color,
 | |
|         get_border.border_top_style, get_border.border_right_style,
 | |
|         get_border.border_bottom_style, get_border.border_left_style,
 | |
|         get_border.border_top_left_radius, get_border.border_top_right_radius,
 | |
|         get_border.border_bottom_left_radius, get_border.border_bottom_right_radius,
 | |
|         get_position.z_index, get_box._servo_overflow_clip_box,
 | |
|         get_inheritedtext._servo_text_decorations_in_effect,
 | |
|         get_pointing.cursor, get_pointing.pointer_events,
 | |
|         get_effects.box_shadow, get_effects.clip, get_inheritedtext.text_shadow, get_effects.filter,
 | |
|         get_effects.transform, get_effects.backface_visibility, get_effects.transform_style,
 | |
|         get_effects.transform_origin, get_effects.perspective, get_effects.perspective_origin,
 | |
|         get_effects.mix_blend_mode, get_effects.opacity, get_inheritedbox.image_rendering,
 | |
| 
 | |
|         // Note: May require REFLOW et al. if `visibility: collapse` is implemented.
 | |
|         get_inheritedbox.visibility
 | |
|     ]);
 | |
| 
 | |
|     // If the layer requirements of this flow have changed due to the value
 | |
|     // of the transform, then reflow is required to rebuild the layers.
 | |
|     if old.transform_requires_layer() != new.transform_requires_layer() {
 | |
|         damage.insert(RestyleDamage::rebuild_and_reflow());
 | |
|     }
 | |
| 
 | |
|     damage
 | |
| }
 |