Implementing Blur filter.

This commit is contained in:
Adenilson Cavalcanti 2015-03-10 16:27:15 -07:00
parent 35fb516662
commit 05dd176186
6 changed files with 222 additions and 69 deletions

View file

@ -8,15 +8,18 @@ use azure::AzFloat;
use azure::azure_hl::{ColorMatrixAttribute, ColorMatrixInput, CompositeInput, DrawTarget};
use azure::azure_hl::{FilterNode, FilterType, LinearTransferAttribute, LinearTransferInput};
use azure::azure_hl::{Matrix5x4, TableTransferAttribute, TableTransferInput};
use azure::azure_hl::{GaussianBlurAttribute, GaussianBlurInput};
use std::num::Float;
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
/// pipeline and the opacity.
pub fn create_filters(draw_target: &DrawTarget,
temporary_draw_target: &DrawTarget,
style_filters: &filter::T)
style_filters: &filter::T,
accumulated_blur_radius: &mut Au)
-> (FilterNode, AzFloat) {
let mut opacity = 1.0;
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);
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)
@ -107,6 +118,23 @@ pub fn temporary_draw_target_needed_for_style_filters(filters: &filter::T) -> bo
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.
fn grayscale(amount: AzFloat) -> Matrix5x4 {
Matrix5x4 {

View file

@ -909,12 +909,30 @@ impl<'a> PaintContext<'a> {
}
// FIXME(pcwalton): This surface might be bigger than necessary and waste memory.
let size = self.draw_target.get_size();
let size = Size2D(size.width, size.height);
let size = self.draw_target.get_size(); //Az size.
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 =
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
}
@ -932,18 +950,36 @@ impl<'a> PaintContext<'a> {
// Set up transforms.
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 rect_temporary = Rect(Point2D(0.0, 0.0), temporary_draw_target.get_size().to_azure_size());
// Create the Azure filter pipeline.
let mut accum_blur = Au(0);
let (filter_node, opacity) = filters::create_filters(&self.draw_target,
temporary_draw_target,
filters);
filters,
&mut accum_blur);
// 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);
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);
}