aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout/layout_task.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/layout/layout_task.rs')
-rw-r--r--components/layout/layout_task.rs353
1 files changed, 208 insertions, 145 deletions
diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs
index 3a511033934..33bf00e837f 100644
--- a/components/layout/layout_task.rs
+++ b/components/layout/layout_task.rs
@@ -7,9 +7,9 @@
#![allow(unsafe_code)]
+use animation;
use construct::ConstructionResult;
use context::{SharedLayoutContext, SharedLayoutContextWrapper};
-use css::node_style::StyledNode;
use display_list_builder::ToGfxColor;
use flow::{self, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
use flow_ref::FlowRef;
@@ -20,8 +20,9 @@ use layout_debug;
use opaque_node::OpaqueNodeMethods;
use parallel::{self, UnsafeFlow};
use sequential;
-use wrapper::{LayoutNode, TLayoutNode, ThreadSafeLayoutNode};
+use wrapper::{LayoutNode, TLayoutNode};
+use azure::azure::AzColor;
use encoding::EncodingRef;
use encoding::all::UTF_8;
use geom::matrix2d::Matrix2D;
@@ -47,14 +48,11 @@ use profile::mem::{self, Report, ReportsChan};
use profile::time::{self, ProfilerMetadata, profile};
use profile::time::{TimerMetadataFrameType, TimerMetadataReflowType};
use script::dom::bindings::js::LayoutJS;
-use script::dom::element::ElementTypeId;
-use script::dom::htmlelement::HTMLElementTypeId;
-use script::dom::node::{LayoutData, Node, NodeTypeId};
-use script::layout_interface::ReflowQueryType;
-use script::layout_interface::{ContentBoxResponse, ContentBoxesResponse};
+use script::dom::node::{LayoutData, Node};
+use script::layout_interface::{Animation, ContentBoxResponse, ContentBoxesResponse};
use script::layout_interface::{HitTestResponse, LayoutChan, LayoutRPC};
-use script::layout_interface::{MouseOverResponse, Msg};
-use script::layout_interface::{Reflow, ReflowGoal, ScriptLayoutChan, TrustedNodeAddress};
+use script::layout_interface::{MouseOverResponse, Msg, Reflow, ReflowGoal, ReflowQueryType};
+use script::layout_interface::{ScriptLayoutChan, ScriptReflow, TrustedNodeAddress};
use script_traits::{ConstellationControlMsg, CompositorEvent, OpaqueScriptLayoutChannel};
use script_traits::{ScriptControlChan, UntrustedNodeAddress};
use std::borrow::ToOwned;
@@ -71,7 +69,7 @@ use style::selector_matching::Stylist;
use style::stylesheets::{Origin, Stylesheet, iter_font_face_rules};
use url::Url;
use util::cursor::Cursor;
-use util::geometry::Au;
+use util::geometry::{Au, MAX_RECT};
use util::logical_geometry::LogicalPoint;
use util::mem::HeapSizeOf;
use util::opts;
@@ -84,6 +82,9 @@ use util::workqueue::WorkQueue;
///
/// This needs to be protected by a mutex so we can do fast RPCs.
pub struct LayoutTaskData {
+ /// The root of the flow tree.
+ pub root_flow: Option<FlowRef>,
+
/// The local image cache.
pub local_image_cache: Arc<Mutex<LocalImageCache<UntrustedNodeAddress>>>,
@@ -107,13 +108,23 @@ pub struct LayoutTaskData {
/// Starts at zero, and increased by one every time a layout completes.
/// This can be used to easily check for invalid stale data.
- pub generation: uint,
+ pub generation: u32,
/// A queued response for the union of the content boxes of a node.
pub content_box_response: Rect<Au>,
/// A queued response for the content boxes of a node.
pub content_boxes_response: Vec<Rect<Au>>,
+
+ /// The list of currently-running animations.
+ pub running_animations: Vec<Animation>,
+
+ /// Receives newly-discovered animations.
+ pub new_animations_receiver: Receiver<Animation>,
+
+ /// A channel on which new animations that have been triggered by style recalculation can be
+ /// sent.
+ pub new_animations_sender: Sender<Animation>,
}
/// Information needed by the layout task.
@@ -130,7 +141,7 @@ pub struct LayoutTask {
/// The port on which we receive messages from the constellation
pub pipeline_port: Receiver<LayoutControlMsg>,
- //// The channel to send messages to ourself.
+ /// The channel on which we or others can send messages to ourselves.
pub chan: LayoutChan,
/// The channel on which messages can be sent to the constellation.
@@ -193,39 +204,37 @@ impl ImageResponder<UntrustedNodeAddress> for LayoutImageResponder {
impl LayoutTaskFactory for LayoutTask {
/// Spawns a new layout task.
fn create(_phantom: Option<&mut LayoutTask>,
- id: PipelineId,
- url: Url,
- chan: OpaqueScriptLayoutChannel,
- pipeline_port: Receiver<LayoutControlMsg>,
- constellation_chan: ConstellationChan,
- failure_msg: Failure,
- script_chan: ScriptControlChan,
- paint_chan: PaintChan,
- resource_task: ResourceTask,
- img_cache_task: ImageCacheTask,
- font_cache_task: FontCacheTask,
- time_profiler_chan: time::ProfilerChan,
- mem_profiler_chan: mem::ProfilerChan,
- shutdown_chan: Sender<()>) {
+ id: PipelineId,
+ url: Url,
+ chan: OpaqueScriptLayoutChannel,
+ pipeline_port: Receiver<LayoutControlMsg>,
+ constellation_chan: ConstellationChan,
+ failure_msg: Failure,
+ script_chan: ScriptControlChan,
+ paint_chan: PaintChan,
+ resource_task: ResourceTask,
+ img_cache_task: ImageCacheTask,
+ font_cache_task: FontCacheTask,
+ time_profiler_chan: time::ProfilerChan,
+ memory_profiler_chan: mem::ProfilerChan,
+ shutdown_chan: Sender<()>) {
let ConstellationChan(con_chan) = constellation_chan.clone();
spawn_named_with_send_on_failure("LayoutTask", task_state::LAYOUT, move || {
{ // Ensures layout task is destroyed before we send shutdown message
let sender = chan.sender();
- let layout =
- LayoutTask::new(
- id,
- url,
- chan.receiver(),
- LayoutChan(sender),
- pipeline_port,
- constellation_chan,
- script_chan,
- paint_chan,
- resource_task,
- img_cache_task,
- font_cache_task,
- time_profiler_chan,
- mem_profiler_chan);
+ let layout = LayoutTask::new(id,
+ url,
+ chan.receiver(),
+ LayoutChan(sender),
+ pipeline_port,
+ constellation_chan,
+ script_chan,
+ paint_chan,
+ resource_task,
+ img_cache_task,
+ font_cache_task,
+ time_profiler_chan,
+ memory_profiler_chan);
layout.start();
}
shutdown_chan.send(()).unwrap();
@@ -294,10 +303,14 @@ impl LayoutTask {
};
// Register this thread as a memory reporter, via its own channel.
- let reporter = Box::new(chan.clone());
+ let reporter = box chan.clone();
let reporter_name = format!("layout-reporter-{}", id.0);
mem_profiler_chan.send(mem::ProfilerMsg::RegisterReporter(reporter_name.clone(), reporter));
+
+ // Create the channel on which new animations can be sent.
+ let (new_animations_sender, new_animations_receiver) = channel();
+
LayoutTask {
id: id,
url: url,
@@ -316,6 +329,7 @@ impl LayoutTask {
first_reflow: Cell::new(true),
rw_data: Arc::new(Mutex::new(
LayoutTaskData {
+ root_flow: None,
local_image_cache: local_image_cache,
constellation_chan: constellation_chan,
screen_size: screen_size,
@@ -326,6 +340,9 @@ impl LayoutTask {
generation: 0,
content_box_response: Rect::zero(),
content_boxes_response: Vec::new(),
+ running_animations: Vec::new(),
+ new_animations_receiver: new_animations_receiver,
+ new_animations_sender: new_animations_sender,
})),
}
}
@@ -342,7 +359,7 @@ impl LayoutTask {
fn build_shared_layout_context(&self,
rw_data: &LayoutTaskData,
screen_size_changed: bool,
- reflow_root: &LayoutNode,
+ reflow_root: Option<&LayoutNode>,
url: &Url)
-> SharedLayoutContext {
SharedLayoutContext {
@@ -354,9 +371,10 @@ impl LayoutTask {
font_cache_task: self.font_cache_task.clone(),
stylist: &*rw_data.stylist,
url: (*url).clone(),
- reflow_root: OpaqueNodeMethods::from_layout_node(reflow_root),
+ reflow_root: reflow_root.map(|node| OpaqueNodeMethods::from_layout_node(node)),
dirty: Rect::zero(),
generation: rw_data.generation,
+ new_animations_sender: rw_data.new_animations_sender.clone(),
}
}
@@ -390,8 +408,12 @@ impl LayoutTask {
match port_to_read {
PortToRead::Pipeline => {
match self.pipeline_port.recv().unwrap() {
+ LayoutControlMsg::TickAnimationsMsg => {
+ self.handle_request_helper(Msg::TickAnimations, possibly_locked_rw_data)
+ }
LayoutControlMsg::ExitNowMsg(exit_type) => {
- self.handle_request_helper(Msg::ExitNow(exit_type), possibly_locked_rw_data)
+ self.handle_request_helper(Msg::ExitNow(exit_type),
+ possibly_locked_rw_data)
}
}
},
@@ -435,8 +457,12 @@ impl LayoutTask {
LayoutTaskData>>)
-> bool {
match request {
- Msg::AddStylesheet(sheet, mq) => self.handle_add_stylesheet(sheet, mq, possibly_locked_rw_data),
- Msg::LoadStylesheet(url, mq) => self.handle_load_stylesheet(url, mq, possibly_locked_rw_data),
+ Msg::AddStylesheet(sheet, mq) => {
+ self.handle_add_stylesheet(sheet, mq, possibly_locked_rw_data)
+ }
+ Msg::LoadStylesheet(url, mq) => {
+ self.handle_load_stylesheet(url, mq, possibly_locked_rw_data)
+ }
Msg::SetQuirksMode => self.handle_set_quirks_mode(possibly_locked_rw_data),
Msg::GetRPC(response_chan) => {
response_chan.send(box LayoutRPCImpl(self.rw_data.clone()) as
@@ -444,10 +470,11 @@ impl LayoutTask {
},
Msg::Reflow(data) => {
profile(time::ProfilerCategory::LayoutPerform,
- self.profiler_metadata(&*data),
+ self.profiler_metadata(&data.reflow_info),
self.time_profiler_chan.clone(),
|| self.handle_reflow(&*data, possibly_locked_rw_data));
},
+ Msg::TickAnimations => self.tick_all_animations(possibly_locked_rw_data),
Msg::ReapLayoutData(dead_layout_data) => {
unsafe {
self.handle_reap_layout_data(dead_layout_data)
@@ -481,15 +508,15 @@ impl LayoutTask {
let stacking_context = rw_data.stacking_context.as_ref();
reports.push(Report {
path: path!["pages", format!("url({})", self.url), "display-list"],
- size: stacking_context.map_or(0, |sc| sc.heap_size_of_children() as u64),
+ size: stacking_context.map_or(0, |sc| sc.heap_size_of_children()),
});
reports_chan.send(reports);
}
- /// Enters a quiescent state in which no new messages except for `layout_interface::Msg::ReapLayoutData` will be
- /// processed until an `ExitNowMsg` is received. A pong is immediately sent on the given
- /// response channel.
+ /// Enters a quiescent state in which no new messages except for
+ /// `layout_interface::Msg::ReapLayoutData` will be processed until an `ExitNowMsg` is
+ /// received. A pong is immediately sent on the given response channel.
fn prepare_to_exit<'a>(&'a self,
response_chan: Sender<()>,
possibly_locked_rw_data: &mut Option<MutexGuard<'a, LayoutTaskData>>) {
@@ -570,7 +597,7 @@ impl LayoutTask {
if mq.evaluate(&rw_data.stylist.device) {
iter_font_face_rules(&sheet, &rw_data.stylist.device, &|family, src| {
- self.font_cache_task.add_web_font(family.to_owned(), (*src).clone());
+ self.font_cache_task.add_web_font((*family).clone(), (*src).clone());
});
rw_data.stylist.add_stylesheet(sheet);
}
@@ -587,7 +614,6 @@ impl LayoutTask {
LayoutTask::return_rw_data(possibly_locked_rw_data, rw_data);
}
- /// Retrieves the flow tree root from the root node.
fn try_get_layout_root(&self, node: LayoutNode) -> Option<FlowRef> {
let mut layout_data_ref = node.mutate_layout_data();
let layout_data =
@@ -697,10 +723,9 @@ impl LayoutTask {
fn build_display_list_for_reflow<'a>(&'a self,
data: &Reflow,
- node: &mut LayoutNode,
layout_root: &mut FlowRef,
shared_layout_context: &mut SharedLayoutContext,
- rw_data: &mut RWGuard<'a>) {
+ rw_data: &mut LayoutTaskData) {
let writing_mode = flow::base(&**layout_root).writing_mode;
profile(time::ProfilerCategory::LayoutDispListBuild,
self.profiler_metadata(data),
@@ -716,7 +741,6 @@ impl LayoutTask {
flow::mut_base(&mut **layout_root).clip =
ClippingRegion::from_rect(&data.page_clip_rect);
- let rw_data = &mut **rw_data;
match rw_data.parallel_traversal {
None => {
sequential::build_display_list_for_subtree(layout_root, shared_layout_context);
@@ -732,40 +756,7 @@ impl LayoutTask {
debug!("Done building display list.");
- // FIXME(pcwalton): This is really ugly and can't handle overflow: scroll. Refactor
- // it with extreme prejudice.
-
- // 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
- // element (http://dev.w3.org/csswg/css-backgrounds/#special-backgrounds) if
- // it is non-transparent. The phrase in the spec "If the canvas background
- // is not opaque, what shows through is UA-dependent." is handled by rust-layers
- // clearing the frame buffer to white. This ensures that setting a background
- // color on an iframe element, while the iframe content itself has a default
- // transparent background color is handled correctly.
- let mut color = color::transparent_black();
- for child in node.traverse_preorder() {
- if child.type_id() == Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLHtmlElement))) ||
- child.type_id() == Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement))) {
- let element_bg_color = {
- let thread_safe_child = ThreadSafeLayoutNode::new(&child);
- thread_safe_child.style()
- .resolve_color(thread_safe_child.style()
- .get_background()
- .background_color)
- .to_gfx_color()
- };
-
- let black = color::transparent_black();
- if element_bg_color != black {
-
- color = element_bg_color;
- break;
- }
- }
- }
-
+ let root_background_color = get_root_flow_background_color(&mut **layout_root);
let root_size = {
let root_flow = flow::base(&**layout_root);
root_flow.position.size.to_physical(root_flow.writing_mode)
@@ -774,7 +765,7 @@ impl LayoutTask {
flow::mut_base(&mut **layout_root).display_list_building_result
.add_to(&mut *display_list);
let paint_layer = Arc::new(PaintLayer::new(layout_root.layer_id(0),
- color,
+ root_background_color,
ScrollPolicy::Scrollable));
let origin = Rect(Point2D(Au(0), Au(0)), root_size);
@@ -802,7 +793,7 @@ impl LayoutTask {
/// The high-level routine that performs layout tasks.
fn handle_reflow<'a>(&'a self,
- data: &Reflow,
+ data: &ScriptReflow,
possibly_locked_rw_data: &mut Option<MutexGuard<'a, LayoutTaskData>>) {
// FIXME: Isolate this transmutation into a "bridge" module.
// FIXME(rust#16366): The following line had to be moved because of a
@@ -814,8 +805,7 @@ impl LayoutTask {
transmute(&mut node)
};
- debug!("layout: received layout request for: {}", data.url.serialize());
- debug!("layout: parsed Node tree");
+ debug!("layout: received layout request for: {}", data.reflow_info.url.serialize());
if log_enabled!(log::DEBUG) {
node.dump();
}
@@ -831,7 +821,6 @@ impl LayoutTask {
// TODO: Calculate the "actual viewport":
// http://www.w3.org/TR/css-device-adapt/#actual-viewport
let viewport_size = data.window_size.initial_viewport;
-
let old_screen_size = rw_data.screen_size;
let current_screen_size = Size2D(Au::from_frac32_px(viewport_size.width.get()),
Au::from_frac32_px(viewport_size.height.get()));
@@ -839,23 +828,19 @@ impl LayoutTask {
// Handle conditions where the entire flow tree is invalid.
let screen_size_changed = current_screen_size != old_screen_size;
-
if screen_size_changed {
let device = Device::new(MediaType::Screen, data.window_size.initial_viewport);
rw_data.stylist.set_device(device);
}
- let needs_dirtying = rw_data.stylist.update();
-
// If the entire flow tree is invalid, then it will be reflowed anyhow.
+ let needs_dirtying = rw_data.stylist.update();
let needs_reflow = screen_size_changed && !needs_dirtying;
-
unsafe {
if needs_dirtying {
LayoutTask::dirty_all_nodes(node);
}
}
-
if needs_reflow {
match self.try_get_layout_root(*node) {
None => {}
@@ -868,13 +853,14 @@ impl LayoutTask {
// Create a layout context for use throughout the following passes.
let mut shared_layout_context = self.build_shared_layout_context(&*rw_data,
screen_size_changed,
- node,
- &data.url);
+ Some(&node),
+ &data.reflow_info.url);
- let mut layout_root = profile(time::ProfilerCategory::LayoutStyleRecalc,
- self.profiler_metadata(data),
- self.time_profiler_chan.clone(),
- || {
+ // Recalculate CSS styles and rebuild flows and fragments.
+ profile(time::ProfilerCategory::LayoutStyleRecalc,
+ self.profiler_metadata(&data.reflow_info),
+ self.time_profiler_chan.clone(),
+ || {
// Perform CSS selector matching and flow construction.
let rw_data = &mut *rw_data;
match rw_data.parallel_traversal {
@@ -882,39 +868,105 @@ impl LayoutTask {
sequential::traverse_dom_preorder(*node, &shared_layout_context);
}
Some(ref mut traversal) => {
- parallel::traverse_dom_preorder(*node, &shared_layout_context, traversal)
+ parallel::traverse_dom_preorder(*node, &shared_layout_context, traversal);
}
}
-
- self.get_layout_root((*node).clone())
});
+ // Retrieve the (possibly rebuilt) root flow.
+ rw_data.root_flow = Some(self.get_layout_root((*node).clone()));
+
+ // Kick off animations if any were triggered.
+ animation::process_new_animations(&mut *rw_data, self.id);
+
+ // Perform post-style recalculation layout passes.
+ self.perform_post_style_recalc_layout_passes(&data.reflow_info,
+ &mut rw_data,
+ &mut shared_layout_context);
+
+ let mut root_flow = (*rw_data.root_flow.as_ref().unwrap()).clone();
+ match data.query_type {
+ ReflowQueryType::ContentBoxQuery(node) => {
+ self.process_content_box_request(node, &mut root_flow, &mut rw_data)
+ }
+ ReflowQueryType::ContentBoxesQuery(node) => {
+ self.process_content_boxes_request(node, &mut root_flow, &mut rw_data)
+ }
+ ReflowQueryType::NoQuery => {}
+ }
+
+
+ // Tell script that we're done.
+ //
+ // FIXME(pcwalton): This should probably be *one* channel, but we can't fix this without
+ // either select or a filtered recv() that only looks for messages of a given type.
+ data.script_join_chan.send(()).unwrap();
+ let ScriptControlChan(ref chan) = data.script_chan;
+ chan.send(ConstellationControlMsg::ReflowComplete(self.id, data.id)).unwrap();
+ }
+
+ fn tick_all_animations<'a>(&'a self,
+ possibly_locked_rw_data: &mut Option<MutexGuard<'a,
+ LayoutTaskData>>) {
+ let mut rw_data = self.lock_rw_data(possibly_locked_rw_data);
+ animation::tick_all_animations(self, &mut rw_data)
+ }
+
+ pub fn tick_animation<'a>(&'a self, animation: Animation, rw_data: &mut LayoutTaskData) {
+ // FIXME(#5466, pcwalton): These data are lies.
+ let reflow_info = Reflow {
+ goal: ReflowGoal::ForDisplay,
+ url: Url::parse("http://animation.com/").unwrap(),
+ iframe: false,
+ page_clip_rect: MAX_RECT,
+ };
+
+ // Perform an abbreviated style recalc that operates without access to the DOM.
+ let mut layout_context = self.build_shared_layout_context(&*rw_data,
+ false,
+ None,
+ &reflow_info.url);
+ let mut root_flow = (*rw_data.root_flow.as_ref().unwrap()).clone();
+ profile(time::ProfilerCategory::LayoutStyleRecalc,
+ self.profiler_metadata(&reflow_info),
+ self.time_profiler_chan.clone(),
+ || animation::recalc_style_for_animation(root_flow.deref_mut(), &animation));
+
+ self.perform_post_style_recalc_layout_passes(&reflow_info,
+ &mut *rw_data,
+ &mut layout_context);
+ }
+
+ fn perform_post_style_recalc_layout_passes<'a>(&'a self,
+ data: &Reflow,
+ rw_data: &mut LayoutTaskData,
+ layout_context: &mut SharedLayoutContext) {
+ let mut root_flow = (*rw_data.root_flow.as_ref().unwrap()).clone();
profile(time::ProfilerCategory::LayoutRestyleDamagePropagation,
self.profiler_metadata(data),
self.time_profiler_chan.clone(),
|| {
- if opts::get().nonincremental_layout || layout_root.compute_layout_damage()
- .contains(REFLOW_ENTIRE_DOCUMENT) {
- layout_root.reflow_entire_document()
+ if opts::get().nonincremental_layout || root_flow.deref_mut()
+ .compute_layout_damage()
+ .contains(REFLOW_ENTIRE_DOCUMENT) {
+ root_flow.deref_mut().reflow_entire_document()
}
});
// Verification of the flow tree, which ensures that all nodes were either marked as leaves
// or as non-leaves. This becomes a no-op in release builds. (It is inconsequential to
// memory safety but is a useful debugging tool.)
- self.verify_flow_tree(&mut layout_root);
+ self.verify_flow_tree(&mut root_flow);
if opts::get().trace_layout {
- layout_debug::begin_trace(layout_root.clone());
+ layout_debug::begin_trace(root_flow.clone());
}
// Resolve generated content.
profile(time::ProfilerCategory::LayoutGeneratedContent,
self.profiler_metadata(data),
self.time_profiler_chan.clone(),
- || {
- sequential::resolve_generated_content(&mut layout_root, &shared_layout_context)
- });
+ || sequential::resolve_generated_content(&mut root_flow, &layout_context));
// Perform the primary layout passes over the flow tree to compute the locations of all
// the boxes.
@@ -922,18 +974,17 @@ impl LayoutTask {
self.profiler_metadata(data),
self.time_profiler_chan.clone(),
|| {
- let rw_data = &mut *rw_data;
match rw_data.parallel_traversal {
None => {
// Sequential mode.
- self.solve_constraints(&mut layout_root, &shared_layout_context)
+ self.solve_constraints(&mut root_flow, &layout_context)
}
Some(_) => {
// Parallel mode.
self.solve_constraints_parallel(data,
rw_data,
- &mut layout_root,
- &mut shared_layout_context);
+ &mut root_flow,
+ &mut *layout_context);
}
}
});
@@ -942,24 +993,13 @@ impl LayoutTask {
match data.goal {
ReflowGoal::ForDisplay => {
self.build_display_list_for_reflow(data,
- node,
- &mut layout_root,
- &mut shared_layout_context,
- &mut rw_data);
+ &mut root_flow,
+ &mut *layout_context,
+ rw_data);
}
ReflowGoal::ForScriptQuery => {}
}
- match data.query_type {
- ReflowQueryType::ContentBoxQuery(node) => {
- self.process_content_box_request(node, &mut layout_root, &mut rw_data)
- }
- ReflowQueryType::ContentBoxesQuery(node) => {
- self.process_content_boxes_request(node, &mut layout_root, &mut rw_data)
- }
- ReflowQueryType::NoQuery => {}
- }
-
self.first_reflow.set(false);
if opts::get().trace_layout {
@@ -967,18 +1007,10 @@ impl LayoutTask {
}
if opts::get().dump_flow_tree {
- layout_root.dump();
+ root_flow.dump();
}
rw_data.generation += 1;
-
- // Tell script that we're done.
- //
- // FIXME(pcwalton): This should probably be *one* channel, but we can't fix this without
- // either select or a filtered recv() that only looks for messages of a given type.
- data.script_join_chan.send(()).unwrap();
- let ScriptControlChan(ref chan) = data.script_chan;
- chan.send(ConstellationControlMsg::ReflowComplete(self.id, data.id)).unwrap();
}
unsafe fn dirty_all_nodes(node: &mut LayoutNode) {
@@ -1172,3 +1204,34 @@ impl FragmentBorderBoxIterator for CollectingFragmentBorderBoxIterator {
self.node_address == fragment.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
+// element (http://dev.w3.org/csswg/css-backgrounds/#special-backgrounds) if
+// it is non-transparent. The phrase in the spec "If the canvas background
+// is not opaque, what shows through is UA-dependent." is handled by rust-layers
+// clearing the frame buffer to white. This ensures that setting a background
+// color on an iframe element, while the iframe content itself has a default
+// transparent background color is handled correctly.
+fn get_root_flow_background_color(flow: &mut Flow) -> AzColor {
+ if !flow.is_block_like() {
+ return color::transparent_black()
+ }
+
+ let block_flow = flow.as_block();
+ let kid = match block_flow.base.children.iter_mut().next() {
+ None => return color::transparent_black(),
+ Some(kid) => kid,
+ };
+ if !kid.is_block_like() {
+ return color::transparent_black()
+ }
+
+ let kid_block_flow = kid.as_block();
+ kid_block_flow.fragment
+ .style
+ .resolve_color(kid_block_flow.fragment.style.get_background().background_color)
+ .to_gfx_color()
+}
+