mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Auto merge of #5546 - Adenilson:blurFilter01, r=pcwalton
See discussion on #5190 and #5496. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/5546) <!-- Reviewable:end -->
This commit is contained in:
commit
1fd6a48cca
6 changed files with 222 additions and 69 deletions
|
@ -8,15 +8,18 @@ use azure::AzFloat;
|
||||||
use azure::azure_hl::{ColorMatrixAttribute, ColorMatrixInput, CompositeInput, DrawTarget};
|
use azure::azure_hl::{ColorMatrixAttribute, ColorMatrixInput, CompositeInput, DrawTarget};
|
||||||
use azure::azure_hl::{FilterNode, FilterType, LinearTransferAttribute, LinearTransferInput};
|
use azure::azure_hl::{FilterNode, FilterType, LinearTransferAttribute, LinearTransferInput};
|
||||||
use azure::azure_hl::{Matrix5x4, TableTransferAttribute, TableTransferInput};
|
use azure::azure_hl::{Matrix5x4, TableTransferAttribute, TableTransferInput};
|
||||||
|
use azure::azure_hl::{GaussianBlurAttribute, GaussianBlurInput};
|
||||||
|
|
||||||
use std::num::Float;
|
use std::num::Float;
|
||||||
use style::computed_values::filter;
|
use style::computed_values::filter;
|
||||||
|
use util::geometry::Au;
|
||||||
|
|
||||||
/// Creates a filter pipeline from a set of CSS filters. Returns the destination end of the filter
|
/// Creates a filter pipeline from a set of CSS filters. Returns the destination end of the filter
|
||||||
/// pipeline and the opacity.
|
/// pipeline and the opacity.
|
||||||
pub fn create_filters(draw_target: &DrawTarget,
|
pub fn create_filters(draw_target: &DrawTarget,
|
||||||
temporary_draw_target: &DrawTarget,
|
temporary_draw_target: &DrawTarget,
|
||||||
style_filters: &filter::T)
|
style_filters: &filter::T,
|
||||||
|
accumulated_blur_radius: &mut Au)
|
||||||
-> (FilterNode, AzFloat) {
|
-> (FilterNode, AzFloat) {
|
||||||
let mut opacity = 1.0;
|
let mut opacity = 1.0;
|
||||||
let mut filter = draw_target.create_filter(FilterType::Composite);
|
let mut filter = draw_target.create_filter(FilterType::Composite);
|
||||||
|
@ -91,6 +94,14 @@ pub fn create_filters(draw_target: &DrawTarget,
|
||||||
contrast.set_input(LinearTransferInput, &filter);
|
contrast.set_input(LinearTransferInput, &filter);
|
||||||
filter = contrast
|
filter = contrast
|
||||||
}
|
}
|
||||||
|
filter::Filter::Blur(amount) => {
|
||||||
|
*accumulated_blur_radius = accumulated_blur_radius.clone() + amount;
|
||||||
|
let amount = amount.to_frac32_px();
|
||||||
|
let blur = draw_target.create_filter(FilterType::GaussianBlur);
|
||||||
|
blur.set_attribute(GaussianBlurAttribute::StdDeviation(amount));
|
||||||
|
blur.set_input(GaussianBlurInput, &filter);
|
||||||
|
filter = blur
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(filter, opacity)
|
(filter, opacity)
|
||||||
|
@ -107,6 +118,23 @@ pub fn temporary_draw_target_needed_for_style_filters(filters: &filter::T) -> bo
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If there is one or more blur filters, we need to know the blur ammount
|
||||||
|
// to expand the draw target size.
|
||||||
|
pub fn calculate_accumulated_blur(style_filters: &filter::T) -> Au {
|
||||||
|
let mut accum_blur = Au::new(0);
|
||||||
|
for style_filter in style_filters.filters.iter() {
|
||||||
|
match *style_filter {
|
||||||
|
filter::Filter::Blur(amount) => {
|
||||||
|
accum_blur = accum_blur.clone() + amount;
|
||||||
|
}
|
||||||
|
_ => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
accum_blur
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Creates a grayscale 5x4 color matrix per CSS-FILTERS § 12.1.1.
|
/// Creates a grayscale 5x4 color matrix per CSS-FILTERS § 12.1.1.
|
||||||
fn grayscale(amount: AzFloat) -> Matrix5x4 {
|
fn grayscale(amount: AzFloat) -> Matrix5x4 {
|
||||||
Matrix5x4 {
|
Matrix5x4 {
|
||||||
|
|
|
@ -909,12 +909,30 @@ impl<'a> PaintContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(pcwalton): This surface might be bigger than necessary and waste memory.
|
// FIXME(pcwalton): This surface might be bigger than necessary and waste memory.
|
||||||
let size = self.draw_target.get_size();
|
let size = self.draw_target.get_size(); //Az size.
|
||||||
let size = Size2D(size.width, size.height);
|
let mut size = Size2D(size.width, size.height); //Geom::Size.
|
||||||
|
|
||||||
|
// Pre-calculate if there is a blur expansion need.
|
||||||
|
let accum_blur = filters::calculate_accumulated_blur(filters);
|
||||||
|
let mut matrix = self.draw_target.get_transform();
|
||||||
|
if accum_blur > Au(0) {
|
||||||
|
// Set the correct size.
|
||||||
|
let side_inflation = accum_blur * BLUR_INFLATION_FACTOR;
|
||||||
|
size = Size2D(size.width + (side_inflation.to_nearest_px() * 2) as i32, size.height + (side_inflation.to_nearest_px() * 2) as i32);
|
||||||
|
|
||||||
|
// Calculate the transform matrix.
|
||||||
|
let old_transform = self.draw_target.get_transform();
|
||||||
|
let inflated_size = Rect(Point2D(0.0, 0.0), Size2D(size.width as AzFloat,
|
||||||
|
size.height as AzFloat));
|
||||||
|
let temporary_draw_target_bounds = old_transform.transform_rect(&inflated_size);
|
||||||
|
matrix = Matrix2D::identity().translate(-temporary_draw_target_bounds.origin.x as AzFloat,
|
||||||
|
-temporary_draw_target_bounds.origin.y as AzFloat).mul(&old_transform);
|
||||||
|
}
|
||||||
|
|
||||||
let temporary_draw_target =
|
let temporary_draw_target =
|
||||||
self.draw_target.create_similar_draw_target(&size, self.draw_target.get_format());
|
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.set_transform(&matrix);
|
||||||
temporary_draw_target
|
temporary_draw_target
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -932,18 +950,36 @@ impl<'a> PaintContext<'a> {
|
||||||
// Set up transforms.
|
// Set up transforms.
|
||||||
let old_transform = self.draw_target.get_transform();
|
let old_transform = self.draw_target.get_transform();
|
||||||
self.draw_target.set_transform(&Matrix2D::identity());
|
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 rect_temporary = Rect(Point2D(0.0, 0.0), temporary_draw_target.get_size().to_azure_size());
|
||||||
|
|
||||||
// Create the Azure filter pipeline.
|
// Create the Azure filter pipeline.
|
||||||
|
let mut accum_blur = Au(0);
|
||||||
let (filter_node, opacity) = filters::create_filters(&self.draw_target,
|
let (filter_node, opacity) = filters::create_filters(&self.draw_target,
|
||||||
temporary_draw_target,
|
temporary_draw_target,
|
||||||
filters);
|
filters,
|
||||||
|
&mut accum_blur);
|
||||||
|
|
||||||
// Perform the blit operation.
|
// Perform the blit operation.
|
||||||
let rect = Rect(Point2D(0.0, 0.0), self.draw_target.get_size().to_azure_size());
|
|
||||||
let mut draw_options = DrawOptions::new(opacity, 0);
|
let mut draw_options = DrawOptions::new(opacity, 0);
|
||||||
draw_options.set_composition_op(blend_mode.to_azure_composition_op());
|
draw_options.set_composition_op(blend_mode.to_azure_composition_op());
|
||||||
self.draw_target.draw_filter(&filter_node, &rect, &rect.origin, draw_options);
|
|
||||||
|
// If there is a blur expansion, shift the transform and update the size.
|
||||||
|
if accum_blur > Au(0) {
|
||||||
|
// Remove both the transient clip and the stacking context clip, because we may need to
|
||||||
|
// draw outside the stacking context's clip.
|
||||||
|
self.remove_transient_clip_if_applicable();
|
||||||
|
self.pop_clip_if_applicable();
|
||||||
|
|
||||||
|
debug!("######### use expanded Rect.");
|
||||||
|
self.draw_target.draw_filter(&filter_node, &rect_temporary, &rect_temporary.origin, draw_options);
|
||||||
|
self.push_clip_if_applicable();
|
||||||
|
} else {
|
||||||
|
debug!("######### use regular Rect.");
|
||||||
|
self.draw_target.draw_filter(&filter_node, &rect, &rect.origin, draw_options);
|
||||||
|
}
|
||||||
|
|
||||||
self.draw_target.set_transform(&old_transform);
|
self.draw_target.set_transform(&old_transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2695,22 +2695,38 @@ pub mod longhands {
|
||||||
</%self:longhand>
|
</%self:longhand>
|
||||||
|
|
||||||
<%self:longhand name="filter">
|
<%self:longhand name="filter">
|
||||||
use values::specified::Angle;
|
//pub use self::computed_value::T as SpecifiedValue;
|
||||||
pub use self::computed_value::T as SpecifiedValue;
|
use values::computed::{Context, ToComputedValue};
|
||||||
pub use self::computed_value::Filter;
|
use values::specified::{Angle, Length};
|
||||||
use values::computed::ComputedValueAsSpecified;
|
use values::CSSFloat;
|
||||||
|
use cssparser::{self, ToCss};
|
||||||
|
use text_writer::{self, TextWriter};
|
||||||
|
|
||||||
impl ComputedValueAsSpecified for SpecifiedValue {}
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub struct SpecifiedValue(Vec<SpecifiedFilter>);
|
||||||
|
|
||||||
|
// TODO(pcwalton): `drop-shadow`
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
pub enum SpecifiedFilter {
|
||||||
|
Blur(Length),
|
||||||
|
Brightness(CSSFloat),
|
||||||
|
Contrast(CSSFloat),
|
||||||
|
Grayscale(CSSFloat),
|
||||||
|
HueRotate(Angle),
|
||||||
|
Invert(CSSFloat),
|
||||||
|
Opacity(CSSFloat),
|
||||||
|
Saturate(CSSFloat),
|
||||||
|
Sepia(CSSFloat),
|
||||||
|
}
|
||||||
|
|
||||||
pub mod computed_value {
|
pub mod computed_value {
|
||||||
use values::specified::Angle;
|
use util::geometry::Au;
|
||||||
use values::CSSFloat;
|
use values::CSSFloat;
|
||||||
use cssparser::ToCss;
|
use values::specified::{Angle};
|
||||||
use text_writer::{self, TextWriter};
|
|
||||||
|
|
||||||
// TODO(pcwalton): `blur`, `drop-shadow`
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub enum Filter {
|
pub enum Filter {
|
||||||
|
Blur(Au),
|
||||||
Brightness(CSSFloat),
|
Brightness(CSSFloat),
|
||||||
Contrast(CSSFloat),
|
Contrast(CSSFloat),
|
||||||
Grayscale(CSSFloat),
|
Grayscale(CSSFloat),
|
||||||
|
@ -2721,54 +2737,16 @@ pub mod longhands {
|
||||||
Sepia(CSSFloat),
|
Sepia(CSSFloat),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for Filter {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
|
|
||||||
match *self {
|
|
||||||
Filter::Brightness(value) => try!(write!(dest, "brightness({})", value)),
|
|
||||||
Filter::Contrast(value) => try!(write!(dest, "contrast({})", value)),
|
|
||||||
Filter::Grayscale(value) => try!(write!(dest, "grayscale({})", value)),
|
|
||||||
Filter::HueRotate(value) => {
|
|
||||||
try!(dest.write_str("hue-rotate("));
|
|
||||||
try!(value.to_css(dest));
|
|
||||||
try!(dest.write_str(")"));
|
|
||||||
}
|
|
||||||
Filter::Invert(value) => try!(write!(dest, "invert({})", value)),
|
|
||||||
Filter::Opacity(value) => try!(write!(dest, "opacity({})", value)),
|
|
||||||
Filter::Saturate(value) => try!(write!(dest, "saturate({})", value)),
|
|
||||||
Filter::Sepia(value) => try!(write!(dest, "sepia({})", value)),
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub struct T {
|
pub struct T { pub filters: Vec<Filter> }
|
||||||
pub filters: Vec<Filter>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for T {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
|
|
||||||
let mut iter = self.filters.iter();
|
|
||||||
if let Some(filter) = iter.next() {
|
|
||||||
try!(filter.to_css(dest));
|
|
||||||
} else {
|
|
||||||
try!(dest.write_str("none"));
|
|
||||||
return Ok(())
|
|
||||||
}
|
|
||||||
for filter in iter {
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
try!(filter.to_css(dest));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl T {
|
impl T {
|
||||||
/// Creates a new filter pipeline.
|
/// Creates a new filter pipeline.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(filters: Vec<Filter>) -> T {
|
pub fn new(filters: Vec<Filter>) -> T {
|
||||||
T {
|
T
|
||||||
filters: filters,
|
{
|
||||||
|
filters: filters,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2788,6 +2766,7 @@ pub mod longhands {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn opacity(&self) -> CSSFloat {
|
pub fn opacity(&self) -> CSSFloat {
|
||||||
let mut opacity = 1.0;
|
let mut opacity = 1.0;
|
||||||
|
|
||||||
for filter in self.filters.iter() {
|
for filter in self.filters.iter() {
|
||||||
if let Filter::Opacity(ref opacity_value) = *filter {
|
if let Filter::Opacity(ref opacity_value) = *filter {
|
||||||
opacity *= *opacity_value
|
opacity *= *opacity_value
|
||||||
|
@ -2798,6 +2777,48 @@ pub mod longhands {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToCss for SpecifiedValue {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
|
||||||
|
let mut iter = self.0.iter();
|
||||||
|
if let Some(filter) = iter.next() {
|
||||||
|
try!(filter.to_css(dest));
|
||||||
|
} else {
|
||||||
|
try!(dest.write_str("none"));
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
|
for filter in iter {
|
||||||
|
try!(dest.write_str(" "));
|
||||||
|
try!(filter.to_css(dest));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToCss for SpecifiedFilter {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
|
||||||
|
match *self {
|
||||||
|
SpecifiedFilter::Blur(value) => {
|
||||||
|
try!(dest.write_str("blur("));
|
||||||
|
try!(value.to_css(dest));
|
||||||
|
try!(dest.write_str(")"));
|
||||||
|
}
|
||||||
|
SpecifiedFilter::Brightness(value) => try!(write!(dest, "brightness({})", value)),
|
||||||
|
SpecifiedFilter::Contrast(value) => try!(write!(dest, "contrast({})", value)),
|
||||||
|
SpecifiedFilter::Grayscale(value) => try!(write!(dest, "grayscale({})", value)),
|
||||||
|
SpecifiedFilter::HueRotate(value) => {
|
||||||
|
try!(dest.write_str("hue-rotate("));
|
||||||
|
try!(value.to_css(dest));
|
||||||
|
try!(dest.write_str(")"));
|
||||||
|
}
|
||||||
|
SpecifiedFilter::Invert(value) => try!(write!(dest, "invert({})", value)),
|
||||||
|
SpecifiedFilter::Opacity(value) => try!(write!(dest, "opacity({})", value)),
|
||||||
|
SpecifiedFilter::Saturate(value) => try!(write!(dest, "saturate({})", value)),
|
||||||
|
SpecifiedFilter::Sepia(value) => try!(write!(dest, "sepia({})", value)),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_initial_value() -> computed_value::T {
|
pub fn get_initial_value() -> computed_value::T {
|
||||||
computed_value::T::new(Vec::new())
|
computed_value::T::new(Vec::new())
|
||||||
|
@ -2806,27 +2827,28 @@ pub mod longhands {
|
||||||
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
|
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
|
||||||
let mut filters = Vec::new();
|
let mut filters = Vec::new();
|
||||||
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
|
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
|
||||||
return Ok(SpecifiedValue::new(filters))
|
return Ok(SpecifiedValue(filters))
|
||||||
}
|
}
|
||||||
loop {
|
loop {
|
||||||
if let Ok(function_name) = input.try(|input| input.expect_function()) {
|
if let Ok(function_name) = input.try(|input| input.expect_function()) {
|
||||||
filters.push(try!(input.parse_nested_block(|input| {
|
filters.push(try!(input.parse_nested_block(|input| {
|
||||||
match_ignore_ascii_case! { function_name,
|
match_ignore_ascii_case! { function_name,
|
||||||
"brightness" => parse_factor(input).map(Filter::Brightness),
|
"blur" => specified::Length::parse_non_negative(input).map(SpecifiedFilter::Blur),
|
||||||
"contrast" => parse_factor(input).map(Filter::Contrast),
|
"brightness" => parse_factor(input).map(SpecifiedFilter::Brightness),
|
||||||
"grayscale" => parse_factor(input).map(Filter::Grayscale),
|
"contrast" => parse_factor(input).map(SpecifiedFilter::Contrast),
|
||||||
"hue-rotate" => Angle::parse(input).map(Filter::HueRotate),
|
"grayscale" => parse_factor(input).map(SpecifiedFilter::Grayscale),
|
||||||
"invert" => parse_factor(input).map(Filter::Invert),
|
"hue-rotate" => Angle::parse(input).map(SpecifiedFilter::HueRotate),
|
||||||
"opacity" => parse_factor(input).map(Filter::Opacity),
|
"invert" => parse_factor(input).map(SpecifiedFilter::Invert),
|
||||||
"saturate" => parse_factor(input).map(Filter::Saturate),
|
"opacity" => parse_factor(input).map(SpecifiedFilter::Opacity),
|
||||||
"sepia" => parse_factor(input).map(Filter::Sepia)
|
"saturate" => parse_factor(input).map(SpecifiedFilter::Saturate),
|
||||||
|
"sepia" => parse_factor(input).map(SpecifiedFilter::Sepia)
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
})));
|
})));
|
||||||
} else if filters.is_empty() {
|
} else if filters.is_empty() {
|
||||||
return Err(())
|
return Err(())
|
||||||
} else {
|
} else {
|
||||||
return Ok(SpecifiedValue::new(filters))
|
return Ok(SpecifiedValue(filters))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2839,6 +2861,26 @@ pub mod longhands {
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToComputedValue for SpecifiedValue {
|
||||||
|
type ComputedValue = computed_value::T;
|
||||||
|
|
||||||
|
fn to_computed_value(&self, context: &computed::Context) -> computed_value::T {
|
||||||
|
computed_value::T{ filters: self.0.iter().map(|value| {
|
||||||
|
match value {
|
||||||
|
&SpecifiedFilter::Blur(factor) => computed_value::Filter::Blur(factor.to_computed_value(context)),
|
||||||
|
&SpecifiedFilter::Brightness(factor) => computed_value::Filter::Brightness(factor),
|
||||||
|
&SpecifiedFilter::Contrast(factor) => computed_value::Filter::Contrast(factor),
|
||||||
|
&SpecifiedFilter::Grayscale(factor) => computed_value::Filter::Grayscale(factor),
|
||||||
|
&SpecifiedFilter::HueRotate(factor) => computed_value::Filter::HueRotate(factor),
|
||||||
|
&SpecifiedFilter::Invert(factor) => computed_value::Filter::Invert(factor),
|
||||||
|
&SpecifiedFilter::Opacity(factor) => computed_value::Filter::Opacity(factor),
|
||||||
|
&SpecifiedFilter::Saturate(factor) => computed_value::Filter::Saturate(factor),
|
||||||
|
&SpecifiedFilter::Sepia(factor) => computed_value::Filter::Sepia(factor),
|
||||||
|
}
|
||||||
|
}).collect() }
|
||||||
|
}
|
||||||
|
}
|
||||||
</%self:longhand>
|
</%self:longhand>
|
||||||
|
|
||||||
<%self:longhand name="transform">
|
<%self:longhand name="transform">
|
||||||
|
|
|
@ -75,6 +75,7 @@ flaky_cpu == append_style_a.html append_style_b.html
|
||||||
!= block_image.html noteq_500x300_white.html
|
!= block_image.html noteq_500x300_white.html
|
||||||
== block_replaced_content_a.html block_replaced_content_ref.html
|
== block_replaced_content_a.html block_replaced_content_ref.html
|
||||||
== block_replaced_content_b.html block_replaced_content_ref.html
|
== block_replaced_content_b.html block_replaced_content_ref.html
|
||||||
|
== blur_a.html blur_ref.html
|
||||||
!= border_black_groove.html border_black_solid.html
|
!= border_black_groove.html border_black_solid.html
|
||||||
!= border_black_ridge.html border_black_groove.html
|
!= border_black_ridge.html border_black_groove.html
|
||||||
!= border_black_ridge.html border_black_solid.html
|
!= border_black_ridge.html border_black_solid.html
|
||||||
|
|
29
tests/ref/blur_a.html
Normal file
29
tests/ref/blur_a.html
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style type="text/css">
|
||||||
|
div {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ex {
|
||||||
|
position: relative;
|
||||||
|
width: 40px; height: 40px;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: black;
|
||||||
|
top: 50px; left: 50px;
|
||||||
|
-webkit-filter: blur(30px);
|
||||||
|
-moz-filter: blur(30px);
|
||||||
|
filter: blur(30px);
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<div class="ex"></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
17
tests/ref/blur_ref.html
Normal file
17
tests/ref/blur_ref.html
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style type="text/css">
|
||||||
|
div {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue