Skip to content
Permalink
Browse files

Bug 1536021 - Shadow stack implementation. r=kvark

  • Loading branch information...
nical authored and moz-gfx committed May 12, 2019
1 parent 1d72cd8 commit b899f2bff265c7e680f2e913c5216a19d2982e2b

Large diffs are not rendered by default.

@@ -19,7 +19,7 @@ use crate::glyph_rasterizer::FontInstance;
use crate::hit_test::{HitTestingItem, HitTestingScene};
use crate::image::simplify_repeated_primitive;
use crate::intern::Interner;
use crate::internal_types::{FastHashMap, FastHashSet, LayoutPrimitiveInfo};
use crate::internal_types::{FastHashMap, FastHashSet, LayoutPrimitiveInfo, Filter};
use crate::picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PictureOptions};
use crate::picture::{BlitReason, PrimitiveList, TileCache};
use crate::prim_store::{PrimitiveInstance, PrimitiveSceneData};
@@ -1280,7 +1280,7 @@ impl<'a> DisplayListFlattener<'a> {
apply_pipeline_clip
);

self.push_shadow(info.shadow, clip_and_scroll);
self.push_shadow(info.shadow, clip_and_scroll, info.should_inflate);
}
DisplayItem::PopAllShadows => {
self.pop_all_shadows();
@@ -1760,7 +1760,7 @@ impl<'a> DisplayListFlattener<'a> {
let filter = filter.sanitize();

let composite_mode = Some(match filter {
FilterOp::ComponentTransfer => {
Filter::ComponentTransfer => {
let filter_data =
&stacking_context.composite_ops.filter_datas[current_filter_data_index];
let filter_data = filter_data.sanitize();
@@ -2098,12 +2098,14 @@ impl<'a> DisplayListFlattener<'a> {
&mut self,
shadow: Shadow,
clip_and_scroll: ScrollNodeAndClipChain,
should_inflate: bool,
) {
// Store this shadow in the pending list, for processing
// during pop_all_shadows.
self.pending_shadow_items.push_back(ShadowItem::Shadow(PendingShadow {
shadow,
clip_and_scroll,
should_inflate,
}));
}

@@ -2202,15 +2204,15 @@ impl<'a> DisplayListFlattener<'a> {
// blur radius is 0, the code in Picture::prepare_for_render will
// detect this and mark the picture to be drawn directly into the
// parent picture, which avoids an intermediate surface and blur.
let blur_filter = FilterOp::Blur(std_deviation).sanitize();
let blur_filter = Filter::Blur(std_deviation).sanitize();
let composite_mode = PictureCompositeMode::Filter(blur_filter);
let composite_mode_key = Some(composite_mode.clone()).into();
let is_backface_visible = true; //TODO: double check this

// Pass through configuration information about whether WR should
// do the bounding rect inflation for text shadows.
let options = PictureOptions {
inflate_if_required: pending_shadow.shadow.should_inflate,
inflate_if_required: pending_shadow.should_inflate,
};

// Create the primitive to draw the shadow picture into the scene.
@@ -2312,16 +2314,16 @@ impl<'a> DisplayListFlattener<'a> {
// Offset the local rect and clip rect by the shadow offset.
let mut info = pending_primitive.info.clone();
info.rect = info.rect.translate(&pending_shadow.shadow.offset);
info.clip_rect = info.clip_rect.translate(&pending_shadow.shadow.offset);
info.clip_rect = info.clip_rect.translate(
&pending_shadow.shadow.offset
);

// Construct and add a primitive for the given shadow.
let shadow_prim_instance = self.create_primitive(
&info,
pending_primitive.clip_and_scroll.clip_chain_id,
pending_primitive.clip_and_scroll.spatial_node_index,
pending_primitive.prim.create_shadow(
&pending_shadow.shadow,
),
pending_primitive.prim.create_shadow(&pending_shadow.shadow),
);

// Add the new primitive to the shadow picture.
@@ -3031,6 +3033,7 @@ pub struct PendingPrimitive<T> {
/// shadows, and handled at once during pop_all_shadows.
pub struct PendingShadow {
shadow: Shadow,
should_inflate: bool,
clip_and_scroll: ScrollNodeAndClipChain,
}

@@ -3,8 +3,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use api::{DebugCommand, DocumentId, ExternalImageData, ExternalImageId};
use api::{ImageFormat, ItemTag, NotificationRequest};
use api::{ImageFormat, ItemTag, NotificationRequest, Shadow, FilterOp, MAX_BLUR_RADIUS};
use api::units::*;
use api;
use crate::device::TextureFilter;
use crate::renderer::PipelineInfo;
use crate::gpu_cache::GpuCacheUpdateList;
@@ -30,6 +31,141 @@ pub type FastHashSet<K> = HashSet<K, BuildHasherDefault<FxHasher>>;
/// A concrete plane splitter type used in WebRender.
pub type PlaneSplitter = BspSplitter<f64, WorldPixel>;

/// An arbitrary number which we assume opacity is invisible below.
const OPACITY_EPSILON: f32 = 0.001;

/// Equivalent to api::FilterOp with added internal information
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum Filter {
Identity,
Blur(f32),
Brightness(f32),
Contrast(f32),
Grayscale(f32),
HueRotate(f32),
Invert(f32),
Opacity(api::PropertyBinding<f32>, f32),
Saturate(f32),
Sepia(f32),
DropShadow(Shadow),
#[allow(dead_code)]
DropShadowStack(Vec<Shadow>),
ColorMatrix([f32; 20]),
SrgbToLinear,
LinearToSrgb,
ComponentTransfer,
}

impl Filter {
/// Ensure that the parameters for a filter operation
/// are sensible.
pub fn sanitize(&self) -> Self {
match self {
Filter::Blur(radius) => Filter::Blur(radius.min(MAX_BLUR_RADIUS)),
Filter::DropShadow(shadow) => Filter::DropShadow(Shadow {
offset: shadow.offset,
blur_radius: shadow.blur_radius.min(MAX_BLUR_RADIUS),
color: shadow.color
}),
Filter::DropShadowStack(ref stack) => {
let mut shadows = Vec::with_capacity(stack.len());
for shadow in stack {
shadows.push(Shadow {
blur_radius: shadow.blur_radius.min(MAX_BLUR_RADIUS),
..*shadow
});
}
Filter::DropShadowStack(shadows)
}
filter => filter.clone(),
}
}

pub fn is_visible(&self) -> bool {
match *self {
Filter::Identity |
Filter::Blur(..) |
Filter::Brightness(..) |
Filter::Contrast(..) |
Filter::Grayscale(..) |
Filter::HueRotate(..) |
Filter::Invert(..) |
Filter::Saturate(..) |
Filter::Sepia(..) |
Filter::DropShadow(..) |
Filter::DropShadowStack(..) |
Filter::ColorMatrix(..) |
Filter::SrgbToLinear |
Filter::LinearToSrgb |
Filter::ComponentTransfer => true,
Filter::Opacity(_, amount) => {
amount > OPACITY_EPSILON
}
}
}

pub fn is_noop(&self) -> bool {
match *self {
Filter::Identity => false, // this is intentional
Filter::Blur(length) => length == 0.0,
Filter::Brightness(amount) => amount == 1.0,
Filter::Contrast(amount) => amount == 1.0,
Filter::Grayscale(amount) => amount == 0.0,
Filter::HueRotate(amount) => amount == 0.0,
Filter::Invert(amount) => amount == 0.0,
Filter::Opacity(_, amount) => amount >= 1.0,
Filter::Saturate(amount) => amount == 1.0,
Filter::Sepia(amount) => amount == 0.0,
Filter::DropShadowStack(ref shadows) => {
for shadow in shadows {
if shadow.offset.x != 0.0 || shadow.offset.y != 0.0 || shadow.blur_radius != 0.0 {
return false;
}
}

true
}
Filter::DropShadow(shadow) => {
shadow.offset.x == 0.0 && shadow.offset.y == 0.0 && shadow.blur_radius == 0.0
},
Filter::ColorMatrix(matrix) => {
matrix == [1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
0.0, 0.0, 0.0, 0.0]
}
Filter::SrgbToLinear |
Filter::LinearToSrgb |
Filter::ComponentTransfer => false,
}
}
}

impl From<FilterOp> for Filter {
fn from(op: FilterOp) -> Self {
match op {
FilterOp::Identity => Filter::Identity,
FilterOp::Blur(r) => Filter::Blur(r),
FilterOp::Brightness(b) => Filter::Brightness(b),
FilterOp::Contrast(c) => Filter::Contrast(c),
FilterOp::Grayscale(g) => Filter::Grayscale(g),
FilterOp::HueRotate(h) => Filter::HueRotate(h),
FilterOp::Invert(i) => Filter::Invert(i),
FilterOp::Opacity(binding, opacity) => Filter::Opacity(binding, opacity),
FilterOp::Saturate(s) => Filter::Saturate(s),
FilterOp::Sepia(s) => Filter::Sepia(s),
FilterOp::DropShadow(shadow) => Filter::DropShadow(shadow),
FilterOp::ColorMatrix(mat) => Filter::ColorMatrix(mat),
FilterOp::SrgbToLinear => Filter::SrgbToLinear,
FilterOp::LinearToSrgb => Filter::LinearToSrgb,
FilterOp::ComponentTransfer => Filter::ComponentTransfer,
}
}
}

/// An ID for a texture that is owned by the `texture_cache` module.
///
/// This can include atlases or standalone textures allocated via the texture

0 comments on commit b899f2b

Please sign in to comment.
You can’t perform that action at this time.