Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement offsetParent/Top/Left/Width/Height. #6784

Merged
merged 2 commits into from Aug 4, 2015
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -1968,12 +1968,14 @@ impl Flow for BlockFlow {

fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>) {
if !iterator.should_process(&self.fragment) {
return
}

iterator.process(&self.fragment,
level,
&self.fragment
.stacking_relative_border_box(&self.base.stacking_relative_position,
&self.base
@@ -281,8 +281,11 @@ pub trait Flow: fmt::Debug + Sync {
fn compute_overflow(&self) -> Rect<Au>;

/// Iterates through border boxes of all of this flow's fragments.
/// Level provides a zero based index indicating the current
/// depth of the flow tree during fragment iteration.
fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>);

/// Mutably iterates through fragments in this flow.
@@ -2157,7 +2157,7 @@ bitflags! {
/// A top-down fragment border box iteration handler.
pub trait FragmentBorderBoxIterator {
/// The operation to perform.
fn process(&mut self, fragment: &Fragment, overflow: &Rect<Au>);
fn process(&mut self, fragment: &Fragment, level: i32, overflow: &Rect<Au>);

/// Returns true if this fragment must be processed in-order. If this returns false,
/// we skip the operation for this fragment, but continue processing siblings.
@@ -1623,6 +1623,7 @@ impl Flow for InlineFlow {

fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>) {
// FIXME(#2795): Get the real container size.
for fragment in self.fragments.fragments.iter() {
@@ -1636,6 +1637,7 @@ impl Flow for InlineFlow {
let relative_containing_block_mode =
self.base.absolute_position_info.relative_containing_block_mode;
iterator.process(fragment,
level,
&fragment.stacking_relative_border_box(stacking_relative_position,
relative_containing_block_size,
relative_containing_block_mode,
@@ -15,7 +15,7 @@ use data::LayoutDataWrapper;
use display_list_builder::ToGfxColor;
use flow::{self, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
use flow_ref::FlowRef;
use fragment::{Fragment, FragmentBorderBoxIterator};
use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
use incremental::{LayoutDamageComputation, REFLOW, REFLOW_ENTIRE_DOCUMENT, REPAINT};
use layout_debug;
use opaque_node::OpaqueNodeMethods;
@@ -53,7 +53,7 @@ use net_traits::image_cache_task::{ImageCacheTask, ImageCacheResult, ImageCacheC
use script::dom::bindings::js::LayoutJS;
use script::dom::node::{LayoutData, Node};
use script::layout_interface::{Animation, ContentBoxResponse, ContentBoxesResponse, NodeGeometryResponse};
use script::layout_interface::{HitTestResponse, LayoutChan, LayoutRPC, MouseOverResponse};
use script::layout_interface::{HitTestResponse, LayoutChan, LayoutRPC, MouseOverResponse, OffsetParentResponse};
use script::layout_interface::{NewLayoutTaskInfo, Msg, Reflow, ReflowGoal, ReflowQueryType};
use script::layout_interface::{ResolvedStyleResponse, ScriptLayoutChan, ScriptReflow, TrustedNodeAddress};
use script_traits::{ConstellationControlMsg, LayoutControlMsg, OpaqueScriptLayoutChannel};
@@ -69,7 +69,7 @@ use std::ops::{Deref, DerefMut};
use std::sync::mpsc::{channel, Sender, Receiver, Select};
use std::sync::{Arc, Mutex, MutexGuard};
use string_cache::Atom;
use style::computed_values::{filter, mix_blend_mode};
use style::computed_values::{self, filter, mix_blend_mode};
use style::media_queries::{MediaType, MediaQueryList, Device};
use style::properties::style_structs;
use style::properties::longhands::{display, position};
@@ -137,6 +137,9 @@ pub struct LayoutTaskData {
/// A queued response for the resolved style property of an element.
pub resolved_style_response: Option<String>,

/// A queued response for the offset parent/rect of a node.
pub offset_parent_response: OffsetParentResponse,

/// The list of currently-running animations.
pub running_animations: Arc<HashMap<OpaqueNode,Vec<Animation>>>,

@@ -382,6 +385,7 @@ impl LayoutTask {
client_rect_response: Rect::zero(),
resolved_style_response: None,
running_animations: Arc::new(HashMap::new()),
offset_parent_response: OffsetParentResponse::empty(),
visible_rects: Arc::new(HashMap::with_hash_state(Default::default())),
new_animations_receiver: new_animations_receiver,
new_animations_sender: new_animations_sender,
@@ -999,6 +1003,29 @@ impl LayoutTask {
};
}

fn process_offset_parent_query<'a>(&'a self,
requested_node: TrustedNodeAddress,
layout_root: &mut FlowRef,
rw_data: &mut RWGuard<'a>) {
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;
rw_data.offset_parent_response = OffsetParentResponse {
node_address: Some(parent.node_address.to_untrusted_node_address()),
rect: Rect::new(origin, size),
};
}
None => {
rw_data.offset_parent_response = OffsetParentResponse::empty();
}
}
}

fn compute_abs_pos_and_build_display_list<'a>(&'a self,
data: &Reflow,
@@ -1198,6 +1225,8 @@ impl LayoutTask {
self.process_node_geometry_request(node, &mut root_flow, &mut rw_data),
ReflowQueryType::ResolvedStyleQuery(node, ref pseudo, ref property) =>
self.process_resolved_style_request(node, pseudo, property, &mut root_flow, &mut rw_data),
ReflowQueryType::OffsetParentQuery(node) =>
self.process_offset_parent_query(node, &mut root_flow, &mut rw_data),
ReflowQueryType::NoQuery => {}
}

@@ -1516,6 +1545,12 @@ impl LayoutRPC for LayoutRPCImpl {
Ok(MouseOverResponse(response_list))
}
}

fn offset_parent(&self) -> OffsetParentResponse {
let &LayoutRPCImpl(ref rw_data) = self;
let rw_data = rw_data.lock().unwrap();
rw_data.offset_parent_response.clone()
}
}

struct UnioningFragmentBorderBoxIterator {
@@ -1533,7 +1568,7 @@ impl UnioningFragmentBorderBoxIterator {
}

impl FragmentBorderBoxIterator for UnioningFragmentBorderBoxIterator {
fn process(&mut self, _: &Fragment, border_box: &Rect<Au>) {
fn process(&mut self, _: &Fragment, _: i32, border_box: &Rect<Au>) {
self.rect = match self.rect {
Some(rect) => {
Some(rect.union(border_box))
@@ -1564,7 +1599,7 @@ impl CollectingFragmentBorderBoxIterator {
}

impl FragmentBorderBoxIterator for CollectingFragmentBorderBoxIterator {
fn process(&mut self, _: &Fragment, border_box: &Rect<Au>) {
fn process(&mut self, _: &Fragment, _: i32, border_box: &Rect<Au>) {
self.rects.push(*border_box);
}

@@ -1587,8 +1622,33 @@ impl FragmentLocatingFragmentIterator {
}
}

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, border_box: &Rect<Au>) {
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,
@@ -1649,7 +1709,7 @@ impl PositionRetrievingFragmentBorderBoxIterator {
}

impl FragmentBorderBoxIterator for PositionRetrievingFragmentBorderBoxIterator {
fn process(&mut self, _: &Fragment, border_box: &Rect<Au>) {
fn process(&mut self, _: &Fragment, _: i32, border_box: &Rect<Au>) {
self.result =
Some(match self.property {
PositionProperty::Left => self.position.x,
@@ -1691,7 +1751,7 @@ impl MarginRetrievingFragmentBorderBoxIterator {
}

impl FragmentBorderBoxIterator for MarginRetrievingFragmentBorderBoxIterator {
fn process(&mut self, fragment: &Fragment, _: &Rect<Au>) {
fn process(&mut self, fragment: &Fragment, _: i32, _: &Rect<Au>) {
let rect = match self.margin_padding {
MarginPadding::Margin => &fragment.margin,
MarginPadding::Padding => &fragment.border_padding
@@ -1709,6 +1769,63 @@ impl FragmentBorderBoxIterator for MarginRetrievingFragmentBorderBoxIterator {
}
}

// 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
// need to propagate the background color from the root HTML/Body
@@ -158,13 +158,15 @@ impl Flow for ListItemFlow {

fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>) {
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position);
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position);

if let Some(ref marker) = self.marker {
if iterator.should_process(marker) {
iterator.process(
marker,
level,
&marker.stacking_relative_border_box(&self.block_flow
.base
.stacking_relative_position,
@@ -98,8 +98,9 @@ impl Flow for MulticolFlow {

fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>) {
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position)
}

fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
@@ -122,22 +122,24 @@ pub fn build_display_list_for_subtree(root: &mut FlowRef,
pub fn iterate_through_flow_tree_fragment_border_boxes(root: &mut FlowRef,
iterator: &mut FragmentBorderBoxIterator) {
fn doit(flow: &mut Flow,
level: i32,
iterator: &mut FragmentBorderBoxIterator,
stacking_context_position: &Point2D<Au>) {
flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position);
flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position);

for kid in flow::mut_base(flow).child_iter() {
let stacking_context_position =
if kid.is_block_flow() && kid.as_block().fragment.establishes_stacking_context() {
*stacking_context_position + flow::base(kid).stacking_relative_position
let margin = Point2D::new(kid.as_block().fragment.margin.inline_start, Au(0));
*stacking_context_position + flow::base(kid).stacking_relative_position + margin
} else {
*stacking_context_position
};

// FIXME(#2795): Get the real container size.
doit(kid, iterator, &stacking_context_position);
doit(kid, level+1, iterator, &stacking_context_position);
}
}

doit(&mut **root, iterator, &ZERO_POINT);
doit(&mut **root, 0, iterator, &ZERO_POINT);
}
@@ -547,8 +547,9 @@ impl Flow for TableFlow {

fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>) {
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position)
}

fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
@@ -95,8 +95,9 @@ impl Flow for TableCaptionFlow {

fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>) {
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position)
}

fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
@@ -209,8 +209,9 @@ impl Flow for TableCellFlow {

fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>) {
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position)
}

fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
@@ -107,6 +107,7 @@ impl Flow for TableColGroupFlow {

fn iterate_through_fragment_border_boxes(&self,
_: &mut FragmentBorderBoxIterator,
_: i32,
_: &Point2D<Au>) {}

fn mutate_fragments(&mut self, _: &mut FnMut(&mut Fragment)) {}
@@ -444,8 +444,9 @@ impl Flow for TableRowFlow {

fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
level: i32,
stacking_context_position: &Point2D<Au>) {
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position)
}

fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.