mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Bug 450340. Support SVG mask/clip-path/filter CSS properties applied to non-SVG content. r=longsonr,sr=mats
This commit is contained in:
parent
720062e552
commit
b52d3794d5
@ -1606,6 +1606,7 @@ GK_ATOM(IBSplitSpecialSibling, "IBSplitSpecialSibling") // nsIFrame*
|
||||
GK_ATOM(lineCursorProperty, "LineCursorProperty") // nsLineBox*
|
||||
GK_ATOM(rowCursorProperty, "RowCursorProperty") // nsTableRowGroupFrame::FrameCursorData*
|
||||
GK_ATOM(maxElementWidthProperty, "MaxElementWidthProperty") // nscoord*
|
||||
GK_ATOM(outlineInnerRectProperty, "OutlineInnerRectProperty") // nsRect*
|
||||
GK_ATOM(outOfFlowDirtyRectProperty, "OutOfFlowDirtyRectProperty") // nsRect*
|
||||
GK_ATOM(overflowAreaProperty, "OverflowArea") // nsRect*
|
||||
GK_ATOM(overflowProperty, "OverflowProperty") // list of nsIFrame*
|
||||
@ -1614,6 +1615,7 @@ GK_ATOM(excessOverflowContainersProperty, "ExcessOverflowContainersProperty") //
|
||||
GK_ATOM(overflowLinesProperty, "OverflowLinesProperty") // list of nsLineBox*
|
||||
GK_ATOM(overflowOutOfFlowsProperty, "OverflowOutOfFlowsProperty") // nsFrameList*
|
||||
GK_ATOM(overflowPlaceholdersProperty, "OverflowPlaceholdersProperty") // nsFrameList*
|
||||
GK_ATOM(preEffectsBBoxProperty, "PreEffectsBBoxProperty") // nsRect*
|
||||
GK_ATOM(rowUnpaginatedHeightProperty, "RowUnpaginatedHeightProperty") // nscoord*
|
||||
GK_ATOM(spaceManagerProperty, "SpaceManagerProperty") // the space manager for a block
|
||||
GK_ATOM(tabWidthProperty, "TabWidthProperty") // nsTArray<TabSetting>* array of tab widths
|
||||
|
@ -54,6 +54,7 @@ class nsSVGFilterElement : public nsSVGFilterElementBase,
|
||||
public nsIDOMSVGUnitTypes
|
||||
{
|
||||
friend class nsSVGFilterFrame;
|
||||
friend class nsAutoFilterInstance;
|
||||
|
||||
protected:
|
||||
friend nsresult NS_NewSVGFilterElement(nsIContent **aResult,
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "nsIFrame.h"
|
||||
#include "gfxRect.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "nsIDOMSVGFilters.h"
|
||||
|
||||
class nsSVGFilterResource;
|
||||
class nsSVGString;
|
||||
|
@ -40,6 +40,8 @@
|
||||
#include "prdtoa.h"
|
||||
#include "nsTextFormatter.h"
|
||||
#include "nsSVGSVGElement.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsSVGIntegrationUtils.h"
|
||||
|
||||
NS_IMPL_ADDREF(nsSVGLength2::DOMBaseVal)
|
||||
NS_IMPL_RELEASE(nsSVGLength2::DOMBaseVal)
|
||||
@ -179,20 +181,51 @@ nsSVGLength2::GetMMPerPixel(nsSVGSVGElement *aCtx) const
|
||||
return mmPerPx;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGLength2::GetMMPerPixel(nsIFrame *aNonSVGFrame) const
|
||||
{
|
||||
nsPresContext* presContext = aNonSVGFrame->PresContext();
|
||||
float pixelsPerInch =
|
||||
presContext->AppUnitsToFloatCSSPixels(presContext->AppUnitsPerInch());
|
||||
return 25.4f/pixelsPerInch;
|
||||
}
|
||||
|
||||
static float
|
||||
FixAxisLength(float aLength)
|
||||
{
|
||||
if (aLength == 0.0f) {
|
||||
NS_WARNING("zero axis length");
|
||||
return 1e-20f;
|
||||
}
|
||||
return aLength;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGLength2::GetAxisLength(nsSVGSVGElement *aCtx) const
|
||||
{
|
||||
if (!aCtx)
|
||||
return 1;
|
||||
|
||||
float d = aCtx->GetLength(mCtxType);
|
||||
return FixAxisLength(aCtx->GetLength(mCtxType));
|
||||
}
|
||||
|
||||
if (d == 0.0f) {
|
||||
NS_WARNING("zero axis length");
|
||||
d = 1e-20f;
|
||||
float
|
||||
nsSVGLength2::GetAxisLength(nsIFrame *aNonSVGFrame) const
|
||||
{
|
||||
gfxRect rect = nsSVGIntegrationUtils::GetSVGRectForNonSVGFrame(aNonSVGFrame);
|
||||
float length;
|
||||
switch (mCtxType) {
|
||||
case nsSVGUtils::X: length = rect.Width(); break;
|
||||
case nsSVGUtils::Y: length = rect.Height(); break;
|
||||
case nsSVGUtils::XY:
|
||||
length = nsSVGUtils::ComputeNormalizedHypotenuse(rect.Width(), rect.Height());
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("Unknown axis type");
|
||||
length = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return d;
|
||||
return FixAxisLength(length);
|
||||
}
|
||||
|
||||
float
|
||||
@ -240,6 +273,39 @@ nsSVGLength2::GetUnitScaleFactor(nsSVGSVGElement *aCtx) const
|
||||
}
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGLength2::GetUnitScaleFactor(nsIFrame *aFrame) const
|
||||
{
|
||||
nsIContent* content = aFrame->GetContent();
|
||||
if (content->IsNodeOfType(nsINode::eSVG))
|
||||
return GetUnitScaleFactor(static_cast<nsSVGElement*>(content));
|
||||
|
||||
switch (mSpecifiedUnitType) {
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER:
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_PX:
|
||||
return 1;
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_MM:
|
||||
return GetMMPerPixel(aFrame);
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_CM:
|
||||
return GetMMPerPixel(aFrame) / 10.0f;
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_IN:
|
||||
return GetMMPerPixel(aFrame) / 25.4f;
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_PT:
|
||||
return GetMMPerPixel(aFrame) * POINTS_PER_INCH_FLOAT / 25.4f;
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_PC:
|
||||
return GetMMPerPixel(aFrame) * POINTS_PER_INCH_FLOAT / 24.4f / 12.0f;
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE:
|
||||
return 100.0f / GetAxisLength(aFrame);
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_EMS:
|
||||
return 1 / GetEmLength(aFrame);
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_EXS:
|
||||
return 1 / GetExLength(aFrame);
|
||||
default:
|
||||
NS_NOTREACHED("Unknown unit type");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGLength2::SetBaseValueInSpecifiedUnits(float aValue,
|
||||
nsSVGElement *aSVGElement)
|
||||
|
@ -43,6 +43,8 @@
|
||||
#include "nsSVGElement.h"
|
||||
#include "nsDOMError.h"
|
||||
|
||||
class nsIFrame;
|
||||
|
||||
class nsSVGLength2
|
||||
{
|
||||
|
||||
@ -64,10 +66,12 @@ public:
|
||||
void GetBaseValueString(nsAString& aValue);
|
||||
void GetAnimValueString(nsAString& aValue);
|
||||
|
||||
float GetBaseValue(nsSVGElement* aSVGElement)
|
||||
float GetBaseValue(nsSVGElement* aSVGElement) const
|
||||
{ return mBaseVal / GetUnitScaleFactor(aSVGElement); }
|
||||
float GetAnimValue(nsSVGElement* aSVGElement)
|
||||
float GetAnimValue(nsSVGElement* aSVGElement) const
|
||||
{ return mAnimVal / GetUnitScaleFactor(aSVGElement); }
|
||||
float GetAnimValue(nsIFrame* aFrame) const
|
||||
{ return mAnimVal / GetUnitScaleFactor(aFrame); }
|
||||
|
||||
PRUint8 GetCtxType() const { return mCtxType; }
|
||||
PRUint8 GetSpecifiedUnitType() const { return mSpecifiedUnitType; }
|
||||
@ -76,9 +80,9 @@ public:
|
||||
float GetAnimValInSpecifiedUnits() const { return mAnimVal; }
|
||||
float GetBaseValInSpecifiedUnits() const { return mBaseVal; }
|
||||
|
||||
float GetBaseValue(nsSVGSVGElement* aCtx)
|
||||
float GetBaseValue(nsSVGSVGElement* aCtx) const
|
||||
{ return mBaseVal / GetUnitScaleFactor(aCtx); }
|
||||
float GetAnimValue(nsSVGSVGElement* aCtx)
|
||||
float GetAnimValue(nsSVGSVGElement* aCtx) const
|
||||
{ return mAnimVal / GetUnitScaleFactor(aCtx); }
|
||||
|
||||
nsresult ToDOMAnimatedLength(nsIDOMSVGAnimatedLength **aResult,
|
||||
@ -93,6 +97,14 @@ private:
|
||||
PRUint8 mCtxType; // X, Y or Unspecified
|
||||
PRPackedBool mIsAnimated;
|
||||
|
||||
float GetMMPerPixel(nsIFrame *aNonSVGFrame) const;
|
||||
float GetAxisLength(nsIFrame *aNonSVGFrame) const;
|
||||
float GetEmLength(nsIFrame *aFrame) const
|
||||
{ return nsSVGUtils::GetFontSize(aFrame); }
|
||||
float GetExLength(nsIFrame *aFrame) const
|
||||
{ return nsSVGUtils::GetFontXHeight(aFrame); }
|
||||
float GetUnitScaleFactor(nsIFrame *aFrame) const;
|
||||
|
||||
float GetMMPerPixel(nsSVGSVGElement *aCtx) const;
|
||||
float GetAxisLength(nsSVGSVGElement *aCtx) const;
|
||||
float GetEmLength(nsSVGElement *aSVGElement) const
|
||||
|
@ -489,7 +489,7 @@ static nsIFrame* GetSpecialSibling(nsIFrame* aFrame)
|
||||
}
|
||||
|
||||
static nsIFrame*
|
||||
GetIBSplitSpecialPrevSibling(nsIFrame* aFrame)
|
||||
GetIBSplitSpecialPrevSiblingForAnonymousBlock(nsIFrame* aFrame)
|
||||
{
|
||||
NS_PRECONDITION(IsFrameSpecial(aFrame) && !IsInlineFrame(aFrame),
|
||||
"Shouldn't call this");
|
||||
@ -608,10 +608,7 @@ FindLastBlock(nsIFrame* aKid)
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlike the special (next) sibling, the special previous sibling
|
||||
* property points only from the anonymous block to the original
|
||||
* inline that preceded it. DO NOT CHANGE THAT -- the
|
||||
* GetParentStyleContextFrame code depends on it! It is useful for
|
||||
* The special-prev-sibling is useful for
|
||||
* finding the "special parent" of a frame (i.e., a frame from which a
|
||||
* good parent style context can be obtained), one looks at the
|
||||
* special previous sibling annotation of the real parent of the frame
|
||||
@ -7837,7 +7834,8 @@ nsCSSFrameConstructor::AppendFrames(nsFrameConstructorState& aState,
|
||||
nsIContent* content = nsnull;
|
||||
nsStyleContext* styleContext = nsnull;
|
||||
if (!inlineSibling) {
|
||||
nsIFrame* firstInline = GetIBSplitSpecialPrevSibling(parentFrame);
|
||||
nsIFrame* firstInline =
|
||||
GetIBSplitSpecialPrevSiblingForAnonymousBlock(parentFrame);
|
||||
NS_ASSERTION(firstInline, "How did that happen?");
|
||||
|
||||
content = firstInline->GetContent();
|
||||
@ -12455,8 +12453,11 @@ nsCSSFrameConstructor::ConstructInline(nsFrameConstructorState& aState,
|
||||
SetFrameIsSpecial(aNewFrame, blockFrame);
|
||||
SetFrameIsSpecial(blockFrame, inlineFrame);
|
||||
MarkIBSpecialPrevSibling(blockFrame, aNewFrame);
|
||||
if (inlineFrame) {
|
||||
MarkIBSpecialPrevSibling(inlineFrame, blockFrame);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG
|
||||
if (gNoisyInlineConstruction) {
|
||||
nsIFrameDebug* frameDebug;
|
||||
|
||||
@ -12725,8 +12726,8 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
|
||||
// too.
|
||||
nsIFrame* floatContainer = aFrame;
|
||||
do {
|
||||
floatContainer =
|
||||
GetFloatContainingBlock(GetIBSplitSpecialPrevSibling(floatContainer));
|
||||
floatContainer = GetFloatContainingBlock(
|
||||
GetIBSplitSpecialPrevSiblingForAnonymousBlock(floatContainer));
|
||||
if (!floatContainer) {
|
||||
break;
|
||||
}
|
||||
|
@ -642,6 +642,16 @@ nsCSSRendering::PaintBorder(nsPresContext* aPresContext,
|
||||
SN();
|
||||
}
|
||||
|
||||
static nsRect
|
||||
GetOutlineInnerRect(nsIFrame* aFrame)
|
||||
{
|
||||
nsRect* savedOutlineInnerRect = static_cast<nsRect*>
|
||||
(aFrame->GetProperty(nsGkAtoms::outlineInnerRectProperty));
|
||||
if (savedOutlineInnerRect)
|
||||
return *savedOutlineInnerRect;
|
||||
return aFrame->GetOverflowRect();
|
||||
}
|
||||
|
||||
void
|
||||
nsCSSRendering::PaintOutline(nsPresContext* aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
@ -671,9 +681,6 @@ nsCSSRendering::PaintOutline(nsPresContext* aPresContext,
|
||||
// get the radius for our outline
|
||||
GetBorderRadiusTwips(aOutlineStyle.mOutlineRadius, aBorderArea.width, twipsRadii);
|
||||
|
||||
nscoord offset;
|
||||
aOutlineStyle.GetOutlineOffset(offset);
|
||||
|
||||
// When the outline property is set on :-moz-anonymous-block or
|
||||
// :-moz-anonyomus-positioned-block pseudo-elements, it inherited that
|
||||
// outline from the inline that was broken because it contained a
|
||||
@ -690,47 +697,35 @@ nsCSSRendering::PaintOutline(nsPresContext* aPresContext,
|
||||
frameForArea = frameForArea->GetFirstChild(nsnull);
|
||||
NS_ASSERTION(frameForArea, "anonymous block with no children?");
|
||||
} while (frameForArea);
|
||||
nsRect overflowArea;
|
||||
nsRect innerRect; // relative to aBorderArea.TopLeft()
|
||||
if (frameForArea == aForFrame) {
|
||||
overflowArea = aForFrame->GetOverflowRect();
|
||||
innerRect = GetOutlineInnerRect(aForFrame);
|
||||
} else {
|
||||
for (; frameForArea; frameForArea = frameForArea->GetNextSibling()) {
|
||||
// The outline has already been included in aForFrame's overflow
|
||||
// area, but not in those of its descendants, so we have to
|
||||
// include it. Otherwise we'll end up drawing the outline inside
|
||||
// the border.
|
||||
nsRect r(frameForArea->GetOverflowRect() +
|
||||
nsRect r(GetOutlineInnerRect(frameForArea) +
|
||||
frameForArea->GetOffsetTo(aForFrame));
|
||||
nscoord delta = PR_MAX(offset + width, 0);
|
||||
r.Inflate(delta, delta);
|
||||
overflowArea.UnionRect(overflowArea, r);
|
||||
innerRect.UnionRect(innerRect, r);
|
||||
}
|
||||
}
|
||||
|
||||
nsRect outerRect(overflowArea + aBorderArea.TopLeft());
|
||||
nsRect innerRect(outerRect);
|
||||
if (width + offset >= 0) {
|
||||
// the overflow area is exactly the outside edge of the outline
|
||||
innerRect.Deflate(width, width);
|
||||
} else {
|
||||
// the overflow area is exactly the rectangle containing the frame and its
|
||||
// children; we can compute the outline directly
|
||||
innerRect.Deflate(-offset, -offset);
|
||||
if (innerRect.width < 0 || innerRect.height < 0) {
|
||||
return; // Protect against negative outline sizes
|
||||
}
|
||||
outerRect = innerRect;
|
||||
outerRect.Inflate(width, width);
|
||||
}
|
||||
|
||||
innerRect += aBorderArea.TopLeft();
|
||||
nscoord offset;
|
||||
aOutlineStyle.GetOutlineOffset(offset);
|
||||
innerRect.Inflate(offset, offset);
|
||||
// If the dirty rect is completely inside the border area (e.g., only the
|
||||
// content is being painted), then we can skip out now
|
||||
// XXX this isn't exactly true for rounded borders, where the inside curves may
|
||||
// encroach into the content area. A safer calculation would be to
|
||||
// shorten insideRect by the radius one each side before performing this test.
|
||||
if (innerRect.Contains(aDirtyRect)) {
|
||||
if (innerRect.Contains(aDirtyRect))
|
||||
return;
|
||||
}
|
||||
|
||||
nsRect outerRect = innerRect;
|
||||
outerRect.Inflate(width, width);
|
||||
|
||||
// Get our conversion values
|
||||
nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
|
||||
|
@ -51,6 +51,9 @@
|
||||
#include "nsFrameManager.h"
|
||||
#include "gfxContext.h"
|
||||
#include "nsStyleStructInlines.h"
|
||||
#ifdef MOZ_SVG
|
||||
#include "nsSVGIntegrationUtils.h"
|
||||
#endif
|
||||
|
||||
nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
||||
PRBool aIsForEvents, PRBool aBuildCaret)
|
||||
@ -267,6 +270,15 @@ nsDisplayList::FlattenTo(nsTArray<nsDisplayItem*>* aElements) {
|
||||
}
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsDisplayList::GetBounds(nsDisplayListBuilder* aBuilder) const {
|
||||
nsRect bounds;
|
||||
for (nsDisplayItem* i = GetBottom(); i != nsnull; i = i->GetAbove()) {
|
||||
bounds.UnionRect(bounds, i->GetBounds(aBuilder));
|
||||
}
|
||||
return bounds;
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayList::OptimizeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion) {
|
||||
@ -671,11 +683,7 @@ nsDisplayWrapList::HitTest(nsDisplayListBuilder* aBuilder, nsPoint aPt,
|
||||
|
||||
nsRect
|
||||
nsDisplayWrapList::GetBounds(nsDisplayListBuilder* aBuilder) {
|
||||
nsRect bounds;
|
||||
for (nsDisplayItem* i = mList.GetBottom(); i != nsnull; i = i->GetAbove()) {
|
||||
bounds.UnionRect(bounds, i->GetBounds(aBuilder));
|
||||
}
|
||||
return bounds;
|
||||
return mList.GetBounds(aBuilder);
|
||||
}
|
||||
|
||||
PRBool
|
||||
@ -928,3 +936,72 @@ nsDisplayWrapList* nsDisplayClip::WrapWithClone(nsDisplayListBuilder* aBuilder,
|
||||
return new (aBuilder)
|
||||
nsDisplayClip(aItem->GetUnderlyingFrame(), mClippingFrame, aItem, mClip);
|
||||
}
|
||||
|
||||
#ifdef MOZ_SVG
|
||||
nsDisplaySVGEffects::nsDisplaySVGEffects(nsIFrame* aFrame, nsDisplayList* aList)
|
||||
: nsDisplayWrapList(aFrame, aList), mEffectsFrame(aFrame),
|
||||
mBounds(aFrame->GetOverflowRect())
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsDisplaySVGEffects);
|
||||
}
|
||||
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
nsDisplaySVGEffects::~nsDisplaySVGEffects()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsDisplaySVGEffects);
|
||||
}
|
||||
#endif
|
||||
|
||||
PRBool nsDisplaySVGEffects::IsOpaque(nsDisplayListBuilder* aBuilder)
|
||||
{
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsDisplaySVGEffects::HitTest(nsDisplayListBuilder* aBuilder, nsPoint aPt,
|
||||
HitTestState* aState)
|
||||
{
|
||||
if (!nsSVGIntegrationUtils::HitTestFrameForEffects(mEffectsFrame,
|
||||
aPt - aBuilder->ToReferenceFrame(mEffectsFrame)))
|
||||
return nsnull;
|
||||
return mList.HitTest(aBuilder, aPt, aState);
|
||||
}
|
||||
|
||||
void nsDisplaySVGEffects::Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsIRenderingContext* aCtx, const nsRect& aDirtyRect)
|
||||
{
|
||||
nsSVGIntegrationUtils::PaintFramesWithEffects(aCtx,
|
||||
mEffectsFrame, aDirtyRect, aBuilder, &mList);
|
||||
}
|
||||
|
||||
PRBool nsDisplaySVGEffects::OptimizeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion) {
|
||||
nsRegion vis;
|
||||
vis.And(*aVisibleRegion, GetBounds(aBuilder));
|
||||
nsPoint offset = aBuilder->ToReferenceFrame(mEffectsFrame);
|
||||
nsRect dirtyRect = nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(mEffectsFrame,
|
||||
vis.GetBounds() - offset) + offset;
|
||||
|
||||
// Our children may be translucent so we should not allow them to subtract
|
||||
// area from aVisibleRegion.
|
||||
nsRegion childrenVisibleRegion(dirtyRect);
|
||||
nsDisplayWrapList::OptimizeVisibility(aBuilder, &childrenVisibleRegion);
|
||||
return !vis.IsEmpty();
|
||||
}
|
||||
|
||||
PRBool nsDisplaySVGEffects::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
|
||||
{
|
||||
if (aItem->GetType() != TYPE_SVG_EFFECTS)
|
||||
return PR_FALSE;
|
||||
// items for the same content element should be merged into a single
|
||||
// compositing group
|
||||
// aItem->GetUnderlyingFrame() returns non-null because it's nsDisplaySVGEffects
|
||||
if (aItem->GetUnderlyingFrame()->GetContent() != mFrame->GetContent())
|
||||
return PR_FALSE;
|
||||
nsDisplaySVGEffects* other = static_cast<nsDisplaySVGEffects*>(aItem);
|
||||
mList.AppendToBottom(&other->mList);
|
||||
mBounds.UnionRect(mBounds,
|
||||
other->mBounds + other->mEffectsFrame->GetOffsetTo(mEffectsFrame));
|
||||
return PR_TRUE;
|
||||
}
|
||||
#endif
|
||||
|
@ -392,6 +392,9 @@ public:
|
||||
TYPE_OUTLINE,
|
||||
TYPE_CLIP,
|
||||
TYPE_OPACITY,
|
||||
#ifdef MOZ_SVG
|
||||
TYPE_SVG_EFFECTS,
|
||||
#endif
|
||||
TYPE_WRAPLIST
|
||||
};
|
||||
|
||||
@ -694,6 +697,10 @@ public:
|
||||
*/
|
||||
void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx,
|
||||
const nsRect& aDirtyRect) const;
|
||||
/**
|
||||
* Get the bounds. Takes the union of the bounds of all children.
|
||||
*/
|
||||
nsRect GetBounds(nsDisplayListBuilder* aBuilder) const;
|
||||
/**
|
||||
* Find the topmost display item that returns a non-null frame, and return
|
||||
* the frame.
|
||||
@ -1252,4 +1259,39 @@ private:
|
||||
nsRect mClip;
|
||||
};
|
||||
|
||||
#ifdef MOZ_SVG
|
||||
/**
|
||||
* A display item to paint a stacking context with effects
|
||||
* set by the stacking context root frame's style.
|
||||
*/
|
||||
class nsDisplaySVGEffects : public nsDisplayWrapList {
|
||||
public:
|
||||
nsDisplaySVGEffects(nsIFrame* aFrame, nsDisplayList* aList);
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplaySVGEffects();
|
||||
#endif
|
||||
|
||||
virtual Type GetType() { return TYPE_SVG_EFFECTS; }
|
||||
virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder);
|
||||
virtual nsIFrame* HitTest(nsDisplayListBuilder* aBuilder, nsPoint aPt,
|
||||
HitTestState* aState);
|
||||
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) {
|
||||
return mBounds + aBuilder->ToReferenceFrame(mEffectsFrame);
|
||||
}
|
||||
virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx,
|
||||
const nsRect& aDirtyRect);
|
||||
virtual PRBool OptimizeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion);
|
||||
virtual PRBool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem);
|
||||
NS_DISPLAY_DECL_NAME("SVGEffects")
|
||||
|
||||
nsIFrame* GetEffectsFrame() { return mEffectsFrame; }
|
||||
|
||||
private:
|
||||
nsIFrame* mEffectsFrame;
|
||||
// relative to mEffectsFrame
|
||||
nsRect mBounds;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /*NSDISPLAYLIST_H_*/
|
||||
|
@ -79,6 +79,7 @@
|
||||
|
||||
#ifdef MOZ_SVG
|
||||
#include "nsSVGUtils.h"
|
||||
#include "nsSVGIntegrationUtils.h"
|
||||
#include "nsSVGForeignObjectFrame.h"
|
||||
#include "nsSVGOuterSVGFrame.h"
|
||||
#endif
|
||||
@ -1037,7 +1038,19 @@ AddItemsToRegion(nsDisplayListBuilder* aBuilder, nsDisplayList* aList,
|
||||
for (nsDisplayItem* item = aList->GetBottom(); item; item = item->GetAbove()) {
|
||||
nsDisplayList* sublist = item->GetList();
|
||||
if (sublist) {
|
||||
if (item->GetType() == nsDisplayItem::TYPE_CLIP) {
|
||||
nsDisplayItem::Type type = item->GetType();
|
||||
#ifdef MOZ_SVG
|
||||
if (type == nsDisplayItem::TYPE_SVG_EFFECTS) {
|
||||
nsDisplaySVGEffects* effectsItem = static_cast<nsDisplaySVGEffects*>(item);
|
||||
if (!aBuilder->IsMovingFrame(effectsItem->GetEffectsFrame())) {
|
||||
// Invalidate the whole thing
|
||||
nsRect r;
|
||||
r.IntersectRect(aClipRect, effectsItem->GetBounds(aBuilder));
|
||||
aRegion->Or(*aRegion, r);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (type == nsDisplayItem::TYPE_CLIP) {
|
||||
nsDisplayClip* clipItem = static_cast<nsDisplayClip*>(item);
|
||||
nsRect clip = aClipRect;
|
||||
// If the clipping frame is moving, then it isn't clipping any
|
||||
@ -1241,45 +1254,63 @@ nsLayoutUtils::BinarySearchForPosition(nsIRenderingContext* aRendContext,
|
||||
}
|
||||
|
||||
static void
|
||||
AddRectsForFrame(nsIFrame* aFrame, nsIFrame* aRelativeTo,
|
||||
nsLayoutUtils::RectCallback* aCallback)
|
||||
AddBoxesForFrame(nsIFrame* aFrame,
|
||||
nsLayoutUtils::BoxCallback* aCallback)
|
||||
{
|
||||
nsIAtom* pseudoType = aFrame->GetStyleContext()->GetPseudoType();
|
||||
|
||||
if (pseudoType == nsCSSAnonBoxes::tableOuter) {
|
||||
AddRectsForFrame(aFrame->GetFirstChild(nsnull), aRelativeTo,
|
||||
aCallback);
|
||||
AddBoxesForFrame(aFrame->GetFirstChild(nsnull), aCallback);
|
||||
nsIFrame* kid = aFrame->GetFirstChild(nsGkAtoms::captionList);
|
||||
if (kid) {
|
||||
AddRectsForFrame(kid, aRelativeTo, aCallback);
|
||||
AddBoxesForFrame(kid, aCallback);
|
||||
}
|
||||
} else if (pseudoType == nsCSSAnonBoxes::mozAnonymousBlock ||
|
||||
pseudoType == nsCSSAnonBoxes::mozAnonymousPositionedBlock ||
|
||||
pseudoType == nsCSSAnonBoxes::mozMathMLAnonymousBlock ||
|
||||
pseudoType == nsCSSAnonBoxes::mozXULAnonymousBlock) {
|
||||
for (nsIFrame* kid = aFrame->GetFirstChild(nsnull); kid; kid = kid->GetNextSibling()) {
|
||||
AddRectsForFrame(kid, aRelativeTo, aCallback);
|
||||
AddBoxesForFrame(kid, aCallback);
|
||||
}
|
||||
} else {
|
||||
aCallback->AddBox(aFrame);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsLayoutUtils::GetAllInFlowBoxes(nsIFrame* aFrame, BoxCallback* aCallback)
|
||||
{
|
||||
while (aFrame) {
|
||||
AddBoxesForFrame(aFrame, aCallback);
|
||||
aFrame = nsLayoutUtils::GetNextContinuationOrSpecialSibling(aFrame);
|
||||
}
|
||||
}
|
||||
|
||||
struct BoxToBorderRect : public nsLayoutUtils::BoxCallback {
|
||||
nsIFrame* mRelativeTo;
|
||||
nsLayoutUtils::RectCallback* mCallback;
|
||||
|
||||
BoxToBorderRect(nsIFrame* aRelativeTo, nsLayoutUtils::RectCallback* aCallback)
|
||||
: mCallback(aCallback), mRelativeTo(aRelativeTo) {}
|
||||
|
||||
virtual void AddBox(nsIFrame* aFrame) {
|
||||
#ifdef MOZ_SVG
|
||||
nsRect r;
|
||||
nsIFrame* outer = nsSVGUtils::GetOuterSVGFrameAndCoveredRegion(aFrame, &r);
|
||||
if (outer) {
|
||||
aCallback->AddRect(r + outer->GetOffsetTo(aRelativeTo));
|
||||
mCallback->AddRect(r + outer->GetOffsetTo(mRelativeTo));
|
||||
} else
|
||||
#endif
|
||||
aCallback->AddRect(nsRect(aFrame->GetOffsetTo(aRelativeTo), aFrame->GetSize()));
|
||||
mCallback->AddRect(nsRect(aFrame->GetOffsetTo(mRelativeTo), aFrame->GetSize()));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
nsLayoutUtils::GetAllInFlowRects(nsIFrame* aFrame, nsIFrame* aRelativeTo,
|
||||
RectCallback* aCallback)
|
||||
{
|
||||
while (aFrame) {
|
||||
AddRectsForFrame(aFrame, aRelativeTo, aCallback);
|
||||
aFrame = nsLayoutUtils::GetNextContinuationOrSpecialSibling(aFrame);
|
||||
}
|
||||
BoxToBorderRect converter(aRelativeTo, aCallback);
|
||||
GetAllInFlowBoxes(aFrame, &converter);
|
||||
}
|
||||
|
||||
struct RectAccumulator : public nsLayoutUtils::RectCallback {
|
||||
@ -1475,6 +1506,23 @@ nsLayoutUtils::GetNextContinuationOrSpecialSibling(nsIFrame *aFrame)
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsLayoutUtils::GetFirstContinuationOrSpecialSibling(nsIFrame *aFrame)
|
||||
{
|
||||
nsIFrame *result = aFrame->GetFirstContinuation();
|
||||
if (result->GetStateBits() & NS_FRAME_IS_SPECIAL) {
|
||||
while (PR_TRUE) {
|
||||
nsIFrame *f = static_cast<nsIFrame*>
|
||||
(result->GetProperty(nsGkAtoms::IBSplitSpecialPrevSibling));
|
||||
if (!f)
|
||||
break;
|
||||
result = f;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsLayoutUtils::IsViewportScrollbarFrame(nsIFrame* aFrame)
|
||||
{
|
||||
|
@ -486,6 +486,19 @@ public:
|
||||
PRInt32& aIndex,
|
||||
PRInt32& aTextWidth);
|
||||
|
||||
class BoxCallback {
|
||||
public:
|
||||
virtual void AddBox(nsIFrame* aFrame) = 0;
|
||||
};
|
||||
/**
|
||||
* Collect all CSS boxes associated with aFrame and its
|
||||
* continuations, "drilling down" through outer table frames and
|
||||
* some anonymous blocks since they're not real CSS boxes.
|
||||
* If aFrame is null, no boxes are returned.
|
||||
* SVG frames return a single box, themselves.
|
||||
*/
|
||||
static void GetAllInFlowBoxes(nsIFrame* aFrame, BoxCallback* aCallback);
|
||||
|
||||
class RectCallback {
|
||||
public:
|
||||
virtual void AddRect(const nsRect& aRect) = 0;
|
||||
@ -579,6 +592,13 @@ public:
|
||||
static nsIFrame*
|
||||
GetNextContinuationOrSpecialSibling(nsIFrame *aFrame);
|
||||
|
||||
/**
|
||||
* Get the first frame in the continuation-plus-special-sibling chain
|
||||
* containing aFrame.
|
||||
*/
|
||||
static nsIFrame*
|
||||
GetFirstContinuationOrSpecialSibling(nsIFrame *aFrame);
|
||||
|
||||
/**
|
||||
* Check whether aFrame is a part of the scrollbar or scrollcorner of
|
||||
* the root content.
|
||||
|
@ -120,6 +120,10 @@
|
||||
#include "nsBlockFrame.h"
|
||||
#include "nsDisplayList.h"
|
||||
|
||||
#ifdef MOZ_SVG
|
||||
#include "nsSVGIntegrationUtils.h"
|
||||
#endif
|
||||
|
||||
#include "gfxContext.h"
|
||||
|
||||
static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
|
||||
@ -1181,7 +1185,15 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
dirtyRect.IntersectRect(dirtyRect,
|
||||
absPosClip - aBuilder->ToReferenceFrame(this));
|
||||
}
|
||||
|
||||
|
||||
#ifdef MOZ_SVG
|
||||
PRBool usingSVGEffects = nsSVGIntegrationUtils::UsingEffectsForFrame(this);
|
||||
if (usingSVGEffects) {
|
||||
dirtyRect =
|
||||
nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, dirtyRect);
|
||||
}
|
||||
#endif
|
||||
|
||||
nsDisplayListCollection set;
|
||||
nsresult rv;
|
||||
{
|
||||
@ -1262,12 +1274,17 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
resultList.AppendToTop(item);
|
||||
}
|
||||
|
||||
if (disp->mOpacity == 1.0f) {
|
||||
aList->AppendToTop(&resultList);
|
||||
} else {
|
||||
#ifdef MOZ_SVG
|
||||
if (usingSVGEffects) {
|
||||
rv = aList->AppendNewToTop(new (aBuilder) nsDisplaySVGEffects(this, &resultList));
|
||||
} else
|
||||
#endif
|
||||
if (disp->mOpacity < 1.0f) {
|
||||
rv = aList->AppendNewToTop(new (aBuilder) nsDisplayOpacity(this, &resultList));
|
||||
} else {
|
||||
aList->AppendToTop(&resultList);
|
||||
}
|
||||
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -1406,7 +1423,11 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
!PresContext()->GetTheme()->WidgetIsContainer(ourDisp->mAppearance))
|
||||
return NS_OK;
|
||||
|
||||
PRBool isComposited = disp->mOpacity != 1.0f;
|
||||
PRBool isComposited = disp->mOpacity != 1.0f
|
||||
#ifdef MOZ_SVG
|
||||
|| nsSVGIntegrationUtils::UsingEffectsForFrame(aChild)
|
||||
#endif
|
||||
;
|
||||
PRBool isPositioned = disp->IsPositioned();
|
||||
if (isComposited || isPositioned || (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
|
||||
// If you change this, also change IsPseudoStackingContextFromStyle()
|
||||
@ -3591,6 +3612,15 @@ void
|
||||
nsIFrame::InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY,
|
||||
nsIFrame* aForChild, PRBool aImmediate)
|
||||
{
|
||||
#ifdef MOZ_SVG
|
||||
if (nsSVGIntegrationUtils::UsingEffectsForFrame(this)) {
|
||||
nsRect r = nsSVGIntegrationUtils::GetInvalidAreaForChangedSource(this,
|
||||
aDamageRect + nsPoint(aX, aY));
|
||||
GetParent()->InvalidateInternal(r, mRect.x, mRect.y, this, aImmediate);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
GetParent()->
|
||||
InvalidateInternal(aDamageRect, aX + mRect.x, aY + mRect.y, this, aImmediate);
|
||||
}
|
||||
@ -3620,12 +3650,53 @@ nsIFrame::InvalidateRoot(const nsRect& aDamageRect,
|
||||
view->GetViewManager()->UpdateView(view, aDamageRect + nsPoint(aX, aY), flags);
|
||||
}
|
||||
|
||||
static nsRect ComputeOutlineRect(const nsIFrame* aFrame, PRBool* aAnyOutline,
|
||||
const nsRect& aOverflowRect) {
|
||||
static void
|
||||
DestroyRectFunc(void* aFrame,
|
||||
nsIAtom* aPropertyName,
|
||||
void* aPropertyValue,
|
||||
void* aDtorData)
|
||||
{
|
||||
delete static_cast<nsRect*>(aPropertyValue);
|
||||
}
|
||||
|
||||
static void
|
||||
SetRectProperty(nsIFrame* aFrame, nsIAtom* aProp, const nsRect& aRect)
|
||||
{
|
||||
nsRect* r = new nsRect(aRect);
|
||||
if (!r)
|
||||
return;
|
||||
aFrame->SetProperty(aProp, r, DestroyRectFunc);
|
||||
}
|
||||
|
||||
static nsRect
|
||||
ComputeOutlineAndEffectsRect(nsIFrame* aFrame, PRBool* aAnyOutlineOrEffects,
|
||||
const nsRect& aOverflowRect,
|
||||
PRBool aStoreRectProperties) {
|
||||
nsRect r = aOverflowRect;
|
||||
*aAnyOutlineOrEffects = PR_FALSE;
|
||||
|
||||
// box-shadow
|
||||
nsCSSShadowArray* boxShadows = aFrame->GetStyleBorder()->mBoxShadow;
|
||||
if (boxShadows) {
|
||||
nsRect shadows;
|
||||
for (PRUint32 i = 0; i < boxShadows->Length(); ++i) {
|
||||
nsRect tmpRect = r;
|
||||
nsCSSShadowItem* shadow = boxShadows->ShadowAt(i);
|
||||
nscoord xOffset = shadow->mXOffset.GetCoordValue();
|
||||
nscoord yOffset = shadow->mYOffset.GetCoordValue();
|
||||
nscoord outsetRadius = shadow->mRadius.GetCoordValue() +
|
||||
shadow->mSpread.GetCoordValue();
|
||||
|
||||
tmpRect.MoveBy(nsPoint(xOffset, yOffset));
|
||||
tmpRect.Inflate(outsetRadius, outsetRadius);
|
||||
|
||||
shadows.UnionRect(shadows, tmpRect);
|
||||
}
|
||||
r.UnionRect(r, shadows);
|
||||
}
|
||||
|
||||
const nsStyleOutline* outline = aFrame->GetStyleOutline();
|
||||
PRUint8 outlineStyle = outline->GetOutlineStyle();
|
||||
nsRect r = aOverflowRect;
|
||||
*aAnyOutline = PR_FALSE;
|
||||
if (outlineStyle != NS_STYLE_BORDER_STYLE_NONE) {
|
||||
nscoord width;
|
||||
#ifdef DEBUG
|
||||
@ -3634,13 +3705,35 @@ static nsRect ComputeOutlineRect(const nsIFrame* aFrame, PRBool* aAnyOutline,
|
||||
outline->GetOutlineWidth(width);
|
||||
NS_ASSERTION(result, "GetOutlineWidth had no cached outline width");
|
||||
if (width > 0) {
|
||||
if (aStoreRectProperties) {
|
||||
SetRectProperty(aFrame, nsGkAtoms::outlineInnerRectProperty, r);
|
||||
}
|
||||
|
||||
nscoord offset;
|
||||
outline->GetOutlineOffset(offset);
|
||||
nscoord inflateBy = PR_MAX(width + offset, 0);
|
||||
r.Inflate(inflateBy, inflateBy);
|
||||
*aAnyOutline = PR_TRUE;
|
||||
*aAnyOutlineOrEffects = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// Note that we don't remove the outlineInnerRect if a frame loses outline
|
||||
// style. That would require an extra property lookup for every frame,
|
||||
// or a new frame state bit to track whether a property had been stored,
|
||||
// or something like that. It's not worth doing that here. At most it's
|
||||
// only one heap-allocated rect per frame and it will be cleaned up when
|
||||
// the frame dies.
|
||||
|
||||
#ifdef MOZ_SVG
|
||||
if (nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame)) {
|
||||
*aAnyOutlineOrEffects = PR_TRUE;
|
||||
if (aStoreRectProperties) {
|
||||
SetRectProperty(aFrame, nsGkAtoms::preEffectsBBoxProperty, r);
|
||||
}
|
||||
r = nsSVGIntegrationUtils::ComputeFrameEffectsRect(aFrame, r);
|
||||
}
|
||||
#endif
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -3699,10 +3792,10 @@ nsIFrame::CheckInvalidateSizeChange(const nsRect& aOldRect,
|
||||
// invalidated)
|
||||
|
||||
// Invalidate the entire old frame+outline if the frame has an outline
|
||||
PRBool anyOutline;
|
||||
nsRect r = ComputeOutlineRect(this, &anyOutline,
|
||||
aNewDesiredSize.mOverflowArea);
|
||||
if (anyOutline) {
|
||||
PRBool anyOutlineOrEffects;
|
||||
nsRect r = ComputeOutlineAndEffectsRect(this, &anyOutlineOrEffects,
|
||||
aOldOverflowRect, PR_FALSE);
|
||||
if (anyOutlineOrEffects) {
|
||||
r.UnionRect(aOldOverflowRect, r);
|
||||
Invalidate(r);
|
||||
return;
|
||||
@ -5261,16 +5354,6 @@ nsFrame::GetAccessible(nsIAccessible** aAccessible)
|
||||
}
|
||||
#endif
|
||||
|
||||
// Destructor function for the overflow area property
|
||||
static void
|
||||
DestroyRectFunc(void* aFrame,
|
||||
nsIAtom* aPropertyName,
|
||||
void* aPropertyValue,
|
||||
void* aDtorData)
|
||||
{
|
||||
delete static_cast<nsRect*>(aPropertyValue);
|
||||
}
|
||||
|
||||
/** Create or retrieve the previously stored overflow area, if the frame does
|
||||
* not overflow and no creation is required return nsnull.
|
||||
* @param aCreateIfNecessary create a new nsRect for the overflow area
|
||||
@ -5314,29 +5397,11 @@ nsRect
|
||||
nsIFrame::GetAdditionalOverflow(const nsRect& aOverflowArea,
|
||||
const nsSize& aNewSize)
|
||||
{
|
||||
nsRect overflowRect;
|
||||
|
||||
// outline
|
||||
PRBool hasOutline;
|
||||
overflowRect = ComputeOutlineRect(this, &hasOutline, aOverflowArea);
|
||||
|
||||
// box-shadow
|
||||
nsCSSShadowArray* boxShadows = GetStyleBorder()->mBoxShadow;
|
||||
if (boxShadows) {
|
||||
for (PRUint32 i = 0; i < boxShadows->Length(); ++i) {
|
||||
nsRect tmpRect(nsPoint(0, 0), aNewSize);
|
||||
nsCSSShadowItem* shadow = boxShadows->ShadowAt(i);
|
||||
nscoord xOffset = shadow->mXOffset.GetCoordValue();
|
||||
nscoord yOffset = shadow->mYOffset.GetCoordValue();
|
||||
nscoord outsetRadius = shadow->mRadius.GetCoordValue() +
|
||||
shadow->mSpread.GetCoordValue();
|
||||
|
||||
tmpRect.MoveBy(nsPoint(xOffset, yOffset));
|
||||
tmpRect.Inflate(outsetRadius, outsetRadius);
|
||||
|
||||
overflowRect.UnionRect(overflowRect, tmpRect);
|
||||
}
|
||||
}
|
||||
PRBool hasOutlineOrEffects;
|
||||
nsRect overflowRect =
|
||||
ComputeOutlineAndEffectsRect(this, &hasOutlineOrEffects,
|
||||
aOverflowArea, PR_TRUE);
|
||||
|
||||
// Absolute position clipping
|
||||
PRBool hasAbsPosClip;
|
||||
@ -5437,18 +5502,25 @@ nsFrame::GetParentStyleContextFrame(nsPresContext* aPresContext,
|
||||
* as aSpecialSibling. This is needed because the split inline's
|
||||
* style context is the parent of the anonymous block's srtyle context.
|
||||
*
|
||||
* If aFrame is not the anonymous block, aSpecialSibling is not
|
||||
* touched.
|
||||
* If aFrame is not the anonymous block, aSpecialSibling is set to null.
|
||||
*/
|
||||
static nsresult
|
||||
GetIBSpecialSibling(nsPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
nsIFrame** aSpecialSibling)
|
||||
GetIBSpecialSiblingForAnonymousBlock(nsPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
nsIFrame** aSpecialSibling)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "Must have a non-null frame!");
|
||||
NS_ASSERTION(aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL,
|
||||
"GetIBSpecialSibling should not be called on a non-special frame");
|
||||
|
||||
|
||||
nsIAtom* type = aFrame->GetStyleContext()->GetPseudoType();
|
||||
if (type != nsCSSAnonBoxes::mozAnonymousBlock &&
|
||||
type != nsCSSAnonBoxes::mozAnonymousPositionedBlock) {
|
||||
// it's not the anonymous block
|
||||
*aSpecialSibling = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Find the first-in-flow of the frame. (Ugh. This ends up
|
||||
// being O(N^2) when it is called O(N) times.)
|
||||
aFrame = aFrame->GetFirstInFlow();
|
||||
@ -5532,10 +5604,11 @@ nsFrame::CorrectStyleParentFrame(nsIFrame* aProspectiveParent,
|
||||
if (parent->GetStateBits() & NS_FRAME_IS_SPECIAL) {
|
||||
nsIFrame* sibling;
|
||||
nsresult rv =
|
||||
GetIBSpecialSibling(parent->PresContext(), parent, &sibling);
|
||||
GetIBSpecialSiblingForAnonymousBlock(parent->PresContext(), parent, &sibling);
|
||||
if (NS_FAILED(rv)) {
|
||||
// If GetIBSpecialSibling fails, then what? we used to return what is
|
||||
// now |aProspectiveParent|, but maybe |parent| would make more sense?
|
||||
// If GetIBSpecialSiblingForAnonymousBlock fails, then what?
|
||||
// we used to return what is now |aProspectiveParent|, but maybe
|
||||
// |parent| would make more sense?
|
||||
NS_NOTREACHED("Shouldn't get here");
|
||||
return aProspectiveParent;
|
||||
}
|
||||
@ -5594,10 +5667,11 @@ nsFrame::DoGetParentStyleContextFrame(nsPresContext* aPresContext,
|
||||
* If this frame is the anonymous block created when an inline
|
||||
* with a block inside it got split, then the parent style context
|
||||
* is on the first of the three special frames. We can get to it
|
||||
* using GetIBSpecialSibling
|
||||
* using GetIBSpecialSiblingForAnonymousBlock
|
||||
*/
|
||||
if (mState & NS_FRAME_IS_SPECIAL) {
|
||||
nsresult rv = GetIBSpecialSibling(aPresContext, this, aProviderFrame);
|
||||
nsresult rv =
|
||||
GetIBSpecialSiblingForAnonymousBlock(aPresContext, this, aProviderFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_NOTREACHED("Shouldn't get here");
|
||||
*aProviderFrame = nsnull;
|
||||
|
@ -84,6 +84,9 @@ include pagination/reftest.list
|
||||
# svg/
|
||||
include svg/reftest.list
|
||||
|
||||
# svg-integration/
|
||||
include svg-integration/reftest.list
|
||||
|
||||
# table-background/
|
||||
include table-background/reftest.list
|
||||
|
||||
|
8
layout/reftests/svg-integration/clipPath-html-01-ref.svg
Normal file
8
layout/reftests/svg-integration/clipPath-html-01-ref.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect x="250" y="0" width="250" height="500" fill="lime"/>
|
||||
</svg>
|
After Width: | Height: | Size: 288 B |
17
layout/reftests/svg-integration/clipPath-html-01.xhtml
Normal file
17
layout/reftests/svg-integration/clipPath-html-01.xhtml
Normal file
@ -0,0 +1,17 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<body style="margin:0">
|
||||
<div style="position:absolute; top:0; left:0; clip-path: url(#c1); width:500px; height:500px; background:lime;"></div>
|
||||
|
||||
<svg:svg height="0">
|
||||
<svg:clipPath id="c1" clipPathUnits="objectBoundingBox">
|
||||
<svg:rect x="0.5" y="0" width="0.5" height="1"/>
|
||||
</svg:clipPath>
|
||||
</svg:svg>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/svg-integration/clipPath-html-02-ref.svg
Normal file
9
layout/reftests/svg-integration/clipPath-html-02-ref.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect x="0" y="0" width="500" height="200" fill="lime"/>
|
||||
<rect x="0" y="200" width="500" height="120" fill="blue"/>
|
||||
</svg>
|
After Width: | Height: | Size: 348 B |
20
layout/reftests/svg-integration/clipPath-html-02.xhtml
Normal file
20
layout/reftests/svg-integration/clipPath-html-02.xhtml
Normal file
@ -0,0 +1,20 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<body style="margin:0">
|
||||
<div style="clip-path: url(#c1); width:500px; height:200px; background:lime;">
|
||||
<div style="height:200px;"/>
|
||||
<div style="height:200px; background:blue;"/>
|
||||
</div>
|
||||
|
||||
<svg:svg height="0">
|
||||
<svg:clipPath id="c1" clipPathUnits="objectBoundingBox">
|
||||
<svg:rect x="0" y="0" width="1" height="0.8"/>
|
||||
</svg:clipPath>
|
||||
</svg:svg>
|
||||
</body>
|
||||
</html>
|
10
layout/reftests/svg-integration/clipPath-html-03-ref.svg
Normal file
10
layout/reftests/svg-integration/clipPath-html-03-ref.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect x="0" y="0" width="100" height="150" fill="lime"/>
|
||||
<rect x="100" y="0" width="100" height="200" fill="lime"/>
|
||||
<rect x="100" y="200" width="100" height="100" fill="blue"/>
|
||||
</svg>
|
After Width: | Height: | Size: 411 B |
21
layout/reftests/svg-integration/clipPath-html-03.xhtml
Normal file
21
layout/reftests/svg-integration/clipPath-html-03.xhtml
Normal file
@ -0,0 +1,21 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<body style="margin:0">
|
||||
<div style="clip-path: url(#c1); width:500px; height:200px; background:lime;">
|
||||
<div style="height:200px;"/>
|
||||
<div style="height:200px; background:blue;"/>
|
||||
</div>
|
||||
|
||||
<svg:svg height="0">
|
||||
<svg:clipPath id="c1" clipPathUnits="userSpaceOnuse">
|
||||
<svg:rect x="0" y="0" width="100" height="150"/>
|
||||
<svg:rect x="100" y="0" width="100" height="300"/>
|
||||
</svg:clipPath>
|
||||
</svg:svg>
|
||||
</body>
|
||||
</html>
|
14
layout/reftests/svg-integration/clipPath-html-04-ref.xhtml
Normal file
14
layout/reftests/svg-integration/clipPath-html-04-ref.xhtml
Normal file
@ -0,0 +1,14 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<body style="margin:0; line-height:100px;">
|
||||
<span style="display:inline-block; width:200px;"
|
||||
/><span style="background:lime;"><span style="display:inline-block; width:50px;"/></span><br/>
|
||||
<span style="display:inline-block; width:50px;"
|
||||
/><span style="background:lime;"><span style="display:inline-block; width:50px;"/></span>
|
||||
</body>
|
||||
</html>
|
24
layout/reftests/svg-integration/clipPath-html-04.xhtml
Normal file
24
layout/reftests/svg-integration/clipPath-html-04.xhtml
Normal file
@ -0,0 +1,24 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<head>
|
||||
<style>
|
||||
.unit { display:inline-block; width:100px; height:1px; }
|
||||
</style>
|
||||
</head>
|
||||
<body style="margin:0; width:350px; line-height:100px;">
|
||||
<span class="unit"/><span class="unit"
|
||||
/><span style="clip-path:url(#c1); background:lime;"><span class="unit"/><span class="unit"
|
||||
/></span>
|
||||
|
||||
<svg:svg height="0">
|
||||
<svg:clipPath id="c1" clipPathUnits="userSpaceOnuse">
|
||||
<svg:rect x="50" y="0" width="200" height="200"/>
|
||||
</svg:clipPath>
|
||||
</svg:svg>
|
||||
</body>
|
||||
</html>
|
14
layout/reftests/svg-integration/clipPath-html-05-ref.xhtml
Normal file
14
layout/reftests/svg-integration/clipPath-html-05-ref.xhtml
Normal file
@ -0,0 +1,14 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<body style="margin:0; line-height:100px;">
|
||||
<span style="display:inline-block; width:200px;"
|
||||
/><span style="background:lime;"><span style="display:inline-block; width:70px;"/></span><br/>
|
||||
<span style="display:inline-block; width:30px;"
|
||||
/><span style="background:lime;"><span style="display:inline-block; width:70px;"/></span>
|
||||
</body>
|
||||
</html>
|
24
layout/reftests/svg-integration/clipPath-html-05.xhtml
Normal file
24
layout/reftests/svg-integration/clipPath-html-05.xhtml
Normal file
@ -0,0 +1,24 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<head>
|
||||
<style>
|
||||
.unit { display:inline-block; width:100px; height:1px; }
|
||||
</style>
|
||||
</head>
|
||||
<body style="margin:0; width:350px; line-height:100px;">
|
||||
<span class="unit"/><span class="unit"
|
||||
/><span style="clip-path:url(#c1); background:lime;"><span class="unit"/><span class="unit"
|
||||
/></span>
|
||||
|
||||
<svg:svg height="0">
|
||||
<svg:clipPath id="c1" clipPathUnits="objectBoundingBox">
|
||||
<svg:rect x="0.1" y="0" width="0.8" height="1"/>
|
||||
</svg:clipPath>
|
||||
</svg:svg>
|
||||
</body>
|
||||
</html>
|
20
layout/reftests/svg-integration/clipPath-html-06-ref.xhtml
Normal file
20
layout/reftests/svg-integration/clipPath-html-06-ref.xhtml
Normal file
@ -0,0 +1,20 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<head>
|
||||
<style>
|
||||
.unit { display:inline-block; width:50px; height:10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body style="margin:0">
|
||||
<span>
|
||||
<span class="unit"></span>
|
||||
<div style="height:200px;"/>
|
||||
<span class="unit" style="background:lime;"></span>
|
||||
</span>
|
||||
</body>
|
||||
</html>
|
26
layout/reftests/svg-integration/clipPath-html-06.xhtml
Normal file
26
layout/reftests/svg-integration/clipPath-html-06.xhtml
Normal file
@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<head>
|
||||
<style>
|
||||
.unit { display:inline-block; width:100px; height:10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body style="margin:0">
|
||||
<span style="clip-path: url(#c1);">
|
||||
<span class="unit" style="background:lime;"></span>
|
||||
<div style="height:200px; width:100px;"/>
|
||||
<span class="unit" style="background:lime;"></span>
|
||||
</span>
|
||||
|
||||
<svg:svg height="0">
|
||||
<svg:clipPath id="c1" clipPathUnits="objectBoundingBox">
|
||||
<svg:rect x="0" y="0.5" width="0.5" height="0.5"/>
|
||||
</svg:clipPath>
|
||||
</svg:svg>
|
||||
</body>
|
||||
</html>
|
14
layout/reftests/svg-integration/filter-html-01-ref.svg
Normal file
14
layout/reftests/svg-integration/filter-html-01-ref.svg
Normal file
@ -0,0 +1,14 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<filter id="f1">
|
||||
<feFlood flood-color="black" result="black"/>
|
||||
<feGaussianBlur in="SourceAlpha" stdDeviation="10"/>
|
||||
<feComposite in="black" operator="in"/>
|
||||
<feComposite in="SourceGraphic"/>
|
||||
</filter>
|
||||
<rect x="50" y="50" width="200" height="200" fill="lime" filter="url(#f1)"/>
|
||||
</svg>
|
After Width: | Height: | Size: 527 B |
20
layout/reftests/svg-integration/filter-html-01.xhtml
Normal file
20
layout/reftests/svg-integration/filter-html-01.xhtml
Normal file
@ -0,0 +1,20 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<body style="margin:0">
|
||||
<div style="background:lime; width:200px; height:200px; margin:50px; filter:url(#f1)"/>
|
||||
|
||||
<svg:svg height="0">
|
||||
<svg:filter id="f1">
|
||||
<svg:feFlood flood-color="black" result="black"/>
|
||||
<svg:feGaussianBlur in="SourceAlpha" stdDeviation="10"/>
|
||||
<svg:feComposite in="black" operator="in"/>
|
||||
<svg:feComposite in="SourceGraphic"/>
|
||||
</svg:filter>
|
||||
</svg:svg>
|
||||
</body>
|
||||
</html>
|
13
layout/reftests/svg-integration/mask-html-01-ref.svg
Normal file
13
layout/reftests/svg-integration/mask-html-01-ref.svg
Normal file
@ -0,0 +1,13 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<linearGradient id="g" gradientUnits="objectBoundingBox" x2="0" y2="1">
|
||||
<stop stop-color="lime" offset="0"/>
|
||||
<stop stop-color="lime" stop-opacity="0" offset="1"/>
|
||||
</linearGradient>
|
||||
<circle cx="125" cy="125" r="125" id="circle" fill="lime"/>
|
||||
<rect x="250" y="0" width="250" height="500" fill="url(#g)"/>
|
||||
</svg>
|
After Width: | Height: | Size: 547 B |
22
layout/reftests/svg-integration/mask-html-01.xhtml
Normal file
22
layout/reftests/svg-integration/mask-html-01.xhtml
Normal file
@ -0,0 +1,22 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<body style="margin:0">
|
||||
<div style="mask: url(#m1); width:500px; height:500px; background:lime;"></div>
|
||||
|
||||
<svg:svg height="0">
|
||||
<svg:mask id="m1" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox">
|
||||
<svg:linearGradient id="g" gradientUnits="objectBoundingBox" x2="0" y2="1">
|
||||
<svg:stop stop-color="white" offset="0"/>
|
||||
<svg:stop stop-color="white" stop-opacity="0" offset="1"/>
|
||||
</svg:linearGradient>
|
||||
<svg:circle cx="0.25" cy="0.25" r="0.25" id="circle" fill="white"/>
|
||||
<svg:rect x="0.5" y="0" width="0.5" height="1" fill="url(#g)"/>
|
||||
</svg:mask>
|
||||
</svg:svg>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/svg-integration/reftest.list
Normal file
9
layout/reftests/svg-integration/reftest.list
Normal file
@ -0,0 +1,9 @@
|
||||
== clipPath-html-01.xhtml clipPath-html-01-ref.svg
|
||||
== clipPath-html-02.xhtml clipPath-html-02-ref.svg
|
||||
== clipPath-html-03.xhtml clipPath-html-03-ref.svg
|
||||
== clipPath-html-04.xhtml clipPath-html-04-ref.xhtml
|
||||
== clipPath-html-05.xhtml clipPath-html-05-ref.xhtml
|
||||
== clipPath-html-06.xhtml clipPath-html-06-ref.xhtml
|
||||
== filter-html-01.xhtml filter-html-01-ref.svg
|
||||
== mask-html-01.xhtml mask-html-01-ref.svg
|
||||
|
@ -128,6 +128,9 @@
|
||||
/* we currently inherit from the inline that is split */
|
||||
outline: inherit;
|
||||
-moz-outline-offset: inherit;
|
||||
clip-path: inherit;
|
||||
filter: inherit;
|
||||
mask: inherit;
|
||||
}
|
||||
|
||||
*|*::-moz-xul-anonymous-block {
|
||||
|
@ -80,6 +80,7 @@ CPPSRCS = \
|
||||
nsSVGGradientFrame.cpp \
|
||||
nsSVGImageFrame.cpp \
|
||||
nsSVGInnerSVGFrame.cpp \
|
||||
nsSVGIntegrationUtils.cpp \
|
||||
nsSVGLeafFrame.cpp \
|
||||
nsSVGMarkerFrame.cpp \
|
||||
nsSVGMaskFrame.cpp \
|
||||
@ -103,6 +104,7 @@ include $(topsrcdir)/config/config.mk
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
EXPORTS = \
|
||||
nsSVGIntegrationUtils.h \
|
||||
nsSVGUtils.h \
|
||||
nsSVGFilterInstance.h \
|
||||
nsSVGForeignObjectFrame.h \
|
||||
|
@ -51,8 +51,8 @@ class nsIDOMSVGMatrix;
|
||||
class nsSVGRenderState;
|
||||
|
||||
#define NS_ISVGCHILDFRAME_IID \
|
||||
{ 0xe4ecddbf, 0xde7c, 0x4cd9, \
|
||||
{ 0x92, 0x4a, 0xfa, 0x81, 0xba, 0x83, 0x26, 0x69 } }
|
||||
{ 0x8b80b2a0, 0x2e1f, 0x4775, \
|
||||
{ 0xab, 0x47, 0xbe, 0xeb, 0x4b, 0x81, 0x63, 0x6d } }
|
||||
|
||||
class nsISVGChildFrame : public nsISupports {
|
||||
public:
|
||||
@ -98,6 +98,7 @@ public:
|
||||
// Set whether we should stop multiplying matrices when building up
|
||||
// the current transformation matrix at this frame.
|
||||
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate)=0;
|
||||
virtual PRBool GetMatrixPropagation()=0;
|
||||
|
||||
// Set the current transformation matrix to a particular matrix.
|
||||
// Value is only used if matrix propagation is prevented
|
||||
|
@ -61,7 +61,7 @@ NS_NewSVGClipPathFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsStyleCo
|
||||
|
||||
nsresult
|
||||
nsSVGClipPathFrame::ClipPaint(nsSVGRenderState* aContext,
|
||||
nsISVGChildFrame* aParent,
|
||||
nsIFrame* aParent,
|
||||
nsIDOMSVGMatrix *aMatrix)
|
||||
{
|
||||
// If the flag is set when we get here, it means this clipPath frame
|
||||
@ -103,7 +103,7 @@ nsSVGClipPathFrame::ClipPaint(nsSVGRenderState* aContext,
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSVGClipPathFrame::ClipHitTest(nsISVGChildFrame* aParent,
|
||||
nsSVGClipPathFrame::ClipHitTest(nsIFrame* aParent,
|
||||
nsIDOMSVGMatrix *aMatrix,
|
||||
const nsPoint &aPoint)
|
||||
{
|
||||
|
@ -54,10 +54,10 @@ protected:
|
||||
public:
|
||||
// nsSVGClipPathFrame methods:
|
||||
nsresult ClipPaint(nsSVGRenderState* aContext,
|
||||
nsISVGChildFrame* aParent,
|
||||
nsIFrame* aParent,
|
||||
nsIDOMSVGMatrix *aMatrix);
|
||||
|
||||
PRBool ClipHitTest(nsISVGChildFrame* aParent,
|
||||
PRBool ClipHitTest(nsIFrame* aParent,
|
||||
nsIDOMSVGMatrix *aMatrix,
|
||||
const nsPoint &aPoint);
|
||||
|
||||
@ -100,7 +100,7 @@ public:
|
||||
nsSVGClipPathFrame *mFrame;
|
||||
};
|
||||
|
||||
nsISVGChildFrame *mClipParent;
|
||||
nsIFrame *mClipParent;
|
||||
nsCOMPtr<nsIDOMSVGMatrix> mClipParentMatrix;
|
||||
|
||||
// nsSVGContainerFrame methods:
|
||||
|
@ -88,7 +88,7 @@ nsSVGContainerFrame::Init(nsIContent* aContent,
|
||||
nsIFrame* aParent,
|
||||
nsIFrame* aPrevInFlow)
|
||||
{
|
||||
AddStateBits(NS_STATE_SVG_NONDISPLAY_CHILD);
|
||||
AddStateBits(NS_STATE_SVG_NONDISPLAY_CHILD | NS_STATE_SVG_PROPAGATE_TRANSFORM);
|
||||
nsresult rv = nsSVGContainerFrameBase::Init(aContent, aParent, aPrevInFlow);
|
||||
return rv;
|
||||
}
|
||||
@ -98,6 +98,7 @@ nsSVGDisplayContainerFrame::Init(nsIContent* aContent,
|
||||
nsIFrame* aParent,
|
||||
nsIFrame* aPrevInFlow)
|
||||
{
|
||||
AddStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
|
||||
if (!(GetStateBits() & NS_STATE_IS_OUTER_SVG)) {
|
||||
AddStateBits(aParent->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD);
|
||||
}
|
||||
@ -277,3 +278,20 @@ nsSVGDisplayContainerFrame::GetBBox(nsIDOMSVGRect **_retval)
|
||||
{
|
||||
return nsSVGUtils::GetBBox(&mFrames, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGDisplayContainerFrame::SetMatrixPropagation(PRBool aPropagate)
|
||||
{
|
||||
if (aPropagate) {
|
||||
AddStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
|
||||
} else {
|
||||
RemoveStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSVGDisplayContainerFrame::GetMatrixPropagation()
|
||||
{
|
||||
return (GetStateBits() & NS_STATE_SVG_PROPAGATE_TRANSFORM) != 0;
|
||||
}
|
||||
|
@ -109,7 +109,8 @@ public:
|
||||
virtual void NotifySVGChanged(PRUint32 aFlags);
|
||||
NS_IMETHOD NotifyRedrawSuspended();
|
||||
NS_IMETHOD NotifyRedrawUnsuspended();
|
||||
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate) { return NS_ERROR_FAILURE; }
|
||||
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
|
||||
virtual PRBool GetMatrixPropagation();
|
||||
NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM) { return NS_ERROR_FAILURE; }
|
||||
virtual already_AddRefed<nsIDOMSVGMatrix> GetOverrideCTM() { return nsnull; }
|
||||
NS_IMETHOD GetBBox(nsIDOMSVGRect **_retval);
|
||||
|
@ -127,7 +127,7 @@ nsSVGFilterProperty::UpdateRect()
|
||||
{
|
||||
nsSVGFilterFrame *filter = GetFilterFrame(nsnull);
|
||||
if (filter) {
|
||||
mFilterRect = filter->GetInvalidationRegion(mFrame, mFrame->GetRect());
|
||||
mFilterRect = filter->GetFilterBBox(mFrame, nsnull);
|
||||
} else {
|
||||
mFilterRect = nsRect();
|
||||
}
|
||||
|
@ -42,11 +42,13 @@
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsSVGUtils.h"
|
||||
#include "nsSVGFilterElement.h"
|
||||
#include "nsSVGFilterInstance.h"
|
||||
#include "nsSVGFilters.h"
|
||||
#include "gfxASurface.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "nsSVGFilterPaintCallback.h"
|
||||
#include "nsSVGRect.h"
|
||||
#include "nsSVGFilterInstance.h"
|
||||
|
||||
nsIFrame*
|
||||
NS_NewSVGFilterFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsStyleContext* aContext)
|
||||
@ -78,63 +80,68 @@ MapDeviceRectToFilterSpace(const gfxMatrix& aMatrix,
|
||||
return rect;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGFilterFrame::CreateInstance(nsISVGChildFrame *aTarget,
|
||||
const nsIntRect *aDirtyOutputRect,
|
||||
const nsIntRect *aDirtyInputRect,
|
||||
nsSVGFilterInstance **aInstance)
|
||||
class NS_STACK_CLASS nsAutoFilterInstance {
|
||||
public:
|
||||
nsAutoFilterInstance(nsIFrame *aTarget,
|
||||
nsSVGFilterFrame *aFilterFrame,
|
||||
nsSVGFilterPaintCallback *aPaint,
|
||||
const nsIntRect *aDirtyOutputRect,
|
||||
const nsIntRect *aDirtyInputRect,
|
||||
const nsIntRect *aOverrideSourceBBox);
|
||||
~nsAutoFilterInstance();
|
||||
|
||||
// If this returns null, then draw nothing. Either the filter draws
|
||||
// nothing or it is "in error".
|
||||
nsSVGFilterInstance* get() { return mInstance; }
|
||||
|
||||
private:
|
||||
nsAutoPtr<nsSVGFilterInstance> mInstance;
|
||||
// Store mTarget separately even though mInstance has it, because if
|
||||
// mInstance creation fails we still need to be able to clean up
|
||||
nsISVGChildFrame* mTarget;
|
||||
};
|
||||
|
||||
nsAutoFilterInstance::nsAutoFilterInstance(nsIFrame *aTarget,
|
||||
nsSVGFilterFrame *aFilterFrame,
|
||||
nsSVGFilterPaintCallback *aPaint,
|
||||
const nsIntRect *aDirtyOutputRect,
|
||||
const nsIntRect *aDirtyInputRect,
|
||||
const nsIntRect *aOverrideSourceBBox)
|
||||
{
|
||||
*aInstance = nsnull;
|
||||
nsCOMPtr<nsIDOMSVGMatrix> ctm = nsSVGUtils::GetCanvasTM(aTarget);
|
||||
|
||||
nsIFrame *frame;
|
||||
CallQueryInterface(aTarget, &frame);
|
||||
CallQueryInterface(aTarget, &mTarget);
|
||||
if (mTarget) {
|
||||
mTarget->SetMatrixPropagation(PR_FALSE);
|
||||
mTarget->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
|
||||
nsISVGChildFrame::TRANSFORM_CHANGED);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMSVGMatrix> ctm = nsSVGUtils::GetCanvasTM(frame);
|
||||
|
||||
nsSVGElement *target = static_cast<nsSVGElement*>(frame->GetContent());
|
||||
|
||||
aTarget->SetMatrixPropagation(PR_FALSE);
|
||||
aTarget->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
|
||||
nsISVGChildFrame::TRANSFORM_CHANGED);
|
||||
|
||||
nsSVGFilterElement *filter = static_cast<nsSVGFilterElement*>(mContent);
|
||||
|
||||
float x, y, width, height;
|
||||
nsCOMPtr<nsIDOMSVGRect> bbox;
|
||||
aTarget->GetBBox(getter_AddRefs(bbox));
|
||||
|
||||
nsSVGLength2 *tmpX, *tmpY, *tmpWidth, *tmpHeight;
|
||||
tmpX = &filter->mLengthAttributes[nsSVGFilterElement::X];
|
||||
tmpY = &filter->mLengthAttributes[nsSVGFilterElement::Y];
|
||||
tmpWidth = &filter->mLengthAttributes[nsSVGFilterElement::WIDTH];
|
||||
tmpHeight = &filter->mLengthAttributes[nsSVGFilterElement::HEIGHT];
|
||||
nsSVGFilterElement *filter = static_cast<nsSVGFilterElement*>(
|
||||
aFilterFrame->GetContent());
|
||||
|
||||
PRUint16 units =
|
||||
filter->mEnumAttributes[nsSVGFilterElement::FILTERUNITS].GetAnimValue();
|
||||
|
||||
// Compute filter effects region as per spec
|
||||
if (units == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
|
||||
if (!bbox)
|
||||
return NS_OK;
|
||||
|
||||
bbox->GetX(&x);
|
||||
x += nsSVGUtils::ObjectSpace(bbox, tmpX);
|
||||
bbox->GetY(&y);
|
||||
y += nsSVGUtils::ObjectSpace(bbox, tmpY);
|
||||
width = nsSVGUtils::ObjectSpace(bbox, tmpWidth);
|
||||
height = nsSVGUtils::ObjectSpace(bbox, tmpHeight);
|
||||
nsCOMPtr<nsIDOMSVGRect> bbox;
|
||||
if (aOverrideSourceBBox) {
|
||||
NS_NewSVGRect(getter_AddRefs(bbox),
|
||||
aOverrideSourceBBox->x, aOverrideSourceBBox->y,
|
||||
aOverrideSourceBBox->width, aOverrideSourceBBox->height);
|
||||
} else {
|
||||
x = nsSVGUtils::UserSpace(target, tmpX);
|
||||
y = nsSVGUtils::UserSpace(target, tmpY);
|
||||
width = nsSVGUtils::UserSpace(target, tmpWidth);
|
||||
height = nsSVGUtils::UserSpace(target, tmpHeight);
|
||||
bbox = nsSVGUtils::GetBBox(aTarget);
|
||||
}
|
||||
|
||||
if (!bbox && units == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
|
||||
return;
|
||||
|
||||
gfxRect filterArea = nsSVGUtils::GetRelativeRect(units,
|
||||
&filter->mLengthAttributes[nsSVGFilterElement::X], bbox, aTarget);
|
||||
filterArea.RoundOut();
|
||||
|
||||
PRBool resultOverflows;
|
||||
gfxIntSize filterRes;
|
||||
|
||||
// Compute size of filter buffer
|
||||
if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::filterRes)) {
|
||||
if (filter->HasAttr(kNameSpaceID_None, nsGkAtoms::filterRes)) {
|
||||
PRInt32 filterResX, filterResY;
|
||||
filter->GetAnimatedIntegerValues(&filterResX, &filterResY, nsnull);
|
||||
|
||||
@ -148,26 +155,21 @@ nsSVGFilterFrame::CreateInstance(nsISVGChildFrame *aTarget,
|
||||
#endif
|
||||
|
||||
filterRes =
|
||||
nsSVGUtils::ConvertToSurfaceSize(gfxSize(width, height) * scale,
|
||||
nsSVGUtils::ConvertToSurfaceSize(filterArea.size * scale,
|
||||
&resultOverflows);
|
||||
}
|
||||
|
||||
// 0 disables rendering, < 0 is error
|
||||
if (filterRes.width <= 0 || filterRes.height <= 0)
|
||||
return NS_OK;
|
||||
|
||||
#ifdef DEBUG_tor
|
||||
fprintf(stderr, "filter bbox: %f,%f %fx%f\n", x, y, width, height);
|
||||
fprintf(stderr, "filterRes: %u %u\n", filterRes.width, filterRes.height);
|
||||
#endif
|
||||
return;
|
||||
|
||||
// 'fini' is the matrix we will finally use to transform filter space
|
||||
// to surface space for drawing
|
||||
nsCOMPtr<nsIDOMSVGMatrix> scale, fini;
|
||||
NS_NewSVGMatrix(getter_AddRefs(scale),
|
||||
width / filterRes.width, 0.0f,
|
||||
0.0f, height / filterRes.height,
|
||||
x, y);
|
||||
filterArea.Width() / filterRes.width, 0.0f,
|
||||
0.0f, filterArea.Height() / filterRes.height,
|
||||
filterArea.X(), filterArea.Y());
|
||||
ctm->Multiply(scale, getter_AddRefs(fini));
|
||||
|
||||
gfxMatrix finiM = nsSVGUtils::ConvertSVGMatrixToThebes(fini);
|
||||
@ -182,101 +184,122 @@ nsSVGFilterFrame::CreateInstance(nsISVGChildFrame *aTarget,
|
||||
// Setup instance data
|
||||
PRUint16 primitiveUnits =
|
||||
filter->mEnumAttributes[nsSVGFilterElement::PRIMITIVEUNITS].GetAnimValue();
|
||||
*aInstance = new nsSVGFilterInstance(aTarget, mContent, bbox,
|
||||
gfxRect(x, y, width, height),
|
||||
nsIntSize(filterRes.width, filterRes.height),
|
||||
fini,
|
||||
dirtyOutputRect, dirtyInputRect,
|
||||
primitiveUnits);
|
||||
return *aInstance ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
mInstance = new nsSVGFilterInstance(aTarget, aPaint, filter, bbox, filterArea,
|
||||
nsIntSize(filterRes.width, filterRes.height),
|
||||
fini,
|
||||
dirtyOutputRect, dirtyInputRect,
|
||||
primitiveUnits);
|
||||
}
|
||||
|
||||
static void
|
||||
RestoreTargetState(nsISVGChildFrame *aTarget)
|
||||
nsAutoFilterInstance::~nsAutoFilterInstance()
|
||||
{
|
||||
aTarget->SetOverrideCTM(nsnull);
|
||||
aTarget->SetMatrixPropagation(PR_TRUE);
|
||||
aTarget->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
|
||||
if (!mTarget)
|
||||
return;
|
||||
|
||||
mTarget->SetOverrideCTM(nsnull);
|
||||
mTarget->SetMatrixPropagation(PR_TRUE);
|
||||
mTarget->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
|
||||
nsISVGChildFrame::TRANSFORM_CHANGED);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGFilterFrame::FilterPaint(nsSVGRenderState *aContext,
|
||||
nsISVGChildFrame *aTarget,
|
||||
nsIFrame *aTarget,
|
||||
nsSVGFilterPaintCallback *aPaintCallback,
|
||||
const nsIntRect *aDirtyRect)
|
||||
{
|
||||
nsAutoPtr<nsSVGFilterInstance> instance;
|
||||
nsresult rv = CreateInstance(aTarget, aDirtyRect, nsnull, getter_Transfers(instance));
|
||||
nsAutoFilterInstance instance(aTarget, this, aPaintCallback,
|
||||
aDirtyRect, nsnull, nsnull);
|
||||
if (!instance.get())
|
||||
return NS_OK;
|
||||
|
||||
if (NS_SUCCEEDED(rv) && instance) {
|
||||
// Transformation from user space to filter space
|
||||
nsCOMPtr<nsIDOMSVGMatrix> filterTransform =
|
||||
instance->GetUserSpaceToFilterSpaceTransform();
|
||||
aTarget->SetOverrideCTM(filterTransform);
|
||||
aTarget->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
|
||||
nsISVGChildFrame::TRANSFORM_CHANGED);
|
||||
|
||||
nsRefPtr<gfxASurface> result;
|
||||
rv = instance->Render(getter_AddRefs(result));
|
||||
if (NS_SUCCEEDED(rv) && result) {
|
||||
nsSVGUtils::CompositeSurfaceMatrix(aContext->GetGfxContext(),
|
||||
result, instance->GetFilterSpaceToDeviceSpaceTransform(), 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
RestoreTargetState(aTarget);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
aTarget->PaintSVG(aContext, nsnull);
|
||||
nsRefPtr<gfxASurface> result;
|
||||
nsresult rv = instance.get()->Render(getter_AddRefs(result));
|
||||
if (NS_SUCCEEDED(rv) && result) {
|
||||
nsSVGUtils::CompositeSurfaceMatrix(aContext->GetGfxContext(),
|
||||
result, instance.get()->GetFilterSpaceToDeviceSpaceTransform(), 1.0);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsSVGFilterFrame::GetInvalidationRegion(nsIFrame *aTarget, const nsRect& aRect)
|
||||
static nsresult
|
||||
TransformFilterSpaceToDeviceSpace(nsSVGFilterInstance *aInstance, nsIntRect *aRect)
|
||||
{
|
||||
nsISVGChildFrame *svg;
|
||||
CallQueryInterface(aTarget, &svg);
|
||||
|
||||
nscoord p2a = aTarget->PresContext()->AppUnitsPerDevPixel();
|
||||
nsRect result = aRect;
|
||||
nsIntRect rect = aRect;
|
||||
rect.ScaleRoundOut(1.0/p2a);
|
||||
|
||||
nsAutoPtr<nsSVGFilterInstance> instance;
|
||||
nsresult rv = CreateInstance(svg, nsnull, &rect, getter_Transfers(instance));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (!instance) {
|
||||
// The filter draws nothing, so nothing is dirty.
|
||||
result = nsRect();
|
||||
} else {
|
||||
// We've passed in the source's dirty area so the instance knows about it.
|
||||
// Now we can ask the instance to compute the area of the filter output
|
||||
// that's dirty.
|
||||
nsIntRect filterSpaceDirtyRect;
|
||||
rv = instance->ComputeOutputDirtyRect(&filterSpaceDirtyRect);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
gfxMatrix m = nsSVGUtils::ConvertSVGMatrixToThebes(
|
||||
instance->GetFilterSpaceToDeviceSpaceTransform());
|
||||
gfxRect r(filterSpaceDirtyRect.x, filterSpaceDirtyRect.y,
|
||||
filterSpaceDirtyRect.width, filterSpaceDirtyRect.height);
|
||||
r = m.TransformBounds(r);
|
||||
r.RoundOut();
|
||||
nsIntRect deviceRect;
|
||||
rv = nsSVGUtils::GfxRectToIntRect(r, &deviceRect);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
deviceRect.ScaleRoundOut(p2a);
|
||||
result = deviceRect;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RestoreTargetState(svg);
|
||||
|
||||
return result;
|
||||
gfxMatrix m = nsSVGUtils::ConvertSVGMatrixToThebes(
|
||||
aInstance->GetFilterSpaceToDeviceSpaceTransform());
|
||||
gfxRect r(aRect->x, aRect->y, aRect->width, aRect->height);
|
||||
r = m.TransformBounds(r);
|
||||
r.RoundOut();
|
||||
nsIntRect deviceRect;
|
||||
nsresult rv = nsSVGUtils::GfxRectToIntRect(r, &deviceRect);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
*aRect = deviceRect;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIntRect
|
||||
nsSVGFilterFrame::GetInvalidationBBox(nsIFrame *aTarget, const nsIntRect& aRect)
|
||||
{
|
||||
nsAutoFilterInstance instance(aTarget, this, nsnull, nsnull, &aRect, nsnull);
|
||||
if (!instance.get())
|
||||
return nsIntRect();
|
||||
|
||||
// We've passed in the source's dirty area so the instance knows about it.
|
||||
// Now we can ask the instance to compute the area of the filter output
|
||||
// that's dirty.
|
||||
nsIntRect dirtyRect;
|
||||
nsresult rv = instance.get()->ComputeOutputDirtyRect(&dirtyRect);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = TransformFilterSpaceToDeviceSpace(instance.get(), &dirtyRect);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
return dirtyRect;
|
||||
}
|
||||
|
||||
return nsIntRect();
|
||||
}
|
||||
|
||||
nsIntRect
|
||||
nsSVGFilterFrame::GetSourceForInvalidArea(nsIFrame *aTarget, const nsIntRect& aRect)
|
||||
{
|
||||
nsAutoFilterInstance instance(aTarget, this, nsnull, &aRect, nsnull, nsnull);
|
||||
if (!instance.get())
|
||||
return nsIntRect();
|
||||
|
||||
// Now we can ask the instance to compute the area of the source
|
||||
// that's needed.
|
||||
nsIntRect neededRect;
|
||||
nsresult rv = instance.get()->ComputeSourceNeededRect(&neededRect);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = TransformFilterSpaceToDeviceSpace(instance.get(), &neededRect);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
return neededRect;
|
||||
}
|
||||
|
||||
return nsIntRect();
|
||||
}
|
||||
|
||||
nsIntRect
|
||||
nsSVGFilterFrame::GetFilterBBox(nsIFrame *aTarget, const nsIntRect *aSourceBBox)
|
||||
{
|
||||
nsAutoFilterInstance instance(aTarget, this, nsnull, nsnull, nsnull, aSourceBBox);
|
||||
if (!instance.get())
|
||||
return nsIntRect();
|
||||
|
||||
// We've passed in the source's bounding box so the instance knows about
|
||||
// it. Now we can ask the instance to compute the bounding box of
|
||||
// the filter output.
|
||||
nsIntRect bbox;
|
||||
nsresult rv = instance.get()->ComputeOutputBBox(&bbox);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = TransformFilterSpaceToDeviceSpace(instance.get(), &bbox);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
return bbox;
|
||||
}
|
||||
|
||||
return nsIntRect();
|
||||
}
|
||||
|
||||
nsIAtom *
|
||||
nsSVGFilterFrame::GetType() const
|
||||
{
|
||||
|
@ -40,7 +40,8 @@
|
||||
#include "nsRect.h"
|
||||
#include "nsSVGContainerFrame.h"
|
||||
|
||||
class nsSVGFilterInstance;
|
||||
class nsSVGRenderState;
|
||||
class nsSVGFilterPaintCallback;
|
||||
|
||||
typedef nsSVGContainerFrame nsSVGFilterFrameBase;
|
||||
class nsSVGFilterFrame : public nsSVGFilterFrameBase
|
||||
@ -50,17 +51,33 @@ class nsSVGFilterFrame : public nsSVGFilterFrameBase
|
||||
protected:
|
||||
nsSVGFilterFrame(nsStyleContext* aContext) : nsSVGFilterFrameBase(aContext) {}
|
||||
|
||||
public:
|
||||
public:
|
||||
nsresult FilterPaint(nsSVGRenderState *aContext,
|
||||
nsISVGChildFrame *aTarget,
|
||||
nsIFrame *aTarget, nsSVGFilterPaintCallback *aPaintCallback,
|
||||
const nsIntRect* aDirtyRect);
|
||||
|
||||
// Returns invalidation region for filter (can be bigger than the
|
||||
// referencing geometry to filter region sizing) in app units
|
||||
// relative to the origin of the outer svg.
|
||||
// aRect is the area that would be invalidated. Normally you'd just pass
|
||||
// aTarget->GetRect() here.
|
||||
nsRect GetInvalidationRegion(nsIFrame *aTarget, const nsRect& aRect);
|
||||
/**
|
||||
* Returns the area that could change when the given rect of the source changes.
|
||||
* The rectangles are relative to the origin of the outer svg, if aTarget is SVG,
|
||||
* relative to aTarget itself otherwise, in device pixels.
|
||||
*/
|
||||
nsIntRect GetInvalidationBBox(nsIFrame *aTarget, const nsIntRect& aRect);
|
||||
|
||||
/**
|
||||
* Returns the area in device pixels that is needed from the source when
|
||||
* the given area needs to be repainted.
|
||||
* The rectangles are relative to the origin of the outer svg, if aTarget is SVG,
|
||||
* relative to aTarget itself otherwise, in device pixels.
|
||||
*/
|
||||
nsIntRect GetSourceForInvalidArea(nsIFrame *aTarget, const nsIntRect& aRect);
|
||||
|
||||
/**
|
||||
* Returns the bounding box of the post-filter area of aTarget.
|
||||
* The rectangles are relative to the origin of the outer svg, if aTarget is SVG,
|
||||
* relative to aTarget itself otherwise, in device pixels.
|
||||
* @param aSourceBBox overrides the normal bbox for the source, if non-null
|
||||
*/
|
||||
nsIntRect GetFilterBBox(nsIFrame *aTarget, const nsIntRect *aSourceBBox);
|
||||
|
||||
/**
|
||||
* Get the "type" of the frame
|
||||
@ -68,13 +85,6 @@ public:
|
||||
* @see nsGkAtoms::svgFilterFrame
|
||||
*/
|
||||
virtual nsIAtom* GetType() const;
|
||||
|
||||
private:
|
||||
// implementation helpers
|
||||
nsresult CreateInstance(nsISVGChildFrame *aTarget,
|
||||
const nsIntRect *aDirtyOutputRect,
|
||||
const nsIntRect *aDirtyInputRect,
|
||||
nsSVGFilterInstance **aInstance);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -38,6 +38,9 @@
|
||||
#include "nsSVGUtils.h"
|
||||
#include "nsIDOMSVGUnitTypes.h"
|
||||
#include "nsSVGMatrix.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "nsSVGFilterPaintCallback.h"
|
||||
#include "nsSVGFilterElement.h"
|
||||
|
||||
static double Square(double aX)
|
||||
{
|
||||
@ -48,10 +51,11 @@ float
|
||||
nsSVGFilterInstance::GetPrimitiveLength(nsSVGLength2 *aLength) const
|
||||
{
|
||||
float value;
|
||||
if (mPrimitiveUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
|
||||
if (mPrimitiveUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
|
||||
value = nsSVGUtils::ObjectSpace(mTargetBBox, aLength);
|
||||
else
|
||||
value = nsSVGUtils::UserSpace(TargetElement(), aLength);
|
||||
} else {
|
||||
value = nsSVGUtils::UserSpace(mTargetFrame, aLength);
|
||||
}
|
||||
|
||||
switch (aLength->GetCtxType()) {
|
||||
case nsSVGUtils::X:
|
||||
@ -123,29 +127,9 @@ nsSVGFilterInstance::ComputeFilterPrimitiveSubregion(PrimitiveInfo* aPrimitive)
|
||||
gfxRect(0, 0, mFilterSpaceSize.width, mFilterSpaceSize.height);
|
||||
}
|
||||
|
||||
nsSVGLength2 *tmpX, *tmpY, *tmpWidth, *tmpHeight;
|
||||
tmpX = &fE->mLengthAttributes[nsSVGFE::X];
|
||||
tmpY = &fE->mLengthAttributes[nsSVGFE::Y];
|
||||
tmpWidth = &fE->mLengthAttributes[nsSVGFE::WIDTH];
|
||||
tmpHeight = &fE->mLengthAttributes[nsSVGFE::HEIGHT];
|
||||
|
||||
float x, y, width, height;
|
||||
if (mPrimitiveUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
|
||||
mTargetBBox->GetX(&x);
|
||||
x += nsSVGUtils::ObjectSpace(mTargetBBox, tmpX);
|
||||
mTargetBBox->GetY(&y);
|
||||
y += nsSVGUtils::ObjectSpace(mTargetBBox, tmpY);
|
||||
width = nsSVGUtils::ObjectSpace(mTargetBBox, tmpWidth);
|
||||
height = nsSVGUtils::ObjectSpace(mTargetBBox, tmpHeight);
|
||||
} else {
|
||||
nsSVGElement* targetElement = TargetElement();
|
||||
x = nsSVGUtils::UserSpace(targetElement, tmpX);
|
||||
y = nsSVGUtils::UserSpace(targetElement, tmpY);
|
||||
width = nsSVGUtils::UserSpace(targetElement, tmpWidth);
|
||||
height = nsSVGUtils::UserSpace(targetElement, tmpHeight);
|
||||
}
|
||||
|
||||
gfxRect region = UserSpaceToFilterSpace(gfxRect(x, y, width, height));
|
||||
gfxRect feArea = nsSVGUtils::GetRelativeRect(mPrimitiveUnits,
|
||||
&fE->mLengthAttributes[nsSVGFE::X], mTargetBBox, mTargetFrame);
|
||||
gfxRect region = UserSpaceToFilterSpace(feArea);
|
||||
|
||||
if (!fE->HasAttr(kNameSpaceID_None, nsGkAtoms::x))
|
||||
region.pos.x = defaultFilterSubregion.X();
|
||||
@ -340,19 +324,52 @@ nsSVGFilterInstance::ComputeUnionOfAllNeededBoxes()
|
||||
nsresult
|
||||
nsSVGFilterInstance::BuildSourceImages()
|
||||
{
|
||||
if (mSourceColorAlpha.mResultNeededBox.IsEmpty() &&
|
||||
mSourceAlpha.mResultNeededBox.IsEmpty())
|
||||
nsIntRect neededRect;
|
||||
neededRect.UnionRect(mSourceColorAlpha.mResultNeededBox,
|
||||
mSourceAlpha.mResultNeededBox);
|
||||
if (neededRect.IsEmpty())
|
||||
return NS_OK;
|
||||
|
||||
nsRefPtr<gfxImageSurface> sourceColorAlpha = CreateImage();
|
||||
if (!sourceColorAlpha)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsSVGRenderState tmpState(sourceColorAlpha);
|
||||
nsresult rv = mTargetFrame->PaintSVG(&tmpState, nsnull);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
{
|
||||
// Paint to an offscreen surface first, then copy it to an image
|
||||
// surface. This can be faster especially when the stuff we're painting
|
||||
// contains native themes.
|
||||
nsRefPtr<gfxASurface> offscreen =
|
||||
gfxPlatform::GetPlatform()->CreateOffscreenSurface(
|
||||
gfxIntSize(mSurfaceRect.width, mSurfaceRect.height),
|
||||
gfxASurface::ImageFormatARGB32);
|
||||
if (!offscreen || offscreen->CairoStatus())
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
offscreen->SetDeviceOffset(gfxPoint(-mSurfaceRect.x, -mSurfaceRect.y));
|
||||
|
||||
nsSVGRenderState tmpState(offscreen);
|
||||
nsCOMPtr<nsIDOMSVGMatrix> userSpaceToFilterSpaceTransform
|
||||
= GetUserSpaceToFilterSpaceTransform();
|
||||
if (!userSpaceToFilterSpaceTransform)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
gfxMatrix m =
|
||||
nsSVGUtils::ConvertSVGMatrixToThebes(userSpaceToFilterSpaceTransform);
|
||||
gfxRect r(neededRect.x, neededRect.y, neededRect.width, neededRect.height);
|
||||
m.Invert();
|
||||
r = m.TransformBounds(r);
|
||||
r.RoundOut();
|
||||
nsIntRect dirty;
|
||||
nsresult rv = nsSVGUtils::GfxRectToIntRect(r, &dirty);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
mPaintCallback->Paint(&tmpState, mTargetFrame, &dirty,
|
||||
userSpaceToFilterSpaceTransform);
|
||||
|
||||
gfxContext copyContext(sourceColorAlpha);
|
||||
copyContext.SetSource(offscreen);
|
||||
copyContext.Paint();
|
||||
}
|
||||
|
||||
if (!mSourceColorAlpha.mResultNeededBox.IsEmpty()) {
|
||||
NS_ASSERTION(mSourceColorAlpha.mImageUsers > 0, "Some user must have needed this");
|
||||
mSourceColorAlpha.mImage.mImage = sourceColorAlpha;
|
||||
@ -528,3 +545,50 @@ nsSVGFilterInstance::ComputeOutputDirtyRect(nsIntRect* aDirty)
|
||||
*aDirty = result->mResultChangeBox;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGFilterInstance::ComputeSourceNeededRect(nsIntRect* aDirty)
|
||||
{
|
||||
nsresult rv = BuildSources();
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
rv = BuildPrimitives();
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (mPrimitives.IsEmpty()) {
|
||||
// Nothing should be rendered, so nothing is needed.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ComputeResultBoundingBoxes();
|
||||
ComputeNeededBoxes();
|
||||
aDirty->UnionRect(mSourceColorAlpha.mResultNeededBox,
|
||||
mSourceAlpha.mResultNeededBox);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGFilterInstance::ComputeOutputBBox(nsIntRect* aDirty)
|
||||
{
|
||||
nsresult rv = BuildSources();
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
rv = BuildPrimitives();
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (mPrimitives.IsEmpty()) {
|
||||
// Nothing should be rendered.
|
||||
*aDirty = nsIntRect();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ComputeResultBoundingBoxes();
|
||||
|
||||
PrimitiveInfo* result = &mPrimitives[mPrimitives.Length() - 1];
|
||||
*aDirty = result->mResultBoundingBox;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -51,6 +51,8 @@
|
||||
|
||||
class nsSVGLength2;
|
||||
class nsSVGElement;
|
||||
class nsSVGFilterElement;
|
||||
class nsSVGFilterPaintCallback;
|
||||
|
||||
/**
|
||||
* This class performs all filter processing.
|
||||
@ -64,8 +66,9 @@ class NS_STACK_CLASS nsSVGFilterInstance
|
||||
public:
|
||||
float GetPrimitiveLength(nsSVGLength2 *aLength) const;
|
||||
|
||||
nsSVGFilterInstance(nsISVGChildFrame *aTargetFrame,
|
||||
nsIContent* aFilterElement,
|
||||
nsSVGFilterInstance(nsIFrame *aTargetFrame,
|
||||
nsSVGFilterPaintCallback *aPaintCallback,
|
||||
nsSVGFilterElement *aFilterElement,
|
||||
nsIDOMSVGRect *aTargetBBox,
|
||||
const gfxRect& aFilterRect,
|
||||
const nsIntSize& aFilterSpaceSize,
|
||||
@ -74,6 +77,7 @@ public:
|
||||
const nsIntRect& aDirtyInputRect,
|
||||
PRUint16 aPrimitiveUnits) :
|
||||
mTargetFrame(aTargetFrame),
|
||||
mPaintCallback(aPaintCallback),
|
||||
mFilterElement(aFilterElement),
|
||||
mTargetBBox(aTargetBBox),
|
||||
mFilterSpaceToDeviceSpaceTransform(aFilterSpaceToDeviceSpaceTransform),
|
||||
@ -100,6 +104,8 @@ public:
|
||||
|
||||
nsresult Render(gfxASurface** aOutput);
|
||||
nsresult ComputeOutputDirtyRect(nsIntRect* aDirty);
|
||||
nsresult ComputeSourceNeededRect(nsIntRect* aDirty);
|
||||
nsresult ComputeOutputBBox(nsIntRect* aBBox);
|
||||
|
||||
already_AddRefed<nsIDOMSVGMatrix> GetUserSpaceToFilterSpaceTransform() const;
|
||||
nsIDOMSVGMatrix* GetFilterSpaceToDeviceSpaceTransform() const {
|
||||
@ -174,15 +180,10 @@ private:
|
||||
aRect->IntersectRect(*aRect, filterSpace);
|
||||
}
|
||||
void ClipToGfxRect(nsIntRect* aRect, const gfxRect& aGfx) const;
|
||||
nsSVGElement* TargetElement() const
|
||||
{
|
||||
nsIFrame* f;
|
||||
CallQueryInterface(mTargetFrame, &f);
|
||||
return static_cast<nsSVGElement*>(f->GetContent());
|
||||
}
|
||||
|
||||
nsISVGChildFrame* mTargetFrame;
|
||||
nsIContent* mFilterElement;
|
||||
nsIFrame* mTargetFrame;
|
||||
nsSVGFilterPaintCallback* mPaintCallback;
|
||||
nsSVGFilterElement* mFilterElement;
|
||||
nsCOMPtr<nsIDOMSVGRect> mTargetBBox;
|
||||
nsCOMPtr<nsIDOMSVGMatrix> mFilterSpaceToDeviceSpaceTransform;
|
||||
gfxRect mFilterRect;
|
||||
|
64
layout/svg/base/src/nsSVGFilterPaintCallback.h
Normal file
64
layout/svg/base/src/nsSVGFilterPaintCallback.h
Normal file
@ -0,0 +1,64 @@
|
||||
/* -*- 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 Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* 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 ***** */
|
||||
|
||||
#ifndef __NS_SVGFILTERPAINTCALLBACK_H__
|
||||
#define __NS_SVGFILTERPAINTCALLBACK_H__
|
||||
|
||||
#include "nsRect.h"
|
||||
|
||||
class nsIFrame;
|
||||
class nsIDOMSVGMatrix;
|
||||
class nsSVGRenderState;
|
||||
|
||||
class nsSVGFilterPaintCallback {
|
||||
public:
|
||||
/**
|
||||
* Paint the frame contents. aTransform should be applied to aContext
|
||||
* (either via SetOverrideCTM or by applying the transform to aContext
|
||||
* directly).
|
||||
* SVG frames will have had matrix propagation set to false already.
|
||||
* frames have to do their own thing.
|
||||
* The caller will do a Save()/Restore() as necessary so feel free
|
||||
* to mess with context state.
|
||||
* @param aDirtyRect the dirty rect *in user space pixels*
|
||||
* @param aTransform the user-space-to-filter-space transform to apply.
|
||||
* May be null if the identity matrix is requested.
|
||||
*/
|
||||
virtual void Paint(nsSVGRenderState *aContext, nsIFrame *aTarget,
|
||||
const nsIntRect *aDirtyRect, nsIDOMSVGMatrix *aTransform) = 0;
|
||||
};
|
||||
|
||||
#endif
|
@ -97,6 +97,7 @@ nsSVGForeignObjectFrame::Init(nsIContent* aContent,
|
||||
nsIFrame* aPrevInFlow)
|
||||
{
|
||||
nsresult rv = nsSVGForeignObjectFrameBase::Init(aContent, aParent, aPrevInFlow);
|
||||
AddStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsSVGUtils::GetOuterSVGFrame(this)->RegisterForeignObject(this);
|
||||
}
|
||||
@ -450,10 +451,20 @@ nsSVGForeignObjectFrame::NotifyRedrawUnsuspended()
|
||||
NS_IMETHODIMP
|
||||
nsSVGForeignObjectFrame::SetMatrixPropagation(PRBool aPropagate)
|
||||
{
|
||||
mPropagateTransform = aPropagate;
|
||||
if (aPropagate) {
|
||||
AddStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
|
||||
} else {
|
||||
RemoveStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSVGForeignObjectFrame::GetMatrixPropagation()
|
||||
{
|
||||
return (GetStateBits() & NS_STATE_SVG_PROPAGATE_TRANSFORM) != 0;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGForeignObjectFrame::SetOverrideCTM(nsIDOMSVGMatrix *aCTM)
|
||||
{
|
||||
@ -514,7 +525,7 @@ nsSVGForeignObjectFrame::GetTMIncludingOffset()
|
||||
already_AddRefed<nsIDOMSVGMatrix>
|
||||
nsSVGForeignObjectFrame::GetCanvasTM()
|
||||
{
|
||||
if (!mPropagateTransform) {
|
||||
if (!GetMatrixPropagation()) {
|
||||
nsIDOMSVGMatrix *retval;
|
||||
if (mOverrideCTM) {
|
||||
retval = mOverrideCTM;
|
||||
|
@ -114,6 +114,7 @@ public:
|
||||
NS_IMETHOD NotifyRedrawSuspended();
|
||||
NS_IMETHOD NotifyRedrawUnsuspended();
|
||||
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
|
||||
virtual PRBool GetMatrixPropagation();
|
||||
NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM);
|
||||
virtual already_AddRefed<nsIDOMSVGMatrix> GetOverrideCTM();
|
||||
NS_IMETHOD GetBBox(nsIDOMSVGRect **_retval);
|
||||
|
@ -80,13 +80,6 @@ nsSVGGFrame::NotifySVGChanged(PRUint32 aFlags)
|
||||
nsSVGGFrameBase::NotifySVGChanged(aFlags);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGGFrame::SetMatrixPropagation(PRBool aPropagate)
|
||||
{
|
||||
mPropagateTransform = aPropagate;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGGFrame::SetOverrideCTM(nsIDOMSVGMatrix *aCTM)
|
||||
{
|
||||
@ -105,7 +98,7 @@ nsSVGGFrame::GetOverrideCTM()
|
||||
already_AddRefed<nsIDOMSVGMatrix>
|
||||
nsSVGGFrame::GetCanvasTM()
|
||||
{
|
||||
if (!mPropagateTransform) {
|
||||
if (!GetMatrixPropagation()) {
|
||||
nsIDOMSVGMatrix *retval;
|
||||
if (mOverrideCTM) {
|
||||
retval = mOverrideCTM;
|
||||
|
@ -73,7 +73,6 @@ public:
|
||||
|
||||
// nsISVGChildFrame interface:
|
||||
virtual void NotifySVGChanged(PRUint32 aFlags);
|
||||
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
|
||||
NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM);
|
||||
virtual already_AddRefed<nsIDOMSVGMatrix> GetOverrideCTM();
|
||||
|
||||
|
@ -65,7 +65,8 @@ nsSVGGeometryFrame::Init(nsIContent* aContent,
|
||||
nsIFrame* aParent,
|
||||
nsIFrame* aPrevInFlow)
|
||||
{
|
||||
AddStateBits(aParent->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD);
|
||||
AddStateBits((aParent->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) |
|
||||
NS_STATE_SVG_PROPAGATE_TRANSFORM);
|
||||
nsresult rv = nsSVGGeometryFrameBase::Init(aContent, aParent, aPrevInFlow);
|
||||
return rv;
|
||||
}
|
||||
|
@ -1284,6 +1284,23 @@ nsSVGGlyphFrame::EnsureTextRun(float *aDrawScale, float *aMetricsScale,
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGGlyphFrame::SetMatrixPropagation(PRBool aPropagate)
|
||||
{
|
||||
if (aPropagate) {
|
||||
AddStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
|
||||
} else {
|
||||
RemoveStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSVGGlyphFrame::GetMatrixPropagation()
|
||||
{
|
||||
return (GetStateBits() & NS_STATE_SVG_PROPAGATE_TRANSFORM) != 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// helper class
|
||||
|
||||
|
@ -125,7 +125,8 @@ public:
|
||||
virtual void NotifySVGChanged(PRUint32 aFlags);
|
||||
NS_IMETHOD NotifyRedrawSuspended();
|
||||
NS_IMETHOD NotifyRedrawUnsuspended();
|
||||
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate) { return NS_OK; }
|
||||
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
|
||||
virtual PRBool GetMatrixPropagation();
|
||||
NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM) { return NS_ERROR_FAILURE; }
|
||||
virtual already_AddRefed<nsIDOMSVGMatrix> GetOverrideCTM() { return nsnull; }
|
||||
NS_IMETHOD_(PRBool) IsDisplayContainer() { return PR_FALSE; }
|
||||
|
@ -85,7 +85,6 @@ public:
|
||||
// nsISVGChildFrame interface:
|
||||
NS_IMETHOD PaintSVG(nsSVGRenderState *aContext, nsIntRect *aDirtyRect);
|
||||
virtual void NotifySVGChanged(PRUint32 aFlags);
|
||||
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
|
||||
NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM);
|
||||
virtual already_AddRefed<nsIDOMSVGMatrix> GetOverrideCTM();
|
||||
NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint);
|
||||
@ -228,13 +227,6 @@ nsSVGInnerSVGFrame::NotifySVGChanged(PRUint32 aFlags)
|
||||
nsSVGInnerSVGFrameBase::NotifySVGChanged(aFlags);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGInnerSVGFrame::SetMatrixPropagation(PRBool aPropagate)
|
||||
{
|
||||
mPropagateTransform = aPropagate;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGInnerSVGFrame::SetOverrideCTM(nsIDOMSVGMatrix *aCTM)
|
||||
{
|
||||
|
414
layout/svg/base/src/nsSVGIntegrationUtils.cpp
Normal file
414
layout/svg/base/src/nsSVGIntegrationUtils.cpp
Normal file
@ -0,0 +1,414 @@
|
||||
/* -*- 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):
|
||||
* rocallahan@mozilla.com
|
||||
*
|
||||
* 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 "nsSVGIntegrationUtils.h"
|
||||
|
||||
#include "nsSVGUtils.h"
|
||||
#include "nsSVGEffects.h"
|
||||
#include "nsRegion.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsSVGMatrix.h"
|
||||
#include "nsSVGFilterPaintCallback.h"
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
PRBool
|
||||
nsSVGIntegrationUtils::UsingEffectsForFrame(const nsIFrame* aFrame)
|
||||
{
|
||||
const nsStyleSVGReset *style = aFrame->GetStyleSVGReset();
|
||||
return style->mFilter || style->mClipPath || style->mMask;
|
||||
}
|
||||
|
||||
// Get the union the frame border-box rects over all continuations,
|
||||
// relative to aFirst. This defines "user space" for non-SVG frames.
|
||||
static nsRect GetNonSVGUserSpace(nsIFrame* aFirst)
|
||||
{
|
||||
NS_ASSERTION(!aFirst->GetPrevContinuation(), "Not first continuation");
|
||||
return nsLayoutUtils::GetAllInFlowRectsUnion(aFirst, aFirst);
|
||||
}
|
||||
|
||||
static nsRect
|
||||
GetPreEffectsOverflowRect(nsIFrame* aFrame)
|
||||
{
|
||||
nsRect* r = static_cast<nsRect*>(aFrame->GetProperty(nsGkAtoms::preEffectsBBoxProperty));
|
||||
if (r)
|
||||
return *r;
|
||||
return aFrame->GetOverflowRect();
|
||||
}
|
||||
|
||||
struct BBoxCollector : public nsLayoutUtils::BoxCallback {
|
||||
nsIFrame* mReferenceFrame;
|
||||
nsIFrame* mCurrentFrame;
|
||||
const nsRect& mCurrentFrameOverflowArea;
|
||||
nsRect mResult;
|
||||
|
||||
BBoxCollector(nsIFrame* aReferenceFrame, nsIFrame* aCurrentFrame,
|
||||
const nsRect& aCurrentFrameOverflowArea)
|
||||
: mReferenceFrame(aReferenceFrame), mCurrentFrame(aCurrentFrame),
|
||||
mCurrentFrameOverflowArea(aCurrentFrameOverflowArea) {}
|
||||
|
||||
virtual void AddBox(nsIFrame* aFrame) {
|
||||
nsRect overflow = aFrame == mCurrentFrame ? mCurrentFrameOverflowArea
|
||||
: GetPreEffectsOverflowRect(aFrame);
|
||||
mResult.UnionRect(mResult, overflow + aFrame->GetOffsetTo(mReferenceFrame));
|
||||
}
|
||||
};
|
||||
|
||||
static nsRect
|
||||
GetSVGBBox(nsIFrame* aNonSVGFrame, nsIFrame* aCurrentFrame,
|
||||
const nsRect& aCurrentOverflow, const nsRect& aUserSpaceRect)
|
||||
{
|
||||
NS_ASSERTION(!aNonSVGFrame->GetPrevContinuation(),
|
||||
"Need first continuation here");
|
||||
// Compute union of all overflow areas relative to 'first'.
|
||||
BBoxCollector collector(aNonSVGFrame, aCurrentFrame, aCurrentOverflow);
|
||||
nsLayoutUtils::GetAllInFlowBoxes(aNonSVGFrame, &collector);
|
||||
// Get it into "user space" for non-SVG frames
|
||||
return collector.mResult - aUserSpaceRect.TopLeft();
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsSVGIntegrationUtils::ComputeFrameEffectsRect(nsIFrame* aFrame,
|
||||
const nsRect& aOverflowRect)
|
||||
{
|
||||
PRBool isOK;
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aFrame);
|
||||
nsSVGEffects::EffectProperties effectProperties =
|
||||
nsSVGEffects::GetEffectProperties(firstFrame);
|
||||
nsSVGFilterFrame *filterFrame = effectProperties.mFilter ?
|
||||
effectProperties.mFilter->GetFilterFrame(&isOK) : nsnull;
|
||||
if (!filterFrame)
|
||||
return aOverflowRect;
|
||||
|
||||
// XXX this isn't really right. We can't compute the correct filter
|
||||
// bbox until all aFrame's continuations have been reflowed.
|
||||
// but then it's too late to set the overflow areas for the earlier frames.
|
||||
nsRect userSpaceRect = GetNonSVGUserSpace(firstFrame);
|
||||
nsRect r = GetSVGBBox(firstFrame, aFrame, aOverflowRect, userSpaceRect);
|
||||
// r is relative to user space
|
||||
PRUint32 appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
r.ScaleRoundOutInverse(appUnitsPerDevPixel);
|
||||
r = filterFrame->GetFilterBBox(firstFrame, &r);
|
||||
r.ScaleRoundOut(appUnitsPerDevPixel);
|
||||
// Make it relative to aFrame again
|
||||
return r + userSpaceRect.TopLeft() - aFrame->GetOffsetTo(firstFrame);
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsSVGIntegrationUtils::GetInvalidAreaForChangedSource(nsIFrame* aFrame,
|
||||
const nsRect& aInvalidRect)
|
||||
{
|
||||
// Don't bother calling GetEffectProperties; the filter property should
|
||||
// already have been set up during reflow/ComputeFrameEffectsRect
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aFrame);
|
||||
nsSVGFilterFrame* filterFrame = nsSVGEffects::GetFilterFrame(firstFrame);
|
||||
if (!filterFrame)
|
||||
return aInvalidRect;
|
||||
|
||||
PRInt32 appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
nsRect userSpaceRect = GetNonSVGUserSpace(firstFrame);
|
||||
nsPoint offset = aFrame->GetOffsetTo(firstFrame) - userSpaceRect.TopLeft();
|
||||
nsRect r = aInvalidRect + offset;
|
||||
r.ScaleRoundOutInverse(appUnitsPerDevPixel);
|
||||
r = filterFrame->GetInvalidationBBox(firstFrame, r);
|
||||
r.ScaleRoundOut(appUnitsPerDevPixel);
|
||||
return r - offset;
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(nsIFrame* aFrame,
|
||||
const nsRect& aDamageRect)
|
||||
{
|
||||
// Don't bother calling GetEffectProperties; the filter property should
|
||||
// already have been set up during reflow/ComputeFrameEffectsRect
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aFrame);
|
||||
nsSVGFilterFrame* filterFrame =
|
||||
nsSVGEffects::GetFilterFrame(firstFrame);
|
||||
if (!filterFrame)
|
||||
return aDamageRect;
|
||||
|
||||
PRInt32 appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
nsRect userSpaceRect = GetNonSVGUserSpace(firstFrame);
|
||||
nsPoint offset = aFrame->GetOffsetTo(firstFrame) - userSpaceRect.TopLeft();
|
||||
nsRect r = aDamageRect + offset;
|
||||
r.ScaleRoundOutInverse(appUnitsPerDevPixel);
|
||||
r = filterFrame->GetSourceForInvalidArea(firstFrame, r);
|
||||
r.ScaleRoundOut(appUnitsPerDevPixel);
|
||||
return r - offset;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSVGIntegrationUtils::HitTestFrameForEffects(nsIFrame* aFrame, const nsPoint& aPt)
|
||||
{
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aFrame);
|
||||
nsRect userSpaceRect = GetNonSVGUserSpace(firstFrame);
|
||||
// get point relative to userSpaceRect
|
||||
nsPoint pt = aPt + aFrame->GetOffsetTo(firstFrame) - userSpaceRect.TopLeft();
|
||||
return nsSVGUtils::HitTestClip(firstFrame, pt);
|
||||
}
|
||||
|
||||
class RegularFramePaintCallback : public nsSVGFilterPaintCallback
|
||||
{
|
||||
public:
|
||||
RegularFramePaintCallback(nsDisplayListBuilder* aBuilder,
|
||||
nsDisplayList* aInnerList,
|
||||
const nsPoint& aOffset)
|
||||
: mBuilder(aBuilder), mInnerList(aInnerList), mOffset(aOffset) {}
|
||||
|
||||
virtual void Paint(nsSVGRenderState *aContext, nsIFrame *aTarget,
|
||||
const nsIntRect* aDirtyRect, nsIDOMSVGMatrix *aTransform)
|
||||
{
|
||||
nsIRenderingContext* ctx = aContext->GetRenderingContext(aTarget);
|
||||
gfxContext* gfxCtx = aContext->GetGfxContext();
|
||||
|
||||
if (aTransform) {
|
||||
// Transform by aTransform first
|
||||
gfxMatrix m = nsSVGUtils::ConvertSVGMatrixToThebes(aTransform);
|
||||
gfxCtx->Multiply(m);
|
||||
}
|
||||
|
||||
// We're expected to paint with 1 unit equal to 1 CSS pixel. But
|
||||
// mInnerList->Paint expects 1 unit to equal 1 device pixel. So
|
||||
// adjust.
|
||||
gfxFloat scale =
|
||||
nsPresContext::AppUnitsToFloatCSSPixels(aTarget->PresContext()->AppUnitsPerDevPixel());
|
||||
gfxCtx->Scale(scale, scale);
|
||||
|
||||
nsIRenderingContext::AutoPushTranslation push(ctx, -mOffset.x, -mOffset.y);
|
||||
nsRect dirty;
|
||||
if (aDirtyRect) {
|
||||
dirty = *aDirtyRect;
|
||||
dirty.ScaleRoundOut(nsIDeviceContext::AppUnitsPerCSSPixel());
|
||||
dirty += mOffset;
|
||||
} else {
|
||||
dirty = mInnerList->GetBounds(mBuilder);
|
||||
}
|
||||
mInnerList->Paint(mBuilder, ctx, dirty);
|
||||
}
|
||||
|
||||
private:
|
||||
nsDisplayListBuilder* mBuilder;
|
||||
nsDisplayList* mInnerList;
|
||||
nsPoint mOffset;
|
||||
};
|
||||
|
||||
void
|
||||
nsSVGIntegrationUtils::PaintFramesWithEffects(nsIRenderingContext* aCtx,
|
||||
nsIFrame* aEffectsFrame,
|
||||
const nsRect& aDirtyRect,
|
||||
nsDisplayListBuilder* aBuilder,
|
||||
nsDisplayList* aInnerList)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
nsISVGChildFrame *svgChildFrame;
|
||||
CallQueryInterface(aEffectsFrame, &svgChildFrame);
|
||||
#endif
|
||||
NS_ASSERTION(!svgChildFrame, "Should never be called on an SVG frame");
|
||||
|
||||
float opacity = aEffectsFrame->GetStyleDisplay()->mOpacity;
|
||||
if (opacity == 0.0f)
|
||||
return;
|
||||
|
||||
/* Properties are added lazily and may have been removed by a restyle,
|
||||
so make sure all applicable ones are set again. */
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aEffectsFrame);
|
||||
nsSVGEffects::EffectProperties effectProperties =
|
||||
nsSVGEffects::GetEffectProperties(firstFrame);
|
||||
|
||||
/* SVG defines the following rendering model:
|
||||
*
|
||||
* 1. Render geometry
|
||||
* 2. Apply filter
|
||||
* 3. Apply clipping, masking, group opacity
|
||||
*
|
||||
* We follow this, but perform a couple of optimizations:
|
||||
*
|
||||
* + Use cairo's clipPath when representable natively (single object
|
||||
* clip region).
|
||||
*
|
||||
* + Merge opacity and masking if both used together.
|
||||
*/
|
||||
|
||||
PRBool isOK = PR_TRUE;
|
||||
nsSVGClipPathFrame *clipPathFrame = effectProperties.mClipPath ?
|
||||
effectProperties.mClipPath->GetClipPathFrame(&isOK) : nsnull;
|
||||
nsSVGFilterFrame *filterFrame = effectProperties.mFilter ?
|
||||
effectProperties.mFilter->GetFilterFrame(&isOK) : nsnull;
|
||||
nsSVGMaskFrame *maskFrame = effectProperties.mMask ?
|
||||
effectProperties.mMask->GetMaskFrame(&isOK) : nsnull;
|
||||
|
||||
PRBool isTrivialClip = clipPathFrame ? clipPathFrame->IsTrivial() : PR_TRUE;
|
||||
|
||||
if (!isOK) {
|
||||
// Some resource is missing. We shouldn't paint anything.
|
||||
return;
|
||||
}
|
||||
|
||||
gfxContext* gfx = aCtx->ThebesContext();
|
||||
gfxMatrix savedCTM = gfx->CurrentMatrix();
|
||||
nsSVGRenderState svgContext(aCtx);
|
||||
|
||||
nsRect userSpaceRect = GetNonSVGUserSpace(firstFrame) + aBuilder->ToReferenceFrame(firstFrame);
|
||||
PRInt32 appUnitsPerDevPixel = aEffectsFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
userSpaceRect.ScaleRoundPreservingCentersInverse(appUnitsPerDevPixel);
|
||||
userSpaceRect.ScaleRoundOut(appUnitsPerDevPixel);
|
||||
aCtx->Translate(userSpaceRect.x, userSpaceRect.y);
|
||||
|
||||
nsCOMPtr<nsIDOMSVGMatrix> matrix = GetInitialMatrix(aEffectsFrame);
|
||||
|
||||
PRBool complexEffects = PR_FALSE;
|
||||
/* Check if we need to do additional operations on this child's
|
||||
* rendering, which necessitates rendering into another surface. */
|
||||
if (opacity != 1.0f || maskFrame || (clipPathFrame && !isTrivialClip)) {
|
||||
complexEffects = PR_TRUE;
|
||||
gfx->Save();
|
||||
gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
|
||||
}
|
||||
|
||||
/* If this frame has only a trivial clipPath, set up cairo's clipping now so
|
||||
* we can just do normal painting and get it clipped appropriately.
|
||||
*/
|
||||
if (clipPathFrame && isTrivialClip) {
|
||||
gfx->Save();
|
||||
clipPathFrame->ClipPaint(&svgContext, aEffectsFrame, matrix);
|
||||
}
|
||||
|
||||
/* Paint the child */
|
||||
if (filterFrame) {
|
||||
RegularFramePaintCallback paint(aBuilder, aInnerList, userSpaceRect.TopLeft());
|
||||
nsRect r = aDirtyRect - userSpaceRect.TopLeft();
|
||||
r.ScaleRoundOutInverse(appUnitsPerDevPixel);
|
||||
filterFrame->FilterPaint(&svgContext, aEffectsFrame, &paint, &r);
|
||||
} else {
|
||||
gfx->SetMatrix(savedCTM);
|
||||
aInnerList->Paint(aBuilder, aCtx, aDirtyRect);
|
||||
aCtx->Translate(userSpaceRect.x, userSpaceRect.y);
|
||||
}
|
||||
|
||||
if (clipPathFrame && isTrivialClip) {
|
||||
gfx->Restore();
|
||||
}
|
||||
|
||||
/* No more effects, we're done. */
|
||||
if (!complexEffects) {
|
||||
gfx->SetMatrix(savedCTM);
|
||||
return;
|
||||
}
|
||||
|
||||
gfx->PopGroupToSource();
|
||||
|
||||
nsRefPtr<gfxPattern> maskSurface =
|
||||
maskFrame ? maskFrame->ComputeMaskAlpha(&svgContext, aEffectsFrame,
|
||||
matrix, opacity) : nsnull;
|
||||
|
||||
nsRefPtr<gfxPattern> clipMaskSurface;
|
||||
if (clipPathFrame && !isTrivialClip) {
|
||||
gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
|
||||
|
||||
nsresult rv = clipPathFrame->ClipPaint(&svgContext, aEffectsFrame, matrix);
|
||||
clipMaskSurface = gfx->PopGroup();
|
||||
|
||||
if (NS_SUCCEEDED(rv) && clipMaskSurface) {
|
||||
// Still more set after clipping, so clip to another surface
|
||||
if (maskSurface || opacity != 1.0f) {
|
||||
gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
|
||||
gfx->Mask(clipMaskSurface);
|
||||
gfx->PopGroupToSource();
|
||||
} else {
|
||||
gfx->Mask(clipMaskSurface);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (maskSurface) {
|
||||
gfx->Mask(maskSurface);
|
||||
} else if (opacity != 1.0f) {
|
||||
gfx->Paint(opacity);
|
||||
}
|
||||
|
||||
gfx->Restore();
|
||||
gfx->SetMatrix(savedCTM);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMSVGMatrix>
|
||||
nsSVGIntegrationUtils::GetInitialMatrix(nsIFrame* aNonSVGFrame)
|
||||
{
|
||||
NS_ASSERTION(!aNonSVGFrame->IsFrameOfType(nsIFrame::eSVG),
|
||||
"SVG frames should not get here");
|
||||
PRInt32 appUnitsPerDevPixel = aNonSVGFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
nsCOMPtr<nsIDOMSVGMatrix> matrix;
|
||||
float devPxPerCSSPx =
|
||||
1 / nsPresContext::AppUnitsToFloatCSSPixels(appUnitsPerDevPixel);
|
||||
NS_NewSVGMatrix(getter_AddRefs(matrix),
|
||||
devPxPerCSSPx, 0.0f,
|
||||
0.0f, devPxPerCSSPx);
|
||||
return matrix.forget();
|
||||
}
|
||||
|
||||
gfxRect
|
||||
nsSVGIntegrationUtils::GetSVGRectForNonSVGFrame(nsIFrame* aNonSVGFrame)
|
||||
{
|
||||
NS_ASSERTION(!aNonSVGFrame->IsFrameOfType(nsIFrame::eSVG),
|
||||
"SVG frames should not get here");
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aNonSVGFrame);
|
||||
nsRect r = GetNonSVGUserSpace(firstFrame);
|
||||
nsPresContext* presContext = firstFrame->PresContext();
|
||||
return gfxRect(0, 0, presContext->AppUnitsToFloatCSSPixels(r.width),
|
||||
presContext->AppUnitsToFloatCSSPixels(r.height));
|
||||
}
|
||||
|
||||
gfxRect
|
||||
nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(nsIFrame* aNonSVGFrame)
|
||||
{
|
||||
NS_ASSERTION(!aNonSVGFrame->IsFrameOfType(nsIFrame::eSVG),
|
||||
"SVG frames should not get here");
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aNonSVGFrame);
|
||||
nsRect userSpaceRect = GetNonSVGUserSpace(firstFrame);
|
||||
nsRect r = GetSVGBBox(firstFrame, nsnull, nsRect(), userSpaceRect);
|
||||
gfxRect result(r.x, r.y, r.width, r.height);
|
||||
nsPresContext* presContext = aNonSVGFrame->PresContext();
|
||||
result.ScaleInverse(presContext->AppUnitsPerCSSPixel());
|
||||
return result;
|
||||
}
|
116
layout/svg/base/src/nsSVGIntegrationUtils.h
Normal file
116
layout/svg/base/src/nsSVGIntegrationUtils.h
Normal file
@ -0,0 +1,116 @@
|
||||
/* -*- 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):
|
||||
* rocallahan@mozilla.com
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#ifndef NSSVGINTEGRATIONUTILS_H_
|
||||
#define NSSVGINTEGRATIONUTILS_H_
|
||||
|
||||
#include "nsPoint.h"
|
||||
#include "nsRect.h"
|
||||
#include "gfxRect.h"
|
||||
|
||||
class nsIFrame;
|
||||
class nsDisplayListBuilder;
|
||||
class nsDisplayList;
|
||||
class nsIRenderingContext;
|
||||
class nsIDOMSVGMatrix;
|
||||
|
||||
/***** Integration of SVG effects with regular frame painting *****/
|
||||
|
||||
class nsSVGIntegrationUtils
|
||||
{
|
||||
public:
|
||||
static PRBool
|
||||
UsingEffectsForFrame(const nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Adjust overflow rect for effects.
|
||||
* XXX this is a problem. We really need to compute the effects rect for
|
||||
* a whole chain of frames for a given element at once. but we have no
|
||||
* way to do this effectively with Gecko's current reflow architecture.
|
||||
* See http://groups.google.com/group/mozilla.dev.tech.layout/msg/6b179066f3051f65
|
||||
*/
|
||||
static nsRect
|
||||
ComputeFrameEffectsRect(nsIFrame* aFrame, const nsRect& aOverflowRect);
|
||||
/**
|
||||
* Adjust the frame's invalidation area to cover effects
|
||||
*/
|
||||
static nsRect
|
||||
GetInvalidAreaForChangedSource(nsIFrame* aFrame, const nsRect& aInvalidRect);
|
||||
/**
|
||||
* Figure out which area of the source is needed given an area to
|
||||
* repaint
|
||||
*/
|
||||
static nsRect
|
||||
GetRequiredSourceForInvalidArea(nsIFrame* aFrame, const nsRect& aDamageRect);
|
||||
/**
|
||||
* Returns true if the given point is not clipped out by effects.
|
||||
* @param aPt in appunits relative to aFrame
|
||||
*/
|
||||
static PRBool
|
||||
HitTestFrameForEffects(nsIFrame* aFrame, const nsPoint& aPt);
|
||||
|
||||
/**
|
||||
* Paint non-SVG frame with SVG effects.
|
||||
* @param aOffset the offset in appunits where aFrame should be positioned
|
||||
* in aCtx's coordinate system
|
||||
*/
|
||||
static void
|
||||
PaintFramesWithEffects(nsIRenderingContext* aCtx,
|
||||
nsIFrame* aEffectsFrame, const nsRect& aDirtyRect,
|
||||
nsDisplayListBuilder* aBuilder,
|
||||
nsDisplayList* aInnerList);
|
||||
|
||||
static already_AddRefed<nsIDOMSVGMatrix>
|
||||
GetInitialMatrix(nsIFrame* aNonSVGFrame);
|
||||
/**
|
||||
* Returns aNonSVGFrame's rect in CSS pixel units. This is the union
|
||||
* of all its continuations' rectangles. The top-left is always 0,0
|
||||
* since "user space" origin for non-SVG frames is the top-left of the
|
||||
* union of all the continuations' rectangles.
|
||||
*/
|
||||
static gfxRect
|
||||
GetSVGRectForNonSVGFrame(nsIFrame* aNonSVGFrame);
|
||||
/**
|
||||
* Returns aNonSVGFrame's bounding box in CSS units. This is the union
|
||||
* of all its continuations' overflow areas, relative to the top-left
|
||||
* of all the continuations' rectangles.
|
||||
*/
|
||||
static gfxRect
|
||||
GetSVGBBoxForNonSVGFrame(nsIFrame* aNonSVGFrame);
|
||||
};
|
||||
|
||||
#endif /*NSSVGINTEGRATIONUTILS_H_*/
|
@ -61,7 +61,7 @@ NS_NewSVGMaskFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsStyleContex
|
||||
|
||||
already_AddRefed<gfxPattern>
|
||||
nsSVGMaskFrame::ComputeMaskAlpha(nsSVGRenderState *aContext,
|
||||
nsISVGChildFrame* aParent,
|
||||
nsIFrame* aParent,
|
||||
nsIDOMSVGMatrix* aMatrix,
|
||||
float aOpacity)
|
||||
{
|
||||
@ -79,67 +79,23 @@ nsSVGMaskFrame::ComputeMaskAlpha(nsSVGRenderState *aContext,
|
||||
gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
|
||||
|
||||
{
|
||||
nsIFrame *frame;
|
||||
CallQueryInterface(aParent, &frame);
|
||||
nsSVGElement *parent = static_cast<nsSVGElement*>(frame->GetContent());
|
||||
|
||||
float x, y, width, height;
|
||||
|
||||
nsSVGMaskElement *mask = static_cast<nsSVGMaskElement*>(mContent);
|
||||
|
||||
nsSVGLength2 *tmpX, *tmpY, *tmpWidth, *tmpHeight;
|
||||
tmpX = &mask->mLengthAttributes[nsSVGMaskElement::X];
|
||||
tmpY = &mask->mLengthAttributes[nsSVGMaskElement::Y];
|
||||
tmpWidth = &mask->mLengthAttributes[nsSVGMaskElement::WIDTH];
|
||||
tmpHeight = &mask->mLengthAttributes[nsSVGMaskElement::HEIGHT];
|
||||
|
||||
PRUint16 units =
|
||||
mask->mEnumAttributes[nsSVGMaskElement::MASKUNITS].GetAnimValue();
|
||||
|
||||
nsCOMPtr<nsIDOMSVGRect> bbox;
|
||||
if (units == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
|
||||
|
||||
aParent->SetMatrixPropagation(PR_FALSE);
|
||||
aParent->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
|
||||
nsISVGChildFrame::TRANSFORM_CHANGED);
|
||||
|
||||
nsCOMPtr<nsIDOMSVGRect> bbox;
|
||||
aParent->GetBBox(getter_AddRefs(bbox));
|
||||
|
||||
aParent->SetMatrixPropagation(PR_TRUE);
|
||||
aParent->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
|
||||
nsISVGChildFrame::TRANSFORM_CHANGED);
|
||||
|
||||
bbox = nsSVGUtils::GetBBox(aParent);
|
||||
if (!bbox)
|
||||
return nsnull;
|
||||
|
||||
#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, tmpX);
|
||||
bbox->GetY(&y);
|
||||
y += nsSVGUtils::ObjectSpace(bbox, tmpY);
|
||||
width = nsSVGUtils::ObjectSpace(bbox, tmpWidth);
|
||||
height = nsSVGUtils::ObjectSpace(bbox, tmpHeight);
|
||||
} else {
|
||||
x = nsSVGUtils::UserSpace(parent, tmpX);
|
||||
y = nsSVGUtils::UserSpace(parent, tmpY);
|
||||
width = nsSVGUtils::UserSpace(parent, tmpWidth);
|
||||
height = nsSVGUtils::UserSpace(parent, tmpHeight);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_tor
|
||||
fprintf(stderr, "mask clip: %f,%f %fx%f\n", x, y, width, height);
|
||||
#endif
|
||||
gfxRect maskArea = nsSVGUtils::GetRelativeRect(units,
|
||||
&mask->mLengthAttributes[nsSVGMaskElement::X], bbox, aParent);
|
||||
|
||||
gfx->Save();
|
||||
nsSVGUtils::SetClipRect(gfx, aMatrix, x, y, width, height);
|
||||
nsSVGUtils::SetClipRect(gfx, aMatrix, maskArea.X(), maskArea.Y(),
|
||||
maskArea.Width(), maskArea.Height());
|
||||
}
|
||||
|
||||
mMaskParent = aParent;
|
||||
|
@ -57,7 +57,7 @@ protected:
|
||||
public:
|
||||
// nsSVGMaskFrame method:
|
||||
already_AddRefed<gfxPattern> ComputeMaskAlpha(nsSVGRenderState *aContext,
|
||||
nsISVGChildFrame* aParent,
|
||||
nsIFrame* aParent,
|
||||
nsIDOMSVGMatrix* aMatrix,
|
||||
float aOpacity = 1.0f);
|
||||
|
||||
@ -95,7 +95,7 @@ private:
|
||||
nsSVGMaskFrame *mFrame;
|
||||
};
|
||||
|
||||
nsISVGChildFrame *mMaskParent;
|
||||
nsIFrame *mMaskParent;
|
||||
nsCOMPtr<nsIDOMSVGMatrix> mMaskParentMatrix;
|
||||
// recursion prevention flag
|
||||
PRPackedBool mInUse;
|
||||
|
@ -499,10 +499,20 @@ nsSVGPathGeometryFrame::NotifyRedrawUnsuspended()
|
||||
NS_IMETHODIMP
|
||||
nsSVGPathGeometryFrame::SetMatrixPropagation(PRBool aPropagate)
|
||||
{
|
||||
mPropagateTransform = aPropagate;
|
||||
if (aPropagate) {
|
||||
AddStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
|
||||
} else {
|
||||
RemoveStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSVGPathGeometryFrame::GetMatrixPropagation()
|
||||
{
|
||||
return (GetStateBits() & NS_STATE_SVG_PROPAGATE_TRANSFORM) != 0;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGPathGeometryFrame::SetOverrideCTM(nsIDOMSVGMatrix *aCTM)
|
||||
{
|
||||
@ -538,7 +548,7 @@ nsSVGPathGeometryFrame::GetCanvasTM(nsIDOMSVGMatrix * *aCTM)
|
||||
{
|
||||
*aCTM = nsnull;
|
||||
|
||||
if (!mPropagateTransform) {
|
||||
if (!GetMatrixPropagation()) {
|
||||
if (mOverrideCTM) {
|
||||
*aCTM = mOverrideCTM;
|
||||
NS_ADDREF(*aCTM);
|
||||
|
@ -65,8 +65,7 @@ class nsSVGPathGeometryFrame : public nsSVGPathGeometryFrameBase,
|
||||
nsStyleContext* aContext);
|
||||
protected:
|
||||
nsSVGPathGeometryFrame(nsStyleContext* aContext) :
|
||||
nsSVGPathGeometryFrameBase(aContext),
|
||||
mPropagateTransform(PR_TRUE) {}
|
||||
nsSVGPathGeometryFrameBase(aContext) {}
|
||||
|
||||
public:
|
||||
// nsISupports interface:
|
||||
@ -112,6 +111,7 @@ protected:
|
||||
NS_IMETHOD NotifyRedrawSuspended();
|
||||
NS_IMETHOD NotifyRedrawUnsuspended();
|
||||
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
|
||||
virtual PRBool GetMatrixPropagation();
|
||||
NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM);
|
||||
virtual already_AddRefed<nsIDOMSVGMatrix> GetOverrideCTM();
|
||||
NS_IMETHOD GetBBox(nsIDOMSVGRect **_retval);
|
||||
@ -143,7 +143,6 @@ private:
|
||||
void RemovePathProperties();
|
||||
|
||||
nsCOMPtr<nsIDOMSVGMatrix> mOverrideCTM;
|
||||
PRPackedBool mPropagateTransform;
|
||||
};
|
||||
|
||||
#endif // __NS_SVGPATHGEOMETRYFRAME_H__
|
||||
|
@ -102,13 +102,6 @@ nsSVGTSpanFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
||||
//----------------------------------------------------------------------
|
||||
// nsISVGChildFrame methods
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGTSpanFrame::SetMatrixPropagation(PRBool aPropagate)
|
||||
{
|
||||
mPropagateTransform = aPropagate;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGTSpanFrame::SetOverrideCTM(nsIDOMSVGMatrix *aCTM)
|
||||
{
|
||||
|
@ -81,7 +81,6 @@ public:
|
||||
}
|
||||
#endif
|
||||
// nsISVGChildFrame interface:
|
||||
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
|
||||
NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM);
|
||||
virtual already_AddRefed<nsIDOMSVGMatrix> GetOverrideCTM();
|
||||
|
||||
|
@ -212,13 +212,6 @@ nsSVGTextFrame::NotifyRedrawUnsuspended()
|
||||
return nsSVGTextFrameBase::NotifyRedrawUnsuspended();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGTextFrame::SetMatrixPropagation(PRBool aPropagate)
|
||||
{
|
||||
mPropagateTransform = aPropagate;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGTextFrame::SetOverrideCTM(nsIDOMSVGMatrix *aCTM)
|
||||
{
|
||||
@ -282,7 +275,7 @@ nsSVGTextFrame::GetBBox(nsIDOMSVGRect **_retval)
|
||||
already_AddRefed<nsIDOMSVGMatrix>
|
||||
nsSVGTextFrame::GetCanvasTM()
|
||||
{
|
||||
if (!mPropagateTransform) {
|
||||
if (!GetMatrixPropagation()) {
|
||||
nsIDOMSVGMatrix *retval;
|
||||
if (mOverrideCTM) {
|
||||
retval = mOverrideCTM;
|
||||
|
@ -51,7 +51,6 @@ protected:
|
||||
nsSVGTextFrame(nsStyleContext* aContext)
|
||||
: nsSVGTextFrameBase(aContext),
|
||||
mMetricsState(unsuspended),
|
||||
mPropagateTransform(PR_TRUE),
|
||||
mPositioningDirty(PR_TRUE) {}
|
||||
|
||||
public:
|
||||
@ -75,7 +74,6 @@ public:
|
||||
#endif
|
||||
|
||||
// nsISVGChildFrame interface:
|
||||
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
|
||||
NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM);
|
||||
virtual already_AddRefed<nsIDOMSVGMatrix> GetOverrideCTM();
|
||||
virtual void NotifySVGChanged(PRUint32 aFlags);
|
||||
@ -119,7 +117,6 @@ private:
|
||||
enum UpdateState { unsuspended, suspended };
|
||||
UpdateState mMetricsState;
|
||||
|
||||
PRPackedBool mPropagateTransform;
|
||||
PRPackedBool mPositioningDirty;
|
||||
};
|
||||
|
||||
|
@ -83,6 +83,8 @@
|
||||
#include "nsIDOMSVGUnitTypes.h"
|
||||
#include "nsSVGRect.h"
|
||||
#include "nsSVGEffects.h"
|
||||
#include "nsSVGIntegrationUtils.h"
|
||||
#include "nsSVGFilterPaintCallback.h"
|
||||
|
||||
gfxASurface *nsSVGUtils::mThebesComputationalSurface = nsnull;
|
||||
|
||||
@ -217,8 +219,14 @@ nsSVGUtils::GetFontSize(nsIContent *aContent)
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
return nsPresContext::AppUnitsToFloatCSSPixels(frame->GetStyleFont()->mSize) /
|
||||
frame->PresContext()->TextZoom();
|
||||
return GetFontSize(frame);
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGUtils::GetFontSize(nsIFrame *aFrame)
|
||||
{
|
||||
return nsPresContext::AppUnitsToFloatCSSPixels(aFrame->GetStyleFont()->mSize) /
|
||||
aFrame->PresContext()->TextZoom();
|
||||
}
|
||||
|
||||
float
|
||||
@ -230,8 +238,14 @@ nsSVGUtils::GetFontXHeight(nsIContent *aContent)
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
return GetFontXHeight(frame);
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGUtils::GetFontXHeight(nsIFrame *aFrame)
|
||||
{
|
||||
nsCOMPtr<nsIFontMetrics> fontMetrics;
|
||||
nsLayoutUtils::GetFontMetricsForFrame(frame, getter_AddRefs(fontMetrics));
|
||||
nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fontMetrics));
|
||||
|
||||
if (!fontMetrics) {
|
||||
NS_WARNING("no FontMetrics in GetFontXHeight()");
|
||||
@ -241,7 +255,7 @@ nsSVGUtils::GetFontXHeight(nsIContent *aContent)
|
||||
nscoord xHeight;
|
||||
fontMetrics->GetXHeight(xHeight);
|
||||
return nsPresContext::AppUnitsToFloatCSSPixels(xHeight) /
|
||||
frame->PresContext()->TextZoom();
|
||||
aFrame->PresContext()->TextZoom();
|
||||
}
|
||||
|
||||
void
|
||||
@ -580,7 +594,7 @@ nsSVGUtils::FindFilterInvalidation(nsIFrame *aFrame, const nsRect& aRect)
|
||||
if (property) {
|
||||
nsSVGFilterFrame *filter = property->GetFilterFrame(nsnull);
|
||||
if (filter) {
|
||||
rect = filter->GetInvalidationRegion(aFrame, rect);
|
||||
rect = filter->GetInvalidationBBox(aFrame, rect);
|
||||
}
|
||||
}
|
||||
aFrame = aFrame->GetParent();
|
||||
@ -655,7 +669,7 @@ nsSVGUtils::ComputeNormalizedHypotenuse(double aWidth, double aHeight)
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGUtils::ObjectSpace(nsIDOMSVGRect *aRect, nsSVGLength2 *aLength)
|
||||
nsSVGUtils::ObjectSpace(nsIDOMSVGRect *aRect, const nsSVGLength2 *aLength)
|
||||
{
|
||||
float fraction, axis;
|
||||
|
||||
@ -685,11 +699,17 @@ nsSVGUtils::ObjectSpace(nsIDOMSVGRect *aRect, nsSVGLength2 *aLength)
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGUtils::UserSpace(nsSVGElement *aSVGElement, nsSVGLength2 *aLength)
|
||||
nsSVGUtils::UserSpace(nsSVGElement *aSVGElement, const nsSVGLength2 *aLength)
|
||||
{
|
||||
return aLength->GetAnimValue(aSVGElement);
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGUtils::UserSpace(nsIFrame *aNonSVGContext, const nsSVGLength2 *aLength)
|
||||
{
|
||||
return aLength->GetAnimValue(aNonSVGContext);
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGUtils::TransformPoint(nsIDOMSVGMatrix *matrix,
|
||||
float *x, float *y)
|
||||
@ -851,6 +871,9 @@ nsSVGUtils::GetViewBoxTransform(float aViewportWidth, float aViewportHeight,
|
||||
already_AddRefed<nsIDOMSVGMatrix>
|
||||
nsSVGUtils::GetCanvasTM(nsIFrame *aFrame)
|
||||
{
|
||||
if (!aFrame->IsFrameOfType(nsIFrame::eSVG))
|
||||
return nsSVGIntegrationUtils::GetInitialMatrix(aFrame);
|
||||
|
||||
if (!aFrame->IsLeaf()) {
|
||||
// foreignObject is the one non-leaf svg frame that isn't a SVGContainer
|
||||
if (aFrame->GetType() == nsGkAtoms::svgForeignObjectFrame) {
|
||||
@ -917,6 +940,26 @@ nsSVGUtils::RemoveObserver(nsISupports *aObserver, nsISupports *aTarget)
|
||||
|
||||
// ************************************************************
|
||||
|
||||
class SVGPaintCallback : public nsSVGFilterPaintCallback
|
||||
{
|
||||
public:
|
||||
virtual void Paint(nsSVGRenderState *aContext, nsIFrame *aTarget,
|
||||
const nsIntRect* aDirtyRect, nsIDOMSVGMatrix *aTransform)
|
||||
{
|
||||
nsISVGChildFrame *svgChildFrame;
|
||||
CallQueryInterface(aTarget, &svgChildFrame);
|
||||
NS_ASSERTION(svgChildFrame, "Expected SVG frame here");
|
||||
|
||||
if (aTransform) {
|
||||
svgChildFrame->SetOverrideCTM(aTransform);
|
||||
svgChildFrame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
|
||||
nsISVGChildFrame::TRANSFORM_CHANGED);
|
||||
}
|
||||
|
||||
svgChildFrame->PaintSVG(aContext, const_cast<nsIntRect*>(aDirtyRect));
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
nsSVGUtils::PaintChildWithEffects(nsSVGRenderState *aContext,
|
||||
nsIntRect *aDirtyRect,
|
||||
@ -938,14 +981,21 @@ nsSVGUtils::PaintChildWithEffects(nsSVGRenderState *aContext,
|
||||
nsSVGEffects::EffectProperties effectProperties =
|
||||
nsSVGEffects::GetEffectProperties(aFrame);
|
||||
|
||||
/* Check if we need to draw anything */
|
||||
PRBool isOK = PR_TRUE;
|
||||
nsSVGFilterFrame *filterFrame = effectProperties.mFilter ?
|
||||
effectProperties.mFilter->GetFilterFrame(&isOK) : nsnull;
|
||||
|
||||
/* Check if we need to draw anything. HasValidCoveredRect only returns
|
||||
* true for path geometry and glyphs, so basically we're traversing
|
||||
* all containers and we can only skip leaves here.
|
||||
*/
|
||||
if (aDirtyRect && svgChildFrame->HasValidCoveredRect()) {
|
||||
nsRect rect = *aDirtyRect;
|
||||
rect.ScaleRoundOut(aFrame->PresContext()->AppUnitsPerDevPixel());
|
||||
if (effectProperties.mFilter) {
|
||||
if (!rect.Intersects(FindFilterInvalidation(aFrame, aFrame->GetRect())))
|
||||
if (filterFrame) {
|
||||
if (!aDirtyRect->Intersects(filterFrame->GetFilterBBox(aFrame, nsnull)))
|
||||
return;
|
||||
} else {
|
||||
nsRect rect = *aDirtyRect;
|
||||
rect.ScaleRoundOut(aFrame->PresContext()->AppUnitsPerDevPixel());
|
||||
if (!rect.Intersects(aFrame->GetRect()))
|
||||
return;
|
||||
}
|
||||
@ -971,11 +1021,8 @@ nsSVGUtils::PaintChildWithEffects(nsSVGRenderState *aContext,
|
||||
gfxContext *gfx = aContext->GetGfxContext();
|
||||
PRBool complexEffects = PR_FALSE;
|
||||
|
||||
PRBool isOK = PR_TRUE;
|
||||
nsSVGClipPathFrame *clipPathFrame = effectProperties.mClipPath ?
|
||||
effectProperties.mClipPath->GetClipPathFrame(&isOK) : nsnull;
|
||||
nsSVGFilterFrame *filterFrame = effectProperties.mFilter ?
|
||||
effectProperties.mFilter->GetFilterFrame(&isOK) : nsnull;
|
||||
nsSVGMaskFrame *maskFrame = effectProperties.mMask ?
|
||||
effectProperties.mMask->GetMaskFrame(&isOK) : nsnull;
|
||||
|
||||
@ -1002,12 +1049,13 @@ nsSVGUtils::PaintChildWithEffects(nsSVGRenderState *aContext,
|
||||
*/
|
||||
if (clipPathFrame && isTrivialClip) {
|
||||
gfx->Save();
|
||||
clipPathFrame->ClipPaint(aContext, svgChildFrame, matrix);
|
||||
clipPathFrame->ClipPaint(aContext, aFrame, matrix);
|
||||
}
|
||||
|
||||
/* Paint the child */
|
||||
if (filterFrame) {
|
||||
filterFrame->FilterPaint(aContext, svgChildFrame, aDirtyRect);
|
||||
SVGPaintCallback paintCallback;
|
||||
filterFrame->FilterPaint(aContext, aFrame, &paintCallback, aDirtyRect);
|
||||
} else {
|
||||
svgChildFrame->PaintSVG(aContext, aDirtyRect);
|
||||
}
|
||||
@ -1023,14 +1071,14 @@ nsSVGUtils::PaintChildWithEffects(nsSVGRenderState *aContext,
|
||||
gfx->PopGroupToSource();
|
||||
|
||||
nsRefPtr<gfxPattern> maskSurface =
|
||||
maskFrame ? maskFrame->ComputeMaskAlpha(aContext, svgChildFrame,
|
||||
maskFrame ? maskFrame->ComputeMaskAlpha(aContext, aFrame,
|
||||
matrix, opacity) : nsnull;
|
||||
|
||||
nsRefPtr<gfxPattern> clipMaskSurface;
|
||||
if (clipPathFrame && !isTrivialClip) {
|
||||
gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
|
||||
|
||||
nsresult rv = clipPathFrame->ClipPaint(aContext, svgChildFrame, matrix);
|
||||
nsresult rv = clipPathFrame->ClipPaint(aContext, aFrame, matrix);
|
||||
clipMaskSurface = gfx->PopGroup();
|
||||
|
||||
if (NS_SUCCEEDED(rv) && clipMaskSurface) {
|
||||
@ -1077,11 +1125,8 @@ nsSVGUtils::HitTestClip(nsIFrame *aFrame, const nsPoint &aPoint)
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsISVGChildFrame* SVGFrame;
|
||||
CallQueryInterface(aFrame, &SVGFrame);
|
||||
|
||||
nsCOMPtr<nsIDOMSVGMatrix> matrix = GetCanvasTM(aFrame);
|
||||
return clipPathFrame->ClipHitTest(SVGFrame, matrix, aPoint);
|
||||
return clipPathFrame->ClipHitTest(aFrame, matrix, aPoint);
|
||||
}
|
||||
|
||||
nsIFrame *
|
||||
@ -1327,6 +1372,58 @@ nsSVGUtils::GfxRectToIntRect(const gfxRect& aIn, nsIntRect* aOut)
|
||||
? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMSVGRect>
|
||||
nsSVGUtils::GetBBox(nsIFrame *aFrame)
|
||||
{
|
||||
nsISVGChildFrame *svg;
|
||||
CallQueryInterface(aFrame, &svg);
|
||||
if (!svg) {
|
||||
nsIDOMSVGRect *rect = nsnull;
|
||||
gfxRect r = nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(aFrame);
|
||||
NS_NewSVGRect(&rect, r);
|
||||
return rect;
|
||||
}
|
||||
|
||||
PRBool needToDisablePropagation = svg->GetMatrixPropagation();
|
||||
if (needToDisablePropagation) {
|
||||
svg->SetMatrixPropagation(PR_FALSE);
|
||||
svg->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
|
||||
nsISVGChildFrame::TRANSFORM_CHANGED);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMSVGRect> bbox;
|
||||
svg->GetBBox(getter_AddRefs(bbox));
|
||||
|
||||
if (needToDisablePropagation) {
|
||||
svg->SetMatrixPropagation(PR_TRUE);
|
||||
svg->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
|
||||
nsISVGChildFrame::TRANSFORM_CHANGED);
|
||||
}
|
||||
|
||||
return bbox.forget();
|
||||
}
|
||||
|
||||
gfxRect
|
||||
nsSVGUtils::GetRelativeRect(PRUint16 aUnits, const nsSVGLength2 *aXYWH,
|
||||
nsIDOMSVGRect *aBBox, nsIFrame *aFrame)
|
||||
{
|
||||
float x, y, width, height;
|
||||
if (aUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
|
||||
aBBox->GetX(&x);
|
||||
x += ObjectSpace(aBBox, &aXYWH[0]);
|
||||
aBBox->GetY(&y);
|
||||
y += ObjectSpace(aBBox, &aXYWH[1]);
|
||||
width = ObjectSpace(aBBox, &aXYWH[2]);
|
||||
height = ObjectSpace(aBBox, &aXYWH[3]);
|
||||
} else {
|
||||
x = nsSVGUtils::UserSpace(aFrame, &aXYWH[0]);
|
||||
y = nsSVGUtils::UserSpace(aFrame, &aXYWH[1]);
|
||||
width = nsSVGUtils::UserSpace(aFrame, &aXYWH[2]);
|
||||
height = nsSVGUtils::UserSpace(aFrame, &aXYWH[3]);
|
||||
}
|
||||
return gfxRect(x, y, width, height);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSVGUtils::CanOptimizeOpacity(nsIFrame *aFrame)
|
||||
{
|
||||
@ -1363,33 +1460,45 @@ nsSVGUtils::MaxExpansion(nsIDOMSVGMatrix *aMatrix)
|
||||
already_AddRefed<nsIDOMSVGMatrix>
|
||||
nsSVGUtils::AdjustMatrixForUnits(nsIDOMSVGMatrix *aMatrix,
|
||||
nsSVGEnum *aUnits,
|
||||
nsISVGChildFrame *aFrame)
|
||||
nsIFrame *aFrame)
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGMatrix> fini = aMatrix;
|
||||
|
||||
if (aFrame &&
|
||||
aUnits->GetAnimValue() == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
|
||||
nsCOMPtr<nsIDOMSVGRect> rect;
|
||||
nsresult rv = aFrame->GetBBox(getter_AddRefs(rect));
|
||||
float minx, miny, width, height;
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
float minx, miny, width, height;
|
||||
rect->GetX(&minx);
|
||||
rect->GetY(&miny);
|
||||
rect->GetWidth(&width);
|
||||
rect->GetHeight(&height);
|
||||
|
||||
// Correct for scaling in outersvg CTM
|
||||
nsIFrame *frame;
|
||||
CallQueryInterface(aFrame, &frame);
|
||||
nsPresContext *presCtx = frame->PresContext();
|
||||
float cssPxPerDevPx =
|
||||
presCtx->AppUnitsToFloatCSSPixels(presCtx->AppUnitsPerDevPixel());
|
||||
minx *= cssPxPerDevPx;
|
||||
miny *= cssPxPerDevPx;
|
||||
width *= cssPxPerDevPx;
|
||||
height *= cssPxPerDevPx;
|
||||
PRBool gotRect = PR_FALSE;
|
||||
if (aFrame->IsFrameOfType(nsIFrame::eSVG)) {
|
||||
nsISVGChildFrame *svgFrame;
|
||||
CallQueryInterface(aFrame, &svgFrame);
|
||||
nsCOMPtr<nsIDOMSVGRect> rect;
|
||||
svgFrame->GetBBox(getter_AddRefs(rect));
|
||||
if (rect) {
|
||||
gotRect = PR_TRUE;
|
||||
rect->GetX(&minx);
|
||||
rect->GetY(&miny);
|
||||
rect->GetWidth(&width);
|
||||
rect->GetHeight(&height);
|
||||
// Correct for scaling in outersvg CTM
|
||||
nsPresContext *presCtx = aFrame->PresContext();
|
||||
float scaleInv =
|
||||
presCtx->AppUnitsToGfxUnits(presCtx->AppUnitsPerCSSPixel());
|
||||
minx /= scaleInv;
|
||||
miny /= scaleInv;
|
||||
width /= scaleInv;
|
||||
height /= scaleInv;
|
||||
}
|
||||
} else {
|
||||
gotRect = PR_TRUE;
|
||||
gfxRect r = nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(aFrame);
|
||||
minx = r.X();
|
||||
miny = r.Y();
|
||||
width = r.Width();
|
||||
height = r.Height();
|
||||
}
|
||||
|
||||
if (gotRect) {
|
||||
nsCOMPtr<nsIDOMSVGMatrix> tmp;
|
||||
aMatrix->Translate(minx, miny, getter_AddRefs(tmp));
|
||||
tmp->ScaleNonUniform(width, height, getter_AddRefs(fini));
|
||||
@ -1444,6 +1553,8 @@ nsSVGRenderState::GetRenderingContext(nsIFrame *aFrame)
|
||||
if (!mRenderingContext) {
|
||||
nsIDeviceContext* devCtx = aFrame->PresContext()->DeviceContext();
|
||||
devCtx->CreateRenderingContextInstance(*getter_AddRefs(mRenderingContext));
|
||||
if (!mRenderingContext)
|
||||
return nsnull;
|
||||
mRenderingContext->Init(devCtx, mGfxContext);
|
||||
}
|
||||
return mRenderingContext;
|
||||
|
@ -100,6 +100,8 @@ class nsISVGChildFrame;
|
||||
/* are we the child of a non-display container? */
|
||||
#define NS_STATE_SVG_NONDISPLAY_CHILD 0x02000000
|
||||
|
||||
#define NS_STATE_SVG_PROPAGATE_TRANSFORM 0x04000000
|
||||
|
||||
/**
|
||||
* Byte offsets of channels in a native packed gfxColor or cairo image surface.
|
||||
*/
|
||||
@ -192,11 +194,12 @@ public:
|
||||
* Get a font-size (em) of an nsIContent
|
||||
*/
|
||||
static float GetFontSize(nsIContent *aContent);
|
||||
|
||||
static float GetFontSize(nsIFrame *aFrame);
|
||||
/*
|
||||
* Get an x-height of of an nsIContent
|
||||
*/
|
||||
static float GetFontXHeight(nsIContent *aContent);
|
||||
static float GetFontXHeight(nsIFrame *aFrame);
|
||||
|
||||
/*
|
||||
* Converts image data from premultipled to unpremultiplied alpha
|
||||
@ -299,13 +302,19 @@ public:
|
||||
Input: rect - bounding box
|
||||
length - length to be converted
|
||||
*/
|
||||
static float ObjectSpace(nsIDOMSVGRect *aRect, nsSVGLength2 *aLength);
|
||||
static float ObjectSpace(nsIDOMSVGRect *aRect, const nsSVGLength2 *aLength);
|
||||
|
||||
/* Computes the input length in terms of user space coordinates.
|
||||
Input: content - object to be used for determining user space
|
||||
Input: length - length to be converted
|
||||
*/
|
||||
static float UserSpace(nsSVGElement *aSVGElement, const nsSVGLength2 *aLength);
|
||||
|
||||
/* Computes the input length in terms of user space coordinates.
|
||||
Input: aFrame - object to be used for determining user space
|
||||
length - length to be converted
|
||||
*/
|
||||
static float UserSpace(nsSVGElement *aSVGElement, nsSVGLength2 *aLength);
|
||||
static float UserSpace(nsIFrame *aFrame, const nsSVGLength2 *aLength);
|
||||
|
||||
/* Tranforms point by the matrix. In/out: x,y */
|
||||
static void
|
||||
@ -337,8 +346,8 @@ public:
|
||||
nsIDOMSVGAnimatedPreserveAspectRatio *aPreserveAspectRatio,
|
||||
PRBool aIgnoreAlign = PR_FALSE);
|
||||
|
||||
/* Paint frame with SVG effects - aDirtyRect is the area being
|
||||
* redrawn, in frame offset pixel coordinates */
|
||||
/* Paint SVG frame with SVG effects - aDirtyRect is the area being
|
||||
* redrawn, in device pixel coordinates relative to the outer svg */
|
||||
static void
|
||||
PaintChildWithEffects(nsSVGRenderState *aContext,
|
||||
nsIntRect *aDirtyRect,
|
||||
@ -371,7 +380,8 @@ public:
|
||||
|
||||
/*
|
||||
* Returns the CanvasTM of the indicated frame, whether it's a
|
||||
* child or container SVG frame.
|
||||
* child SVG frame, container SVG frame, or a regular frame.
|
||||
* For regular frames, we just return an identity matrix.
|
||||
*/
|
||||
static already_AddRefed<nsIDOMSVGMatrix> GetCanvasTM(nsIFrame *aFrame);
|
||||
|
||||
@ -469,7 +479,26 @@ public:
|
||||
static already_AddRefed<nsIDOMSVGMatrix>
|
||||
AdjustMatrixForUnits(nsIDOMSVGMatrix *aMatrix,
|
||||
nsSVGEnum *aUnits,
|
||||
nsISVGChildFrame *aFrame);
|
||||
nsIFrame *aFrame);
|
||||
|
||||
/**
|
||||
* Get bounding-box for aFrame. Matrix propagation is disabled so the
|
||||
* bounding box is computed in terms of aFrame's own user space.
|
||||
*/
|
||||
static already_AddRefed<nsIDOMSVGRect>
|
||||
GetBBox(nsIFrame *aFrame);
|
||||
/**
|
||||
* Compute a rectangle in userSpaceOnUse or objectBoundingBoxUnits.
|
||||
* @param aXYWH pointer to 4 consecutive nsSVGLength2 objects containing
|
||||
* the x, y, width and height values in that order
|
||||
* @param aBBox the bounding box of the object the rect is relative to;
|
||||
* may be null if aUnits is not SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
|
||||
* @param aFrame the object in which to interpret user-space units;
|
||||
* may be null if aUnits is SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
|
||||
*/
|
||||
static gfxRect
|
||||
GetRelativeRect(PRUint16 aUnits, const nsSVGLength2 *aXYWH, nsIDOMSVGRect *aBBox,
|
||||
nsIFrame *aFrame);
|
||||
|
||||
#ifdef DEBUG
|
||||
static void
|
||||
|
Loading…
Reference in New Issue
Block a user