diff options
author | Rizky Luthfianto <mrluthfianto@gmail.com> | 2015-11-19 23:30:39 +0700 |
---|---|---|
committer | Rizky Luthfianto <mrluthfianto@gmail.com> | 2015-11-19 23:30:39 +0700 |
commit | 2c7117d73bf3536aa563f52b7b7c2a578015709d (patch) | |
tree | ee69cdaeb9b237fdbd8573152267bf93a73823df /components | |
parent | a5babb89a02b9b84a8cd62554a5ceef9efb0d481 (diff) | |
download | servo-2c7117d73bf3536aa563f52b7b7c2a578015709d.tar.gz servo-2c7117d73bf3536aa563f52b7b7c2a578015709d.zip |
refactor(layout_task.rs): move some functions to query.rs
Diffstat (limited to 'components')
-rw-r--r-- | components/layout/layout_task.rs | 305 | ||||
-rw-r--r-- | components/layout/query.rs | 290 |
2 files changed, 297 insertions, 298 deletions
diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index 0ce3744d9ac..e4cfcefeaf5 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -13,7 +13,6 @@ use azure::azure::AzColor; use canvas_traits::CanvasMsg; use construct::ConstructionResult; use context::{SharedLayoutContext, StylistWrapper, heap_size_of_local_context}; -use cssparser::ToCss; use data::LayoutDataWrapper; use display_list_builder::ToGfxColor; use euclid::Matrix4; @@ -24,7 +23,6 @@ use euclid::size::Size2D; use flow::{self, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils}; use flow_ref::{self, FlowRef}; use fnv::FnvHasher; -use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo}; use gfx::display_list::{ClippingRegion, DisplayList, LayerInfo, OpaqueNode, StackingContext}; use gfx::font_cache_task::FontCacheTask; use gfx::font_context; @@ -40,21 +38,18 @@ use msg::compositor_msg::{Epoch, LayerId, ScrollPolicy}; use msg::constellation_msg::ScriptMsg as ConstellationMsg; use msg::constellation_msg::{ConstellationChan, Failure, PipelineId}; use net_traits::image_cache_task::{ImageCacheChan, ImageCacheResult, ImageCacheTask}; -use opaque_node::OpaqueNodeMethods; use parallel::{self, WorkQueueData}; use profile_traits::mem::{self, Report, ReportKind, ReportsChan}; use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType}; use profile_traits::time::{self, TimerMetadata, profile}; use query::{LayoutRPCImpl, process_content_box_request, process_content_boxes_request}; -use query::{MarginPadding, MarginRetrievingFragmentBorderBoxIterator, PositionProperty}; -use query::{PositionRetrievingFragmentBorderBoxIterator, Side}; +use query::{process_node_geometry_request, process_offset_parent_query, process_resolved_style_request}; use script::dom::node::LayoutData; use script::layout_interface::Animation; use script::layout_interface::{LayoutRPC, OffsetParentResponse}; use script::layout_interface::{Msg, NewLayoutTaskInfo, Reflow, ReflowGoal, ReflowQueryType}; -use script::layout_interface::{ScriptLayoutChan, ScriptReflow, TrustedNodeAddress}; +use script::layout_interface::{ScriptLayoutChan, ScriptReflow}; use script_traits::{ConstellationControlMsg, LayoutControlMsg, OpaqueScriptLayoutChannel}; -use selectors::parser::PseudoElement; use sequential; use serde_json; use std::borrow::ToOwned; @@ -65,16 +60,12 @@ use std::ops::{Deref, DerefMut}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::mpsc::{channel, Sender, Receiver}; use std::sync::{Arc, Mutex, MutexGuard}; -use string_cache::Atom; -use style::computed_values::{self, filter, mix_blend_mode}; +use style::computed_values::{filter, mix_blend_mode}; use style::media_queries::{Device, MediaType}; -use style::properties::longhands::{display, position}; -use style::properties::style_structs; use style::selector_matching::{Stylist, USER_OR_USER_AGENT_STYLESHEETS}; use style::stylesheets::{CSSRuleIteratorExt, Stylesheet}; -use style::values::AuExtensionMethods; use url::Url; -use util::geometry::{MAX_RECT, ZERO_POINT}; +use util::geometry::MAX_RECT; use util::ipc::OptionalIpcSender; use util::logical_geometry::LogicalPoint; use util::mem::HeapSizeOf; @@ -82,7 +73,7 @@ use util::opts; use util::task::spawn_named_with_send_on_failure; use util::task_state; use util::workqueue::WorkQueue; -use wrapper::{LayoutDocument, LayoutElement, LayoutNode, ServoLayoutNode, ThreadSafeLayoutNode}; +use wrapper::{LayoutDocument, LayoutElement, LayoutNode, ServoLayoutNode}; /// The number of screens of data we're allowed to generate display lists for in each direction. pub const DISPLAY_PORT_SIZE_FACTOR: i32 = 8; @@ -810,168 +801,6 @@ impl LayoutTask { traversal); } - fn process_node_geometry_request(&self, - requested_node: TrustedNodeAddress, - layout_root: &mut FlowRef) - -> Rect<i32> { - let requested_node: OpaqueNode = OpaqueNodeMethods::from_script_node(requested_node); - let mut iterator = FragmentLocatingFragmentIterator::new(requested_node); - sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator); - iterator.client_rect - } - - /// Return the resolved value of property for a given (pseudo)element. - /// https://drafts.csswg.org/cssom/#resolved-value - fn process_resolved_style_request(&self, - requested_node: TrustedNodeAddress, - pseudo: &Option<PseudoElement>, - property: &Atom, - layout_root: &mut FlowRef) - -> Option<String> { - let node = unsafe { ServoLayoutNode::new(&requested_node) }; - - let layout_node = ThreadSafeLayoutNode::new(&node); - let layout_node = match pseudo { - &Some(PseudoElement::Before) => layout_node.get_before_pseudo(), - &Some(PseudoElement::After) => layout_node.get_after_pseudo(), - _ => Some(layout_node) - }; - - let layout_node = match layout_node { - None => { - // The pseudo doesn't exist, return nothing. Chrome seems to query - // the element itself in this case, Firefox uses the resolved value. - // https://www.w3.org/Bugs/Public/show_bug.cgi?id=29006 - return None; - } - Some(layout_node) => layout_node - }; - - let style = &*layout_node.style(); - - let positioned = match style.get_box().position { - position::computed_value::T::relative | - /*position::computed_value::T::sticky |*/ - position::computed_value::T::fixed | - position::computed_value::T::absolute => true, - _ => false - }; - - //TODO: determine whether requested property applies to the element. - // eg. width does not apply to non-replaced inline elements. - // Existing browsers disagree about when left/top/right/bottom apply - // (Chrome seems to think they never apply and always returns resolved values). - // There are probably other quirks. - let applies = true; - - fn used_value_for_position_property(layout_node: ThreadSafeLayoutNode, - layout_root: &mut FlowRef, - requested_node: TrustedNodeAddress, - property: &Atom) -> Option<String> { - let layout_data = layout_node.borrow_layout_data(); - let position = layout_data.as_ref().map(|layout_data| { - match layout_data.data.flow_construction_result { - ConstructionResult::Flow(ref flow_ref, _) => - flow::base(flow_ref.deref()).stacking_relative_position, - // TODO(dzbarsky) search parents until we find node with a flow ref. - // https://github.com/servo/servo/issues/8307 - _ => ZERO_POINT - } - }).unwrap_or(ZERO_POINT); - let property = match *property { - atom!("bottom") => PositionProperty::Bottom, - atom!("top") => PositionProperty::Top, - atom!("left") => PositionProperty::Left, - atom!("right") => PositionProperty::Right, - atom!("width") => PositionProperty::Width, - atom!("height") => PositionProperty::Height, - _ => unreachable!() - }; - let requested_node: OpaqueNode = - OpaqueNodeMethods::from_script_node(requested_node); - let mut iterator = - PositionRetrievingFragmentBorderBoxIterator::new(requested_node, - property, - position); - sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, - &mut iterator); - iterator.result.map(|r| r.to_css_string()) - } - - // TODO: we will return neither the computed nor used value for margin and padding. - // Firefox returns blank strings for the computed value of shorthands, - // so this should be web-compatible. - match *property { - atom!("margin-bottom") | atom!("margin-top") | - atom!("margin-left") | atom!("margin-right") | - atom!("padding-bottom") | atom!("padding-top") | - atom!("padding-left") | atom!("padding-right") - if applies && style.get_box().display != display::computed_value::T::none => { - let (margin_padding, side) = match *property { - atom!("margin-bottom") => (MarginPadding::Margin, Side::Bottom), - atom!("margin-top") => (MarginPadding::Margin, Side::Top), - atom!("margin-left") => (MarginPadding::Margin, Side::Left), - atom!("margin-right") => (MarginPadding::Margin, Side::Right), - atom!("padding-bottom") => (MarginPadding::Padding, Side::Bottom), - atom!("padding-top") => (MarginPadding::Padding, Side::Top), - atom!("padding-left") => (MarginPadding::Padding, Side::Left), - atom!("padding-right") => (MarginPadding::Padding, Side::Right), - _ => unreachable!() - }; - let requested_node: OpaqueNode = - OpaqueNodeMethods::from_script_node(requested_node); - let mut iterator = - MarginRetrievingFragmentBorderBoxIterator::new(requested_node, - side, - margin_padding, - style.writing_mode); - sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, - &mut iterator); - iterator.result.map(|r| r.to_css_string()) - }, - - atom!("bottom") | atom!("top") | atom!("right") | - atom!("left") - if applies && positioned && style.get_box().display != - display::computed_value::T::none => { - used_value_for_position_property(layout_node, layout_root, requested_node, property) - } - atom!("width") | atom!("height") - if applies && style.get_box().display != - display::computed_value::T::none => { - used_value_for_position_property(layout_node, layout_root, requested_node, property) - } - // FIXME: implement used value computation for line-height - ref property => { - style.computed_value_to_string(property.as_slice()).ok() - } - } - } - - fn process_offset_parent_query(&self, - requested_node: TrustedNodeAddress, - layout_root: &mut FlowRef) - -> OffsetParentResponse { - let requested_node: OpaqueNode = OpaqueNodeMethods::from_script_node(requested_node); - let mut iterator = ParentOffsetBorderBoxIterator::new(requested_node); - sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator); - let parent_info_index = iterator.parent_nodes.iter().rposition(|info| info.is_some()); - match parent_info_index { - Some(parent_info_index) => { - let parent = iterator.parent_nodes[parent_info_index].as_ref().unwrap(); - let origin = iterator.node_border_box.origin - parent.border_box.origin; - let size = iterator.node_border_box.size; - OffsetParentResponse { - node_address: Some(parent.node_address.to_untrusted_node_address()), - rect: Rect::new(origin, size), - } - } - None => { - OffsetParentResponse::empty() - } - } - } - fn compute_abs_pos_and_build_display_list(&mut self, data: &Reflow, layout_root: &mut FlowRef, @@ -1203,16 +1032,13 @@ impl LayoutTask { ReflowQueryType::ContentBoxesQuery(node) => rw_data.content_boxes_response = process_content_boxes_request(node, &mut root_flow), ReflowQueryType::NodeGeometryQuery(node) => - rw_data.client_rect_response = self.process_node_geometry_request(node, &mut root_flow), + rw_data.client_rect_response = process_node_geometry_request(node, &mut root_flow), ReflowQueryType::ResolvedStyleQuery(node, ref pseudo, ref property) => { rw_data.resolved_style_response = - self.process_resolved_style_request(node, - pseudo, - property, - &mut root_flow) + process_resolved_style_request(node, pseudo, property, &mut root_flow) } ReflowQueryType::OffsetParentQuery(node) => - rw_data.offset_parent_response = self.process_offset_parent_query(node, &mut root_flow), + rw_data.offset_parent_response = process_offset_parent_query(node, &mut root_flow), ReflowQueryType::NoQuery => {} } } @@ -1461,121 +1287,6 @@ impl LayoutTask { } } -struct FragmentLocatingFragmentIterator { - node_address: OpaqueNode, - client_rect: Rect<i32>, -} - -impl FragmentLocatingFragmentIterator { - fn new(node_address: OpaqueNode) -> FragmentLocatingFragmentIterator { - FragmentLocatingFragmentIterator { - node_address: node_address, - client_rect: Rect::zero() - } - } -} - -struct ParentBorderBoxInfo { - node_address: OpaqueNode, - border_box: Rect<Au>, -} - -struct ParentOffsetBorderBoxIterator { - node_address: OpaqueNode, - last_level: i32, - has_found_node: bool, - node_border_box: Rect<Au>, - parent_nodes: Vec<Option<ParentBorderBoxInfo>>, -} - -impl ParentOffsetBorderBoxIterator { - fn new(node_address: OpaqueNode) -> ParentOffsetBorderBoxIterator { - ParentOffsetBorderBoxIterator { - node_address: node_address, - last_level: -1, - has_found_node: false, - node_border_box: Rect::zero(), - parent_nodes: Vec::new(), - } - } -} - -impl FragmentBorderBoxIterator for FragmentLocatingFragmentIterator { - fn process(&mut self, fragment: &Fragment, _: i32, border_box: &Rect<Au>) { - let style_structs::Border { - border_top_width: top_width, - border_right_width: right_width, - border_bottom_width: bottom_width, - border_left_width: left_width, - .. - } = *fragment.style.get_border(); - self.client_rect.origin.y = top_width.to_px(); - self.client_rect.origin.x = left_width.to_px(); - self.client_rect.size.width = (border_box.size.width - left_width - right_width).to_px(); - self.client_rect.size.height = (border_box.size.height - top_width - bottom_width).to_px(); - } - - fn should_process(&mut self, fragment: &Fragment) -> bool { - fragment.node == self.node_address - } -} - -// https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface -impl FragmentBorderBoxIterator for ParentOffsetBorderBoxIterator { - fn process(&mut self, fragment: &Fragment, level: i32, border_box: &Rect<Au>) { - if fragment.node == self.node_address { - // Found the fragment in the flow tree that matches the - // DOM node being looked for. - self.has_found_node = true; - self.node_border_box = *border_box; - - // offsetParent returns null if the node is fixed. - if fragment.style.get_box().position == computed_values::position::T::fixed { - self.parent_nodes.clear(); - } - } else if level > self.last_level { - // TODO(gw): Is there a less fragile way of checking whether this - // fragment is the body element, rather than just checking that - // the parent nodes stack contains the root node only? - let is_body_element = self.parent_nodes.len() == 1; - - let is_valid_parent = match (is_body_element, - fragment.style.get_box().position, - &fragment.specific) { - // Spec says it's valid if any of these are true: - // 1) Is the body element - // 2) Is static position *and* is a table or table cell - // 3) Is not static position - (true, _, _) | - (false, computed_values::position::T::static_, &SpecificFragmentInfo::Table) | - (false, computed_values::position::T::static_, &SpecificFragmentInfo::TableCell) | - (false, computed_values::position::T::absolute, _) | - (false, computed_values::position::T::relative, _) | - (false, computed_values::position::T::fixed, _) => true, - - // Otherwise, it's not a valid parent - (false, computed_values::position::T::static_, _) => false, - }; - - let parent_info = if is_valid_parent { - Some(ParentBorderBoxInfo { - border_box: *border_box, - node_address: fragment.node, - }) - } else { - None - }; - - self.parent_nodes.push(parent_info); - } else if level < self.last_level { - self.parent_nodes.pop(); - } - } - - fn should_process(&mut self, _: &Fragment) -> bool { - !self.has_found_node - } -} // The default computed value for background-color is transparent (see // http://dev.w3.org/csswg/css-backgrounds/#background-color). However, we diff --git a/components/layout/query.rs b/components/layout/query.rs index c1aa95859c9..5ed91c7a24c 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -4,11 +4,15 @@ //! Utilities for querying the layout, as needed by the layout task. +#![allow(unsafe_code)] + use app_units::Au; +use construct::ConstructionResult; use euclid::point::Point2D; use euclid::rect::Rect; +use flow; use flow_ref::FlowRef; -use fragment::{Fragment, FragmentBorderBoxIterator}; +use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo}; use gfx::display_list::{DisplayItemMetadata, OpaqueNode}; use layout_task::LayoutTaskData; use msg::constellation_msg::ConstellationChan; @@ -17,10 +21,19 @@ use opaque_node::OpaqueNodeMethods; use script::layout_interface::{ContentBoxResponse, ContentBoxesResponse, NodeGeometryResponse}; use script::layout_interface::{HitTestResponse, LayoutRPC, MouseOverResponse, OffsetParentResponse}; use script::layout_interface::{ResolvedStyleResponse, ScriptLayoutChan, TrustedNodeAddress}; +use selectors::parser::PseudoElement; use sequential; +use std::ops::Deref; use std::sync::{Arc, Mutex}; +use string_cache::Atom; +use style::computed_values; +use style::properties::longhands::{display, position}; +use style::properties::style_structs; +use style::values::AuExtensionMethods; use util::cursor::Cursor; +use util::geometry::ZERO_POINT; use util::logical_geometry::WritingMode; +use wrapper::{ServoLayoutNode, ThreadSafeLayoutNode}; pub struct LayoutRPCImpl(pub Arc<Mutex<LayoutTaskData>>); @@ -305,3 +318,278 @@ pub fn process_content_boxes_request(requested_node: TrustedNodeAddress, sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator); iterator.rects } + +struct FragmentLocatingFragmentIterator { + node_address: OpaqueNode, + client_rect: Rect<i32>, +} + +impl FragmentLocatingFragmentIterator { + fn new(node_address: OpaqueNode) -> FragmentLocatingFragmentIterator { + FragmentLocatingFragmentIterator { + node_address: node_address, + client_rect: Rect::zero() + } + } +} + +struct ParentBorderBoxInfo { + node_address: OpaqueNode, + border_box: Rect<Au>, +} + +struct ParentOffsetBorderBoxIterator { + node_address: OpaqueNode, + last_level: i32, + has_found_node: bool, + node_border_box: Rect<Au>, + parent_nodes: Vec<Option<ParentBorderBoxInfo>>, +} + +impl ParentOffsetBorderBoxIterator { + fn new(node_address: OpaqueNode) -> ParentOffsetBorderBoxIterator { + ParentOffsetBorderBoxIterator { + node_address: node_address, + last_level: -1, + has_found_node: false, + node_border_box: Rect::zero(), + parent_nodes: Vec::new(), + } + } +} + +impl FragmentBorderBoxIterator for FragmentLocatingFragmentIterator { + fn process(&mut self, fragment: &Fragment, _: i32, border_box: &Rect<Au>) { + let style_structs::Border { + border_top_width: top_width, + border_right_width: right_width, + border_bottom_width: bottom_width, + border_left_width: left_width, + .. + } = *fragment.style.get_border(); + self.client_rect.origin.y = top_width.to_px(); + self.client_rect.origin.x = left_width.to_px(); + self.client_rect.size.width = (border_box.size.width - left_width - right_width).to_px(); + self.client_rect.size.height = (border_box.size.height - top_width - bottom_width).to_px(); + } + + fn should_process(&mut self, fragment: &Fragment) -> bool { + fragment.node == self.node_address + } +} + +// https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface +impl FragmentBorderBoxIterator for ParentOffsetBorderBoxIterator { + fn process(&mut self, fragment: &Fragment, level: i32, border_box: &Rect<Au>) { + if fragment.node == self.node_address { + // Found the fragment in the flow tree that matches the + // DOM node being looked for. + self.has_found_node = true; + self.node_border_box = *border_box; + + // offsetParent returns null if the node is fixed. + if fragment.style.get_box().position == computed_values::position::T::fixed { + self.parent_nodes.clear(); + } + } else if level > self.last_level { + // TODO(gw): Is there a less fragile way of checking whether this + // fragment is the body element, rather than just checking that + // the parent nodes stack contains the root node only? + let is_body_element = self.parent_nodes.len() == 1; + + let is_valid_parent = match (is_body_element, + fragment.style.get_box().position, + &fragment.specific) { + // Spec says it's valid if any of these are true: + // 1) Is the body element + // 2) Is static position *and* is a table or table cell + // 3) Is not static position + (true, _, _) | + (false, computed_values::position::T::static_, &SpecificFragmentInfo::Table) | + (false, computed_values::position::T::static_, &SpecificFragmentInfo::TableCell) | + (false, computed_values::position::T::absolute, _) | + (false, computed_values::position::T::relative, _) | + (false, computed_values::position::T::fixed, _) => true, + + // Otherwise, it's not a valid parent + (false, computed_values::position::T::static_, _) => false, + }; + + let parent_info = if is_valid_parent { + Some(ParentBorderBoxInfo { + border_box: *border_box, + node_address: fragment.node, + }) + } else { + None + }; + + self.parent_nodes.push(parent_info); + } else if level < self.last_level { + self.parent_nodes.pop(); + } + } + + fn should_process(&mut self, _: &Fragment) -> bool { + !self.has_found_node + } +} + +pub fn process_node_geometry_request(requested_node: TrustedNodeAddress, + layout_root: &mut FlowRef) + -> Rect<i32> { + let requested_node: OpaqueNode = OpaqueNodeMethods::from_script_node(requested_node); + let mut iterator = FragmentLocatingFragmentIterator::new(requested_node); + sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator); + iterator.client_rect +} + +/// Return the resolved value of property for a given (pseudo)element. +/// https://drafts.csswg.org/cssom/#resolved-value +pub fn process_resolved_style_request(requested_node: TrustedNodeAddress, + pseudo: &Option<PseudoElement>, + property: &Atom, + layout_root: &mut FlowRef) + -> Option<String> { + let node = unsafe { ServoLayoutNode::new(&requested_node) }; + + let layout_node = ThreadSafeLayoutNode::new(&node); + let layout_node = match pseudo { + &Some(PseudoElement::Before) => layout_node.get_before_pseudo(), + &Some(PseudoElement::After) => layout_node.get_after_pseudo(), + _ => Some(layout_node) + }; + + let layout_node = match layout_node { + None => { + // The pseudo doesn't exist, return nothing. Chrome seems to query + // the element itself in this case, Firefox uses the resolved value. + // https://www.w3.org/Bugs/Public/show_bug.cgi?id=29006 + return None; + } + Some(layout_node) => layout_node + }; + + let style = &*layout_node.style(); + + let positioned = match style.get_box().position { + position::computed_value::T::relative | + /*position::computed_value::T::sticky |*/ + position::computed_value::T::fixed | + position::computed_value::T::absolute => true, + _ => false + }; + + //TODO: determine whether requested property applies to the element. + // eg. width does not apply to non-replaced inline elements. + // Existing browsers disagree about when left/top/right/bottom apply + // (Chrome seems to think they never apply and always returns resolved values). + // There are probably other quirks. + let applies = true; + + fn used_value_for_position_property(layout_node: ThreadSafeLayoutNode, + layout_root: &mut FlowRef, + requested_node: TrustedNodeAddress, + property: &Atom) -> Option<String> { + let layout_data = layout_node.borrow_layout_data(); + let position = layout_data.as_ref().map(|layout_data| { + match layout_data.data.flow_construction_result { + ConstructionResult::Flow(ref flow_ref, _) => + flow::base(flow_ref.deref()).stacking_relative_position, + // TODO(dzbarsky) search parents until we find node with a flow ref. + // https://github.com/servo/servo/issues/8307 + _ => ZERO_POINT + } + }).unwrap_or(ZERO_POINT); + let property = match *property { + atom!("bottom") => PositionProperty::Bottom, + atom!("top") => PositionProperty::Top, + atom!("left") => PositionProperty::Left, + atom!("right") => PositionProperty::Right, + atom!("width") => PositionProperty::Width, + atom!("height") => PositionProperty::Height, + _ => unreachable!() + }; + let requested_node: OpaqueNode = + OpaqueNodeMethods::from_script_node(requested_node); + let mut iterator = + PositionRetrievingFragmentBorderBoxIterator::new(requested_node, + property, + position); + sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, + &mut iterator); + iterator.result.map(|r| r.to_css_string()) + } + + // TODO: we will return neither the computed nor used value for margin and padding. + // Firefox returns blank strings for the computed value of shorthands, + // so this should be web-compatible. + match *property { + atom!("margin-bottom") | atom!("margin-top") | + atom!("margin-left") | atom!("margin-right") | + atom!("padding-bottom") | atom!("padding-top") | + atom!("padding-left") | atom!("padding-right") + if applies && style.get_box().display != display::computed_value::T::none => { + let (margin_padding, side) = match *property { + atom!("margin-bottom") => (MarginPadding::Margin, Side::Bottom), + atom!("margin-top") => (MarginPadding::Margin, Side::Top), + atom!("margin-left") => (MarginPadding::Margin, Side::Left), + atom!("margin-right") => (MarginPadding::Margin, Side::Right), + atom!("padding-bottom") => (MarginPadding::Padding, Side::Bottom), + atom!("padding-top") => (MarginPadding::Padding, Side::Top), + atom!("padding-left") => (MarginPadding::Padding, Side::Left), + atom!("padding-right") => (MarginPadding::Padding, Side::Right), + _ => unreachable!() + }; + let requested_node: OpaqueNode = + OpaqueNodeMethods::from_script_node(requested_node); + let mut iterator = + MarginRetrievingFragmentBorderBoxIterator::new(requested_node, + side, + margin_padding, + style.writing_mode); + sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, + &mut iterator); + iterator.result.map(|r| r.to_css_string()) + }, + + atom!("bottom") | atom!("top") | atom!("right") | + atom!("left") + if applies && positioned && style.get_box().display != + display::computed_value::T::none => { + used_value_for_position_property(layout_node, layout_root, requested_node, property) + } + atom!("width") | atom!("height") + if applies && style.get_box().display != + display::computed_value::T::none => { + used_value_for_position_property(layout_node, layout_root, requested_node, property) + } + // FIXME: implement used value computation for line-height + ref property => { + style.computed_value_to_string(property.as_slice()).ok() + } + } +} + +pub fn process_offset_parent_query(requested_node: TrustedNodeAddress, + layout_root: &mut FlowRef) + -> OffsetParentResponse { + let requested_node: OpaqueNode = OpaqueNodeMethods::from_script_node(requested_node); + let mut iterator = ParentOffsetBorderBoxIterator::new(requested_node); + sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator); + let parent_info_index = iterator.parent_nodes.iter().rposition(|info| info.is_some()); + match parent_info_index { + Some(parent_info_index) => { + let parent = iterator.parent_nodes[parent_info_index].as_ref().unwrap(); + let origin = iterator.node_border_box.origin - parent.border_box.origin; + let size = iterator.node_border_box.size; + OffsetParentResponse { + node_address: Some(parent.node_address.to_untrusted_node_address()), + rect: Rect::new(origin, size), + } + } + None => { + OffsetParentResponse::empty() + } + } +} |