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

layout: Implement `filter` per CSS-FILTERS § 5. #4557

Merged
merged 1 commit into from Jan 9, 2015
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -56,8 +56,7 @@ impl CanvasPaintTask {

fn fill_rect(&self, rect: &Rect<f32>) {
let drawopts = DrawOptions::new(1.0, 0);
self.drawtarget.fill_rect(rect, PatternRef::ColorPatternRef(&self.fill_color),
Some(&drawopts));
self.drawtarget.fill_rect(rect, PatternRef::Color(&self.fill_color), Some(&drawopts));
}

fn clear_rect(&self, rect: &Rect<f32>) {
@@ -70,7 +69,7 @@ impl CanvasPaintTask {
}

fn create(size: Size2D<i32>) -> DrawTarget {
DrawTarget::new(BackendType::SkiaBackend, size, SurfaceFormat::B8G8R8A8)
DrawTarget::new(BackendType::Skia, size, SurfaceFormat::B8G8R8A8)
}

fn recreate(&mut self, size: Size2D<i32>) {
@@ -41,7 +41,7 @@ use std::fmt;
use std::slice::Items;
use std::sync::Arc;
use style::ComputedValues;
use style::computed_values::{border_style, cursor, pointer_events};
use style::computed_values::{border_style, cursor, filter, pointer_events};

// It seems cleaner to have layout code not mention Azure directly, so let's just reexport this for
// layout to use.
@@ -163,8 +163,8 @@ pub struct StackingContext {
pub overflow: Rect<Au>,
/// The `z-index` for this stacking context.
pub z_index: i32,
/// The opacity of this stacking context.
pub opacity: AzFloat,
/// CSS filters to be applied to this stacking context (including opacity).
pub filters: filter::T,
}

impl StackingContext {
@@ -174,7 +174,7 @@ impl StackingContext {
bounds: &Rect<Au>,
overflow: &Rect<Au>,
z_index: i32,
opacity: AzFloat,
filters: filter::T,
layer: Option<Arc<PaintLayer>>)
-> StackingContext {
StackingContext {
@@ -183,7 +183,7 @@ impl StackingContext {
bounds: *bounds,
overflow: *overflow,
z_index: z_index,
opacity: opacity,
filters: filters,
}
}

@@ -194,7 +194,7 @@ impl StackingContext {
transform: &Matrix2D<AzFloat>,
clip_rect: Option<&Rect<Au>>) {
let temporary_draw_target =
paint_context.get_or_create_temporary_draw_target(self.opacity);
paint_context.get_or_create_temporary_draw_target(&self.filters);
{
let mut paint_subcontext = PaintContext {
draw_target: temporary_draw_target.clone(),
@@ -306,7 +306,8 @@ impl StackingContext {
paint_subcontext.draw_target.set_transform(&old_transform)
}

paint_context.draw_temporary_draw_target_if_necessary(&temporary_draw_target, self.opacity)
paint_context.draw_temporary_draw_target_if_necessary(&temporary_draw_target,
&self.filters)
}

/// Translate the given tile rect into the coordinate system of a child stacking context.
@@ -0,0 +1,198 @@
/* 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 http://mozilla.org/MPL/2.0/. */

//! CSS and SVG filter support.

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 std::num::FloatMath;
use style::computed_values::filter;

/// 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)
-> (FilterNode, AzFloat) {
let mut opacity = 1.0;
let mut filter = draw_target.create_filter(FilterType::Composite);
filter.set_input(CompositeInput, &temporary_draw_target.snapshot());
for style_filter in style_filters.filters.iter() {
match *style_filter {
filter::Filter::HueRotate(angle) => {
let hue_rotate = draw_target.create_filter(FilterType::ColorMatrix);
let matrix = self::hue_rotate(angle.radians() as AzFloat);
hue_rotate.set_attribute(ColorMatrixAttribute::Matrix(matrix));
hue_rotate.set_input(ColorMatrixInput, &filter);
filter = hue_rotate
}
filter::Filter::Opacity(opacity_value) => opacity *= opacity_value as AzFloat,
filter::Filter::Saturate(amount) => {
let saturate = draw_target.create_filter(FilterType::ColorMatrix);
let matrix = self::saturate(amount as AzFloat);
saturate.set_attribute(ColorMatrixAttribute::Matrix(matrix));
saturate.set_input(ColorMatrixInput, &filter);
filter = saturate
}
filter::Filter::Sepia(amount) => {
let sepia = draw_target.create_filter(FilterType::ColorMatrix);
let matrix = self::sepia(amount as AzFloat);
sepia.set_attribute(ColorMatrixAttribute::Matrix(matrix));
sepia.set_input(ColorMatrixInput, &filter);
filter = sepia
}
filter::Filter::Grayscale(amount) => {
let amount = amount as AzFloat;
let grayscale = draw_target.create_filter(FilterType::ColorMatrix);
grayscale.set_attribute(ColorMatrixAttribute::Matrix(self::grayscale(amount)));
grayscale.set_input(ColorMatrixInput, &filter);
filter = grayscale
}
filter::Filter::Invert(amount) => {
let amount = amount as AzFloat;
let invert = draw_target.create_filter(FilterType::TableTransfer);
invert.set_attribute(TableTransferAttribute::DisableR(false));
invert.set_attribute(TableTransferAttribute::DisableG(false));
invert.set_attribute(TableTransferAttribute::DisableB(false));
invert.set_attribute(TableTransferAttribute::TableR(&[1.0, amount - 1.0]));
invert.set_attribute(TableTransferAttribute::TableG(&[1.0, amount - 1.0]));
invert.set_attribute(TableTransferAttribute::TableB(&[1.0, amount - 1.0]));
invert.set_input(TableTransferInput, &filter);
filter = invert
}
filter::Filter::Brightness(amount) => {
let amount = amount as AzFloat;
let brightness = draw_target.create_filter(FilterType::LinearTransfer);
brightness.set_attribute(LinearTransferAttribute::DisableR(false));
brightness.set_attribute(LinearTransferAttribute::DisableG(false));
brightness.set_attribute(LinearTransferAttribute::DisableB(false));
brightness.set_attribute(LinearTransferAttribute::SlopeR(amount));
brightness.set_attribute(LinearTransferAttribute::SlopeG(amount));
brightness.set_attribute(LinearTransferAttribute::SlopeB(amount));
brightness.set_input(LinearTransferInput, &filter);
filter = brightness
}
filter::Filter::Contrast(amount) => {
let amount = amount as AzFloat;
let contrast = draw_target.create_filter(FilterType::LinearTransfer);
contrast.set_attribute(LinearTransferAttribute::DisableR(false));
contrast.set_attribute(LinearTransferAttribute::DisableG(false));
contrast.set_attribute(LinearTransferAttribute::DisableB(false));
contrast.set_attribute(LinearTransferAttribute::SlopeR(amount));
contrast.set_attribute(LinearTransferAttribute::SlopeG(amount));
contrast.set_attribute(LinearTransferAttribute::SlopeB(amount));
contrast.set_attribute(LinearTransferAttribute::InterceptR(-0.5 * amount + 0.5));
contrast.set_attribute(LinearTransferAttribute::InterceptG(-0.5 * amount + 0.5));
contrast.set_attribute(LinearTransferAttribute::InterceptB(-0.5 * amount + 0.5));
contrast.set_input(LinearTransferInput, &filter);
filter = contrast
}
}
}
(filter, opacity)
}

/// Determines if we need a temporary draw target for the given set of filters.
pub fn temporary_draw_target_needed_for_style_filters(filters: &filter::T) -> bool {
for filter in filters.filters.iter() {
match *filter {
filter::Filter::Opacity(value) if value == 1.0 => continue,
_ => return true,
}
}
false
}

/// Creates a grayscale 5x4 color matrix per CSS-FILTERS § 12.1.1.
fn grayscale(amount: AzFloat) -> Matrix5x4 {
Matrix5x4 {
m11: 0.2126 + 0.7874 * (1.0 - amount),
m21: 0.7152 - 0.7152 * (1.0 - amount),
m31: 0.0722 - 0.0722 * (1.0 - amount),
m41: 0.0,
m51: 0.0,
m12: 0.2126 - 0.2126 * (1.0 - amount),
m22: 0.7152 + 0.2848 * (1.0 - amount),
m32: 0.0722 - 0.0722 * (1.0 - amount),
m42: 0.0,
m52: 0.0,
m13: 0.2126 - 0.2126 * (1.0 - amount),
m23: 0.7152 - 0.7152 * (1.0 - amount),
m33: 0.0722 + 0.9278 * (1.0 - amount),
m43: 0.0,
m53: 0.0,
m14: 0.0, m24: 0.0, m34: 0.0, m44: 1.0, m54: 0.0,
}
}

/// Creates a 5x4 hue rotation color matrix per CSS-FILTERS § 8.5.
fn hue_rotate(angle: AzFloat) -> Matrix5x4 {
let (c, s) = (angle.cos(), angle.sin());
Matrix5x4 {
m11: 0.213 + c * 0.787 + s * -0.213,
m21: 0.715 + c * -0.715 + s * -0.715,
m31: 0.072 + c * -0.072 + s * 0.928,
m41: 0.0,
m51: 0.0,
m12: 0.213 + c * -0.213 + s * 0.143,
m22: 0.715 + c * 0.285 + s * 0.140,
m32: 0.072 + c * -0.072 + s * -0.283,
m42: 0.0,
m52: 0.0,
m13: 0.213 + c * -0.213 + s * -0.787,
m23: 0.715 + c * -0.715 + s * 0.715,
m33: 0.072 + c * 0.928 + s * 0.072,
m43: 0.0,
m53: 0.0,
m14: 0.0, m24: 0.0, m34: 0.0, m44: 1.0, m54: 0.0,
}
}

/// Creates a 5x4 saturation color matrix per CSS-FILTERS § 8.5.
fn saturate(amount: AzFloat) -> Matrix5x4 {
Matrix5x4 {
m11: 0.213 + 0.787 * amount,
m21: 0.715 - 0.715 * amount,
m31: 0.072 - 0.072 * amount,
m41: 0.0,
m51: 0.0,
m12: 0.213 - 0.213 * amount,
m22: 0.715 + 0.285 * amount,
m32: 0.072 - 0.072 * amount,
m42: 0.0,
m52: 0.0,
m13: 0.213 - 0.213 * amount,
m23: 0.715 - 0.715 * amount,
m33: 0.072 + 0.928 * amount,
m43: 0.0,
m53: 0.0,
m14: 0.0, m24: 0.0, m34: 0.0, m44: 1.0, m54: 0.0,
}
}

/// Creates a sepia 5x4 color matrix per CSS-FILTERS § 12.1.1.
fn sepia(amount: AzFloat) -> Matrix5x4 {
Matrix5x4 {
m11: 0.393 + 0.607 * (1.0 - amount),
m21: 0.769 - 0.769 * (1.0 - amount),
m31: 0.189 - 0.189 * (1.0 - amount),
m41: 0.0,
m51: 0.0,
m12: 0.349 - 0.349 * (1.0 - amount),
m22: 0.686 + 0.314 * (1.0 - amount),
m32: 0.168 - 0.168 * (1.0 - amount),
m42: 0.0,
m52: 0.0,
m13: 0.272 - 0.272 * (1.0 - amount),
m23: 0.534 - 0.534 * (1.0 - amount),
m33: 0.131 + 0.869 * (1.0 - amount),
m43: 0.0,
m53: 0.0,
m14: 0.0, m24: 0.0, m34: 0.0, m44: 1.0, m54: 0.0,
}
}

@@ -30,14 +30,14 @@ use azure::scaled_font::FontInfo;

#[cfg(any(target_os="linux", target_os = "android"))]
fn create_scaled_font(template: &Arc<FontTemplateData>, pt_size: Au) -> ScaledFont {
ScaledFont::new(BackendType::SkiaBackend, FontInfo::FontData(&template.bytes),
ScaledFont::new(BackendType::Skia, FontInfo::FontData(&template.bytes),
pt_size.to_subpx() as AzFloat)
}

#[cfg(target_os="macos")]
fn create_scaled_font(template: &Arc<FontTemplateData>, pt_size: Au) -> ScaledFont {
let cgfont = template.ctfont.as_ref().unwrap().copy_to_CGFont();
ScaledFont::new(BackendType::SkiaBackend, &cgfont, pt_size.to_subpx() as AzFloat)
ScaledFont::new(BackendType::Skia, &cgfont, pt_size.to_subpx() as AzFloat)
}

static SMALL_CAPS_SCALE_FACTOR: f64 = 0.8; // Matches FireFox (see gfxFont.h)
@@ -68,6 +68,7 @@ pub mod font_template;

// Misc.
mod buffer_map;
mod filters;

// Platform-specific implementations.
#[path="platform/mod.rs"]
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.