diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2016-03-31 00:47:07 +0530 |
---|---|---|
committer | bors-servo <lbergstrom+bors@mozilla.com> | 2016-03-31 00:47:07 +0530 |
commit | 723989b9dddeb9bcdc28dc7d640fd6fd7247a27f (patch) | |
tree | 1cc0d0875809577e8d2dafab2a3623b043022523 | |
parent | e1485718128bff632eff5445583e925ff796bdba (diff) | |
parent | 46829bd53ced5d7d5a4b4c6600f2061cc8720536 (diff) | |
download | servo-723989b9dddeb9bcdc28dc7d640fd6fd7247a27f.tar.gz servo-723989b9dddeb9bcdc28dc7d640fd6fd7247a27f.zip |
Auto merge of #10252 - emilio:selection, r=mbrubeck
Implement ::selection pseudo-element
It only supports `color` and `background`, for now, but it shouldn't be hard to add more properties (like text-shadow).
r? @mbrubeck
<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/10252)
<!-- Reviewable:end -->
-rw-r--r-- | components/layout/construct.rs | 19 | ||||
-rw-r--r-- | components/layout/display_list_builder.rs | 13 | ||||
-rw-r--r-- | components/layout/flow.rs | 3 | ||||
-rw-r--r-- | components/layout/fragment.rs | 12 | ||||
-rw-r--r-- | components/layout/generated_content.rs | 1 | ||||
-rw-r--r-- | components/layout/inline.rs | 1 | ||||
-rw-r--r-- | components/layout/query.rs | 11 | ||||
-rw-r--r-- | components/layout/text.rs | 1 | ||||
-rw-r--r-- | components/layout/wrapper.rs | 25 | ||||
-rw-r--r-- | components/style/selector_impl.rs | 3 | ||||
-rw-r--r-- | tests/unit/layout/size_of.rs | 2 | ||||
-rw-r--r-- | tests/unit/util/lib.rs | 2 |
12 files changed, 70 insertions, 23 deletions
diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 239dc52e01c..d9727e5c8d9 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -217,6 +217,7 @@ impl InlineFragmentsAccumulator { address: node.opaque(), pseudo: node.get_pseudo_element_type().strip(), style: node.style().clone(), + selected_style: node.selected_style().clone(), flags: InlineFragmentNodeFlags::empty(), }), bidi_control_chars: None, @@ -360,6 +361,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let fragment = Fragment::from_opaque_node_and_style(child_node.opaque(), PseudoElementType::Normal, style, + child_node.selected_style().clone(), child_node.restyle_damage(), SpecificFragmentInfo::TableRow); let mut new_child: FlowRef = Arc::new(TableRowFlow::from_fragment(fragment)); @@ -373,6 +375,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let fragment = Fragment::from_opaque_node_and_style(child_node.opaque(), PseudoElementType::Normal, style, + child_node.selected_style().clone(), child_node.restyle_damage(), SpecificFragmentInfo::Table); let mut new_child: FlowRef = Arc::new(TableFlow::from_fragment(fragment)); @@ -387,6 +390,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> Fragment::from_opaque_node_and_style(child_node.opaque(), PseudoElementType::Normal, style, + child_node.selected_style().clone(), child_node.restyle_damage(), SpecificFragmentInfo::TableWrapper); let mut new_child: FlowRef = Arc::new(TableWrapperFlow::from_fragment(fragment, None)); @@ -584,6 +588,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let fragment = Fragment::from_opaque_node_and_style(whitespace_node, whitespace_pseudo, whitespace_style, + node.selected_style().clone(), whitespace_damage, fragment_info); inline_fragment_accumulator.fragments.fragments.push_back(fragment); @@ -713,6 +718,8 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let mut style = (*style).clone(); properties::modify_style_for_text(&mut style); + let selected_style = node.selected_style(); + match text_content { TextContent::Text(string) => { let info = box UnscannedTextFragmentInfo::new(string, selection); @@ -720,7 +727,8 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> fragments.fragments.push_back(Fragment::from_opaque_node_and_style( node.opaque(), node.get_pseudo_element_type().strip(), - style.clone(), + style, + selected_style.clone(), node.restyle_damage(), specific_fragment_info)) } @@ -740,6 +748,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> node.opaque(), node.get_pseudo_element_type().strip(), style.clone(), + selected_style.clone(), node.restyle_damage(), specific_fragment_info)) } @@ -823,6 +832,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let kid_node = flow.as_block().fragment.node; let kid_pseudo = flow.as_block().fragment.pseudo.clone(); let kid_style = flow.as_block().fragment.style.clone(); + let kid_selected_style = flow.as_block().fragment.selected_style.clone(); let kid_restyle_damage = flow.as_block().fragment.restyle_damage; let fragment_info = SpecificFragmentInfo::InlineAbsolute( InlineAbsoluteFragmentInfo::new(flow)); @@ -830,6 +840,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> kid_node, kid_pseudo, kid_style, + kid_selected_style, kid_restyle_damage, fragment_info)); fragment_accumulator.fragments @@ -865,6 +876,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let fragment = Fragment::from_opaque_node_and_style(whitespace_node, whitespace_pseudo, whitespace_style, + node.selected_style().clone(), whitespace_damage, fragment_info); fragment_accumulator.fragments.fragments.push_back(fragment) @@ -962,6 +974,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let fragment = Fragment::from_opaque_node_and_style(node.opaque(), node.get_pseudo_element_type().strip(), modified_style.clone(), + node.selected_style().clone(), node.restyle_damage(), fragment_info); @@ -994,6 +1007,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let fragment = Fragment::from_opaque_node_and_style(node.opaque(), PseudoElementType::Normal, style, + node.selected_style().clone(), node.restyle_damage(), fragment_info); @@ -1853,7 +1867,8 @@ fn control_chars_to_fragment(node: &InlineFragmentNodeInfo, properties::modify_style_for_text(&mut style); Fragment::from_opaque_node_and_style(node.address, node.pseudo, - style, + style.clone(), + node.selected_style.clone(), restyle_damage, info) } diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 7c65db972cf..e6034bb29ab 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -104,10 +104,6 @@ impl<'a> DisplayListBuildState<'a> { /// The logical width of an insertion point: at the moment, a one-pixel-wide line. const INSERTION_POINT_LOGICAL_WIDTH: Au = Au(1 * AU_PER_PX); -// Colors for selected text. TODO (#8077): Use the ::selection pseudo-element to set these. -const SELECTION_FOREGROUND_COLOR: RGBA = RGBA { red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0 }; -const SELECTION_BACKGROUND_COLOR: RGBA = RGBA { red: 0.69, green: 0.84, blue: 1.0, alpha: 1.0 }; - // TODO(gw): The transforms spec says that perspective length must // be positive. However, there is some confusion between the spec // and browser implementations as to handling the case of 0 for the @@ -931,6 +927,8 @@ impl FragmentDisplayListBuilding for Fragment { // // TODO: Allow non-text fragments to be selected too. if scanned_text_fragment_info.selected() { + let style = self.selected_style(); + let background_color = style.resolve_color(style.get_background().background_color); state.add_display_item( DisplayItem::SolidColorClass(box SolidColorDisplayItem { base: BaseDisplayItem::new(stacking_relative_border_box, @@ -938,7 +936,7 @@ impl FragmentDisplayListBuilding for Fragment { &*self.style, Cursor::DefaultCursor), &clip), - color: SELECTION_BACKGROUND_COLOR.to_gfx_color() + color: background_color.to_gfx_color(), }), display_list_section); } @@ -1116,11 +1114,14 @@ impl FragmentDisplayListBuilding for Fragment { // // NB: According to CSS-BACKGROUNDS, text shadows render in *reverse* order (front // to back). + + // TODO(emilio): Allow changing more properties by ::selection let text_color = if text_fragment.selected() { - SELECTION_FOREGROUND_COLOR + self.selected_style().get_color().color } else { self.style().get_color().color }; + for text_shadow in self.style.get_effects().text_shadow.0.iter().rev() { let offset = &Point2D::new(text_shadow.offset_x, text_shadow.offset_y); let color = self.style().resolve_color(text_shadow.color); diff --git a/components/layout/flow.rs b/components/layout/flow.rs index 41f502d5770..6f603c7a1ac 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -1286,6 +1286,7 @@ impl<'a> ImmutableFlowUtils for &'a Flow { node.opaque(), PseudoElementType::Normal, style, + node.selected_style().clone(), node.restyle_damage(), SpecificFragmentInfo::TableRow); Arc::new(TableRowFlow::from_fragment(fragment)) @@ -1298,6 +1299,7 @@ impl<'a> ImmutableFlowUtils for &'a Flow { node.opaque(), PseudoElementType::Normal, style, + node.selected_style().clone(), node.restyle_damage(), SpecificFragmentInfo::TableCell); let hide = node.style().get_inheritedtable().empty_cells == empty_cells::T::hide; @@ -1308,6 +1310,7 @@ impl<'a> ImmutableFlowUtils for &'a Flow { Fragment::from_opaque_node_and_style(node.opaque(), PseudoElementType::Normal, style, + node.selected_style().clone(), node.restyle_damage(), SpecificFragmentInfo::Generic); Arc::new(BlockFlow::from_fragment(fragment, None)) diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index f5f1677ad3d..8a6d8bf1c85 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -85,6 +85,9 @@ pub struct Fragment { /// The CSS style of this fragment. pub style: Arc<ServoComputedValues>, + /// The CSS style of this fragment when it's selected + pub selected_style: Arc<ServoComputedValues>, + /// The position of this fragment relative to its owning flow. The size includes padding and /// border, but not margin. /// @@ -798,6 +801,7 @@ impl Fragment { Fragment { node: node.opaque(), style: style, + selected_style: node.selected_style().clone(), restyle_damage: restyle_damage, border_box: LogicalRect::zero(writing_mode), border_padding: LogicalMargin::zero(writing_mode), @@ -815,6 +819,7 @@ impl Fragment { pub fn from_opaque_node_and_style(node: OpaqueNode, pseudo: PseudoElementType<()>, style: Arc<ServoComputedValues>, + selected_style: Arc<ServoComputedValues>, mut restyle_damage: RestyleDamage, specific: SpecificFragmentInfo) -> Fragment { @@ -825,6 +830,7 @@ impl Fragment { Fragment { node: node, style: style, + selected_style: selected_style, restyle_damage: restyle_damage, border_box: LogicalRect::zero(writing_mode), border_padding: LogicalMargin::zero(writing_mode), @@ -858,6 +864,7 @@ impl Fragment { Fragment { node: self.node, style: self.style.clone(), + selected_style: self.selected_style.clone(), restyle_damage: restyle_damage, border_box: new_border_box, border_padding: self.border_padding, @@ -1286,6 +1293,11 @@ impl Fragment { &*self.style } + #[inline(always)] + pub fn selected_style(&self) -> &ServoComputedValues { + &*self.selected_style + } + pub fn white_space(&self) -> white_space::T { self.style().get_inheritedtext().white_space } diff --git a/components/layout/generated_content.rs b/components/layout/generated_content.rs index d3e9df73f79..7cde02a8781 100644 --- a/components/layout/generated_content.rs +++ b/components/layout/generated_content.rs @@ -438,6 +438,7 @@ fn render_text(layout_context: &LayoutContext, box UnscannedTextFragmentInfo::new(string, None)); fragments.push_back(Fragment::from_opaque_node_and_style(node, pseudo, + style.clone(), style, RestyleDamage::rebuild_and_reflow(), info)); diff --git a/components/layout/inline.rs b/components/layout/inline.rs index 7cfa976de4b..c0e209d5f78 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -1854,6 +1854,7 @@ impl fmt::Debug for InlineFlow { pub struct InlineFragmentNodeInfo { pub address: OpaqueNode, pub style: Arc<ServoComputedValues>, + pub selected_style: Arc<ServoComputedValues>, pub pseudo: PseudoElementType<()>, pub flags: InlineFragmentNodeFlags, } diff --git a/components/layout/query.rs b/components/layout/query.rs index a998f1dae13..65296bc1b4e 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -534,11 +534,12 @@ pub fn process_resolved_style_request<N: LayoutNode>( requested_node: N, pseudo: &Option<PseudoElement>, property: &Atom, layout_root: &mut FlowRef) -> Option<String> { let layout_node = requested_node.to_threadsafe(); - let layout_node = match pseudo { - &Some(PseudoElement::Before) => layout_node.get_before_pseudo(), - &Some(PseudoElement::After) => layout_node.get_after_pseudo(), - &Some(PseudoElement::DetailsSummary) => layout_node.get_details_summary_pseudo(), - &Some(PseudoElement::DetailsContent) => layout_node.get_details_content_pseudo(), + let layout_node = match *pseudo { + Some(PseudoElement::Before) => layout_node.get_before_pseudo(), + Some(PseudoElement::After) => layout_node.get_after_pseudo(), + Some(PseudoElement::DetailsSummary) => layout_node.get_details_summary_pseudo(), + Some(PseudoElement::DetailsContent) => layout_node.get_details_content_pseudo(), + Some(PseudoElement::Selection) => None, _ => Some(layout_node) }; diff --git a/components/layout/text.rs b/components/layout/text.rs index 50b36e05e8b..30ce9f4bb41 100644 --- a/components/layout/text.rs +++ b/components/layout/text.rs @@ -368,6 +368,7 @@ impl TextRunScanner { let new_fragment = old_fragment.transform( bounding_box_size, SpecificFragmentInfo::ScannedText(new_text_fragment_info)); + out_fragments.push(new_fragment) } } diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 387e5238d07..a0f7c54de93 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -702,11 +702,14 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq { }) } + // TODO(emilio): Since the ::-details-* pseudos are internal, just affecting one element, and + // only changing `display` property when the element `open` attribute changes, this should be + // eligible for not being cascaded eagerly, reading the display property from layout instead. #[inline] fn get_details_summary_pseudo(&self) -> Option<Self> { if self.is_element() && - self.as_element().get_local_name() == &atom!("details") && - self.as_element().get_namespace() == &ns!(html) { + self.as_element().get_local_name() == &atom!("details") && + self.as_element().get_namespace() == &ns!(html) { self.borrow_layout_data().unwrap() .style_data.per_pseudo .get(&PseudoElement::DetailsSummary) @@ -721,8 +724,8 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq { #[inline] fn get_details_content_pseudo(&self) -> Option<Self> { if self.is_element() && - self.as_element().get_local_name() == &atom!("details") && - self.as_element().get_namespace() == &ns!(html) { + self.as_element().get_local_name() == &atom!("details") && + self.as_element().get_namespace() == &ns!(html) { self.borrow_layout_data().unwrap() .style_data.per_pseudo .get(&PseudoElement::DetailsContent) @@ -764,6 +767,13 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq { }) } + #[inline] + fn selected_style(&self) -> Ref<Arc<ServoComputedValues>> { + Ref::map(self.borrow_layout_data().unwrap(), |data| { + data.style_data.per_pseudo.get(&PseudoElement::Selection).unwrap_or(data.style_data.style.as_ref().unwrap()) + }) + } + /// Removes the style from this node. /// /// Unlike the version on TNode, this handles pseudo-elements. @@ -1015,7 +1025,7 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { } fn text_content(&self) -> TextContent { - if self.pseudo != PseudoElementType::Normal { + if self.pseudo.is_before_or_after() { let data = &self.borrow_layout_data().unwrap().style_data; let style = if self.pseudo.is_before() { @@ -1136,7 +1146,6 @@ impl<ConcreteNode> Iterator for ThreadSafeLayoutNodeChildrenIterator<ConcreteNod type Item = ConcreteNode; fn next(&mut self) -> Option<ConcreteNode> { match self.parent_node.get_pseudo_element_type() { - PseudoElementType::Before(_) | PseudoElementType::After(_) => None, PseudoElementType::DetailsSummary(_) => { @@ -1162,8 +1171,8 @@ impl<ConcreteNode> Iterator for ThreadSafeLayoutNodeChildrenIterator<ConcreteNod let node = self.current_node.clone(); let node = node.and_then(|node| { if node.is_element() && - node.as_element().get_local_name() == &atom!("summary") && - node.as_element().get_namespace() == &ns!(html) { + node.as_element().get_local_name() == &atom!("summary") && + node.as_element().get_namespace() == &ns!(html) { unsafe { node.dangerous_next_sibling() } } else { Some(node) diff --git a/components/style/selector_impl.rs b/components/style/selector_impl.rs index 7fcdab1cc6b..7d6c7efc267 100644 --- a/components/style/selector_impl.rs +++ b/components/style/selector_impl.rs @@ -26,6 +26,7 @@ pub trait SelectorImplExt : SelectorImpl + Sized { pub enum PseudoElement { Before, After, + Selection, DetailsSummary, DetailsContent, } @@ -105,6 +106,7 @@ impl SelectorImpl for ServoSelectorImpl { let pseudo_element = match_ignore_ascii_case! { name, "before" => Before, "after" => After, + "selection" => Selection, "-servo-details-summary" => if context.in_user_agent_stylesheet { DetailsSummary } else { @@ -136,6 +138,7 @@ impl SelectorImplExt for ServoSelectorImpl { fun(PseudoElement::After); fun(PseudoElement::DetailsContent); fun(PseudoElement::DetailsSummary); + fun(PseudoElement::Selection); } #[inline] diff --git a/tests/unit/layout/size_of.rs b/tests/unit/layout/size_of.rs index 4c47cee0bd8..f79e352cdc9 100644 --- a/tests/unit/layout/size_of.rs +++ b/tests/unit/layout/size_of.rs @@ -7,7 +7,7 @@ use std::mem::size_of; #[test] fn test_size_of_fragment() { - let expected = 160; + let expected = 168; let actual = size_of::<Fragment>(); if actual < expected { diff --git a/tests/unit/util/lib.rs b/tests/unit/util/lib.rs index b3157b85ca0..a844057a4b0 100644 --- a/tests/unit/util/lib.rs +++ b/tests/unit/util/lib.rs @@ -2,7 +2,7 @@ * 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/. */ -#![cfg_attr(test, feature(plugin, custom_derive, heap_api))] +#![cfg_attr(test, feature(plugin, custom_derive))] #![cfg_attr(test, plugin(plugins))] #![feature(alloc)] |