mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-04 19:33:18 +00:00
Bug 948265 - Add CSS drop-shadow filter to nsCSSFilterInstance. r=mstange
This commit is contained in:
parent
181e45f4b1
commit
f797e1291f
@ -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: Drop Shadow Default Color</title>
|
||||
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
|
||||
<style type="text/css">
|
||||
#target {
|
||||
filter: url(#drop-shadow);
|
||||
background-color: #00f;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>You should see a blue square with a green drop shadow.</p>
|
||||
<div id="target"></div>
|
||||
<svg width="0" height="0">
|
||||
<filter id="drop-shadow" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse">
|
||||
<feDropShadow dx="10" dy="10" stdDeviation="3" flood-color="#0f0" color-interpolation-filters="sRGB"/>
|
||||
</filter>
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
@ -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 Filters: Drop Shadow Default Color</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-drop-shadow">
|
||||
<link rel="help" href="http://www.w3.org/TR/css3-background/#the-box-shadow">
|
||||
<link rel="match" href="drop-shadow-default-color-ref.html">
|
||||
<meta name="assert"
|
||||
content="If the color is unspecified in a CSS drop-shadow filter
|
||||
function, it should default to the value of the CSS color
|
||||
property.">
|
||||
<style type="text/css">
|
||||
#target {
|
||||
filter: drop-shadow(10px 10px 3px);
|
||||
color: #0f0;
|
||||
background-color: #00f;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>You should see a blue square with a green drop shadow.</p>
|
||||
<div id="target"></div>
|
||||
</body>
|
||||
</html>
|
@ -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 Filters: Negative Drop Shadow Offset</title>
|
||||
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
|
||||
<style type="text/css">
|
||||
#target {
|
||||
filter: url(#drop-shadow);
|
||||
background-color: #00f;
|
||||
position: relative;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>You should see a blue square with a green drop shadow in its top left corner.</p>
|
||||
<div id="target"></div>
|
||||
<svg width="0" height="0">
|
||||
<filter id="drop-shadow" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse">
|
||||
<feDropShadow dx="-10" dy="-10" stdDeviation="3" flood-color="#0f0" color-interpolation-filters="sRGB"/>
|
||||
</filter>
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
@ -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 Filters: Negative Drop Shadow Offset</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-drop-shadow">
|
||||
<link rel="match" href="drop-shadow-negative-offset-ref.html">
|
||||
<meta name="assert"
|
||||
content="Given negative shadow offsets, the CSS drop-shadow filter
|
||||
function should add a drop shadow extending from the top left
|
||||
corner of an HTML element.">
|
||||
<style type="text/css">
|
||||
#target {
|
||||
filter: drop-shadow(-10px -10px 3px #0f0);
|
||||
background-color: #00f;
|
||||
position: relative;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>You should see a blue square with a green drop shadow in its top left corner.</p>
|
||||
<div id="target"></div>
|
||||
</body>
|
||||
</html>
|
28
layout/reftests/svg/filters/css-filters/drop-shadow-ref.html
Normal file
28
layout/reftests/svg/filters/css-filters/drop-shadow-ref.html
Normal 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: Drop Shadow on HTML Element</title>
|
||||
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
|
||||
<style type="text/css">
|
||||
#target {
|
||||
filter: url(#drop-shadow);
|
||||
background-color: #00f;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>You should see a blue square with a green drop shadow.</p>
|
||||
<div id="target"></div>
|
||||
<svg width="0" height="0">
|
||||
<filter id="drop-shadow" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse">
|
||||
<feDropShadow dx="10" dy="10" stdDeviation="3" flood-color="#0f0" color-interpolation-filters="sRGB"/>
|
||||
</filter>
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
28
layout/reftests/svg/filters/css-filters/drop-shadow.html
Normal file
28
layout/reftests/svg/filters/css-filters/drop-shadow.html
Normal 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: Drop Shadow on 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-drop-shadow">
|
||||
<link rel="match" href="drop-shadow-ref.html">
|
||||
<meta name="assert"
|
||||
content="The CSS drop-shadow filter function should add a drop shadow to
|
||||
an HTML element.">
|
||||
<style type="text/css">
|
||||
#target {
|
||||
filter: drop-shadow(10px 10px 3px #0f0);
|
||||
background-color: #00f;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>You should see a blue square with a green drop shadow.</p>
|
||||
<div id="target"></div>
|
||||
</body>
|
||||
</html>
|
@ -7,3 +7,6 @@ default-preferences pref(layout.css.filters.enabled,true)
|
||||
== blur.svg blur-ref.svg
|
||||
== blur-zero-radius.html blur-zero-radius-ref.html
|
||||
== blur-zoomed-page.html blur-zoomed-page-ref.html
|
||||
== drop-shadow.html drop-shadow-ref.html
|
||||
== drop-shadow-default-color.html drop-shadow-default-color-ref.html
|
||||
== drop-shadow-negative-offset.html drop-shadow-negative-offset-ref.html
|
||||
|
@ -9,6 +9,7 @@
|
||||
// Keep others in (case-insensitive) order:
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsStyleStruct.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
@ -16,9 +17,11 @@ using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
nsCSSFilterInstance::nsCSSFilterInstance(const nsStyleFilter& aFilter,
|
||||
nsIFrame *aTargetFrame,
|
||||
const nsIntRect& aTargetBBoxInFilterSpace,
|
||||
const gfxMatrix& aFrameSpaceInCSSPxToFilterSpaceTransform)
|
||||
: mFilter(aFilter)
|
||||
, mTargetFrame(aTargetFrame)
|
||||
, mTargetBBoxInFilterSpace(aTargetBBoxInFilterSpace)
|
||||
, mFrameSpaceInCSSPxToFilterSpaceTransform(aFrameSpaceInCSSPxToFilterSpaceTransform)
|
||||
{
|
||||
@ -38,6 +41,9 @@ nsCSSFilterInstance::BuildPrimitives(nsTArray<FilterPrimitiveDescription>& aPrim
|
||||
case NS_STYLE_FILTER_BRIGHTNESS:
|
||||
case NS_STYLE_FILTER_CONTRAST:
|
||||
case NS_STYLE_FILTER_DROP_SHADOW:
|
||||
descr = CreatePrimitiveDescription(PrimitiveType::DropShadow, aPrimitiveDescrs);
|
||||
result = SetAttributesForDropShadow(descr);
|
||||
break;
|
||||
case NS_STYLE_FILTER_GRAYSCALE:
|
||||
case NS_STYLE_FILTER_HUE_ROTATE:
|
||||
case NS_STYLE_FILTER_INVERT:
|
||||
@ -78,17 +84,49 @@ nsCSSFilterInstance::CreatePrimitiveDescription(PrimitiveType aType,
|
||||
nsresult
|
||||
nsCSSFilterInstance::SetAttributesForBlur(FilterPrimitiveDescription& aDescr)
|
||||
{
|
||||
// Get the radius from the style.
|
||||
nsStyleCoord radiusStyleCoord = mFilter.GetFilterParameter();
|
||||
if (radiusStyleCoord.GetUnit() != eStyleUnit_Coord) {
|
||||
const nsStyleCoord& radiusInFrameSpace = mFilter.GetFilterParameter();
|
||||
if (radiusInFrameSpace.GetUnit() != eStyleUnit_Coord) {
|
||||
NS_NOTREACHED("unexpected unit");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Get the radius in frame space.
|
||||
nscoord radiusInFrameSpace = radiusStyleCoord.GetCoordValue();
|
||||
Size radiusInFilterSpace = BlurRadiusToFilterSpace(radiusInFrameSpace.GetCoordValue());
|
||||
aDescr.Attributes().Set(eGaussianBlurStdDeviation, radiusInFilterSpace);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCSSFilterInstance::SetAttributesForDropShadow(FilterPrimitiveDescription& aDescr)
|
||||
{
|
||||
nsCSSShadowArray* shadows = mFilter.GetDropShadow();
|
||||
if (!shadows || shadows->Length() != 1) {
|
||||
NS_NOTREACHED("Exactly one drop shadow should have been parsed.");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCSSShadowItem* shadow = shadows->ShadowAt(0);
|
||||
|
||||
// Set drop shadow blur radius.
|
||||
Size radiusInFilterSpace = BlurRadiusToFilterSpace(shadow->mRadius);
|
||||
aDescr.Attributes().Set(eDropShadowStdDeviation, radiusInFilterSpace);
|
||||
|
||||
// Set offset.
|
||||
IntPoint offsetInFilterSpace = OffsetToFilterSpace(shadow->mXOffset, shadow->mYOffset);
|
||||
aDescr.Attributes().Set(eDropShadowOffset, offsetInFilterSpace);
|
||||
|
||||
// Set color. If unspecified, use the CSS color property.
|
||||
nscolor shadowColor = shadow->mHasColor ?
|
||||
shadow->mColor : mTargetFrame->StyleColor()->mColor;
|
||||
aDescr.Attributes().Set(eDropShadowColor, ToAttributeColor(shadowColor));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Size
|
||||
nsCSSFilterInstance::BlurRadiusToFilterSpace(nscoord aRadiusInFrameSpace)
|
||||
{
|
||||
float radiusInFrameSpaceInCSSPx =
|
||||
nsPresContext::AppUnitsToFloatCSSPixels(radiusInFrameSpace);
|
||||
nsPresContext::AppUnitsToFloatCSSPixels(aRadiusInFrameSpace);
|
||||
|
||||
// Convert the radius to filter space.
|
||||
gfxSize radiusInFilterSpace(radiusInFrameSpaceInCSSPx,
|
||||
@ -101,15 +139,40 @@ nsCSSFilterInstance::SetAttributesForBlur(FilterPrimitiveDescription& aDescr)
|
||||
// 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;
|
||||
return Size();
|
||||
}
|
||||
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;
|
||||
return ToSize(radiusInFilterSpace);
|
||||
}
|
||||
|
||||
IntPoint
|
||||
nsCSSFilterInstance::OffsetToFilterSpace(nscoord aXOffsetInFrameSpace,
|
||||
nscoord aYOffsetInFrameSpace)
|
||||
{
|
||||
gfxPoint offsetInFilterSpace(nsPresContext::AppUnitsToFloatCSSPixels(aXOffsetInFrameSpace),
|
||||
nsPresContext::AppUnitsToFloatCSSPixels(aYOffsetInFrameSpace));
|
||||
|
||||
// Convert the radius to filter space.
|
||||
gfxSize frameSpaceInCSSPxToFilterSpaceScale =
|
||||
mFrameSpaceInCSSPxToFilterSpaceTransform.ScaleFactors(true);
|
||||
offsetInFilterSpace.x *= frameSpaceInCSSPxToFilterSpaceScale.width;
|
||||
offsetInFilterSpace.y *= frameSpaceInCSSPxToFilterSpaceScale.height;
|
||||
|
||||
return IntPoint(int32_t(offsetInFilterSpace.x), int32_t(offsetInFilterSpace.y));
|
||||
}
|
||||
|
||||
Color
|
||||
nsCSSFilterInstance::ToAttributeColor(nscolor aColor)
|
||||
{
|
||||
return Color(
|
||||
NS_GET_R(aColor) / 255.0,
|
||||
NS_GET_G(aColor) / 255.0,
|
||||
NS_GET_B(aColor) / 255.0,
|
||||
NS_GET_A(aColor) / 255.0
|
||||
);
|
||||
}
|
||||
|
||||
int32_t
|
||||
|
@ -9,7 +9,11 @@
|
||||
#include "FilterSupport.h"
|
||||
#include "gfxMatrix.h"
|
||||
#include "gfxRect.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "nsColor.h"
|
||||
|
||||
class nsIFrame;
|
||||
struct nsStyleFilter;
|
||||
template<class T> class nsTArray;
|
||||
|
||||
@ -20,8 +24,11 @@ template<class T> class nsTArray;
|
||||
*/
|
||||
class nsCSSFilterInstance
|
||||
{
|
||||
typedef mozilla::gfx::Color Color;
|
||||
typedef mozilla::gfx::FilterPrimitiveDescription FilterPrimitiveDescription;
|
||||
typedef mozilla::gfx::IntPoint IntPoint;
|
||||
typedef mozilla::gfx::PrimitiveType PrimitiveType;
|
||||
typedef mozilla::gfx::Size Size;
|
||||
|
||||
public:
|
||||
/**
|
||||
@ -34,6 +41,7 @@ public:
|
||||
* the filtered element's frame space in CSS pixels to filter space.
|
||||
*/
|
||||
nsCSSFilterInstance(const nsStyleFilter& aFilter,
|
||||
nsIFrame *aTargetFrame,
|
||||
const nsIntRect& mTargetBBoxInFilterSpace,
|
||||
const gfxMatrix& aFrameSpaceInCSSPxToFilterSpaceTransform);
|
||||
|
||||
@ -55,6 +63,7 @@ private:
|
||||
* Sets aDescr's attributes using the style info in mFilter.
|
||||
*/
|
||||
nsresult SetAttributesForBlur(FilterPrimitiveDescription& aDescr);
|
||||
nsresult SetAttributesForDropShadow(FilterPrimitiveDescription& aDescr);
|
||||
|
||||
/**
|
||||
* Returns the index of the last result in the aPrimitiveDescrs, which we'll
|
||||
@ -71,11 +80,34 @@ private:
|
||||
void SetBounds(FilterPrimitiveDescription& aDescr,
|
||||
const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs);
|
||||
|
||||
/**
|
||||
* Converts an nscolor to a Color, suitable for use as a
|
||||
* FilterPrimitiveDescription attribute.
|
||||
*/
|
||||
Color ToAttributeColor(nscolor aColor);
|
||||
|
||||
/**
|
||||
* Converts a blur radius in frame space to filter space.
|
||||
*/
|
||||
Size BlurRadiusToFilterSpace(nscoord aRadiusInFrameSpace);
|
||||
|
||||
/**
|
||||
* Converts a point defined by a pair of nscoord x, y coordinates from frame
|
||||
* space to filter space.
|
||||
*/
|
||||
IntPoint OffsetToFilterSpace(nscoord aXOffsetInFrameSpace,
|
||||
nscoord aYOffsetInFrameSpace);
|
||||
|
||||
/**
|
||||
* The CSS filter originally from the style system.
|
||||
*/
|
||||
const nsStyleFilter& mFilter;
|
||||
|
||||
/**
|
||||
* The frame for the element that is currently being filtered.
|
||||
*/
|
||||
nsIFrame* mTargetFrame;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
@ -260,7 +260,8 @@ nsFilterInstance::BuildPrimitivesForFilter(const nsStyleFilter& aFilter)
|
||||
}
|
||||
|
||||
// Build primitives for a CSS filter.
|
||||
nsCSSFilterInstance cssFilterInstance(aFilter, mTargetBBoxInFilterSpace,
|
||||
nsCSSFilterInstance cssFilterInstance(aFilter, mTargetFrame,
|
||||
mTargetBBoxInFilterSpace,
|
||||
mFrameSpaceInCSSPxToFilterSpaceTransform);
|
||||
return cssFilterInstance.BuildPrimitives(mPrimitiveDescriptions);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user