Bug 948265 - Add nsCSSFilterInstance with support for adding CSS blur filters to filter graphs. r=mstange

This commit is contained in:
Max Vujovic 2014-08-06 10:48:47 -07:00
parent 7962d26866
commit ccfb7c4ac1
29 changed files with 875 additions and 32 deletions

View File

@ -95,8 +95,6 @@ namespace gfx {
// Some convenience FilterNode creation functions.
static const float kMaxStdDeviation = 500;
namespace FilterWrappers {
static TemporaryRef<FilterNode>
@ -1312,9 +1310,9 @@ FilterSupport::ComputeResultChangeRegion(const FilterDescription& aFilter,
return resultChangeRegions[resultChangeRegions.Length() - 1];
}
static nsIntRegion
PostFilterExtentsForPrimitive(const FilterPrimitiveDescription& aDescription,
const nsTArray<nsIntRegion>& aInputExtents)
nsIntRegion
FilterSupport::PostFilterExtentsForPrimitive(const FilterPrimitiveDescription& aDescription,
const nsTArray<nsIntRegion>& aInputExtents)
{
const AttributeMap& atts = aDescription.Attributes();
switch (aDescription.Type()) {

View File

@ -164,6 +164,9 @@ MOZ_BEGIN_ENUM_CLASS(AttributeType)
Max
MOZ_END_ENUM_CLASS(AttributeType)
// Limits
const float kMaxStdDeviation = 500;
// A class that stores values of different types, keyed by an attribute name.
// The Get*() methods assert that they're called for the same type that the
// attribute was Set() with.
@ -444,6 +447,13 @@ public:
ComputePostFilterExtents(const FilterDescription& aFilter,
const nsIntRegion& aSourceGraphicExtents);
/**
* Computes the size of a single FilterPrimitiveDescription's output given a
* set of input extents.
*/
static nsIntRegion
PostFilterExtentsForPrimitive(const FilterPrimitiveDescription& aDescription,
const nsTArray<nsIntRegion>& aInputExtents);
};
}

View File

@ -0,0 +1,6 @@
# These tests verify that CSS filter chains behave properly.
# e.g. filter: blur(3px) grayscale(0.5) invert(0.2);
default-preferences pref(layout.css.filters.enabled,true)
== same-filter.html same-filter-ref.html

View File

@ -0,0 +1,30 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS Filter Chains: Filters of the Same Type</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<style type="text/css">
#target {
filter: url(#blur);
background-color: #0f0;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a blurred green square.</p>
<div id="target"></div>
<svg width="0" height="0">
<filter id="blur" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse">
<feGaussianBlur stdDeviation="1" color-interpolation-filters="sRGB"/>
<feGaussianBlur stdDeviation="2" color-interpolation-filters="sRGB"/>
<feGaussianBlur stdDeviation="3" color-interpolation-filters="sRGB"/>
</filter>
</svg>
</body>
</html>

View File

@ -0,0 +1,28 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS Filter Chains: Filters of the Same Type</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<link rel="help" href="http://www.w3.org/TR/filter-effects-1/#FilterProperty">
<link rel="match" href="same-filter-ref.html">
<meta name="assert"
content="Multiple chained CSS filter functions of the same type should
render correctly.">
<style type="text/css">
#target {
filter: blur(1px) blur(2px) blur(3px);
background-color: #0f0;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a blurred green square.</p>
<div id="target"></div>
</body>
</html>

View File

@ -0,0 +1,28 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS Filters: Blur an HTML Element</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<style type="text/css">
#target {
filter: url(#blur);
background-color: #0f0;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a blurred green square.</p>
<div id="target"></div>
<svg width="0" height="0">
<filter id="blur">
<feGaussianBlur stdDeviation="3" color-interpolation-filters="sRGB"/>
</filter>
</svg>
</body>
</html>

View File

@ -0,0 +1,29 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<svg id="svg-root"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="testmeta">
<title>CSS Filters: Blur an SVG Element</title>
<link rel="copyright"
href="http://www.w3.org/Graphics/SVG/Test/Copyright"/>
<link rel="license"
href="http://www.w3.org/Consortium/Legal/2008/03-bsd-license.html"/>
<link rel="author"
title="Max Vujovic"
href="mailto:mvujovic@adobe.com"/>
<link rel="help"
href="http://www.w3.org/TR/filter-effects-1/#funcdef-blur"/>
<metadata class="flags">namespace svg</metadata>
</g>
<g id="test-body-content">
<filter id="blur" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse">
<feGaussianBlur stdDeviation="3" color-interpolation-filters="sRGB"/>
</filter>
<rect x="20" y="20" width="100" height="100" fill="#0f0" filter="url(#blur)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,22 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS Filters: Blur with Zero Radius</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<style type="text/css">
#target {
background-color: #0f0;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a green square. It should not be blurred.</p>
<div id="target"></div>
</body>
</html>

View File

@ -0,0 +1,27 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS Filters: Blur with Zero Radius</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<link rel="help" href="http://www.w3.org/TR/filter-effects-1/#funcdef-blur">
<link rel="match" href="blur-zero-radius-ref.html">
<meta name="assert" content="Given a zero blur radius, the CSS blur filter
function will not blur an HTML element.">
<style type="text/css">
#target {
filter: blur(0);
background-color: #0f0;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a green square. It should not be blurred.</p>
<div id="target"></div>
</body>
</html>

View File

@ -0,0 +1,30 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS Filters: Blur on a 2x Zoomed Page</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<style type="text/css">
body {
margin: 2rem;
}
#target {
filter: url(#blur);
background-color: #0f0;
width: 200px;
height: 200px;
}
</style>
</head>
<body>
<div id="target"></div>
<svg width="0" height="0">
<filter id="blur" x="-100" y="-100" width="400" height="400" filterUnits="userSpaceOnUse">
<feGaussianBlur stdDeviation="6" color-interpolation-filters="sRGB"/>
</filter>
</svg>
</body>
</html>

View File

@ -0,0 +1,33 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html reftest-zoom="2.0">
<head>
<title>CSS Filters: Blur on a 2x Zoomed Page</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<link rel="help" href="http://www.w3.org/TR/filter-effects-1/#funcdef-blur">
<link rel="match" href="blur-zoomed-page-ref.html">
<meta name="assert"
content="The results of the CSS blur filter function should scale up
proportionally when the page is zoomed. At 1x zoom, you should
see a blurred green square. At 2x zoom, you should see a
blurred green square with a blur radius that's twice as
large.">
<style type="text/css">
body {
margin: 1rem;
}
#target {
filter: blur(3px);
background-color: #0f0;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<div id="target"></div>
</body>
</html>

View File

@ -0,0 +1,28 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS Filters: Blur an HTML Element</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<link rel="help" href="http://www.w3.org/TR/filter-effects-1/#funcdef-blur">
<link rel="match" href="blur-ref.html">
<meta name="assert"
content="Given a valid blur radius, the CSS blur filter function should
blur an HTML element.">
<style type="text/css">
#target {
filter: blur(3px);
background-color: #0f0;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a blurred green square.</p>
<div id="target"></div>
</body>
</html>

View File

@ -0,0 +1,32 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<svg id="svg-root"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="testmeta">
<title>CSS Filters: Blur an SVG Element</title>
<link rel="copyright"
href="http://www.w3.org/Graphics/SVG/Test/Copyright"/>
<link rel="license"
href="http://www.w3.org/Consortium/Legal/2008/03-bsd-license.html"/>
<link rel="author"
title="Max Vujovic"
href="mailto:mvujovic@adobe.com"/>
<link rel="help"
href="http://www.w3.org/TR/filter-effects-1/#funcdef-blur"/>
<link rel="match"
href="blur-ref.svg"/>
<metadata class="flags">namespace svg</metadata>
<desc class="assert">
This test verifies that the CSS blur filter function can filter SVG
elements. If the test passes, you should see a green square.
</desc>
</g>
<g id="test-body-content">
<rect x="20" y="20" width="100" height="100" fill="#0f0" filter="blur(3px)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,9 @@
# These tests verify that CSS filters behave properly.
# e.g. filter: blur(3px)
default-preferences pref(layout.css.filters.enabled,true)
== blur.html blur-ref.html
== blur.svg blur-ref.svg
== blur-zero-radius.html blur-zero-radius-ref.html
== blur-zoomed-page.html blur-zoomed-page-ref.html

View File

@ -0,0 +1,32 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS and SVG Filter Chains: Clip Input CSS Filter with Following SVG Filter's Filter Region</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<style type="text/css">
#target {
filter: url(#blur) url(#clip-and-red-to-green);
background-color: #f00;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a blurred green square.</p>
<div id="target"></div>
<svg width="0" height="0">
<filter id="blur" x="-50" y="-50" width="200" height="200">
<feGaussianBlur stdDeviation="3" color-interpolation-filters="sRGB"/>
</filter>
<!-- Use a small filter region that clips the blur extents. -->
<filter id="clip-and-red-to-green" x="0" y="0" width="100" height="100" filterUnits="userSpaceOnUse">
<feColorMatrix type="hueRotate" values="90" color-interpolation-filters="sRGB"/>
</filter>
</svg>
</body>
</html>

View File

@ -0,0 +1,34 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS and SVG Filter Chains: Clip Input CSS Filter with Following SVG Filter's Filter Region</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<link rel="help" href="http://www.w3.org/TR/filter-effects-1/#FilterEffectsRegion">
<link rel="match" href="css-filter-first-ref.html">
<meta name="assert"
content="An SVG filter's filter region should clip the input from a CSS
filter function.">
<style type="text/css">
#target {
filter: blur(3px) url(#clip-and-red-to-green);
background-color: #f00;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a blurred green square.</p>
<div id="target"></div>
<svg width="0" height="0">
<!-- Use a small filter region that clips the blur extents. -->
<filter id="clip-and-red-to-green" x="0" y="0" width="100" height="100" filterUnits="userSpaceOnUse">
<feColorMatrix type="hueRotate" values="90" color-interpolation-filters="sRGB"/>
</filter>
</svg>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS and SVG Filter Chains: CSS Filter as First Filter</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<style type="text/css">
#target {
filter: url(#blur-and-red-to-green);
background-color: #f00;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a blurred green square.</p>
<div id="target"></div>
<svg width="0" height="0">
<filter id="blur-and-red-to-green" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse">
<!-- Blur the red square. -->
<feGaussianBlur stdDeviation="3" color-interpolation-filters="sRGB"/>
<!-- Turn the red square into a green square. -->
<feColorMatrix type="hueRotate" values="90" color-interpolation-filters="sRGB"/>
</filter>
</svg>
</body>
</html>

View File

@ -0,0 +1,33 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS and SVG Filter Chains: CSS Filter as First Filter</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<link rel="help" href="http://www.w3.org/TR/filter-effects-1/#FilterProperty">
<link rel="match" href="css-filter-first-ref.html">
<meta name="assert"
content="A filter chain starting with a CSS filter function followed by
an SVG reference filter should render correctly.">
<style type="text/css">
#target {
filter: blur(3px) url(#red-to-green);
background-color: #f00;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a blurred green square.</p>
<div id="target"></div>
<svg width="0" height="0">
<filter id="red-to-green" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse">
<feColorMatrix type="hueRotate" values="90" color-interpolation-filters="sRGB"/>
</filter>
</svg>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS and SVG Filter Chains: CSS Filter as Last Filter</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<style type="text/css">
#target {
filter: url(#red-to-green-and-blur);
background-color: #f00;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a blurred green square.</p>
<div id="target"></div>
<svg width="0" height="0">
<filter id="red-to-green-and-blur" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse">
<!-- Turn the red square into a green square. -->
<feColorMatrix type="hueRotate" values="90" color-interpolation-filters="sRGB"/>
<!-- Blur the red square. -->
<feGaussianBlur stdDeviation="3" color-interpolation-filters="sRGB"/>
</filter>
</svg>
</body>
</html>

View File

@ -0,0 +1,34 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS and SVG Filter Chains: CSS Filter as Last Filter</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<link rel="help" href="http://www.w3.org/TR/filter-effects-1/#FilterProperty">
<link rel="match" href="css-filter-last-ref.html">
<meta name="assert"
content="A filter chain starting with an SVG reference filter followed
by a CSS filter function should render correctly.">
<style type="text/css">
#target {
filter: url(#red-to-green) blur(3px);
background-color: #f00;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a blurred green square.</p>
<div id="target"></div>
<svg width="0" height="0">
<filter id="red-to-green" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse">
<!-- Turn the red square into a green square. -->
<feColorMatrix type="hueRotate" values="90" color-interpolation-filters="sRGB"/>
</filter>
</svg>
</body>
</html>

View File

@ -0,0 +1,38 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS and SVG Filter Chains: CSS Filter as Last Filter</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<style type="text/css">
#target {
filter: url(#magenta-to-green-and-blur);
background-color: #f0f;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a blurred green square.</p>
<div id="target"></div>
<svg width="0" height="0">
<filter id="magenta-to-green-and-blur" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse">
<!-- Turn the magenta square into a red square. -->
<feComponentTransfer color-interpolation-filters="sRGB">
<feFuncR type="identity"/>
<feFuncG type="table" tableValues="0 0"/>
<feFuncB type="table" tableValues="0 0"/>
<feFuncA type="identity"/>
</feComponentTransfer>
<!-- Blur the red square. -->
<feGaussianBlur stdDeviation="3" color-interpolation-filters="sRGB"/>
<!-- Turn the blurred red square into a blurred green square. -->
<feColorMatrix type="hueRotate" values="90" color-interpolation-filters="sRGB"/>
</filter>
</svg>
</body>
</html>

View File

@ -0,0 +1,42 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS and SVG Filter Chains: CSS Filter as Middle Filter</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<link rel="help" href="http://www.w3.org/TR/filter-effects-1/#FilterProperty">
<link rel="match" href="css-filter-middle-ref.html">
<meta name="assert"
content="A filter chain starting with an SVG reference filter, followed
by a CSS filter function, and followed by an SVG reference
filter should render correctly.">
<style type="text/css">
#target {
filter: url(#magenta-to-red) blur(3px) url(#red-to-green);
background-color: #f0f;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a blurred green square.</p>
<div id="target"></div>
<svg width="0" height="0">
<filter id="magenta-to-red" color-interpolation-filters="sRGB">
<feComponentTransfer>
<feFuncR type="identity"/>
<feFuncG type="table" tableValues="0 0"/>
<feFuncB type="table" tableValues="0 0"/>
<feFuncA type="identity"/>
</feComponentTransfer>
</filter>
<filter id="red-to-green" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feColorMatrix type="hueRotate" values="90"/>
</filter>
</svg>
</body>
</html>

View File

@ -0,0 +1,10 @@
# These tests verify that filter chains of combined CSS and SVG filters behave
# properly.
# e.g. filter: url(#f1) blur(3px) url(#2) grayscale(0.5);
default-preferences pref(layout.css.filters.enabled,true)
== clip-input-css-filter.html clip-input-css-filter-ref.html
== css-filter-first.html css-filter-first-ref.html
== css-filter-last.html css-filter-last-ref.html
== css-filter-middle.html css-filter-middle-ref.html

View File

@ -2,6 +2,15 @@
# subregion. The fe*-2 tests test with no clipping (which stresses
# the automatic optimal surface-size computation a bit more).
# CSS filter tests
include css-filters/reftest.list
# CSS filter chain tests
include css-filter-chains/reftest.list
# Combined CSS and SVG filter chain tests
include css-svg-filter-chains/reftest.list
# SVG filter chain tests
include svg-filter-chains/reftest.list

View File

@ -15,6 +15,7 @@ EXPORTS += [
]
UNIFIED_SOURCES += [
'nsCSSFilterInstance.cpp',
'nsFilterInstance.cpp',
'nsSVGAFrame.cpp',
'nsSVGClipPathFrame.cpp',

View File

@ -0,0 +1,140 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
// Main header first:
#include "nsCSSFilterInstance.h"
// Keep others in (case-insensitive) order:
#include "gfx2DGlue.h"
#include "gfxUtils.h"
#include "nsStyleStruct.h"
#include "nsTArray.h"
using namespace mozilla;
using namespace mozilla::gfx;
nsCSSFilterInstance::nsCSSFilterInstance(const nsStyleFilter& aFilter,
const nsIntRect& aTargetBBoxInFilterSpace,
const gfxMatrix& aFrameSpaceInCSSPxToFilterSpaceTransform)
: mFilter(aFilter)
, mTargetBBoxInFilterSpace(aTargetBBoxInFilterSpace)
, mFrameSpaceInCSSPxToFilterSpaceTransform(aFrameSpaceInCSSPxToFilterSpaceTransform)
{
}
nsresult
nsCSSFilterInstance::BuildPrimitives(nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs)
{
FilterPrimitiveDescription descr;
nsresult result;
switch(mFilter.GetType()) {
case NS_STYLE_FILTER_BLUR:
descr = CreatePrimitiveDescription(PrimitiveType::GaussianBlur, aPrimitiveDescrs);
result = SetAttributesForBlur(descr);
break;
case NS_STYLE_FILTER_BRIGHTNESS:
case NS_STYLE_FILTER_CONTRAST:
case NS_STYLE_FILTER_DROP_SHADOW:
case NS_STYLE_FILTER_GRAYSCALE:
case NS_STYLE_FILTER_HUE_ROTATE:
case NS_STYLE_FILTER_INVERT:
case NS_STYLE_FILTER_OPACITY:
case NS_STYLE_FILTER_SATURATE:
case NS_STYLE_FILTER_SEPIA:
return NS_ERROR_NOT_IMPLEMENTED;
default:
NS_NOTREACHED("not a valid CSS filter type");
return NS_ERROR_FAILURE;
}
if (NS_FAILED(result)) {
return result;
}
// Compute the primitive's bounds now that we've determined its attributes.
// Some attributes like blur radius can influence the bounds.
SetBounds(descr, aPrimitiveDescrs);
// Add this primitive to the filter chain.
aPrimitiveDescrs.AppendElement(descr);
return NS_OK;
}
FilterPrimitiveDescription
nsCSSFilterInstance::CreatePrimitiveDescription(PrimitiveType aType,
const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs) {
FilterPrimitiveDescription descr(aType);
int32_t inputIndex = GetLastResultIndex(aPrimitiveDescrs);
descr.SetInputPrimitive(0, inputIndex);
descr.SetIsTainted(inputIndex < 0 ? true : aPrimitiveDescrs[inputIndex].IsTainted());
descr.SetInputColorSpace(0, ColorSpace::SRGB);
descr.SetOutputColorSpace(ColorSpace::SRGB);
return descr;
}
nsresult
nsCSSFilterInstance::SetAttributesForBlur(FilterPrimitiveDescription& aDescr)
{
// Get the radius from the style.
nsStyleCoord radiusStyleCoord = mFilter.GetFilterParameter();
if (radiusStyleCoord.GetUnit() != eStyleUnit_Coord) {
NS_NOTREACHED("unexpected unit");
return NS_ERROR_FAILURE;
}
// Get the radius in frame space.
nscoord radiusInFrameSpace = radiusStyleCoord.GetCoordValue();
float radiusInFrameSpaceInCSSPx =
nsPresContext::AppUnitsToFloatCSSPixels(radiusInFrameSpace);
// Convert the radius to filter space.
gfxSize radiusInFilterSpace(radiusInFrameSpaceInCSSPx,
radiusInFrameSpaceInCSSPx);
gfxSize frameSpaceInCSSPxToFilterSpaceScale =
mFrameSpaceInCSSPxToFilterSpaceTransform.ScaleFactors(true);
radiusInFilterSpace.Scale(frameSpaceInCSSPxToFilterSpaceScale.width,
frameSpaceInCSSPxToFilterSpaceScale.height);
// Check the radius limits.
if (radiusInFilterSpace.width < 0 || radiusInFilterSpace.height < 0) {
NS_NOTREACHED("we shouldn't have parsed a negative radius in the style");
return NS_ERROR_FAILURE;
}
gfxFloat maxStdDeviation = (gfxFloat)kMaxStdDeviation;
radiusInFilterSpace.width = std::min(radiusInFilterSpace.width, maxStdDeviation);
radiusInFilterSpace.height = std::min(radiusInFilterSpace.height, maxStdDeviation);
// Set the radius parameter.
aDescr.Attributes().Set(eGaussianBlurStdDeviation, ToSize(radiusInFilterSpace));
return NS_OK;
}
int32_t
nsCSSFilterInstance::GetLastResultIndex(const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs)
{
uint32_t numPrimitiveDescrs = aPrimitiveDescrs.Length();
return !numPrimitiveDescrs ?
FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic :
numPrimitiveDescrs - 1;
}
void
nsCSSFilterInstance::SetBounds(FilterPrimitiveDescription& aDescr,
const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs) {
int32_t inputIndex = GetLastResultIndex(aPrimitiveDescrs);
nsIntRect inputBounds = (inputIndex < 0) ?
mTargetBBoxInFilterSpace : ThebesIntRect(aPrimitiveDescrs[inputIndex].PrimitiveSubregion());
nsTArray<nsIntRegion> inputExtents;
inputExtents.AppendElement(inputBounds);
nsIntRegion outputExtents =
FilterSupport::PostFilterExtentsForPrimitive(aDescr, inputExtents);
IntRect outputBounds = ToIntRect(outputExtents.GetBounds());
aDescr.SetPrimitiveSubregion(outputBounds);
aDescr.SetFilterSpaceBounds(outputBounds);
}

View File

@ -0,0 +1,92 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef __NS_CSSFILTERINSTANCE_H__
#define __NS_CSSFILTERINSTANCE_H__
#include "FilterSupport.h"
#include "gfxMatrix.h"
#include "gfxRect.h"
struct nsStyleFilter;
template<class T> class nsTArray;
/**
* This class helps nsFilterInstance build its filter graph. It turns a CSS
* filter function (e.g. blur(3px)) from the style system into a
* FilterPrimitiveDescription connected to the filter graph.
*/
class nsCSSFilterInstance
{
typedef mozilla::gfx::FilterPrimitiveDescription FilterPrimitiveDescription;
typedef mozilla::gfx::PrimitiveType PrimitiveType;
public:
/**
* @param aFilter The CSS filter from the style system. This class stores
* aFilter by reference, so callers should avoid modifying or deleting
* aFilter during the lifetime of nsCSSFilterInstance.
* @param mTargetBBoxInFilterSpace The frame of element being filtered, in
* filter space.
* @param aFrameSpaceInCSSPxToFilterSpaceTransform The transformation from
* the filtered element's frame space in CSS pixels to filter space.
*/
nsCSSFilterInstance(const nsStyleFilter& aFilter,
const nsIntRect& mTargetBBoxInFilterSpace,
const gfxMatrix& aFrameSpaceInCSSPxToFilterSpaceTransform);
/**
* Creates at least one new FilterPrimitiveDescription based on the filter
* from the style system. Appends the new FilterPrimitiveDescription(s) to the
* aPrimitiveDescrs list.
*/
nsresult BuildPrimitives(nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs);
private:
/**
* Returns a new FilterPrimitiveDescription with its basic properties set up.
*/
FilterPrimitiveDescription CreatePrimitiveDescription(PrimitiveType aType,
const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs);
/**
* Sets aDescr's attributes using the style info in mFilter.
*/
nsresult SetAttributesForBlur(FilterPrimitiveDescription& aDescr);
/**
* Returns the index of the last result in the aPrimitiveDescrs, which we'll
* use as the input to this CSS filter.
*/
int32_t GetLastResultIndex(const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs);
/**
* Sets aDescr's filter region and primitive subregion to appropriate values
* based on this CSS filter's input and its attributes. For example, a CSS
* blur filter will have bounds equal to its input bounds, inflated by the
* blur extents.
*/
void SetBounds(FilterPrimitiveDescription& aDescr,
const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs);
/**
* The CSS filter originally from the style system.
*/
const nsStyleFilter& mFilter;
/**
* The bounding box of the element being filtered, in filter space. Used for
* input bounds if this CSS filter is the first in the filter chain.
*/
nsIntRect mTargetBBoxInFilterSpace;
/**
* The transformation from the filtered element's frame space in CSS pixels to
* filter space. Used to transform style values to filter space.
*/
gfxMatrix mFrameSpaceInCSSPxToFilterSpaceTransform;
};
#endif

View File

@ -11,6 +11,7 @@
#include "gfxUtils.h"
#include "nsISVGChildFrame.h"
#include "nsRenderingContext.h"
#include "nsCSSFilterInstance.h"
#include "nsSVGFilterInstance.h"
#include "nsSVGFilterPaintCallback.h"
#include "nsSVGUtils.h"
@ -124,18 +125,16 @@ nsFilterInstance::nsFilterInstance(nsIFrame *aTargetFrame,
mTargetBBox = aOverrideBBox ?
*aOverrideBBox : nsSVGUtils::GetBBox(mTargetFrame);
// Compute user space to filter space transforms.
nsresult rv = ComputeUserSpaceToFilterSpaceScale();
if (NS_FAILED(rv)) {
return;
}
rv = BuildPrimitives();
if (NS_FAILED(rv)) {
return;
}
if (mPrimitiveDescriptions.IsEmpty()) {
// Nothing should be rendered.
gfxRect targetBBoxInFilterSpace = UserSpaceToFilterSpace(mTargetBBox);
targetBBoxInFilterSpace.RoundOut();
if (!gfxUtils::GfxRectToIntRect(targetBBoxInFilterSpace, &mTargetBBoxInFilterSpace)) {
// The target's bbox is way too big if there is float->int overflow.
return;
}
@ -151,8 +150,6 @@ nsFilterInstance::nsFilterInstance(nsIFrame *aTargetFrame,
nsSVGUtils::GetCanvasTM(mTargetFrame, nsISVGChildFrame::FOR_PAINTING);
}
// Convert the passed in rects from frame to filter space:
mAppUnitsPerCSSPx = mTargetFrame->PresContext()->AppUnitsPerCSSPixel();
mFilterSpaceToFrameSpaceInCSSPxTransform =
@ -162,6 +159,18 @@ nsFilterInstance::nsFilterInstance(nsIFrame *aTargetFrame,
mFilterSpaceToFrameSpaceInCSSPxTransform;
mFrameSpaceInCSSPxToFilterSpaceTransform.Invert();
// Build the filter graph.
rv = BuildPrimitives();
if (NS_FAILED(rv)) {
return;
}
if (mPrimitiveDescriptions.IsEmpty()) {
// Nothing should be rendered.
return;
}
// Convert the passed in rects from frame space to filter space:
mPostFilterDirtyRegion = FrameSpaceToFilterSpace(aPostFilterDirtyRegion);
mPreFilterDirtyRegion = FrameSpaceToFilterSpace(aPreFilterDirtyRegion);
if (aPreFilterVisualOverflowRectOverride) {
@ -250,8 +259,10 @@ nsFilterInstance::BuildPrimitivesForFilter(const nsStyleFilter& aFilter)
return svgFilterInstance.BuildPrimitives(mPrimitiveDescriptions, mInputImages);
}
// Eventually, we will build primitives for CSS filters, too.
return NS_ERROR_FAILURE;
// Build primitives for a CSS filter.
nsCSSFilterInstance cssFilterInstance(aFilter, mTargetBBoxInFilterSpace,
mFrameSpaceInCSSPxToFilterSpaceTransform);
return cssFilterInstance.BuildPrimitives(mPrimitiveDescriptions);
}
void
@ -269,15 +280,10 @@ nsFilterInstance::ComputeNeededBoxes()
filter, mPostFilterDirtyRegion,
sourceGraphicNeededRegion, fillPaintNeededRegion, strokePaintNeededRegion);
nsIntRect sourceBoundsInt;
gfxRect sourceBounds = UserSpaceToFilterSpace(mTargetBBox);
sourceBounds.RoundOut();
// Detect possible float->int overflow
if (!gfxUtils::GfxRectToIntRect(sourceBounds, &sourceBoundsInt))
return;
sourceBoundsInt.UnionRect(sourceBoundsInt, mTargetBounds);
nsIntRect sourceBounds;
sourceBounds.UnionRect(mTargetBBoxInFilterSpace, mTargetBounds);
sourceGraphicNeededRegion.And(sourceGraphicNeededRegion, sourceBoundsInt);
sourceGraphicNeededRegion.And(sourceGraphicNeededRegion, sourceBounds);
mSourceGraphic.mNeededBounds = sourceGraphicNeededRegion.GetBounds();
mFillPaint.mNeededBounds = fillPaintNeededRegion.GetBounds();
@ -463,17 +469,12 @@ nsFilterInstance::ComputePostFilterExtents(nsRect* aPostFilterExtents)
{
*aPostFilterExtents = nsRect();
nsIntRect sourceBoundsInt;
gfxRect sourceBounds = UserSpaceToFilterSpace(mTargetBBox);
sourceBounds.RoundOut();
// Detect possible float->int overflow
if (!gfxUtils::GfxRectToIntRect(sourceBounds, &sourceBoundsInt))
return NS_ERROR_FAILURE;
sourceBoundsInt.UnionRect(sourceBoundsInt, mTargetBounds);
nsIntRect sourceBounds;
sourceBounds.UnionRect(mTargetBBoxInFilterSpace, mTargetBounds);
FilterDescription filter(mPrimitiveDescriptions);
nsIntRegion postFilterExtents =
FilterSupport::ComputePostFilterExtents(filter, sourceBoundsInt);
FilterSupport::ComputePostFilterExtents(filter, sourceBounds);
*aPostFilterExtents = FilterSpaceToFrameSpace(postFilterExtents.GetBounds());
return NS_OK;
}

View File

@ -272,6 +272,11 @@ private:
*/
gfxRect mTargetBBox;
/**
* The SVG bbox of the element that is being filtered, in filter space.
*/
nsIntRect mTargetBBoxInFilterSpace;
/**
* The transform from filter space to outer-<svg> device space.
*/