aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <metajack+bors@gmail.com>2014-12-03 15:22:00 -0700
committerbors-servo <metajack+bors@gmail.com>2014-12-03 15:22:00 -0700
commit68c90e27970808bddcb8c8a4e782bd4405e67a5c (patch)
tree19ba94ff619ff8cc32a9ffaf9fe73bb0afdaf948
parent873ca6cadddc1a40bead1f5dd0128bb16cfaa11b (diff)
parent1c1c507c03757a3e4b76ca799b866b047d69a7b5 (diff)
downloadservo-68c90e27970808bddcb8c8a4e782bd4405e67a5c.tar.gz
servo-68c90e27970808bddcb8c8a4e782bd4405e67a5c.zip
auto merge of #4036 : pcwalton/servo/opacity, r=SimonSapin
This adds the infrastructure necessary to support stacking contexts that are not containing blocks for absolutely-positioned elements. Our infrastructure did not support that before. This minor revamp actually ended up simplifying the logic around display list building and stacking-relative position computation for absolutely-positioned flows, which was nice. This will need this PR: https://github.com/servo/rust-azure/pull/112 I have not updated the Cargo.lock file yet because I want the merge commit. r? @glennw f? @SimonSapin
-rw-r--r--components/gfx/display_list/mod.rs157
-rw-r--r--components/gfx/render_context.rs68
-rw-r--r--components/gfx/render_task.rs2
-rw-r--r--components/layout/block.rs43
-rw-r--r--components/layout/display_list_builder.rs63
-rw-r--r--components/layout/fragment.rs3
-rw-r--r--components/layout/inline.rs21
-rw-r--r--components/layout/layout_task.rs19
-rw-r--r--components/servo/Cargo.lock4
-rw-r--r--components/style/properties/mod.rs.mako31
-rw-r--r--ports/android/glut_app/Cargo.lock2
-rw-r--r--ports/cef/Cargo.lock2
-rw-r--r--tests/ref/basic.list3
-rw-r--r--tests/ref/opacity_simple_a.html27
-rw-r--r--tests/ref/opacity_simple_ref.html20
-rw-r--r--tests/ref/opacity_stacking_context_a.html48
-rw-r--r--tests/ref/opacity_stacking_context_ref.html48
17 files changed, 418 insertions, 143 deletions
diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs
index 4045c7b9799..68b0e3d38ed 100644
--- a/components/gfx/display_list/mod.rs
+++ b/components/gfx/display_list/mod.rs
@@ -146,6 +146,8 @@ pub struct StackingContext {
pub clip_rect: Rect<Au>,
/// The `z-index` for this stacking context.
pub z_index: i32,
+ /// The opacity of this stacking context.
+ pub opacity: AzFloat,
}
impl StackingContext {
@@ -157,6 +159,7 @@ impl StackingContext {
pub fn new(display_list: Box<DisplayList>,
bounds: Rect<Au>,
z_index: i32,
+ opacity: AzFloat,
layer: Option<Arc<RenderLayer>>)
-> StackingContext {
StackingContext {
@@ -165,6 +168,7 @@ impl StackingContext {
bounds: bounds,
clip_rect: bounds,
z_index: z_index,
+ opacity: opacity,
}
}
@@ -174,82 +178,107 @@ impl StackingContext {
tile_bounds: &Rect<AzFloat>,
current_transform: &Matrix2D<AzFloat>,
current_clip_stack: &mut Vec<Rect<Au>>) {
- // Optimize the display list to throw out out-of-bounds display items and so forth.
- let display_list = DisplayListOptimizer::new(tile_bounds).optimize(&*self.display_list);
-
- // Sort positioned children according to z-index.
- let mut positioned_children = SmallVec8::new();
- for kid in display_list.children.iter() {
- positioned_children.push((*kid).clone());
- }
- positioned_children.as_slice_mut().sort_by(|this, other| this.z_index.cmp(&other.z_index));
-
- // Steps 1 and 2: Borders and background for the root.
- for display_item in display_list.background_and_borders.iter() {
- display_item.draw_into_context(render_context, current_transform, current_clip_stack)
- }
-
- // Step 3: Positioned descendants with negative z-indices.
- for positioned_kid in positioned_children.iter() {
- if positioned_kid.z_index >= 0 {
- break
+ let temporary_draw_target =
+ render_context.get_or_create_temporary_draw_target(self.opacity);
+ {
+ let mut render_subcontext = RenderContext {
+ draw_target: temporary_draw_target.clone(),
+ font_ctx: &mut *render_context.font_ctx,
+ page_rect: render_context.page_rect,
+ screen_rect: render_context.screen_rect,
+ ..*render_context
+ };
+
+ // Optimize the display list to throw out out-of-bounds display items and so forth.
+ let display_list =
+ DisplayListOptimizer::new(tile_bounds).optimize(&*self.display_list);
+
+ // Sort positioned children according to z-index.
+ let mut positioned_children = SmallVec8::new();
+ for kid in display_list.children.iter() {
+ positioned_children.push((*kid).clone());
}
- if positioned_kid.layer.is_none() {
- let new_transform =
- current_transform.translate(positioned_kid.bounds.origin.x.to_nearest_px()
- as AzFloat,
- positioned_kid.bounds.origin.y.to_nearest_px()
- as AzFloat);
- let new_tile_rect =
- self.compute_tile_rect_for_child_stacking_context(tile_bounds,
- &**positioned_kid);
- positioned_kid.optimize_and_draw_into_context(render_context,
- &new_tile_rect,
- &new_transform,
- current_clip_stack);
+ positioned_children.as_slice_mut()
+ .sort_by(|this, other| this.z_index.cmp(&other.z_index));
+
+ // Steps 1 and 2: Borders and background for the root.
+ for display_item in display_list.background_and_borders.iter() {
+ display_item.draw_into_context(&mut render_subcontext,
+ current_transform,
+ current_clip_stack)
}
- }
- // Step 4: Block backgrounds and borders.
- for display_item in display_list.block_backgrounds_and_borders.iter() {
- display_item.draw_into_context(render_context, current_transform, current_clip_stack)
- }
+ // Step 3: Positioned descendants with negative z-indices.
+ for positioned_kid in positioned_children.iter() {
+ if positioned_kid.z_index >= 0 {
+ break
+ }
+ if positioned_kid.layer.is_none() {
+ let new_transform =
+ current_transform.translate(positioned_kid.bounds.origin.x.to_nearest_px()
+ as AzFloat,
+ positioned_kid.bounds.origin.y.to_nearest_px()
+ as AzFloat);
+ let new_tile_rect =
+ self.compute_tile_rect_for_child_stacking_context(tile_bounds,
+ &**positioned_kid);
+ positioned_kid.optimize_and_draw_into_context(&mut render_subcontext,
+ &new_tile_rect,
+ &new_transform,
+ current_clip_stack);
+ }
+ }
- // Step 5: Floats.
- for display_item in display_list.floats.iter() {
- display_item.draw_into_context(render_context, current_transform, current_clip_stack)
- }
+ // Step 4: Block backgrounds and borders.
+ for display_item in display_list.block_backgrounds_and_borders.iter() {
+ display_item.draw_into_context(&mut render_subcontext,
+ current_transform,
+ current_clip_stack)
+ }
- // TODO(pcwalton): Step 6: Inlines that generate stacking contexts.
+ // Step 5: Floats.
+ for display_item in display_list.floats.iter() {
+ display_item.draw_into_context(&mut render_subcontext,
+ current_transform,
+ current_clip_stack)
+ }
- // Step 7: Content.
- for display_item in display_list.content.iter() {
- display_item.draw_into_context(render_context, current_transform, current_clip_stack)
- }
+ // TODO(pcwalton): Step 6: Inlines that generate stacking contexts.
- // Steps 8 and 9: Positioned descendants with nonnegative z-indices.
- for positioned_kid in positioned_children.iter() {
- if positioned_kid.z_index < 0 {
- continue
+ // Step 7: Content.
+ for display_item in display_list.content.iter() {
+ display_item.draw_into_context(&mut render_subcontext,
+ current_transform,
+ current_clip_stack)
}
- if positioned_kid.layer.is_none() {
- let new_transform =
- current_transform.translate(positioned_kid.bounds.origin.x.to_nearest_px()
- as AzFloat,
- positioned_kid.bounds.origin.y.to_nearest_px()
- as AzFloat);
- let new_tile_rect =
- self.compute_tile_rect_for_child_stacking_context(tile_bounds,
- &**positioned_kid);
- positioned_kid.optimize_and_draw_into_context(render_context,
- &new_tile_rect,
- &new_transform,
- current_clip_stack);
+ // Steps 8 and 9: Positioned descendants with nonnegative z-indices.
+ for positioned_kid in positioned_children.iter() {
+ if positioned_kid.z_index < 0 {
+ continue
+ }
+
+ if positioned_kid.layer.is_none() {
+ let new_transform =
+ current_transform.translate(positioned_kid.bounds.origin.x.to_nearest_px()
+ as AzFloat,
+ positioned_kid.bounds.origin.y.to_nearest_px()
+ as AzFloat);
+ let new_tile_rect =
+ self.compute_tile_rect_for_child_stacking_context(tile_bounds,
+ &**positioned_kid);
+ positioned_kid.optimize_and_draw_into_context(&mut render_subcontext,
+ &new_tile_rect,
+ &new_transform,
+ current_clip_stack);
+ }
}
+
+ // TODO(pcwalton): Step 10: Outlines.
}
- // TODO(pcwalton): Step 10: Outlines.
+ render_context.draw_temporary_draw_target_if_necessary(&temporary_draw_target,
+ self.opacity)
}
/// Translate the given tile rect into the coordinate system of a child stacking context.
diff --git a/components/gfx/render_context.rs b/components/gfx/render_context.rs
index 973d1925a3f..6dbe84be15a 100644
--- a/components/gfx/render_context.rs
+++ b/components/gfx/render_context.rs
@@ -4,6 +4,7 @@
//! Painting of display lists using Moz2D/Azure.
+use azure::azure::AzIntSize;
use azure::azure_hl::{B8G8R8A8, A8, Color, ColorPattern, ColorPatternRef, DrawOptions};
use azure::azure_hl::{DrawSurfaceOptions, DrawTarget, ExtendClamp, GradientStop, Linear};
use azure::azure_hl::{LinearGradientPattern, LinearGradientPatternRef, SourceOp, StrokeOptions};
@@ -33,7 +34,7 @@ use text::TextRun;
use text::glyph::CharIndex;
pub struct RenderContext<'a> {
- pub draw_target: &'a DrawTarget,
+ pub draw_target: DrawTarget,
pub font_ctx: &'a mut Box<FontContext>,
/// The rectangle that this context encompasses in page coordinates.
pub page_rect: Rect<f32>,
@@ -54,8 +55,8 @@ enum DashSize {
}
impl<'a> RenderContext<'a> {
- pub fn get_draw_target(&self) -> &'a DrawTarget {
- self.draw_target
+ pub fn get_draw_target(&self) -> &DrawTarget {
+ &self.draw_target
}
pub fn draw_solid_color(&self, bounds: &Rect<Au>, color: Color) {
@@ -153,7 +154,13 @@ impl<'a> RenderContext<'a> {
self.draw_target.fill_rect(&rect, ColorPatternRef(&pattern), Some(&draw_options));
}
- fn draw_border_segment(&self, direction: Direction, bounds: &Rect<Au>, border: SideOffsets2D<f32>, radius: &BorderRadii<AzFloat>, color: SideOffsets2D<Color>, style: SideOffsets2D<border_style::T>) {
+ fn draw_border_segment(&self,
+ direction: Direction,
+ bounds: &Rect<Au>,
+ border: SideOffsets2D<f32>,
+ radius: &BorderRadii<AzFloat>,
+ color: SideOffsets2D<Color>,
+ style: SideOffsets2D<border_style::T>) {
let (style_select, color_select) = match direction {
Top => (style.top, color.top),
Left => (style.left, color.left),
@@ -641,6 +648,49 @@ impl<'a> RenderContext<'a> {
LinearGradientPatternRef(&pattern),
None);
}
+
+ pub fn get_or_create_temporary_draw_target(&mut self, opacity: AzFloat) -> DrawTarget {
+ if opacity == 1.0 {
+ return self.draw_target.clone()
+ }
+
+ // FIXME(pcwalton): This surface might be bigger than necessary and waste memory.
+ let size = self.draw_target.get_size();
+ let size = Size2D {
+ width: size.width,
+ height: size.height,
+ };
+
+ let temporary_draw_target =
+ self.draw_target.create_similar_draw_target(&size, self.draw_target.get_format());
+ temporary_draw_target.set_transform(&self.draw_target.get_transform());
+ temporary_draw_target
+ }
+
+ /// If we created a temporary draw target, then draw it to the main draw target. This is called
+ /// after doing all the painting, and the temporary draw target must not be used afterward.
+ pub fn draw_temporary_draw_target_if_necessary(&mut self,
+ temporary_draw_target: &DrawTarget,
+ opacity: AzFloat) {
+ if (*temporary_draw_target) == self.draw_target {
+ // We're directly rendering to the surface; nothing to do.
+ return
+ }
+
+ let old_transform = self.draw_target.get_transform();
+ self.draw_target.set_transform(&Matrix2D::identity());
+ temporary_draw_target.set_transform(&Matrix2D::identity());
+ let rect = Rect(Point2D(0.0, 0.0), self.draw_target.get_size().to_azure_size());
+ let source_surface = temporary_draw_target.snapshot();
+ let draw_surface_options = DrawSurfaceOptions::new(Linear, true);
+ let draw_options = DrawOptions::new(opacity, 0);
+ self.draw_target.draw_surface(source_surface,
+ rect,
+ rect,
+ draw_surface_options,
+ draw_options);
+ self.draw_target.set_transform(&old_transform);
+ }
}
pub trait ToAzurePoint {
@@ -665,6 +715,16 @@ impl ToAzureRect for Rect<Au> {
}
}
+pub trait ToAzureSize {
+ fn to_azure_size(&self) -> Size2D<AzFloat>;
+}
+
+impl ToAzureSize for AzIntSize {
+ fn to_azure_size(&self) -> Size2D<AzFloat> {
+ Size2D(self.width as AzFloat, self.height as AzFloat)
+ }
+}
+
trait ToSideOffsetsPx {
fn to_float_px(&self) -> SideOffsets2D<AzFloat>;
}
diff --git a/components/gfx/render_task.rs b/components/gfx/render_task.rs
index 6dc3335faff..6013fc8f936 100644
--- a/components/gfx/render_task.rs
+++ b/components/gfx/render_task.rs
@@ -505,7 +505,7 @@ impl WorkerThread {
{
// Build the render context.
let mut render_context = RenderContext {
- draw_target: &draw_target,
+ draw_target: draw_target.clone(),
font_ctx: &mut self.font_context,
page_rect: tile.page_rect,
screen_rect: tile.screen_rect,
diff --git a/components/layout/block.rs b/components/layout/block.rs
index 94e56fba369..a721244d826 100644
--- a/components/layout/block.rs
+++ b/components/layout/block.rs
@@ -1722,20 +1722,31 @@ impl Flow for BlockFlow {
}
// Compute absolute position info for children.
+ let stacking_relative_position_of_absolute_containing_block_for_children =
+ if self.fragment.establishes_stacking_context() {
+ let logical_border_width = self.fragment.style().logical_border_width();
+ let position = LogicalPoint::new(self.base.writing_mode,
+ logical_border_width.inline_start,
+ logical_border_width.block_start);
+ let position = position.to_physical(self.base.writing_mode, container_size);
+ if self.is_positioned() {
+ position
+ } else {
+ // We establish a stacking context but are not positioned. (This will happen
+ // if, for example, the element has `position: static` but has `opacity` or
+ // `transform` set.) In this case, absolutely-positioned children will not be
+ // positioned relative to us but will instead be positioned relative to our
+ // containing block.
+ position - self.base.stacking_relative_position
+ }
+ } else {
+ self.base
+ .absolute_position_info
+ .stacking_relative_position_of_absolute_containing_block
+ };
let absolute_position_info_for_children = AbsolutePositionInfo {
stacking_relative_position_of_absolute_containing_block:
- if self.fragment.establishes_stacking_context() {
- let logical_border_width = self.fragment.style().logical_border_width();
- LogicalPoint::new(self.base.writing_mode,
- logical_border_width.inline_start,
- logical_border_width.block_start).to_physical(
- self.base.writing_mode,
- container_size)
- } else {
- self.base
- .absolute_position_info
- .stacking_relative_position_of_absolute_containing_block
- },
+ stacking_relative_position_of_absolute_containing_block_for_children,
relative_containing_block_size: self.fragment.content_box().size,
layers_needed_for_positioned_flows: self.base
.flags
@@ -1760,17 +1771,11 @@ impl Flow for BlockFlow {
origin_for_children +
(kid_base.position.start + relative_offset).to_physical(writing_mode,
container_size);
- kid_base.absolute_position_info = absolute_position_info_for_children
}
+ flow::mut_base(kid).absolute_position_info = absolute_position_info_for_children;
flow::mut_base(kid).clip_rect = clip_rect
}
-
- // Process absolute descendant links.
- for absolute_descendant in self.base.abs_descendants.iter() {
- flow::mut_base(absolute_descendant).absolute_position_info =
- absolute_position_info_for_children
- }
}
fn mark_as_root(&mut self) {
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs
index 0fe3f659941..56eb4e4cf34 100644
--- a/components/layout/display_list_builder.rs
+++ b/components/layout/display_list_builder.rs
@@ -12,8 +12,7 @@
use block::BlockFlow;
use context::LayoutContext;
-use flow::{mod, Flow};
-use flow::{IS_ABSOLUTELY_POSITIONED, NEEDS_LAYER};
+use flow::{mod, Flow, NEEDS_LAYER};
use fragment::{Fragment, GenericFragment, IframeFragment, IframeFragmentInfo, ImageFragment};
use fragment::{ImageFragmentInfo, InlineAbsoluteHypotheticalFragment, InlineBlockFragment};
use fragment::{ScannedTextFragment, ScannedTextFragmentInfo, TableFragment};
@@ -811,6 +810,10 @@ pub trait BlockFlowDisplayListBuilding {
fn build_display_list_for_absolutely_positioned_block(&mut self,
layout_context: &LayoutContext);
fn build_display_list_for_floating_block(&mut self, layout_context: &LayoutContext);
+ fn create_stacking_context(&self,
+ display_list: Box<DisplayList>,
+ layer: Option<Arc<RenderLayer>>)
+ -> Arc<StackingContext>;
}
impl BlockFlowDisplayListBuilding for BlockFlow {
@@ -828,19 +831,8 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
&self.base.clip_rect);
for kid in self.base.children.iter_mut() {
- if flow::base(kid).flags.contains(IS_ABSOLUTELY_POSITIONED) {
- // All absolute flows will be handled by their containing block.
- continue
- }
-
flow::mut_base(kid).display_list_building_result.add_to(display_list);
}
-
- // Process absolute descendant links.
- for abs_descendant_link in self.base.abs_descendants.iter() {
- // TODO(pradeep): Send in our absolute position directly.
- flow::mut_base(abs_descendant_link).display_list_building_result.add_to(display_list);
- }
}
fn build_display_list_for_block(&mut self,
@@ -850,7 +842,12 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
self.build_display_list_for_block_base(&mut *display_list,
layout_context,
background_border_level);
- self.base.display_list_building_result = DisplayListResult(display_list);
+
+ self.base.display_list_building_result = if self.fragment.establishes_stacking_context() {
+ StackingContextResult(self.create_stacking_context(display_list, None))
+ } else {
+ DisplayListResult(display_list)
+ }
}
fn build_display_list_for_absolutely_positioned_block(&mut self,
@@ -860,18 +857,11 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
layout_context,
RootOfStackingContextLevel);
- let bounds = Rect(self.base.stacking_relative_position,
- self.base.overflow.size.to_physical(self.base.writing_mode));
- let z_index = self.fragment.style().get_box().z_index.number_or_zero();
-
if !self.base.absolute_position_info.layers_needed_for_positioned_flows &&
!self.base.flags.contains(NEEDS_LAYER) {
// We didn't need a layer.
self.base.display_list_building_result =
- StackingContextResult(Arc::new(StackingContext::new(display_list,
- bounds,
- z_index,
- None)));
+ StackingContextResult(self.create_stacking_context(display_list, None));
return
}
@@ -884,13 +874,10 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
let transparent = color::rgba(1.0, 1.0, 1.0, 0.0);
let stacking_context =
- Arc::new(StackingContext::new(display_list,
- bounds,
- z_index,
- Some(Arc::new(RenderLayer::new(self.layer_id(0),
- transparent,
- scroll_policy)))));
-
+ self.create_stacking_context(display_list,
+ Some(Arc::new(RenderLayer::new(self.layer_id(0),
+ transparent,
+ scroll_policy))));
self.base.display_list_building_result = StackingContextResult(stacking_context)
}
@@ -900,7 +887,23 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
layout_context,
RootOfStackingContextLevel);
display_list.form_float_pseudo_stacking_context();
- self.base.display_list_building_result = DisplayListResult(display_list);
+
+ self.base.display_list_building_result = if self.fragment.establishes_stacking_context() {
+ StackingContextResult(self.create_stacking_context(display_list, None))
+ } else {
+ DisplayListResult(display_list)
+ }
+ }
+
+ fn create_stacking_context(&self,
+ display_list: Box<DisplayList>,
+ layer: Option<Arc<RenderLayer>>)
+ -> Arc<StackingContext> {
+ let bounds = Rect(self.base.stacking_relative_position,
+ self.base.overflow.size.to_physical(self.base.writing_mode));
+ let z_index = self.fragment.style().get_box().z_index.number_or_zero();
+ let opacity = self.fragment.style().get_effects().opacity as f32;
+ Arc::new(StackingContext::new(display_list, bounds, z_index, opacity, layer))
}
}
diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs
index def9cd33776..53aff17d0ac 100644
--- a/components/layout/fragment.rs
+++ b/components/layout/fragment.rs
@@ -1494,6 +1494,9 @@ impl Fragment {
/// Returns true if this fragment establishes a new stacking context and false otherwise.
pub fn establishes_stacking_context(&self) -> bool {
+ if self.style().get_effects().opacity != 1.0 {
+ return true
+ }
match self.style().get_box().position {
position::absolute | position::fixed => {
// FIXME(pcwalton): This should only establish a new stacking context when
diff --git a/components/layout/inline.rs b/components/layout/inline.rs
index 73332023d5d..96421f26cff 100644
--- a/components/layout/inline.rs
+++ b/components/layout/inline.rs
@@ -20,7 +20,7 @@ use model::IntrinsicISizesContribution;
use text;
use collections::{RingBuf};
-use geom::{Rect, Size2D};
+use geom::Size2D;
use gfx::display_list::DisplayList;
use gfx::font::FontMetrics;
use gfx::font_context::FontContext;
@@ -1141,9 +1141,10 @@ impl Flow for InlineFlow {
let stacking_relative_position = match fragment.specific {
InlineBlockFragment(ref mut info) => {
let block_flow = info.flow_ref.as_block();
+ block_flow.base.absolute_position_info = self.base.absolute_position_info;
+
// FIXME(#2795): Get the real container size
let container_size = Size2D::zero();
-
block_flow.base.stacking_relative_position =
self.base.stacking_relative_position +
fragment.border_box.start.to_physical(self.base.writing_mode,
@@ -1152,6 +1153,8 @@ impl Flow for InlineFlow {
}
InlineAbsoluteHypotheticalFragment(ref mut info) => {
let block_flow = info.flow_ref.as_block();
+ block_flow.base.absolute_position_info = self.base.absolute_position_info;
+
// FIXME(#2795): Get the real container size
let container_size = Size2D::zero();
block_flow.base.stacking_relative_position =
@@ -1184,15 +1187,6 @@ impl Flow for InlineFlow {
fn update_late_computed_block_position_if_necessary(&mut self, _: Au) {}
fn build_display_list(&mut self, layout_context: &LayoutContext) {
- let size = self.base.position.size.to_physical(self.base.writing_mode);
- if !Rect(self.base.stacking_relative_position, size).intersects(&layout_context.shared
- .dirty) {
- debug!("inline block (stacking relative pos {}, size {}) didn't intersect dirty rect",
- self.base.stacking_relative_position,
- size);
- return
- }
-
// TODO(#228): Once we form lines and have their cached bounds, we can be smarter and
// not recurse on a line if nothing in it can intersect the dirty region.
debug!("Flow: building display list for {:u} inline fragments", self.fragments.len());
@@ -1211,6 +1205,11 @@ impl Flow for InlineFlow {
flow::mut_base(block_flow).display_list_building_result
.add_to(&mut *display_list)
}
+ InlineAbsoluteHypotheticalFragment(ref mut block_flow) => {
+ let block_flow = block_flow.flow_ref.deref_mut();
+ flow::mut_base(block_flow).display_list_building_result
+ .add_to(&mut *display_list)
+ }
_ => {}
}
}
diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs
index 8fe2afb35ab..6f030d98ea6 100644
--- a/components/layout/layout_task.rs
+++ b/components/layout/layout_task.rs
@@ -25,27 +25,27 @@ use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use geom::scale_factor::ScaleFactor;
+use gfx::color;
use gfx::display_list::{DisplayList, OpaqueNode, StackingContext};
-use gfx::render_task::{RenderInitMsg, RenderChan, RenderLayer};
-use gfx::{render_task, color};
+use gfx::font_cache_task::FontCacheTask;
+use gfx::render_task::{mod, RenderInitMsg, RenderChan, RenderLayer};
use layout_traits;
use layout_traits::{LayoutControlMsg, LayoutTaskFactory};
use log;
use script::dom::bindings::js::JS;
use script::dom::node::{ElementNodeTypeId, LayoutDataRef, Node};
use script::dom::element::{HTMLBodyElementTypeId, HTMLHtmlElementTypeId};
-use script::layout_interface::{
- AddStylesheetMsg, ContentBoxResponse, ContentBoxesResponse, ContentBoxesQuery,
- ContentBoxQuery, ExitNowMsg, GetRPCMsg, HitTestResponse, LayoutChan, LayoutRPC,
- LoadStylesheetMsg, MouseOverResponse, Msg, NoQuery, PrepareToExitMsg, ReapLayoutDataMsg,
- Reflow, ReflowForDisplay, ReflowMsg, ScriptLayoutChan, TrustedNodeAddress,
-};
+use script::layout_interface::{AddStylesheetMsg, ContentBoxResponse, ContentBoxesResponse};
+use script::layout_interface::{ContentBoxesQuery, ContentBoxQuery, ExitNowMsg, GetRPCMsg};
+use script::layout_interface::{HitTestResponse, LayoutChan, LayoutRPC, LoadStylesheetMsg};
+use script::layout_interface::{MouseOverResponse, Msg, NoQuery, PrepareToExitMsg};
+use script::layout_interface::{ReapLayoutDataMsg, Reflow, ReflowForDisplay, ReflowMsg};
+use script::layout_interface::{ScriptLayoutChan, TrustedNodeAddress};
use script_traits::{SendEventMsg, ReflowEvent, ReflowCompleteMsg, OpaqueScriptLayoutChannel};
use script_traits::{ScriptControlChan, UntrustedNodeAddress};
use servo_msg::compositor_msg::Scrollable;
use servo_msg::constellation_msg::{ConstellationChan, PipelineId, Failure, FailureMsg};
use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg};
-use gfx::font_cache_task::{FontCacheTask};
use servo_net::local_image_cache::{ImageResponder, LocalImageCache};
use servo_net::resource_task::{ResourceTask, load_bytes_iter};
use servo_util::geometry::Au;
@@ -679,6 +679,7 @@ impl LayoutTask {
let stacking_context = Arc::new(StackingContext::new(display_list,
origin,
0,
+ 1.0,
Some(render_layer)));
rw_data.stacking_context = Some(stacking_context.clone());
diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock
index 698779f792e..b41e866470d 100644
--- a/components/servo/Cargo.lock
+++ b/components/servo/Cargo.lock
@@ -27,7 +27,7 @@ dependencies = [
[[package]]
name = "azure"
version = "0.1.0"
-source = "git+https://github.com/servo/rust-azure#64853170e435d9320f3fd828b9e7d16bc4c260a3"
+source = "git+https://github.com/servo/rust-azure#d323c3c7c248d3d5a2d46a6a5ee61c6e92aec0b0"
dependencies = [
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
"core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
@@ -212,7 +212,7 @@ source = "git+https://github.com/servo/libfreetype2#f5c49c0da1d5bc6b206c41763440
[[package]]
name = "geom"
version = "0.1.0"
-source = "git+https://github.com/servo/rust-geom#e5e74911ac6d3201009879b72499d6c681302611"
+source = "git+https://github.com/servo/rust-geom#95e746133b4a35b53eb259304668b63ee8de42b8"
[[package]]
name = "gfx"
diff --git a/components/style/properties/mod.rs.mako b/components/style/properties/mod.rs.mako
index 29cc7d3f2fc..bb3e35e8886 100644
--- a/components/style/properties/mod.rs.mako
+++ b/components/style/properties/mod.rs.mako
@@ -1208,6 +1208,37 @@ pub mod longhands {
${switch_to_style_struct("Box")}
${single_keyword("box-sizing", "content-box border-box")}
+
+ ${new_style_struct("Effects", is_inherited=False)}
+
+ <%self:single_component_value name="opacity">
+ pub type SpecifiedValue = CSSFloat;
+ pub mod computed_value {
+ use super::super::CSSFloat;
+ pub type T = CSSFloat;
+ }
+ #[inline]
+ pub fn get_initial_value() -> computed_value::T {
+ 1.0
+ }
+ #[inline]
+ pub fn to_computed_value(value: SpecifiedValue, _: &computed::Context)
+ -> computed_value::T {
+ if value < 0.0 {
+ 0.0
+ } else if value > 1.0 {
+ 1.0
+ } else {
+ value
+ }
+ }
+ fn from_component_value(input: &ComponentValue, _: &Url) -> Result<SpecifiedValue,()> {
+ match *input {
+ Number(ref value) => Ok(value.value),
+ _ => Err(())
+ }
+ }
+ </%self:single_component_value>
}
diff --git a/ports/android/glut_app/Cargo.lock b/ports/android/glut_app/Cargo.lock
index 94074c2d8f2..e9d12a5ed52 100644
--- a/ports/android/glut_app/Cargo.lock
+++ b/ports/android/glut_app/Cargo.lock
@@ -15,7 +15,7 @@ dependencies = [
[[package]]
name = "azure"
version = "0.1.0"
-source = "git+https://github.com/servo/rust-azure#612ffc4fbf80c1bd5faae4b86dfc539dda06fb0c"
+source = "git+https://github.com/servo/rust-azure#d323c3c7c248d3d5a2d46a6a5ee61c6e92aec0b0"
dependencies = [
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
"core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock
index f75b454ec47..97f7e4d84a8 100644
--- a/ports/cef/Cargo.lock
+++ b/ports/cef/Cargo.lock
@@ -26,7 +26,7 @@ dependencies = [
[[package]]
name = "azure"
version = "0.1.0"
-source = "git+https://github.com/servo/rust-azure#612ffc4fbf80c1bd5faae4b86dfc539dda06fb0c"
+source = "git+https://github.com/servo/rust-azure#d323c3c7c248d3d5a2d46a6a5ee61c6e92aec0b0"
dependencies = [
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
"core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
diff --git a/tests/ref/basic.list b/tests/ref/basic.list
index de0dbb6eb28..4170c574013 100644
--- a/tests/ref/basic.list
+++ b/tests/ref/basic.list
@@ -185,4 +185,5 @@ fragment=top != ../html/acid2.html acid2_ref.html
!= linear_gradients_corners_a.html linear_gradients_corners_ref.html
== linear_gradients_lengths_a.html linear_gradients_lengths_ref.html
== incremental_float_a.html incremental_float_ref.html
-== table_specified_width_a.html table_specified_width_ref.html
+== opacity_simple_a.html opacity_simple_ref.html
+== opacity_stacking_context_a.html opacity_stacking_context_ref.html
diff --git a/tests/ref/opacity_simple_a.html b/tests/ref/opacity_simple_a.html
new file mode 100644
index 00000000000..c3dcbba1814
--- /dev/null
+++ b/tests/ref/opacity_simple_a.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Tests that opacity works. -->
+<style>
+section {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ top: 50px;
+ left: 50px;
+}
+#a {
+ background: #800000;
+}
+#b {
+ background: #000080;
+ opacity: 0.75;
+}
+</style>
+</head>
+<body>
+<section id=a></section>
+<section id=b></section>
+</body>
+</html>
+
diff --git a/tests/ref/opacity_simple_ref.html b/tests/ref/opacity_simple_ref.html
new file mode 100644
index 00000000000..dadfaf86169
--- /dev/null
+++ b/tests/ref/opacity_simple_ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Tests that opacity works. -->
+<style>
+section {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ top: 50px;
+ left: 50px;
+ background: #200060;
+}
+</style>
+</head>
+<body>
+<section></section>
+</body>
+</html>
+
diff --git a/tests/ref/opacity_stacking_context_a.html b/tests/ref/opacity_stacking_context_a.html
new file mode 100644
index 00000000000..f108afc4506
--- /dev/null
+++ b/tests/ref/opacity_stacking_context_a.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Tests that `opacity` causes a new stacking context to be formed. -->
+<style>
+section {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+}
+
+#a {
+ background: red;
+ top: 0;
+ left: 0;
+ z-index: 1;
+}
+
+#b {
+ background: #00ff00;
+ top: 25px;
+ left: 25px;
+ z-index: 2;
+}
+
+#c {
+ background: blue;
+ top: 50px;
+ left: 50px;
+ z-index: 3;
+}
+
+#container {
+ opacity: 0.5;
+ width: 200px;
+ height: 200px;
+}
+</style>
+</head>
+<body>
+<section id=a></section>
+<section id=c></section>
+<div id=container>
+ <section id=b></section>
+</div>
+</body>
+</html>
+
diff --git a/tests/ref/opacity_stacking_context_ref.html b/tests/ref/opacity_stacking_context_ref.html
new file mode 100644
index 00000000000..3f332580b1a
--- /dev/null
+++ b/tests/ref/opacity_stacking_context_ref.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Tests that `opacity` causes a new stacking context to be formed. -->
+<style>
+section {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+}
+
+#a {
+ background: red;
+ top: 0;
+ left: 0;
+ z-index: 2;
+}
+
+#b {
+ background: #00ff00;
+ top: 25px;
+ left: 25px;
+ z-index: 1;
+ opacity: 0.5;
+}
+
+#c {
+ background: blue;
+ top: 50px;
+ left: 50px;
+ z-index: 3;
+}
+
+#container {
+ width: 200px;
+ height: 200px;
+}
+</style>
+</head>
+<body>
+<section id=a></section>
+<section id=c></section>
+<div id=container>
+ <section id=b></section>
+</div>
+</body>
+</html>
+