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

Add layout_2020 support for filters and mix-blend-mode #25788

Merged
merged 2 commits into from Feb 19, 2020
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -0,0 +1,91 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::geom::{PhysicalPoint, PhysicalRect, PhysicalSides, PhysicalSize};
use style::computed_values::mix_blend_mode::T as ComputedMixBlendMode;
use style::values::computed::Filter as ComputedFilter;
use style::values::computed::Length;
use webrender_api as wr;

pub trait ToWebRender {
type Type;
fn to_webrender(&self) -> Self::Type;
}

impl ToWebRender for ComputedFilter {
type Type = wr::FilterOp;
fn to_webrender(&self) -> Self::Type {
match *self {
ComputedFilter::Blur(radius) => wr::FilterOp::Blur(radius.px()),
ComputedFilter::Brightness(amount) => wr::FilterOp::Brightness(amount.0),
ComputedFilter::Contrast(amount) => wr::FilterOp::Contrast(amount.0),
ComputedFilter::Grayscale(amount) => wr::FilterOp::Grayscale(amount.0),
ComputedFilter::HueRotate(angle) => wr::FilterOp::HueRotate(angle.radians()),
ComputedFilter::Invert(amount) => wr::FilterOp::Invert(amount.0),
ComputedFilter::Opacity(amount) => wr::FilterOp::Opacity(amount.0.into(), amount.0),
ComputedFilter::Saturate(amount) => wr::FilterOp::Saturate(amount.0),
ComputedFilter::Sepia(amount) => wr::FilterOp::Sepia(amount.0),
// Statically check that DropShadow is impossible.
ComputedFilter::DropShadow(ref shadow) => match *shadow {},
// Statically check that Url is impossible.
ComputedFilter::Url(ref url) => match *url {},
}
}
}
impl ToWebRender for ComputedMixBlendMode {
type Type = wr::MixBlendMode;
fn to_webrender(&self) -> Self::Type {
match *self {
ComputedMixBlendMode::Normal => wr::MixBlendMode::Normal,
ComputedMixBlendMode::Multiply => wr::MixBlendMode::Multiply,
ComputedMixBlendMode::Screen => wr::MixBlendMode::Screen,
ComputedMixBlendMode::Overlay => wr::MixBlendMode::Overlay,
ComputedMixBlendMode::Darken => wr::MixBlendMode::Darken,
ComputedMixBlendMode::Lighten => wr::MixBlendMode::Lighten,
ComputedMixBlendMode::ColorDodge => wr::MixBlendMode::ColorDodge,
ComputedMixBlendMode::ColorBurn => wr::MixBlendMode::ColorBurn,
ComputedMixBlendMode::HardLight => wr::MixBlendMode::HardLight,
ComputedMixBlendMode::SoftLight => wr::MixBlendMode::SoftLight,
ComputedMixBlendMode::Difference => wr::MixBlendMode::Difference,
ComputedMixBlendMode::Exclusion => wr::MixBlendMode::Exclusion,
ComputedMixBlendMode::Hue => wr::MixBlendMode::Hue,
ComputedMixBlendMode::Saturation => wr::MixBlendMode::Saturation,
ComputedMixBlendMode::Color => wr::MixBlendMode::Color,
ComputedMixBlendMode::Luminosity => wr::MixBlendMode::Luminosity,
}
}
}

impl ToWebRender for PhysicalPoint<Length> {
type Type = webrender_api::units::LayoutPoint;
fn to_webrender(&self) -> Self::Type {
webrender_api::units::LayoutPoint::new(self.x.px(), self.y.px())
}
}

impl ToWebRender for PhysicalSize<Length> {
type Type = webrender_api::units::LayoutSize;
fn to_webrender(&self) -> Self::Type {
webrender_api::units::LayoutSize::new(self.width.px(), self.height.px())
}
}

impl ToWebRender for PhysicalRect<Length> {
type Type = webrender_api::units::LayoutRect;
fn to_webrender(&self) -> Self::Type {
webrender_api::units::LayoutRect::new(self.origin.to_webrender(), self.size.to_webrender())
}
}

impl ToWebRender for PhysicalSides<Length> {
type Type = webrender_api::units::LayoutSideOffsets;
fn to_webrender(&self) -> Self::Type {
webrender_api::units::LayoutSideOffsets::new(
self.top.px(),
self.right.px(),
self.bottom.px(),
self.left.px(),
)
}
}
@@ -3,8 +3,9 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::context::LayoutContext;
use crate::display_list::conversions::ToWebRender;
use crate::fragments::{BoxFragment, Fragment};
use crate::geom::{PhysicalPoint, PhysicalRect, ToWebRender};
use crate::geom::{PhysicalPoint, PhysicalRect};
use crate::replaced::IntrinsicSizes;
use embedder_traits::Cursor;
use euclid::{Point2D, SideOffsets2D, Size2D};
@@ -20,6 +21,7 @@ use style::values::specified::ui::CursorKind;
use webrender_api::{self as wr, units};

mod background;
mod conversions;
mod gradient;
pub mod stacking_context;

@@ -2,9 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::display_list::conversions::ToWebRender;
use crate::display_list::DisplayListBuilder;
use crate::fragments::{AnonymousFragment, BoxFragment, Fragment};
use crate::geom::{PhysicalRect, ToWebRender};
use crate::geom::PhysicalRect;
use gfx_traits::{combine_id_with_fragment_type, FragmentType};
use std::cmp::Ordering;
use std::mem;
@@ -15,8 +16,8 @@ use style::computed_values::position::T as ComputedPosition;
use style::computed_values::transform_style::T as ComputedTransformStyle;
use style::values::computed::Length;
use style::values::specified::box_::DisplayOutside;
use webrender_api::units::LayoutVector2D;
use webrender_api::{ExternalScrollId, ScrollSensitivity, SpaceAndClipInfo, SpatialId};
use webrender_api as wr;
use webrender_api::units::{LayoutPoint, LayoutVector2D};

#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
pub(crate) enum StackingContextSection {
@@ -26,7 +27,7 @@ pub(crate) enum StackingContextSection {
}

pub(crate) struct StackingContextFragment<'a> {
space_and_clip: SpaceAndClipInfo,
space_and_clip: wr::SpaceAndClipInfo,
section: StackingContextSection,
containing_block: PhysicalRect<Length>,
fragment: &'a Fragment,
@@ -49,12 +50,12 @@ pub(crate) enum StackingContextType {
}

pub(crate) struct StackingContext<'a> {
/// The fragment that established this stacking context.
initializing_fragment: Option<&'a BoxFragment>,

/// The type of this StackingContext. Used for collecting and sorting.
context_type: StackingContextType,

/// The `z-index` for this stacking context.
pub z_index: i32,

/// Fragments that make up the content of this stacking context.
fragments: Vec<StackingContextFragment<'a>>,

@@ -67,22 +68,44 @@ pub(crate) struct StackingContext<'a> {
}

impl<'a> StackingContext<'a> {
pub(crate) fn new(context_type: StackingContextType, z_index: i32) -> Self {
pub(crate) fn new(
initializing_fragment: &'a BoxFragment,
context_type: StackingContextType,
) -> Self {
Self {
initializing_fragment: Some(initializing_fragment),
context_type,
z_index,
fragments: vec![],
stacking_contexts: vec![],
float_stacking_contexts: vec![],
}
}

pub(crate) fn create_root() -> Self {
Self {
initializing_fragment: None,
context_type: StackingContextType::Real,
fragments: vec![],
stacking_contexts: vec![],
float_stacking_contexts: vec![],
}
}

fn z_index(&self) -> i32 {
match self.initializing_fragment {
Some(fragment) => fragment.effective_z_index(),
None => 0,
}
}

pub(crate) fn sort(&mut self) {
self.fragments.sort_by(|a, b| a.section.cmp(&b.section));

self.stacking_contexts.sort_by(|a, b| {
if a.z_index != 0 || b.z_index != 0 {
return a.z_index.cmp(&b.z_index);
let a_z_index = a.z_index();
let b_z_index = b.z_index();
if a_z_index != 0 || b_z_index != 0 {
return a_z_index.cmp(&b_z_index);
}

match (a.context_type, b.context_type) {
@@ -96,7 +119,60 @@ impl<'a> StackingContext<'a> {
});
}

fn push_webrender_stacking_context_if_necessary(
&self,
builder: &'a mut DisplayListBuilder,
) -> bool {
let fragment = match self.initializing_fragment {
Some(fragment) => fragment,
None => return false,
};

// WebRender only uses the stacking context to apply certain effects. If we don't
// actually need to create a stacking context, just avoid creating one.
let effects = fragment.style.get_effects();
if effects.filter.0.is_empty() &&
effects.opacity == 1.0 &&
effects.mix_blend_mode == ComputedMixBlendMode::Normal
{
return false;
}

// Create the filter pipeline.
let mut filters: Vec<wr::FilterOp> = effects
.filter
.0
.iter()
.map(ToWebRender::to_webrender)
.collect();
if effects.opacity != 1.0 {
filters.push(wr::FilterOp::Opacity(
effects.opacity.into(),
effects.opacity,
));
}

builder.wr.push_stacking_context(
LayoutPoint::zero(), // origin
builder.current_space_and_clip.spatial_id, // spatial_id
wr::PrimitiveFlags::default(),
None, // clip_id
wr::TransformStyle::Flat,
effects.mix_blend_mode.to_webrender(),
&filters,
&vec![], // filter_datas
&vec![], // filter_primitives
wr::RasterSpace::Screen,
false, // cache_tiles,
false, // false
);

true
}

pub(crate) fn build_display_list(&'a self, builder: &'a mut DisplayListBuilder) {
let pushed_context = self.push_webrender_stacking_context_if_necessary(builder);

// Properly order display items that make up a stacking context. "Steps" here
// refer to the steps in CSS 2.1 Appendix E.

@@ -112,7 +188,7 @@ impl<'a> StackingContext<'a> {
let mut child_stacking_contexts = self.stacking_contexts.iter().peekable();
while child_stacking_contexts
.peek()
.map_or(false, |child| child.z_index < 0)
.map_or(false, |child| child.z_index() < 0)
{
let child_context = child_stacking_contexts.next().unwrap();
child_context.build_display_list(builder);
@@ -142,6 +218,10 @@ impl<'a> StackingContext<'a> {
for child_context in child_stacking_contexts {
child_context.build_display_list(builder);
}

if pushed_context {
builder.wr.pop_stacking_context();
}
}
}

@@ -210,11 +290,12 @@ impl BoxFragment {

/// Returns true if this fragment establishes a new stacking context and false otherwise.
fn establishes_stacking_context(&self) -> bool {
if self.style.get_effects().opacity != 1.0 {
let effects = self.style.get_effects();
if effects.opacity != 1.0 {
return true;
}

if self.style.get_effects().mix_blend_mode != ComputedMixBlendMode::Normal {
if effects.mix_blend_mode != ComputedMixBlendMode::Normal {
return true;
}

@@ -289,8 +370,7 @@ impl BoxFragment {
},
};

let mut child_stacking_context =
StackingContext::new(context_type, self.effective_z_index());
let mut child_stacking_context = StackingContext::new(self, context_type);
self.build_stacking_context_tree_for_children(
fragment,
builder,
@@ -352,7 +432,7 @@ impl BoxFragment {
// frame that is the parent of this one once we have full support for stacking
// contexts and transforms.
builder.current_space_and_clip.spatial_id =
SpatialId::root_reference_frame(builder.wr.pipeline_id);
wr::SpatialId::root_reference_frame(builder.wr.pipeline_id);
}

fn build_scroll_frame_if_necessary(
@@ -369,14 +449,14 @@ impl BoxFragment {
let id =
combine_id_with_fragment_type(self.tag.id() as usize, FragmentType::FragmentBody)
as u64;
let external_id = ExternalScrollId(id, builder.wr.pipeline_id);
let external_id = wr::ExternalScrollId(id, builder.wr.pipeline_id);

let sensitivity = if ComputedOverflow::Hidden == overflow_x &&
ComputedOverflow::Hidden == overflow_y
{
ScrollSensitivity::Script
wr::ScrollSensitivity::Script
} else {
ScrollSensitivity::ScriptAndInputEvents
wr::ScrollSensitivity::ScriptAndInputEvents
};

let padding_rect = self
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::context::LayoutContext;
use crate::display_list::stacking_context::{StackingContext, StackingContextType};
use crate::display_list::stacking_context::StackingContext;
use crate::dom_traversal::{Contents, NodeExt};
use crate::flow::construct::ContainsFloats;
use crate::flow::float::FloatBox;
@@ -182,7 +182,7 @@ impl BoxTreeRoot {

impl FragmentTreeRoot {
pub fn build_display_list(&self, builder: &mut crate::display_list::DisplayListBuilder) {
let mut stacking_context = StackingContext::new(StackingContextType::Real, 0);
let mut stacking_context = StackingContext::create_root();
for fragment in &self.children {
fragment.build_stacking_context_tree(
builder,
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.