diff options
author | bors-servo <metajack+bors@gmail.com> | 2014-12-03 15:22:00 -0700 |
---|---|---|
committer | bors-servo <metajack+bors@gmail.com> | 2014-12-03 15:22:00 -0700 |
commit | 68c90e27970808bddcb8c8a4e782bd4405e67a5c (patch) | |
tree | 19ba94ff619ff8cc32a9ffaf9fe73bb0afdaf948 | |
parent | 873ca6cadddc1a40bead1f5dd0128bb16cfaa11b (diff) | |
parent | 1c1c507c03757a3e4b76ca799b866b047d69a7b5 (diff) | |
download | servo-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.rs | 157 | ||||
-rw-r--r-- | components/gfx/render_context.rs | 68 | ||||
-rw-r--r-- | components/gfx/render_task.rs | 2 | ||||
-rw-r--r-- | components/layout/block.rs | 43 | ||||
-rw-r--r-- | components/layout/display_list_builder.rs | 63 | ||||
-rw-r--r-- | components/layout/fragment.rs | 3 | ||||
-rw-r--r-- | components/layout/inline.rs | 21 | ||||
-rw-r--r-- | components/layout/layout_task.rs | 19 | ||||
-rw-r--r-- | components/servo/Cargo.lock | 4 | ||||
-rw-r--r-- | components/style/properties/mod.rs.mako | 31 | ||||
-rw-r--r-- | ports/android/glut_app/Cargo.lock | 2 | ||||
-rw-r--r-- | ports/cef/Cargo.lock | 2 | ||||
-rw-r--r-- | tests/ref/basic.list | 3 | ||||
-rw-r--r-- | tests/ref/opacity_simple_a.html | 27 | ||||
-rw-r--r-- | tests/ref/opacity_simple_ref.html | 20 | ||||
-rw-r--r-- | tests/ref/opacity_stacking_context_a.html | 48 | ||||
-rw-r--r-- | tests/ref/opacity_stacking_context_ref.html | 48 |
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> + |