Bug 316764 - implement <mask> and fix <clipPath> for multiple

overlapping children.  r=scootermorris


git-svn-id: svn://10.0.0.236/trunk@187897 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
tor%cs.brown.edu 2006-01-20 17:00:43 +00:00
parent b5bf49f861
commit fe2017034e
35 changed files with 1494 additions and 134 deletions

View File

@ -895,6 +895,8 @@ GK_ATOM(markerHeight, "markerHeight")
GK_ATOM(markerUnits, "markerUnits")
GK_ATOM(markerWidth, "markerWidth")
GK_ATOM(mask, "mask")
GK_ATOM(maskContentUnits, "maskContentUnits")
GK_ATOM(maskUnits, "maskUnits")
GK_ATOM(matrix, "matrix")
GK_ATOM(metadata, "metadata")
GK_ATOM(mm, "mm")
@ -1259,6 +1261,7 @@ GK_ATOM(svgInnerSVGFrame, "SVGInnerSVGFrame")
GK_ATOM(svgLinearGradientFrame, "SVGLinearGradientFrame")
GK_ATOM(svgLineFrame, "SVGLineFrame")
GK_ATOM(svgMarkerFrame, "SVGMarkerFrame")
GK_ATOM(svgMaskFrame, "SVGMaskFrame")
GK_ATOM(svgOuterSVGFrame, "SVGOuterSVGFrame")
GK_ATOM(svgPathFrame, "SVGPathFrame")
GK_ATOM(svgPathGeometryFrame, "SVGPathGeometryFrame")

View File

@ -102,6 +102,7 @@ CPPSRCS = \
nsSVGLengthList.cpp \
nsSVGLineElement.cpp \
nsSVGMarkerElement.cpp \
nsSVGMaskElement.cpp \
nsSVGMatrix.cpp \
nsSVGMetadataElement.cpp \
nsSVGNumber.cpp \

View File

@ -126,6 +126,8 @@ nsresult
NS_NewSVGFEUnimplementedMOZElement(nsIContent **aResult, nsINodeInfo *aNodeInfo);
nsresult
NS_NewSVGPatternElement(nsIContent **aResult, nsINodeInfo *aNodeInfo);
nsresult
NS_NewSVGMaskElement(nsIContent **aResult, nsINodeInfo *aNodeInfo);
nsresult
NS_NewSVGElement(nsIContent** aResult, nsINodeInfo *aNodeInfo)
@ -233,6 +235,8 @@ NS_NewSVGElement(nsIContent** aResult, nsINodeInfo *aNodeInfo)
return NS_NewSVGFEUnimplementedMOZElement(aResult, aNodeInfo);
if (name == nsSVGAtoms::pattern)
return NS_NewSVGPatternElement(aResult, aNodeInfo);
if (name == nsSVGAtoms::mask)
return NS_NewSVGMaskElement(aResult, aNodeInfo);
// if we don't know what to create, just create a standard xml element:
return NS_NewXMLElement(aResult, aNodeInfo);

View File

@ -56,7 +56,7 @@ SVG_UNSUPPORTED_FEATURE("http://www.w3.org/TR/SVG11/feature#ColorProfile")
SVG_SUPPORTED_FEATURE("http://www.w3.org/TR/SVG11/feature#Gradient")
SVG_SUPPORTED_FEATURE("http://www.w3.org/TR/SVG11/feature#Pattern")
SVG_SUPPORTED_FEATURE("http://www.w3.org/TR/SVG11/feature#Clip")
SVG_UNSUPPORTED_FEATURE("http://www.w3.org/TR/SVG11/feature#Mask")
SVG_SUPPORTED_FEATURE("http://www.w3.org/TR/SVG11/feature#Mask")
SVG_UNSUPPORTED_FEATURE("http://www.w3.org/TR/SVG11/feature#Filter")
// Basic features

View File

@ -0,0 +1,258 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Mozilla SVG project.
*
* The Initial Developer of the Original Code is IBM Corporation.
* Portions created by the Initial Developer are Copyright (C) 2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsSVGLength.h"
#include "nsSVGAnimatedLength.h"
#include "nsSVGEnum.h"
#include "nsSVGAnimatedEnumeration.h"
#include "nsIDOMSVGAnimatedEnum.h"
#include "nsIDOMSVGMaskElement.h"
#include "nsCOMPtr.h"
#include "nsISVGSVGElement.h"
#include "nsSVGStylableElement.h"
#include "nsSVGAtoms.h"
//--------------------- Masks ------------------------
typedef nsSVGStylableElement nsSVGMaskElementBase;
class nsSVGMaskElement : public nsSVGMaskElementBase,
public nsIDOMSVGMaskElement
{
protected:
friend nsresult NS_NewSVGMaskElement(nsIContent **aResult,
nsINodeInfo *aNodeInfo);
nsSVGMaskElement(nsINodeInfo* aNodeInfo);
virtual ~nsSVGMaskElement();
nsresult Init();
public:
// interfaces:
NS_DECL_ISUPPORTS_INHERITED
// Mask Element
NS_DECL_NSIDOMSVGMASKELEMENT
NS_FORWARD_NSIDOMNODE_NO_CLONENODE(nsSVGElement::)
NS_FORWARD_NSIDOMELEMENT(nsSVGElement::)
NS_FORWARD_NSIDOMSVGELEMENT(nsSVGElement::)
protected:
// nsIDOMSVGMaskElement values
nsCOMPtr<nsIDOMSVGAnimatedEnumeration> mMaskUnits;
nsCOMPtr<nsIDOMSVGAnimatedEnumeration> mMaskContentUnits;
nsCOMPtr<nsIDOMSVGAnimatedLength> mX;
nsCOMPtr<nsIDOMSVGAnimatedLength> mY;
nsCOMPtr<nsIDOMSVGAnimatedLength> mWidth;
nsCOMPtr<nsIDOMSVGAnimatedLength> mHeight;
};
NS_IMPL_NS_NEW_SVG_ELEMENT(Mask)
//----------------------------------------------------------------------
// nsISupports methods
NS_IMPL_ADDREF_INHERITED(nsSVGMaskElement,nsSVGMaskElementBase)
NS_IMPL_RELEASE_INHERITED(nsSVGMaskElement,nsSVGMaskElementBase)
NS_INTERFACE_MAP_BEGIN(nsSVGMaskElement)
NS_INTERFACE_MAP_ENTRY(nsIDOMNode)
NS_INTERFACE_MAP_ENTRY(nsIDOMElement)
NS_INTERFACE_MAP_ENTRY(nsIDOMSVGElement)
NS_INTERFACE_MAP_ENTRY(nsIDOMSVGMaskElement)
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGMaskElement)
NS_INTERFACE_MAP_END_INHERITING(nsSVGMaskElementBase)
//----------------------------------------------------------------------
// Implementation
nsSVGMaskElement::nsSVGMaskElement(nsINodeInfo* aNodeInfo)
: nsSVGMaskElementBase(aNodeInfo)
{
}
nsSVGMaskElement::~nsSVGMaskElement()
{
}
nsresult
nsSVGMaskElement::Init()
{
nsresult rv = nsSVGMaskElementBase::Init();
NS_ENSURE_SUCCESS(rv,rv);
// Define enumeration mappings
static struct nsSVGEnumMapping pUnitMap[] = {
{&nsSVGAtoms::objectBoundingBox, nsIDOMSVGMaskElement::SVG_MUNITS_OBJECTBOUNDINGBOX},
{&nsSVGAtoms::userSpaceOnUse, nsIDOMSVGMaskElement::SVG_MUNITS_USERSPACEONUSE},
{nsnull, 0}
};
// Create mapped attributes
// DOM property: maskUnits , #IMPLIED attrib: maskUnits
{
nsCOMPtr<nsISVGEnum> units;
rv = NS_NewSVGEnum(getter_AddRefs(units),
nsIDOMSVGMaskElement::SVG_MUNITS_OBJECTBOUNDINGBOX, pUnitMap);
NS_ENSURE_SUCCESS(rv,rv);
rv = NS_NewSVGAnimatedEnumeration(getter_AddRefs(mMaskUnits), units);
NS_ENSURE_SUCCESS(rv,rv);
rv = AddMappedSVGValue(nsSVGAtoms::maskUnits, mMaskUnits);
NS_ENSURE_SUCCESS(rv,rv);
}
// DOM property: maskContentUnits , #IMPLIED attrib: maskContentUnits
{
nsCOMPtr<nsISVGEnum> units;
rv = NS_NewSVGEnum(getter_AddRefs(units),
nsIDOMSVGMaskElement::SVG_MUNITS_USERSPACEONUSE, pUnitMap);
NS_ENSURE_SUCCESS(rv,rv);
rv = NS_NewSVGAnimatedEnumeration(getter_AddRefs(mMaskContentUnits), units);
NS_ENSURE_SUCCESS(rv,rv);
rv = AddMappedSVGValue(nsSVGAtoms::maskContentUnits, mMaskContentUnits);
NS_ENSURE_SUCCESS(rv,rv);
}
// DOM property: x , #IMPLIED attrib: x
{
nsCOMPtr<nsISVGLength> length;
rv = NS_NewSVGLength(getter_AddRefs(length),
-10.0,nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE);
NS_ENSURE_SUCCESS(rv,rv);
rv = NS_NewSVGAnimatedLength(getter_AddRefs(mX), length);
NS_ENSURE_SUCCESS(rv,rv);
rv = AddMappedSVGValue(nsSVGAtoms::x, mX);
NS_ENSURE_SUCCESS(rv,rv);
}
// DOM property: y , #IMPLIED attrib: y
{
nsCOMPtr<nsISVGLength> length;
rv = NS_NewSVGLength(getter_AddRefs(length),
-10.0,nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE);
NS_ENSURE_SUCCESS(rv,rv);
rv = NS_NewSVGAnimatedLength(getter_AddRefs(mY), length);
NS_ENSURE_SUCCESS(rv,rv);
rv = AddMappedSVGValue(nsSVGAtoms::y, mY);
NS_ENSURE_SUCCESS(rv,rv);
}
// DOM property: width , #IMPLIED attrib: width
{
nsCOMPtr<nsISVGLength> length;
rv = NS_NewSVGLength(getter_AddRefs(length),
120.0,nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE);
NS_ENSURE_SUCCESS(rv,rv);
rv = NS_NewSVGAnimatedLength(getter_AddRefs(mWidth), length);
NS_ENSURE_SUCCESS(rv,rv);
rv = AddMappedSVGValue(nsSVGAtoms::width, mWidth);
NS_ENSURE_SUCCESS(rv,rv);
}
// DOM property: height , #IMPLIED attrib: height
{
nsCOMPtr<nsISVGLength> length;
rv = NS_NewSVGLength(getter_AddRefs(length),
120.0,nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE);
NS_ENSURE_SUCCESS(rv,rv);
rv = NS_NewSVGAnimatedLength(getter_AddRefs(mHeight), length);
NS_ENSURE_SUCCESS(rv,rv);
rv = AddMappedSVGValue(nsSVGAtoms::height, mHeight);
NS_ENSURE_SUCCESS(rv,rv);
}
return NS_OK;
}
//----------------------------------------------------------------------
// nsIDOMNode method
NS_IMPL_DOM_CLONENODE_WITH_INIT(nsSVGMaskElement)
//----------------------------------------------------------------------
// nsIDOMSVGMaskElement methods
/* readonly attribute nsIDOMSVGAnimatedEnumeration maskUnits; */
NS_IMETHODIMP nsSVGMaskElement::GetMaskUnits(nsIDOMSVGAnimatedEnumeration * *aMaskUnits)
{
*aMaskUnits = mMaskUnits;
NS_IF_ADDREF(*aMaskUnits);
return NS_OK;
}
/* readonly attribute nsIDOMSVGAnimatedEnumeration maskContentUnits; */
NS_IMETHODIMP nsSVGMaskElement::GetMaskContentUnits(nsIDOMSVGAnimatedEnumeration * *aMaskUnits)
{
*aMaskUnits = mMaskContentUnits;
NS_IF_ADDREF(*aMaskUnits);
return NS_OK;
}
/* readonly attribute nsIDOMSVGAnimatedLength x; */
NS_IMETHODIMP nsSVGMaskElement::GetX(nsIDOMSVGAnimatedLength * *aX)
{
*aX = mX;
NS_IF_ADDREF(*aX);
return NS_OK;
}
/* readonly attribute nsIDOMSVGAnimatedLength y; */
NS_IMETHODIMP nsSVGMaskElement::GetY(nsIDOMSVGAnimatedLength * *aY)
{
*aY = mY;
NS_IF_ADDREF(*aY);
return NS_OK;
}
/* readonly attribute nsIDOMSVGAnimatedLength width; */
NS_IMETHODIMP nsSVGMaskElement::GetWidth(nsIDOMSVGAnimatedLength * *aWidth)
{
*aWidth = mWidth;
NS_IF_ADDREF(*aWidth);
return NS_OK;
}
/* readonly attribute nsIDOMSVGAnimatedLength height; */
NS_IMETHODIMP nsSVGMaskElement::GetHeight(nsIDOMSVGAnimatedLength * *aHeight)
{
*aHeight = mHeight;
NS_IF_ADDREF(*aHeight);
return NS_OK;
}

View File

@ -85,6 +85,7 @@ XPIDLSRCS = \
nsIDOMSVGLineElement.idl \
nsIDOMSVGLocatable.idl \
nsIDOMSVGMarkerElement.idl \
nsIDOMSVGMaskElement.idl \
nsIDOMSVGMatrix.idl \
nsIDOMSVGMetadataElement.idl \
nsIDOMSVGNumber.idl \

View File

@ -0,0 +1,75 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Mozilla SVG project.
*
* The Initial Developer of the Original Code is IBM Corporation.
* Portions created by the Initial Developer are Copyright (C) 2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsIDOMSVGElement.idl"
interface nsIDOMSVGAnimatedLength;
interface nsIDOMSVGAnimatedEnumeration;
[scriptable, uuid(fdd7039c-35b6-465a-b7a3-c98a815b583e)]
interface nsIDOMSVGMaskElement
: nsIDOMSVGElement
/*
The SVG DOM makes use of multiple interface inheritance.
Since XPCOM only supports single interface inheritance,
the best thing that we can do is to promise that whenever
an object implements _this_ interface it will also
implement the following interfaces. (We then have to QI to
hop between them.)
SVGElement,
SVGTests,
SVGLangSpace,
SVGExternalResourcesRequired,
SVGStylable,
SVGUnitTypes {
*/
{
// These constants are taken from SVGUnitTypes
const unsigned short SVG_MUNITS_UNKNOWN = 0;
const unsigned short SVG_MUNITS_OBJECTBOUNDINGBOX = 1;
const unsigned short SVG_MUNITS_USERSPACEONUSE = 2;
readonly attribute nsIDOMSVGAnimatedEnumeration maskUnits;
readonly attribute nsIDOMSVGAnimatedEnumeration maskContentUnits;
readonly attribute nsIDOMSVGAnimatedLength x;
readonly attribute nsIDOMSVGAnimatedLength y;
readonly attribute nsIDOMSVGAnimatedLength width;
readonly attribute nsIDOMSVGAnimatedLength height;
};

View File

@ -267,6 +267,7 @@ enum nsDOMClassInfoID {
eDOMClassInfo_SVGLinearGradientElement_id,
eDOMClassInfo_SVGLineElement_id,
eDOMClassInfo_SVGMarkerElement_id,
eDOMClassInfo_SVGMaskElement_id,
eDOMClassInfo_SVGMetadataElement_id,
eDOMClassInfo_SVGPathElement_id,
eDOMClassInfo_SVGPatternElement_id,

View File

@ -365,6 +365,7 @@
#include "nsIDOMSVGLineElement.h"
#include "nsIDOMSVGLocatable.h"
#include "nsIDOMSVGMarkerElement.h"
#include "nsIDOMSVGMaskElement.h"
#include "nsIDOMSVGMatrix.h"
#include "nsIDOMSVGMetadataElement.h"
#include "nsIDOMSVGNumber.h"
@ -931,6 +932,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(SVGMarkerElement, nsElementSH,
ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(SVGMaskElement, nsElementSH,
ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(SVGMetadataElement, nsElementSH,
ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(SVGPathElement, nsElementSH,
@ -2620,6 +2623,12 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(SVGMaskElement, nsIDOMSVGMaskElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGMaskElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGStylable)
DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(SVGMetadataElement, nsIDOMSVGMetadataElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGMetadataElement)
DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES

View File

@ -229,6 +229,8 @@ nsIFrame*
NS_NewSVGFilterFrame(nsIPresShell *aPresShell, nsIContent *aContent);
nsIFrame*
NS_NewSVGPatternFrame(nsIPresShell* aPresShell, nsIContent* aContent);
nsIFrame*
NS_NewSVGMaskFrame(nsIPresShell* aPresShell, nsIContent* aContent);
#endif
#include "nsIDocument.h"
@ -3469,7 +3471,8 @@ IsSpecialContent(nsIContent* aContent,
aTag == nsSVGAtoms::clipPath ||
aTag == nsSVGAtoms::textPath ||
aTag == nsSVGAtoms::filter ||
aTag == nsSVGAtoms::pattern;
aTag == nsSVGAtoms::pattern ||
aTag == nsSVGAtoms::mask;
#endif
#ifdef MOZ_MATHML
@ -7800,6 +7803,9 @@ nsCSSFrameConstructor::ConstructSVGFrame(nsFrameConstructorState& aState,
else if (aTag == nsSVGAtoms::pattern) {
newFrame = NS_NewSVGPatternFrame(mPresShell, aContent);
}
else if (aTag == nsSVGAtoms::mask) {
newFrame = NS_NewSVGMaskFrame(mPresShell, aContent);
}
if (newFrame == nsnull) {
// Either we have an unknown tag, or construction of a frame

View File

@ -4434,6 +4434,8 @@ PRBool CSSParserImpl::ParseSingleValueProperty(nsresult& aErrorCode,
case eCSSProperty_marker_mid:
case eCSSProperty_marker_start:
return ParseVariant(aErrorCode, aValue, VARIANT_HUO, nsnull);
case eCSSProperty_mask:
return ParseVariant(aErrorCode, aValue, VARIANT_HUO, nsnull);
case eCSSProperty_pointer_events:
return ParseVariant(aErrorCode, aValue, VARIANT_HOK,
nsCSSProps::kPointerEventsKTable);

View File

@ -475,6 +475,7 @@ CSS_PROP_SHORTHAND(marker, marker, Marker)
CSS_PROP_SVG(marker-end, marker_end, MarkerEnd, SVG, mMarkerEnd, eCSSType_Value, nsnull)
CSS_PROP_SVG(marker-mid, marker_mid, MarkerMid, SVG, mMarkerMid, eCSSType_Value, nsnull)
CSS_PROP_SVG(marker-start, marker_start, MarkerStart, SVG, mMarkerStart, eCSSType_Value, nsnull)
CSS_PROP_SVGRESET(mask, mask, Mask, SVG, mMask, eCSSType_Value, nsnull)
CSS_PROP_SVG(pointer-events, pointer_events, PointerEvents, SVG, mPointerEvents, eCSSType_Value, kPointerEventsKTable)
CSS_PROP_SVG(shape-rendering, shape_rendering, ShapeRendering, SVG, mShapeRendering, eCSSType_Value, kShapeRenderingKTable)
CSS_PROP_SVGRESET(stop-color, stop_color, StopColor, SVG, mStopColor, eCSSType_Value, nsnull)

View File

@ -1163,6 +1163,7 @@ nsCSSSVG::nsCSSSVG(const nsCSSSVG& aCopy)
mMarkerEnd(aCopy.mMarkerEnd),
mMarkerMid(aCopy.mMarkerMid),
mMarkerStart(aCopy.mMarkerStart),
mMask(aCopy.mMask),
mPointerEvents(aCopy.mPointerEvents),
mShapeRendering(aCopy.mShapeRendering),
mStopColor(aCopy.mStopColor),
@ -1205,6 +1206,7 @@ void nsCSSSVG::List(FILE* out, PRInt32 aIndent) const
mMarkerEnd.AppendToString(buffer, eCSSProperty_marker_end);
mMarkerMid.AppendToString(buffer, eCSSProperty_marker_mid);
mMarkerStart.AppendToString(buffer, eCSSProperty_marker_start);
mMask.AppendToString(buffer, eCSSProperty_mask);
mPointerEvents.AppendToString(buffer, eCSSProperty_pointer_events);
mShapeRendering.AppendToString(buffer, eCSSProperty_shape_rendering);
mStopColor.AppendToString(buffer, eCSSProperty_stop_color);

View File

@ -573,6 +573,7 @@ struct nsCSSSVG : public nsCSSStruct {
nsCSSValue mMarkerEnd;
nsCSSValue mMarkerMid;
nsCSSValue mMarkerStart;
nsCSSValue mMask;
nsCSSValue mPointerEvents;
nsCSSValue mShapeRendering;
nsCSSValue mStopColor;

View File

@ -5011,6 +5011,16 @@ nsRuleNode::ComputeSVGResetData(nsStyleStruct* aStartStruct,
inherited = PR_TRUE;
svgReset->mFilter = parentSVGReset->mFilter;
}
// mask: url, none, inherit
if (eCSSUnit_URL == SVGData.mMask.GetUnit()) {
svgReset->mMask = SVGData.mMask.GetURLValue();
} else if (eCSSUnit_None == SVGData.mMask.GetUnit()) {
svgReset->mMask = nsnull;
} else if (eCSSUnit_Inherit == SVGData.mMask.GetUnit()) {
inherited = PR_TRUE;
svgReset->mMask = parentSVGReset->mMask;
}
if (inherited)
// We inherited, and therefore can't be cached in the rule node. We have to be put right on the

View File

@ -932,9 +932,10 @@ void nsStyleContext::DumpRegressionData(nsPresContext* aPresContext, FILE* out,
else
fprintf(out, "%ld ", (long)svgReset->mStopColor.mPaint.mColor);
fprintf(out, "%s %s %f %d\" />\n",
fprintf(out, "%s %s %s %f %d\" />\n",
URICString(svgReset->mClipPath).get(),
URICString(svgReset->mFilter).get(),
URICString(svgReset->mMask).get(),
svgReset->mStopOpacity,
(int)svgReset->mDominantBaseline);
#endif

View File

@ -838,6 +838,7 @@ nsStyleSVGReset::nsStyleSVGReset()
mStopColor.mPaint.mColor = NS_RGB(0,0,0);
mClipPath = nsnull;
mFilter = nsnull;
mMask = nsnull;
mStopOpacity = 1.0f;
mDominantBaseline = NS_STYLE_DOMINANT_BASELINE_AUTO;
}
@ -851,6 +852,7 @@ nsStyleSVGReset::nsStyleSVGReset(const nsStyleSVGReset& aSource)
mStopColor = aSource.mStopColor;
mClipPath = aSource.mClipPath;
mFilter = aSource.mFilter;
mMask = aSource.mMask;
mStopOpacity = aSource.mStopOpacity;
mDominantBaseline = aSource.mDominantBaseline;
}
@ -860,6 +862,7 @@ nsChangeHint nsStyleSVGReset::CalcDifference(const nsStyleSVGReset& aOther) cons
if (mStopColor != aOther.mStopColor ||
!EqualURIs(mClipPath, aOther.mClipPath) ||
!EqualURIs(mFilter, aOther.mFilter) ||
!EqualURIs(mMask, aOther.mMask) ||
mStopOpacity != aOther.mStopOpacity ||
mDominantBaseline != aOther.mDominantBaseline)
return NS_STYLE_HINT_VISUAL;

View File

@ -1340,6 +1340,7 @@ struct nsStyleSVGReset : public nsStyleStruct {
nsStyleSVGPaint mStopColor; // [reset]
nsCOMPtr<nsIURI> mClipPath; // [reset]
nsCOMPtr<nsIURI> mFilter; // [reset]
nsCOMPtr<nsIURI> mMask; // [reset]
float mStopOpacity; // [reset]

View File

@ -80,6 +80,7 @@ CPPSRCS = \
nsSVGInnerSVGFrame.cpp \
nsSVGLineFrame.cpp \
nsSVGMarkerFrame.cpp \
nsSVGMaskFrame.cpp \
nsSVGOuterSVGFrame.cpp \
nsSVGPathFrame.cpp \
nsSVGPathGeometryFrame.cpp \

View File

@ -44,32 +44,64 @@
#include "nsSVGAnimatedTransformList.h"
#include "nsIDOMSVGAnimatedEnum.h"
#include "nsSVGUtils.h"
#include "nsISVGRendererSurface.h"
#include "nsSVGDefsFrame.h"
#include "nsSVGAtoms.h"
NS_IMETHODIMP_(nsrefcnt)
nsSVGClipPathFrame::AddRef()
{
return NS_OK;
}
typedef nsSVGDefsFrame nsSVGClipPathFrameBase;
NS_IMETHODIMP_(nsrefcnt)
nsSVGClipPathFrame::Release()
class nsSVGClipPathFrame : public nsSVGClipPathFrameBase,
public nsISVGClipPathFrame
{
return NS_OK;
}
friend nsIFrame*
NS_NewSVGClipPathFrame(nsIPresShell* aPresShell, nsIContent* aContent);
NS_IMETHODIMP
nsSVGClipPathFrame::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
if (nsnull == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
virtual ~nsSVGClipPathFrame();
NS_IMETHOD InitSVG();
public:
// nsISupports interface:
NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }
// nsISVGClipPathFrame interface:
NS_IMETHOD ClipPaint(nsISVGRendererCanvas* canvas,
nsISVGRendererSurface* aClipSurface,
nsISVGChildFrame* aParent,
nsCOMPtr<nsIDOMSVGMatrix> aMatrix);
NS_IMETHOD ClipHitTest(nsISVGChildFrame* aParent,
nsCOMPtr<nsIDOMSVGMatrix> aMatrix,
float aX, float aY, PRBool *aHit);
NS_IMETHOD IsTrivial(PRBool *aTrivial);
/**
* Get the "type" of the frame
*
* @see nsLayoutAtoms::svgClipPathFrame
*/
virtual nsIAtom* GetType() const;
#ifdef DEBUG
NS_IMETHOD GetFrameName(nsAString& aResult) const
{
return MakeFrameName(NS_LITERAL_STRING("SVGClipPath"), aResult);
}
if (aIID.Equals(nsSVGClipPathFrame::GetCID())) {
*aInstancePtr = (void*)(nsSVGClipPathFrame*)this;
NS_ADDREF_THIS();
return NS_OK;
}
return (nsSVGDefsFrame::QueryInterface(aIID, aInstancePtr));
}
#endif
private:
nsISVGChildFrame *mClipParent;
nsCOMPtr<nsIDOMSVGMatrix> mClipParentMatrix;
// nsISVGContainerFrame interface:
already_AddRefed<nsIDOMSVGMatrix> GetCanvasTM();
};
NS_INTERFACE_MAP_BEGIN(nsSVGClipPathFrame)
NS_INTERFACE_MAP_ENTRY(nsISVGClipPathFrame)
NS_INTERFACE_MAP_END_INHERITING(nsSVGClipPathFrameBase)
//----------------------------------------------------------------------
// Implementation
@ -89,7 +121,8 @@ NS_NewSVGClipPathFrame(nsIPresShell* aPresShell, nsIContent* aContent)
}
nsresult
NS_GetSVGClipPathFrame(nsSVGClipPathFrame **aResult, nsIURI *aURI, nsIContent *aContent)
NS_GetSVGClipPathFrame(nsISVGClipPathFrame **aResult,
nsIURI *aURI, nsIContent *aContent)
{
*aResult = nsnull;
@ -132,6 +165,7 @@ nsSVGClipPathFrame::InitSVG()
NS_IMETHODIMP
nsSVGClipPathFrame::ClipPaint(nsISVGRendererCanvas* canvas,
nsISVGRendererSurface* aClipSurface,
nsISVGChildFrame* aParent,
nsCOMPtr<nsIDOMSVGMatrix> aMatrix)
{
@ -143,7 +177,17 @@ nsSVGClipPathFrame::ClipPaint(nsISVGRendererCanvas* canvas,
NotifyCanvasTMChanged(PR_TRUE);
rv = canvas->SetRenderMode(nsISVGRendererCanvas::SVG_RENDER_MODE_CLIP);
PRBool isTrivial;
IsTrivial(&isTrivial);
if (isTrivial)
rv = canvas->SetRenderMode(nsISVGRendererCanvas::SVG_RENDER_MODE_CLIP);
else {
rv = canvas->SetRenderMode(nsISVGRendererCanvas::SVG_RENDER_MODE_CLIP_MASK);
canvas->PushSurface(aClipSurface);
}
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
@ -156,6 +200,9 @@ nsSVGClipPathFrame::ClipPaint(nsISVGRendererCanvas* canvas,
}
}
if (!isTrivial)
canvas->PopSurface();
canvas->SetRenderMode(nsISVGRendererCanvas::SVG_RENDER_MODE_NORMAL);
return NS_OK;
@ -193,6 +240,30 @@ nsSVGClipPathFrame::ClipHitTest(nsISVGChildFrame* aParent,
return NS_OK;
}
NS_IMETHODIMP
nsSVGClipPathFrame::IsTrivial(PRBool *aTrivial)
{
*aTrivial = PR_TRUE;
PRBool foundOne = PR_FALSE;
for (nsIFrame* kid = mFrames.FirstChild(); kid;
kid = kid->GetNextSibling()) {
nsISVGChildFrame* SVGFrame = nsnull;
kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
if (SVGFrame) {
nsIFrame *frame = nsnull;
CallQueryInterface(SVGFrame, &frame);
if (foundOne || frame->GetContent()->Tag() == nsSVGAtoms::g) {
*aTrivial = PR_FALSE;
return NS_OK;
}
foundOne = PR_TRUE;
}
}
return NS_OK;
}
nsIAtom *
nsSVGClipPathFrame::GetType() const
{

View File

@ -34,58 +34,46 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsSVGDefsFrame.h"
#include "nsLayoutAtoms.h"
#ifndef __NS_SVGCLIPPATHFRAME_H__
#define __NS_SVGCLIPPATHFRAME_H__
#define NS_SVGCLIPPATHFRAME_CID \
{0xb497bbe2, 0x4434, 0x4d96, {0x9c, 0xe8, 0xf2, 0xad, 0xd1, 0x1f, 0x1d, 0x26}}
#include "nsISupports.h"
typedef nsSVGDefsFrame nsSVGClipPathFrameBase;
class nsISVGRendererCanvas;
class nsISVGRendererSurface;
class nsISVGChildFrame;
class nsIDOMSVGMatrix;
class nsIURI;
class nsIContent;
class nsSVGClipPathFrame : public nsSVGClipPathFrameBase
{
friend nsIFrame*
NS_NewSVGClipPathFrame(nsIPresShell* aPresShell, nsIContent* aContent);
#define NS_ISVGCLIPPATHFRAME_IID \
{0x9309e388, 0xde9b, 0x4848, {0x84, 0xfe, 0x22, 0xc1, 0xd8, 0x0c, 0x89, 0x11}}
virtual ~nsSVGClipPathFrame();
NS_IMETHOD InitSVG();
public:
NS_DECL_ISUPPORTS
NS_DEFINE_STATIC_CID_ACCESSOR(NS_SVGCLIPPATHFRAME_CID)
NS_DECLARE_STATIC_IID_ACCESSOR(NS_SVGCLIPPATHFRAME_CID)
class nsISVGClipPathFrame : public nsISupports {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISVGCLIPPATHFRAME_IID)
NS_IMETHOD ClipPaint(nsISVGRendererCanvas* canvas,
nsISVGRendererSurface* aClipSurface,
nsISVGChildFrame* aParent,
nsCOMPtr<nsIDOMSVGMatrix> aMatrix);
nsCOMPtr<nsIDOMSVGMatrix> aMatrix) = 0;
NS_IMETHOD ClipHitTest(nsISVGChildFrame* aParent,
nsCOMPtr<nsIDOMSVGMatrix> aMatrix,
float aX, float aY, PRBool *aHit);
/**
* Get the "type" of the frame
*
* @see nsLayoutAtoms::svgClipPathFrame
*/
virtual nsIAtom* GetType() const;
float aX, float aY, PRBool *aHit) = 0;
#ifdef DEBUG
NS_IMETHOD GetFrameName(nsAString& aResult) const
{
return MakeFrameName(NS_LITERAL_STRING("SVGClipPath"), aResult);
}
#endif
// Check if this clipPath is made up of more than one geometry object.
// If so, the clipping API in cairo isn't enough and we need to use
// mask based clipping.
private:
nsISVGChildFrame *mClipParent;
nsCOMPtr<nsIDOMSVGMatrix> mClipParentMatrix;
// nsISVGContainerFrame interface:
already_AddRefed<nsIDOMSVGMatrix> GetCanvasTM();
NS_IMETHOD IsTrivial(PRBool *aTrivial) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsSVGClipPathFrame, NS_SVGCLIPPATHFRAME_CID)
NS_DEFINE_STATIC_IID_ACCESSOR(nsISVGClipPathFrame, NS_ISVGCLIPPATHFRAME_IID)
nsresult
NS_GetSVGClipPathFrame(nsSVGClipPathFrame **aResult, nsIURI *aURI, nsIContent *aContent);
NS_GetSVGClipPathFrame(nsISVGClipPathFrame **aResult,
nsIURI *aURI, nsIContent *aContent);
#endif

View File

@ -50,7 +50,7 @@
#include "nsSVGUtils.h"
#include "nsSVGFilterFrame.h"
#include "nsISVGValueUtils.h"
#include <math.h>
#include "nsSVGMaskFrame.h"
//----------------------------------------------------------------------
// Implementation
@ -90,8 +90,6 @@ nsSVGGFrame::PaintSVG(nsISVGRendererCanvas* canvas,
const nsRect& dirtyRectTwips,
PRBool ignoreFilter)
{
nsCOMPtr<nsISVGRendererSurface> surface;
const nsStyleDisplay *display = mStyleContext->GetStyleDisplay();
if (display->mOpacity == 0.0)
return NS_OK;
@ -117,42 +115,65 @@ nsSVGGFrame::PaintSVG(nsISVGRendererCanvas* canvas,
}
}
nsSVGClipPathFrame *clip = NULL;
nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame();
/* check for a clip path */
PRBool trivialClip = PR_TRUE;
nsISVGClipPathFrame *clip = NULL;
nsCOMPtr<nsISVGRendererSurface> clipMaskSurface;
aURI = GetStyleSVGReset()->mClipPath;
if (aURI) {
NS_GetSVGClipPathFrame(&clip, aURI, mContent);
if (clip) {
nsCOMPtr<nsIDOMSVGMatrix> matrix = GetCanvasTM();
canvas->PushClip();
clip->ClipPaint(canvas, this, matrix);
clip->IsTrivial(&trivialClip);
if (trivialClip) {
canvas->PushClip();
} else {
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipMaskSurface));
if (!clipMaskSurface)
clip = nsnull;
}
if (clip) {
nsCOMPtr<nsIDOMSVGMatrix> matrix = GetCanvasTM();
clip->ClipPaint(canvas, clipMaskSurface, this, matrix);
}
}
}
if (display->mOpacity != 1.0) {
nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame();
if (outerSVGFrame) {
nsIFrame *frame = nsnull;
CallQueryInterface(outerSVGFrame, &frame);
/* check for mask */
if (frame) {
nsSize size = frame->GetSize();
float p2t = GetPresContext()->ScaledPixelsToTwips();
PRUint32 width = (PRUint32)ceil(size.width/p2t);
PRUint32 height = (PRUint32)ceil(size.height/p2t);
nsCOMPtr<nsISVGRenderer> renderer;
outerSVGFrame->GetRenderer(getter_AddRefs(renderer));
if (renderer)
renderer->CreateSurface(width, height, getter_AddRefs(surface));
if (surface) {
if (NS_FAILED(canvas->PushSurface(surface)))
surface = nsnull;
}
nsISVGMaskFrame *mask = nsnull;
nsCOMPtr<nsISVGRendererSurface> maskSurface, maskedSurface;
aURI = GetStyleSVGReset()->mMask;
if (aURI) {
NS_GetSVGMaskFrame(&mask, aURI, mContent);
if (mask) {
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskSurface));
if (maskSurface) {
nsCOMPtr<nsIDOMSVGMatrix> matrix = GetCanvasTM();
if (NS_FAILED(mask->MaskPaint(canvas, maskSurface, this, matrix,
display->mOpacity)))
maskSurface = nsnull;
}
}
}
if (maskSurface || clipMaskSurface || display->mOpacity != 1.0) {
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskedSurface));
if (maskedSurface) {
canvas->PushSurface(maskedSurface);
} else
maskSurface = nsnull;
}
for (nsIFrame* kid = mFrames.FirstChild(); kid;
kid = kid->GetNextSibling()) {
nsISVGChildFrame* SVGFrame=nsnull;
@ -161,12 +182,29 @@ nsSVGGFrame::PaintSVG(nsISVGRendererCanvas* canvas,
SVGFrame->PaintSVG(canvas, dirtyRectTwips, PR_FALSE);
}
if (surface) {
if (maskedSurface)
canvas->PopSurface();
canvas->CompositeSurface(surface, 0, 0, display->mOpacity);
if (clipMaskSurface) {
if (!maskSurface && display->mOpacity == 1.0) {
maskSurface = clipMaskSurface;
} else {
nsCOMPtr<nsISVGRendererSurface> clipped;
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipped));
canvas->PushSurface(clipped);
canvas->CompositeSurfaceWithMask(maskedSurface, 0, 0, clipMaskSurface);
canvas->PopSurface();
maskedSurface = clipped;
}
}
if (clip)
if (maskSurface)
canvas->CompositeSurfaceWithMask(maskedSurface, 0, 0, maskSurface);
else if (display->mOpacity != 1.0)
canvas->CompositeSurface(maskedSurface, 0, 0, display->mOpacity);
if (clip && trivialClip)
canvas->PopClip();
return NS_OK;
@ -195,7 +233,7 @@ nsSVGGFrame::GetFrameForPointSVG(float x, float y, nsIFrame** hit)
PRBool clipHit = PR_TRUE;;
nsIURI *aURI;
nsSVGClipPathFrame *clip = NULL;
nsISVGClipPathFrame *clip = NULL;
aURI = GetStyleSVGReset()->mClipPath;
if (aURI)
NS_GetSVGClipPathFrame(&clip, aURI, mContent);

View File

@ -57,6 +57,8 @@
#include "nsLayoutAtoms.h"
#include "nsISVGValueUtils.h"
#include "nsSVGFilterFrame.h"
#include "nsSVGUtils.h"
#include "nsSVGMaskFrame.h"
#define NS_GET_BIT(rowptr, x) (rowptr[(x)>>3] & (1<<(7-(x)&0x7)))
@ -354,19 +356,66 @@ nsSVGImageFrame::PaintSVG(nsISVGRendererCanvas* canvas,
canvas->PushClip();
nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame();
/* check for a clip path */
nsSVGClipPathFrame *clip = NULL;
PRBool trivialClip = PR_TRUE;
nsISVGClipPathFrame *clip = NULL;
nsCOMPtr<nsISVGRendererSurface> clipMaskSurface;
aURI = GetStyleSVGReset()->mClipPath;
if (aURI) {
NS_GetSVGClipPathFrame(&clip, aURI, mContent);
if (clip) {
nsCOMPtr<nsIDOMSVGMatrix> matrix;
GetCanvasTM(getter_AddRefs(matrix));
clip->ClipPaint(canvas, this, matrix);
clip->IsTrivial(&trivialClip);
if (trivialClip) {
canvas->PushClip();
} else {
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipMaskSurface));
if (!clipMaskSurface)
clip = nsnull;
}
if (clip) {
nsCOMPtr<nsIDOMSVGMatrix> matrix;
GetCanvasTM(getter_AddRefs(matrix));
clip->ClipPaint(canvas, clipMaskSurface, this, matrix);
}
}
}
/* check for mask */
nsISVGMaskFrame *mask = nsnull;
nsCOMPtr<nsISVGRendererSurface> maskSurface, maskedSurface;
aURI = GetStyleSVGReset()->mMask;
if (aURI) {
NS_GetSVGMaskFrame(&mask, aURI, mContent);
if (mask) {
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskSurface));
if (maskSurface) {
nsCOMPtr<nsIDOMSVGMatrix> matrix;
GetCanvasTM(getter_AddRefs(matrix));
if (NS_FAILED(mask->MaskPaint(canvas, maskSurface, this, matrix)))
maskSurface = nsnull;
}
}
}
if (maskSurface || clipMaskSurface) {
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskedSurface));
if (maskedSurface) {
canvas->PushSurface(maskedSurface);
} else
maskSurface = nsnull;
}
if (mSurface) {
nsCOMPtr<nsIDOMSVGMatrix> ctm;
GetCanvasTM(getter_AddRefs(ctm));
@ -465,6 +514,26 @@ nsSVGImageFrame::PaintSVG(nsISVGRendererCanvas* canvas,
mStyleContext->GetStyleDisplay()->mOpacity);
}
if (maskedSurface)
canvas->PopSurface();
if (clipMaskSurface) {
if (!maskSurface) {
maskSurface = clipMaskSurface;
} else {
nsCOMPtr<nsISVGRendererSurface> clipped;
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipped));
canvas->PushSurface(clipped);
canvas->CompositeSurfaceWithMask(maskedSurface, 0, 0, clipMaskSurface);
canvas->PopSurface();
maskedSurface = clipped;
}
}
if (maskSurface)
canvas->CompositeSurfaceWithMask(maskedSurface, 0, 0, maskSurface);
canvas->PopClip();
return NS_OK;

View File

@ -57,6 +57,9 @@
#include "nsSVGFilterFrame.h"
#include "nsISVGValueUtils.h"
#include "nsSVGUtils.h"
#include "nsSVGClipPathFrame.h"
#include "nsSVGMaskFrame.h"
#include "nsISVGRendererSurface.h"
typedef nsContainerFrame nsSVGInnerSVGFrameBase;
@ -359,6 +362,8 @@ nsSVGInnerSVGFrame::PaintSVG(nsISVGRendererCanvas* canvas,
// printf("nsSVGInnerSVG(%p)::Paint\n", this);
#endif
const nsStyleDisplay *display = mStyleContext->GetStyleDisplay();
nsIURI *aURI;
/* check for filter */
@ -411,6 +416,63 @@ nsSVGInnerSVGFrame::PaintSVG(nsISVGRendererCanvas* canvas,
canvas->SetClipRect(clipTransform, x, y, width, height);
}
nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame();
/* check for a clip path */
PRBool trivialClip = PR_TRUE;
nsISVGClipPathFrame *clip = NULL;
nsCOMPtr<nsISVGRendererSurface> clipMaskSurface;
aURI = GetStyleSVGReset()->mClipPath;
if (aURI) {
NS_GetSVGClipPathFrame(&clip, aURI, mContent);
if (clip) {
clip->IsTrivial(&trivialClip);
if (!trivialClip) {
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipMaskSurface));
if (!clipMaskSurface)
clip = nsnull;
}
if (clip) {
nsCOMPtr<nsIDOMSVGMatrix> matrix = GetCanvasTM();
clip->ClipPaint(canvas, clipMaskSurface, this, matrix);
}
}
}
/* check for mask */
nsISVGMaskFrame *mask = nsnull;
nsCOMPtr<nsISVGRendererSurface> maskSurface, maskedSurface;
aURI = GetStyleSVGReset()->mMask;
if (aURI) {
NS_GetSVGMaskFrame(&mask, aURI, mContent);
if (mask) {
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskSurface));
if (maskSurface) {
nsCOMPtr<nsIDOMSVGMatrix> matrix = GetCanvasTM();
if (NS_FAILED(mask->MaskPaint(canvas, maskSurface, this, matrix,
display->mOpacity)))
maskSurface = nsnull;
}
}
}
if (maskSurface || clipMaskSurface || display->mOpacity != 1.0) {
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskedSurface));
if (maskedSurface) {
canvas->PushSurface(maskedSurface);
} else
maskSurface = nsnull;
}
for (nsIFrame* kid = mFrames.FirstChild(); kid;
kid = kid->GetNextSibling()) {
nsISVGChildFrame* SVGFrame=nsnull;
@ -419,6 +481,28 @@ nsSVGInnerSVGFrame::PaintSVG(nsISVGRendererCanvas* canvas,
SVGFrame->PaintSVG(canvas, dirtyRectTwips, PR_FALSE);
}
if (maskedSurface)
canvas->PopSurface();
if (clipMaskSurface) {
if (!maskSurface && display->mOpacity == 1.0) {
maskSurface = clipMaskSurface;
} else {
nsCOMPtr<nsISVGRendererSurface> clipped;
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipped));
canvas->PushSurface(clipped);
canvas->CompositeSurfaceWithMask(maskedSurface, 0, 0, clipMaskSurface);
canvas->PopSurface();
maskedSurface = clipped;
}
}
if (maskSurface)
canvas->CompositeSurfaceWithMask(maskedSurface, 0, 0, maskSurface);
else if (display->mOpacity != 1.0)
canvas->CompositeSurface(maskedSurface, 0, 0, display->mOpacity);
canvas->PopClip();
return NS_OK;
@ -748,6 +832,8 @@ nsSVGInnerSVGFrame::WillModifySVGObservable(nsISVGValue* observable,
nsSVGUtils::FindFilterInvalidation(this, getter_AddRefs(region));
outerSVGFrame->InvalidateRegion(region, PR_TRUE);
}
return NS_OK;
}
NS_IMETHODIMP

View File

@ -0,0 +1,422 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Mozilla SVG project.
*
* The Initial Developer of the Original Code is IBM Corporation.
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsIDOMDocument.h"
#include "nsIDocument.h"
#include "nsIDOMSVGMaskElement.h"
#include "nsSVGMaskFrame.h"
#include "nsISVGRendererCanvas.h"
#include "nsIDOMSVGAnimatedEnum.h"
#include "nsSVGUtils.h"
#include "nsISVGValueUtils.h"
#include "nsIDOMSVGAnimatedLength.h"
#include "nsSVGDefsFrame.h"
#include "nsIDOMSVGLength.h"
#include "nsISVGRendererSurface.h"
typedef nsSVGDefsFrame nsSVGMaskFrameBase;
class nsSVGMaskFrame : public nsSVGMaskFrameBase,
public nsISVGMaskFrame
{
friend nsIFrame*
NS_NewSVGMaskFrame(nsIPresShell* aPresShell, nsIContent* aContent);
virtual ~nsSVGMaskFrame();
NS_IMETHOD InitSVG();
public:
// nsISupports interface:
NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }
// nsISVGMaskFrame interface:
NS_IMETHOD MaskPaint(nsISVGRendererCanvas* aCanvas,
nsISVGRendererSurface* aSurface,
nsISVGChildFrame* aParent,
nsCOMPtr<nsIDOMSVGMatrix> aMatrix,
float aOpacity = 1.0f);
/**
* Get the "type" of the frame
*
* @see nsLayoutAtoms::svgMaskFrame
*/
virtual nsIAtom* GetType() const;
#ifdef DEBUG
NS_IMETHOD GetFrameName(nsAString& aResult) const
{
return MakeFrameName(NS_LITERAL_STRING("SVGMask"), aResult);
}
#endif
private:
nsCOMPtr<nsIDOMSVGAnimatedEnumeration> mMaskUnits;
nsCOMPtr<nsIDOMSVGAnimatedEnumeration> mMaskContentUnits;
nsCOMPtr<nsIDOMSVGLength> mX;
nsCOMPtr<nsIDOMSVGLength> mY;
nsCOMPtr<nsIDOMSVGLength> mWidth;
nsCOMPtr<nsIDOMSVGLength> mHeight;
nsISVGChildFrame *mMaskParent;
nsCOMPtr<nsIDOMSVGMatrix> mMaskParentMatrix;
// nsISVGContainerFrame interface:
already_AddRefed<nsIDOMSVGMatrix> GetCanvasTM();
};
NS_INTERFACE_MAP_BEGIN(nsSVGMaskFrame)
NS_INTERFACE_MAP_ENTRY(nsISVGMaskFrame)
NS_INTERFACE_MAP_END_INHERITING(nsSVGMaskFrameBase)
//----------------------------------------------------------------------
// Implementation
nsIFrame*
NS_NewSVGMaskFrame(nsIPresShell* aPresShell, nsIContent* aContent)
{
return new (aPresShell) nsSVGMaskFrame;
}
nsresult
NS_GetSVGMaskFrame(nsISVGMaskFrame **aResult,
nsIURI *aURI, nsIContent *aContent)
{
*aResult = nsnull;
// Get the PresShell
nsIDocument *myDoc = aContent->GetCurrentDoc();
if (!myDoc) {
NS_WARNING("No document for this content!");
return NS_ERROR_FAILURE;
}
nsIPresShell *aPresShell = myDoc->GetShellAt(0);
// Find the referenced frame
nsIFrame *cpframe;
if (!NS_SUCCEEDED(nsSVGUtils::GetReferencedFrame(&cpframe, aURI, aContent, aPresShell)))
return NS_ERROR_FAILURE;
nsIAtom* frameType = cpframe->GetType();
if (frameType != nsLayoutAtoms::svgMaskFrame)
return NS_ERROR_FAILURE;
*aResult = (nsSVGMaskFrame *)cpframe;
return NS_OK;
}
nsSVGMaskFrame::~nsSVGMaskFrame()
{
NS_REMOVE_SVGVALUE_OBSERVER(mX);
NS_REMOVE_SVGVALUE_OBSERVER(mY);
NS_REMOVE_SVGVALUE_OBSERVER(mWidth);
NS_REMOVE_SVGVALUE_OBSERVER(mHeight);
NS_REMOVE_SVGVALUE_OBSERVER(mMaskUnits);
NS_REMOVE_SVGVALUE_OBSERVER(mMaskContentUnits);
}
NS_IMETHODIMP
nsSVGMaskFrame::InitSVG()
{
nsresult rv = nsSVGDefsFrame::InitSVG();
if (NS_FAILED(rv))
return rv;
mMaskParentMatrix = nsnull;
nsCOMPtr<nsIDOMSVGMaskElement> mask = do_QueryInterface(mContent);
NS_ASSERTION(mask, "wrong content element");
{
nsCOMPtr<nsIDOMSVGAnimatedLength> length;
mask->GetX(getter_AddRefs(length));
length->GetBaseVal(getter_AddRefs(mX));
NS_ASSERTION(mX, "no X");
if (!mX) return NS_ERROR_FAILURE;
NS_ADD_SVGVALUE_OBSERVER(mX);
}
{
nsCOMPtr<nsIDOMSVGAnimatedLength> length;
mask->GetY(getter_AddRefs(length));
length->GetBaseVal(getter_AddRefs(mY));
NS_ASSERTION(mY, "no Y");
if (!mY) return NS_ERROR_FAILURE;
NS_ADD_SVGVALUE_OBSERVER(mY);
}
{
nsCOMPtr<nsIDOMSVGAnimatedLength> length;
mask->GetWidth(getter_AddRefs(length));
length->GetBaseVal(getter_AddRefs(mWidth));
NS_ASSERTION(mWidth, "no Width");
if (!mWidth) return NS_ERROR_FAILURE;
NS_ADD_SVGVALUE_OBSERVER(mWidth);
}
{
nsCOMPtr<nsIDOMSVGAnimatedLength> length;
mask->GetHeight(getter_AddRefs(length));
length->GetBaseVal(getter_AddRefs(mHeight));
NS_ASSERTION(mHeight, "no Height");
if (!mHeight) return NS_ERROR_FAILURE;
NS_ADD_SVGVALUE_OBSERVER(mHeight);
}
mask->GetMaskUnits(getter_AddRefs(mMaskUnits));
NS_ADD_SVGVALUE_OBSERVER(mMaskUnits);
mask->GetMaskContentUnits(getter_AddRefs(mMaskContentUnits));
NS_ADD_SVGVALUE_OBSERVER(mMaskContentUnits);
return NS_OK;
}
/* sRGB -> linearRGB mapping table */
static unsigned char rgb2lin[256] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 1, 1,
1, 1, 1, 1, 1, 1, 2, 2,
2, 2, 2, 2, 2, 3, 3, 3,
3, 3, 4, 4, 4, 4, 4, 5,
5, 5, 5, 6, 6, 6, 6, 7,
7, 7, 8, 8, 8, 9, 9, 9,
10, 10, 10, 11, 11, 11, 12, 12,
13, 13, 13, 14, 14, 15, 15, 16,
16, 16, 17, 17, 18, 18, 19, 19,
20, 20, 21, 22, 22, 23, 23, 24,
24, 25, 26, 26, 27, 27, 28, 29,
29, 30, 31, 31, 32, 33, 33, 34,
35, 36, 36, 37, 38, 38, 39, 40,
41, 42, 42, 43, 44, 45, 46, 47,
47, 48, 49, 50, 51, 52, 53, 54,
55, 55, 56, 57, 58, 59, 60, 61,
62, 63, 64, 65, 66, 67, 68, 70,
71, 72, 73, 74, 75, 76, 77, 78,
80, 81, 82, 83, 84, 85, 87, 88,
89, 90, 92, 93, 94, 95, 97, 98,
99, 101, 102, 103, 105, 106, 107, 109,
110, 112, 113, 114, 116, 117, 119, 120,
122, 123, 125, 126, 128, 129, 131, 132,
134, 135, 137, 139, 140, 142, 144, 145,
147, 148, 150, 152, 153, 155, 157, 159,
160, 162, 164, 166, 167, 169, 171, 173,
175, 176, 178, 180, 182, 184, 186, 188,
190, 192, 193, 195, 197, 199, 201, 203,
205, 207, 209, 211, 213, 215, 218, 220,
222, 224, 226, 228, 230, 232, 235, 237,
239, 241, 243, 245, 248, 250, 252, 255
};
NS_IMETHODIMP
nsSVGMaskFrame::MaskPaint(nsISVGRendererCanvas* aCanvas,
nsISVGRendererSurface* aSurface,
nsISVGChildFrame* aParent,
nsCOMPtr<nsIDOMSVGMatrix> aMatrix,
float aOpacity)
{
nsRect dirty;
if (NS_FAILED(aCanvas->PushSurface(aSurface)))
return NS_ERROR_FAILURE;
{
nsIFrame *frame;
CallQueryInterface(aParent, &frame);
nsCOMPtr<nsIContent> parent = frame->GetContent();
float x, y, width, height;
PRUint16 units;
mMaskUnits->GetAnimVal(&units);
if (units == nsIDOMSVGMaskElement::SVG_MUNITS_OBJECTBOUNDINGBOX) {
aParent->SetMatrixPropagation(PR_FALSE);
aParent->NotifyCanvasTMChanged(PR_TRUE);
nsCOMPtr<nsIDOMSVGRect> bbox;
aParent->GetBBox(getter_AddRefs(bbox));
aParent->SetMatrixPropagation(PR_TRUE);
aParent->NotifyCanvasTMChanged(PR_TRUE);
if (!bbox)
return NS_OK;
#ifdef DEBUG_tor
bbox->GetX(&x);
bbox->GetY(&y);
bbox->GetWidth(&width);
bbox->GetHeight(&height);
fprintf(stderr, "mask bbox: %f,%f %fx%f\n", x, y, width, height);
#endif
bbox->GetX(&x);
x += nsSVGUtils::ObjectSpace(bbox, mX, nsSVGUtils::X);
bbox->GetY(&y);
y += nsSVGUtils::ObjectSpace(bbox, mY, nsSVGUtils::Y);
width = nsSVGUtils::ObjectSpace(bbox, mWidth, nsSVGUtils::X);
height = nsSVGUtils::ObjectSpace(bbox, mHeight, nsSVGUtils::Y);
} else {
x = nsSVGUtils::UserSpace(parent, mX, nsSVGUtils::X);
y = nsSVGUtils::UserSpace(parent, mY, nsSVGUtils::Y);
width = nsSVGUtils::UserSpace(parent, mWidth, nsSVGUtils::X);
height = nsSVGUtils::UserSpace(parent, mHeight, nsSVGUtils::Y);
}
#ifdef DEBUG_tor
fprintf(stderr, "mask clip: %f,%f %fx%f\n", x, y, width, height);
#endif
aCanvas->SetClipRect(aMatrix, x, y, width, height);
}
mMaskParent = aParent,
mMaskParentMatrix = aMatrix;
NotifyCanvasTMChanged(PR_TRUE);
for (nsIFrame* kid = mFrames.FirstChild(); kid;
kid = kid->GetNextSibling()) {
nsISVGChildFrame* SVGFrame=nsnull;
kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
if (SVGFrame) {
SVGFrame->PaintSVG(aCanvas, dirty, PR_TRUE);
}
}
aCanvas->PopSurface();
/* Now convert to intensity (sRGB -> linearRGB -> intensity)
and store in alpha channel */
PRUint32 width, height, length;
PRUint8 *data;
PRInt32 stride;
aSurface->Lock();
aSurface->GetWidth(&width);
aSurface->GetHeight(&height);
aSurface->GetData(&data, &length, &stride);
for (PRUint32 y = 0; y < height; y++)
for (PRUint32 x = 0; x < width; x++) {
PRUint32 a;
float r, g, b, intensity;
/* un-premultiply and sRGB -> linearRGB conversion */
a = data[stride * y + 4 * x + 3];
if (a) {
b = rgb2lin[(255 * (PRUint32)data[stride * y + 4 * x]) / a] / 255.0;
g = rgb2lin[(255 * (PRUint32)data[stride * y + 4 * x + 1]) / a] / 255.0;
r = rgb2lin[(255 * (PRUint32)data[stride * y + 4 * x + 2]) / a] / 255.0;
} else {
b = g = r = 0.0f;
}
/* linearRGB -> intensity */
intensity = (r * 0.2125 + g * 0.7154 + b * 0.0721) * (a / 255.0) * aOpacity;
data[stride * y + 4 * x] = 255;
data[stride * y + 4 * x + 1] = 255;
data[stride * y + 4 * x + 2] = 255;
data[stride * y + 4 * x + 3] = (unsigned char)(intensity * 255);
}
aSurface->Unlock();
return NS_OK;
}
nsIAtom *
nsSVGMaskFrame::GetType() const
{
return nsLayoutAtoms::svgMaskFrame;
}
already_AddRefed<nsIDOMSVGMatrix>
nsSVGMaskFrame::GetCanvasTM()
{
// startup cycle
if (!mMaskParentMatrix) {
NS_ASSERTION(mParent, "null parent");
nsISVGContainerFrame *containerFrame;
mParent->QueryInterface(NS_GET_IID(nsISVGContainerFrame),
(void**)&containerFrame);
if (!containerFrame) {
NS_ERROR("invalid parent");
return nsnull;
}
mMaskParentMatrix = containerFrame->GetCanvasTM();
}
nsCOMPtr<nsIDOMSVGMatrix> canvasTM = mMaskParentMatrix;
/* object bounding box? */
PRUint16 units;
nsCOMPtr<nsIDOMSVGMaskElement> path = do_QueryInterface(mContent);
nsCOMPtr<nsIDOMSVGAnimatedEnumeration> aEnum;
path->GetMaskContentUnits(getter_AddRefs(aEnum));
aEnum->GetAnimVal(&units);
if (mMaskParent &&
units == nsIDOMSVGMaskElement::SVG_MUNITS_OBJECTBOUNDINGBOX) {
nsCOMPtr<nsIDOMSVGRect> rect;
nsresult rv = mMaskParent->GetBBox(getter_AddRefs(rect));
if (NS_SUCCEEDED(rv)) {
float minx, miny, width, height;
rect->GetX(&minx);
rect->GetY(&miny);
rect->GetWidth(&width);
rect->GetHeight(&height);
nsCOMPtr<nsIDOMSVGMatrix> tmp, fini;
canvasTM->Translate(minx, miny, getter_AddRefs(tmp));
tmp->ScaleNonUniform(width, height, getter_AddRefs(fini));
canvasTM = fini;
}
}
nsIDOMSVGMatrix* retval = canvasTM.get();
NS_IF_ADDREF(retval);
return retval;
}

View File

@ -0,0 +1,69 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Mozilla SVG project.
*
* The Initial Developer of the Original Code is IBM Corporation.
* Portions created by the Initial Developer are Copyright (C) 2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NS_SVGMASKFRAME_H__
#define __NS_SVGMASKFRAME_H__
#include "nsISupports.h"
class nsISVGRendererCanvas;
class nsISVGRendererSurface;
class nsISVGChildFrame;
class nsIDOMSVGMatrix;
class nsIURI;
class nsIContent;
#define NS_ISVGMASKFRAME_IID \
{0x122fe62b, 0xa4cb, 0x49d4, {0xbf, 0xd7, 0x26, 0x67, 0x58, 0x28, 0xff, 0x02}}
class nsISVGMaskFrame : public nsISupports {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISVGMASKFRAME_IID)
NS_IMETHOD MaskPaint(nsISVGRendererCanvas* aCanvas,
nsISVGRendererSurface* aSurface,
nsISVGChildFrame* aParent,
nsCOMPtr<nsIDOMSVGMatrix> aMatrix,
float aOpacity = 1.0f) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsISVGMaskFrame, NS_ISVGMASKFRAME_IID)
nsresult
NS_GetSVGMaskFrame(nsISVGMaskFrame **aResult,
nsIURI *aURI, nsIContent *aContent);
#endif

View File

@ -62,6 +62,8 @@
#include "nsIViewManager.h"
#include "nsSVGUtils.h"
#include "nsSVGFilterFrame.h"
#include "nsSVGMaskFrame.h"
#include "nsISVGRendererSurface.h"
////////////////////////////////////////////////////////////////////////
// nsSVGPathGeometryFrame
@ -258,25 +260,64 @@ nsSVGPathGeometryFrame::PaintSVG(nsISVGRendererCanvas* canvas,
}
}
nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame();
/* check for a clip path */
nsSVGClipPathFrame *clip = nsnull;
PRBool trivialClip = PR_TRUE;
nsISVGClipPathFrame *clip = NULL;
nsCOMPtr<nsISVGRendererSurface> clipMaskSurface;
aURI = GetStyleSVGReset()->mClipPath;
if (aURI) {
NS_GetSVGClipPathFrame(&clip, aURI, mContent);
if (clip) {
nsCOMPtr<nsIDOMSVGMatrix> matrix;
GetCanvasTM(getter_AddRefs(matrix));
canvas->PushClip();
clip->ClipPaint(canvas, this, matrix);
}
clip->IsTrivial(&trivialClip);
#ifdef DEBUG_tor
nsCAutoString spec;
aURI->GetAsciiSpec(spec);
fprintf(stderr, "CLIPPATH %s %p\n", spec.get(), clip);
#endif
if (trivialClip) {
canvas->PushClip();
} else {
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipMaskSurface));
if (!clipMaskSurface)
clip = nsnull;
}
if (clip) {
nsCOMPtr<nsIDOMSVGMatrix> matrix;
GetCanvasTM(getter_AddRefs(matrix));
clip->ClipPaint(canvas, clipMaskSurface, this, matrix);
}
}
}
/* check for mask */
nsISVGMaskFrame *mask = nsnull;
nsCOMPtr<nsISVGRendererSurface> maskSurface, maskedSurface;
aURI = GetStyleSVGReset()->mMask;
if (aURI) {
NS_GetSVGMaskFrame(&mask, aURI, mContent);
if (mask) {
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskSurface));
if (maskSurface) {
nsCOMPtr<nsIDOMSVGMatrix> matrix;
GetCanvasTM(getter_AddRefs(matrix));
if (NS_FAILED(mask->MaskPaint(canvas, maskSurface, this, matrix)))
maskSurface = nsnull;
}
}
}
if (maskSurface || clipMaskSurface) {
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskedSurface));
if (maskedSurface) {
canvas->PushSurface(maskedSurface);
} else
maskSurface = nsnull;
}
/* render */
@ -314,7 +355,27 @@ nsSVGPathGeometryFrame::PaintSVG(nsISVGRendererCanvas* canvas,
}
}
if (clip)
if (maskedSurface)
canvas->PopSurface();
if (clipMaskSurface) {
if (!maskSurface) {
maskSurface = clipMaskSurface;
} else {
nsCOMPtr<nsISVGRendererSurface> clipped;
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipped));
canvas->PushSurface(clipped);
canvas->CompositeSurfaceWithMask(maskedSurface, 0, 0, clipMaskSurface);
canvas->PopSurface();
maskedSurface = clipped;
}
}
if (maskSurface)
canvas->CompositeSurfaceWithMask(maskedSurface, 0, 0, maskSurface);
if (clip && trivialClip)
canvas->PopClip();
return NS_OK;
@ -336,7 +397,7 @@ nsSVGPathGeometryFrame::GetFrameForPointSVG(float x, float y, nsIFrame** hit)
PRBool clipHit = PR_TRUE;;
nsIURI *aURI;
nsSVGClipPathFrame *clip = NULL;
nsISVGClipPathFrame *clip = NULL;
aURI = GetStyleSVGReset()->mClipPath;
if (aURI)
NS_GetSVGClipPathFrame(&clip, aURI, mContent);

View File

@ -69,6 +69,9 @@
#include "nsSVGFilterFrame.h"
#include "nsSVGUtils.h"
#include "nsDOMError.h"
#include "nsSVGMaskFrame.h"
#include "nsSVGClipPathFrame.h"
#include "nsISVGRendererSurface.h"
typedef nsContainerFrame nsSVGTextFrameBase;
@ -541,11 +544,17 @@ nsSVGTextFrame::PaintSVG(nsISVGRendererCanvas* canvas,
// printf("nsSVGTextFrame(%p)::Paint\n", this);
#endif
const nsStyleDisplay *display = mStyleContext->GetStyleDisplay();
if (display->mOpacity == 0.0)
return NS_OK;
nsIURI *aURI;
/* check for filter */
if (!ignoreFilter) {
if (!mFilter) {
nsIURI *aURI = GetStyleSVGReset()->mFilter;
aURI = GetStyleSVGReset()->mFilter;
if (aURI)
NS_GetSVGFilterFrame(&mFilter, aURI, mContent);
if (mFilter)
@ -560,6 +569,65 @@ nsSVGTextFrame::PaintSVG(nsISVGRendererCanvas* canvas,
}
}
nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame();
/* check for a clip path */
PRBool trivialClip = PR_TRUE;
nsISVGClipPathFrame *clip = NULL;
nsCOMPtr<nsISVGRendererSurface> clipMaskSurface;
aURI = GetStyleSVGReset()->mClipPath;
if (aURI) {
NS_GetSVGClipPathFrame(&clip, aURI, mContent);
if (clip) {
clip->IsTrivial(&trivialClip);
if (trivialClip) {
canvas->PushClip();
} else {
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipMaskSurface));
if (!clipMaskSurface)
clip = nsnull;
}
if (clip) {
nsCOMPtr<nsIDOMSVGMatrix> matrix = GetCanvasTM();
clip->ClipPaint(canvas, clipMaskSurface, this, matrix);
}
}
}
/* check for mask */
nsISVGMaskFrame *mask = nsnull;
nsCOMPtr<nsISVGRendererSurface> maskSurface, maskedSurface;
aURI = GetStyleSVGReset()->mMask;
if (aURI) {
NS_GetSVGMaskFrame(&mask, aURI, mContent);
if (mask) {
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskSurface));
if (maskSurface) {
nsCOMPtr<nsIDOMSVGMatrix> matrix = GetCanvasTM();
if (NS_FAILED(mask->MaskPaint(canvas, maskSurface, this, matrix,
display->mOpacity)))
maskSurface = nsnull;
}
}
}
if (maskSurface || clipMaskSurface || display->mOpacity != 1.0) {
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskedSurface));
if (maskedSurface) {
canvas->PushSurface(maskedSurface);
} else
maskSurface = nsnull;
}
nsIFrame* kid = mFrames.FirstChild();
while (kid) {
nsISVGChildFrame* SVGFrame=0;
@ -569,6 +637,31 @@ nsSVGTextFrame::PaintSVG(nsISVGRendererCanvas* canvas,
kid = kid->GetNextSibling();
}
if (maskedSurface)
canvas->PopSurface();
if (clipMaskSurface) {
if (!maskSurface && display->mOpacity == 1.0) {
maskSurface = clipMaskSurface;
} else {
nsCOMPtr<nsISVGRendererSurface> clipped;
nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipped));
canvas->PushSurface(clipped);
canvas->CompositeSurfaceWithMask(maskedSurface, 0, 0, clipMaskSurface);
canvas->PopSurface();
maskedSurface = clipped;
}
}
if (maskSurface)
canvas->CompositeSurfaceWithMask(maskedSurface, 0, 0, maskSurface);
else if (display->mOpacity != 1.0)
canvas->CompositeSurface(maskedSurface, 0, 0, display->mOpacity);
if (clip && trivialClip)
canvas->PopClip();
return NS_OK;
}

View File

@ -1,3 +1,4 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -64,6 +65,7 @@
#include "nsIDOMSVGPoint.h"
#include "nsSVGPoint.h"
#include "nsDOMError.h"
#include "nsISVGOuterSVGFrame.h"
#if defined(MOZ_SVG_RENDERER_GDIPLUS)
#include <windows.h>
@ -393,6 +395,32 @@ nsSVGUtils::TransformPoint(nsIDOMSVGMatrix *matrix,
xfpoint->GetY(y);
}
nsresult
nsSVGUtils::GetSurface(nsISVGOuterSVGFrame *aOuterSVGFrame,
nsISVGRendererSurface **aSurface)
{
if (!aOuterSVGFrame)
return NS_ERROR_FAILURE;
nsIFrame *frame = nsnull;
CallQueryInterface(aOuterSVGFrame, &frame);
if (!frame)
return NS_ERROR_FAILURE;
nsSize size = frame->GetSize();
float p2t = frame->GetPresContext()->ScaledPixelsToTwips();
PRUint32 width = (PRUint32)ceil(size.width/p2t);
PRUint32 height = (PRUint32)ceil(size.height/p2t);
nsCOMPtr<nsISVGRenderer> renderer;
aOuterSVGFrame->GetRenderer(getter_AddRefs(renderer));
if (renderer)
return renderer->CreateSurface(width, height, aSurface);
else
return NS_ERROR_FAILURE;
}
nsISVGGlyphFragmentLeaf *
nsSVGUtils::GetGlyphFragmentAtCharNum(nsISVGGlyphFragmentNode* node,
PRUint32 charnum)

View File

@ -53,6 +53,8 @@ class nsISVGGlyphFragmentNode;
class nsIDOMSVGLength;
class nsIDOMSVGMatrix;
class nsIURI;
class nsISVGOuterSVGFrame;
class nsISVGRendererSurface;
#ifndef M_PI
#define M_PI 3.14159265358979323846
@ -136,6 +138,10 @@ public:
static float
AngleBisect(float a1, float a2);
/* Generate a new rendering surface the size of the outer svg frame */
static nsresult GetSurface(nsISVGOuterSVGFrame *aOuterSVGFrame,
nsISVGRendererSurface **aSurface);
private:
/*
* Returns the glyph fragment containing a particular character

View File

@ -69,7 +69,7 @@ interface nsISVGRendererSurface;
* Mozilla-native rendering object with a call to
* nsISVGRenderer::createCanvas().
*/
[scriptable, uuid(2e64a227-de4b-4a69-ab82-5dda1579e90f)]
[scriptable, uuid(9cdf3f86-a511-4948-83f8-e25460f03b83)]
interface nsISVGRendererCanvas : nsISupports
{
/**
@ -108,10 +108,11 @@ interface nsISVGRendererCanvas : nsISupports
void flush();
/**
* Set render mode (clipping or normal draw)
* Set render mode (normal, clipping, or clip render to mask)
*/
const unsigned short SVG_RENDER_MODE_NORMAL = 0;
const unsigned short SVG_RENDER_MODE_CLIP = 1;
const unsigned short SVG_RENDER_MODE_NORMAL = 0;
const unsigned short SVG_RENDER_MODE_CLIP = 1;
const unsigned short SVG_RENDER_MODE_CLIP_MASK = 2;
attribute unsigned short renderMode;
/**
@ -139,6 +140,10 @@ interface nsISVGRendererCanvas : nsISupports
in unsigned long x, in unsigned long y,
in float opacity);
void compositeSurfaceWithMask(in nsISVGRendererSurface surface,
in unsigned long x, in unsigned long y,
in nsISVGRendererSurface mask);
void compositeSurfaceMatrix(in nsISVGRendererSurface surface,
in nsIDOMSVGMatrix canvasTM,
in float opacity);

View File

@ -721,10 +721,6 @@ nsSVGCairoCanvas::CompositeSurface(nsISVGRendererSurface *aSurface,
cairo_save(mCR);
cairo_translate(mCR, aX, aY);
PRUint32 width, height;
aSurface->GetWidth(&width);
aSurface->GetHeight(&height);
cairo_set_source_surface(mCR, cairoSurface->GetSurface(), 0.0, 0.0);
cairo_paint_with_alpha(mCR, aOpacity);
cairo_restore(mCR);
@ -732,6 +728,30 @@ nsSVGCairoCanvas::CompositeSurface(nsISVGRendererSurface *aSurface,
return NS_OK;
}
/** Implements void compositeSurfaceWithMask(in nsISVGRendererSurface surface,
in unsigned long x,
in unsigned long y,
in nsISVGRendererSurface mask); */
NS_IMETHODIMP
nsSVGCairoCanvas::CompositeSurfaceWithMask(nsISVGRendererSurface *aSurface,
PRUint32 aX, PRUint32 aY,
nsISVGRendererSurface *aMask)
{
nsCOMPtr<nsISVGCairoSurface> cairoSurface = do_QueryInterface(aSurface);
nsCOMPtr<nsISVGCairoSurface> maskSurface = do_QueryInterface(aMask);
if (!cairoSurface || !maskSurface)
return NS_ERROR_FAILURE;
cairo_save(mCR);
cairo_translate(mCR, aX, aY);
cairo_set_source_surface(mCR, cairoSurface->GetSurface(), 0.0, 0.0);
cairo_mask_surface(mCR, maskSurface->GetSurface(), 0.0, 0.0);
cairo_restore(mCR);
return NS_OK;
}
/** Implements void compositeSurface(in nsISVGRendererSurface surface,
in nsIDOMSVGMatrix canvasTM,
in float opacity); */
@ -768,10 +788,6 @@ nsSVGCairoCanvas::CompositeSurfaceMatrix(nsISVGRendererSurface *aSurface,
cairo_matrix_t matrix = {m[0], m[1], m[2], m[3], m[4], m[5]};
cairo_transform(mCR, &matrix);
PRUint32 width, height;
aSurface->GetWidth(&width);
aSurface->GetHeight(&height);
cairo_set_source_surface(mCR, cairoSurface->GetSurface(), 0.0, 0.0);
cairo_paint_with_alpha(mCR, aOpacity);
cairo_restore(mCR);

View File

@ -277,20 +277,18 @@ nsSVGCairoPathGeometry::Render(nsISVGRendererCanvas *canvas)
PRUint16 renderMode;
canvas->GetRenderMode(&renderMode);
cairo_matrix_t matrix;
if (renderMode == nsISVGRendererCanvas::SVG_RENDER_MODE_NORMAL) {
cairo_new_path(ctx);
cairo_new_path(ctx);
/* save/pop the state so we don't screw up the xform */
cairo_save(ctx);
} else {
cairo_get_matrix(ctx, &matrix);
}
/* save/pop the state so we don't screw up the xform */
cairo_save(ctx);
GeneratePath(ctx, cairoCanvas);
if (renderMode != nsISVGRendererCanvas::SVG_RENDER_MODE_NORMAL) {
cairo_restore(ctx);
PRUint16 rule;
mSource->GetClipRule(&rule);
if (rule == nsISVGGeometrySource::FILL_RULE_EVENODD)
@ -298,7 +296,11 @@ nsSVGCairoPathGeometry::Render(nsISVGRendererCanvas *canvas)
else
cairo_set_fill_rule(ctx, CAIRO_FILL_RULE_WINDING);
cairo_set_matrix(ctx, &matrix);
if (renderMode == nsISVGRendererCanvas::SVG_RENDER_MODE_CLIP_MASK) {
cairo_set_antialias(ctx, CAIRO_ANTIALIAS_NONE);
cairo_set_source_rgba(ctx, 1.0f, 1.0f, 1.0f, 1.0f);
cairo_fill(ctx);
}
return NS_OK;
}

View File

@ -485,6 +485,19 @@ nsSVGGDIPlusCanvas::CompositeSurface(nsISVGRendererSurface *aSurface,
return NS_OK;
}
/** Implements void compositeSurfaceWithMask(in nsISVGRendererSurface surface,
in unsigned long x,
in unsigned long y,
in nsISVGRendererSurface mask); */
NS_IMETHODIMP
nsSVGGDIPlusCanvas::CompositeSurfaceWithMask(nsISVGRendererSurface *aSurface,
PRUint32 aX, PRUint32 aY,
nsISVGRendererSurface *aMask)
{
// XXX
return NS_ERROR_NOT_IMPLEMENTED;
}
/** Implements void compositeSurface(in nsISVGRendererSurface surface,
in nsIDOMSVGMatrix canvasTM,
in float opacity); */

View File

@ -421,6 +421,19 @@ nsSVGLibartCanvas::CompositeSurface(nsISVGRendererSurface *aSurface,
return NS_ERROR_NOT_IMPLEMENTED;
}
/** Implements void compositeSurfaceWithMask(in nsISVGRendererSurface surface,
in unsigned long x,
in unsigned long y,
in nsISVGRendererSurface mask); */
NS_IMETHODIMP
nsSVGLibartCanvas::CompositeSurfaceWithMask(nsISVGRendererSurface *aSurface,
PRUint32 aX, PRUint32 aY,
nsISVGRendererSurface *aMask)
{
// XXX
return NS_ERROR_NOT_IMPLEMENTED;
}
/** Implements void compositeSurface(in nsISVGRendererSurface surface,
in nsIDOMSVGMatrix canvasTM,
in float opacity); */