Bug 614732 - Implement display list based painting and hit-testing for SVG. r=roc.

--HG--
extra : rebase_source : 77e55885fbbf428008f5be787ddeb7e561c0d9bd
This commit is contained in:
Jonathan Watt 2012-07-20 14:12:29 -04:00
parent ea69f808d8
commit 2d338f4adf
30 changed files with 485 additions and 80 deletions

View File

@ -158,27 +158,19 @@ nsSVGGraphicElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
// will be called on us and our ancestors.
nsIFrame* frame =
const_cast<nsSVGGraphicElement*>(this)->GetPrimaryFrame();
if (frame && frame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) {
// No need to do anything.
} else if (aModType == nsIDOMMutationEvent::ADDITION ||
aModType == nsIDOMMutationEvent::REMOVAL) {
// In order to handle view creation/destruction and stacking context
// changes, the code in nsStyleDisplay::CalcDifference uses
// nsChangeHint_ReconstructFrame if the transform was added/removed.
// XXXSDL Currently we don't need to reconstruct SVG frames when their
// transform is set/unset since we don't currently create GFX layers for
// SVG transforms, but we will after bug 614732 is fixed. Also change the
// assertion in ApplyRenderingChangeToTree when we do that.
NS_UpdateHint(retval, nsChangeHint_UpdateOverflow);
if (!frame || (frame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) {
return retval; // no change
}
if (aModType == nsIDOMMutationEvent::ADDITION ||
aModType == nsIDOMMutationEvent::REMOVAL) {
// Reconstruct the frame tree to handle stacking context changes:
NS_UpdateHint(retval, nsChangeHint_ReconstructFrame);
} else {
NS_ABORT_IF_FALSE(aModType == nsIDOMMutationEvent::MODIFICATION,
"Unknown modification type.");
// We just assume the old and new transforms are different.
// XXXSDL Once we use GFX layers for SVG transforms, we will need to pass
// the nsChangeHint_UpdateTransformLayer hint too. Note that the
// assertion in ApplyRenderingChangeToTree will fail if that hint is
// passed on nsIDOMMutationEvent::REMOVAL though.
NS_UpdateHint(retval, nsChangeHint_UpdateOverflow);
NS_UpdateHint(retval, NS_CombineHint(nsChangeHint_UpdateOverflow,
nsChangeHint_UpdateTransformLayer));
}
}
return retval;

View File

@ -942,19 +942,21 @@ nsSVGSVGElement::ChildrenOnlyTransformChanged()
NS_STATE_SVG_NONDISPLAY_CHILD),
"Non-display SVG frames don't maintain overflow rects");
nsChangeHint changeHint;
bool hasChildrenOnlyTransform = HasViewBoxOrSyntheticViewBox() ||
(IsRoot() && (mCurrentTranslate != nsSVGTranslatePoint(0.0f, 0.0f) ||
mCurrentScale != 1.0f));
// XXXSDL Currently we don't destroy frames if
// hasChildrenOnlyTransform != mHasChildrenOnlyTransform
// but we should once we start using GFX layers for SVG transforms
// (see the comment in nsSVGGraphicElement::GetAttributeChangeHint).
nsChangeHint changeHint =
nsChangeHint(nsChangeHint_RepaintFrame |
nsChangeHint_UpdateOverflow |
nsChangeHint_ChildrenOnlyTransform);
if (hasChildrenOnlyTransform != mHasChildrenOnlyTransform) {
// Reconstruct the frame tree to handle stacking context changes:
changeHint = nsChangeHint_ReconstructFrame;
} else {
// We just assume the old and new transforms are different.
changeHint = nsChangeHint(nsChangeHint_RepaintFrame |
nsChangeHint_UpdateOverflow |
nsChangeHint_ChildrenOnlyTransform);
}
nsLayoutUtils::PostRestyleEvent(this, nsRestyleHint(0), changeHint);

View File

@ -7730,6 +7730,21 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame,
// will be invalidated by nsFrame::FinishAndStoreOverflowArea.
aFrame->InvalidateTransformLayer();
}
if (aChange & nsChangeHint_ChildrenOnlyTransform) {
// The long comment in ProcessRestyledFrames that precedes the
// |frame->GetContent()->GetPrimaryFrame()| and abort applies here too.
nsIFrame *f = aFrame->GetContent()->GetPrimaryFrame();
NS_ABORT_IF_FALSE(f->IsFrameOfType(nsIFrame::eSVG |
nsIFrame::eSVGContainer),
"Children-only transforms only expected on SVG frames");
nsIFrame* childFrame = f->GetFirstPrincipalChild();
for ( ; childFrame; childFrame = childFrame->GetNextSibling()) {
childFrame->MarkLayersActive(nsChangeHint_UpdateTransformLayer);
// Invalidate the old transformed area. The new transformed area
// will be invalidated by nsFrame::FinishAndStoreOverflowArea.
childFrame->InvalidateTransformLayer();
}
}
}
}
@ -8016,7 +8031,8 @@ nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
didReflowThisFrame = true;
}
if (hint & (nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView |
nsChangeHint_UpdateOpacityLayer | nsChangeHint_UpdateTransformLayer)) {
nsChangeHint_UpdateOpacityLayer | nsChangeHint_UpdateTransformLayer |
nsChangeHint_ChildrenOnlyTransform)) {
ApplyRenderingChangeToTree(presContext, frame, hint);
didInvalidate = true;
}

View File

@ -57,7 +57,9 @@ enum Type {
TYPE_SELECTION_OVERLAY,
TYPE_SOLID_COLOR,
TYPE_SVG_EFFECTS,
TYPE_SVG_GLYPHS,
TYPE_SVG_OUTER_SVG,
TYPE_SVG_PATH_GEOMETRY,
TYPE_TABLE_CELL_BACKGROUND,
TYPE_TABLE_CELL_SELECTION,
TYPE_TABLE_ROW_BACKGROUND,

View File

@ -33,6 +33,7 @@
#include "nsBoxFrame.h"
#include "nsViewportFrame.h"
#include "nsSVGEffects.h"
#include "nsSVGElement.h"
#include "nsSVGClipPathFrame.h"
#include "sampler.h"
@ -3295,6 +3296,19 @@ nsDisplaySVGEffects::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aContainerParameters)
{
const nsIContent* content = mFrame->GetContent();
bool hasSVGLayout = (mFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
if (hasSVGLayout) {
nsISVGChildFrame *svgChildFrame = do_QueryFrame(mFrame);
if (!svgChildFrame || !mFrame->GetContent()->IsSVG()) {
NS_ASSERTION(false, "why?");
return nsnull;
}
if (!static_cast<const nsSVGElement*>(content)->HasValidDimensions()) {
return nsnull; // The SVG spec says not to draw filters for this
}
}
float opacity = mFrame->GetStyleDisplay()->mOpacity;
if (opacity == 0.0f)
return nsnull;

View File

@ -256,10 +256,9 @@ public:
/**
* Returns true if we're currently building a display list that's
* directly or indirectly under an nsDisplayTransform or SVG
* foreignObject.
* directly or indirectly under an nsDisplayTransform.
*/
bool IsInTransform() { return mInTransform; }
bool IsInTransform() const { return mInTransform; }
/**
* Indicate whether or not we're directly or indirectly under and
* nsDisplayTransform or SVG foreignObject.

View File

@ -1451,15 +1451,28 @@ nsFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder,
return DisplayOutlineUnconditional(aBuilder, aLists);
}
inline static bool IsSVGContentWithCSSClip(const nsIFrame *aFrame)
{
// The CSS spec says that the 'clip' property only applies to absolutely
// positioned elements, whereas the SVG spec says that it applies to SVG
// elements regardless of the value of the 'position' property. Here we obey
// the CSS spec for outer-<svg> (since that's what we generally do), but
// obey the SVG spec for other SVG elements to which 'clip' applies.
nsIAtom *tag = aFrame->GetContent()->Tag();
return (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) &&
(tag == nsGkAtoms::svg || tag == nsGkAtoms::foreignObject);
}
bool
nsIFrame::GetClipPropClipRect(const nsStyleDisplay* aDisp, nsRect* aRect,
const nsSize& aSize) const
{
NS_PRECONDITION(aRect, "Must have aRect out parameter");
if (!aDisp->IsAbsolutelyPositioned() ||
!(aDisp->mClipFlags & NS_STYLE_CLIP_RECT))
if (!(aDisp->mClipFlags & NS_STYLE_CLIP_RECT) ||
!(aDisp->IsAbsolutelyPositioned() || IsSVGContentWithCSSClip(this))) {
return false;
}
*aRect = aDisp->mClip;
if (NS_STYLE_CLIP_RIGHT_AUTO & aDisp->mClipFlags) {
@ -1751,8 +1764,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
nsRect dirtyRect = aDirtyRect;
bool inTransform = aBuilder->IsInTransform();
if ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
disp->HasTransform()) {
if (IsTransformed()) {
if (aBuilder->IsForPainting() &&
nsDisplayTransform::ShouldPrerenderTransformedContent(aBuilder, this)) {
dirtyRect = GetVisualOverflowRectRelativeToSelf();
@ -1803,8 +1815,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, dirtyRect);
}
// Mark the display list items for absolutely positioned children
MarkAbsoluteFramesForDisplayList(aBuilder, dirtyRect);
// Preserve3DChildren() also guarantees that applyAbsPosClipping and usingSVGEffects are false
// We only modify the preserve-3d rect if we are the top of a preserve-3d heirarchy
if (Preserves3DChildren()) {
@ -1915,7 +1927,9 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
/* Else, if the list is non-empty and there is CSS group opacity without SVG
* effects, wrap it up in an opacity item.
*/
else if (disp->mOpacity < 1.0f && !resultList.IsEmpty()) {
else if (disp->mOpacity < 1.0f &&
!nsSVGUtils::CanOptimizeOpacity(this) &&
!resultList.IsEmpty()) {
rv = resultList.AppendNewToTop(
new (aBuilder) nsDisplayOpacity(aBuilder, this, &resultList));
if (NS_FAILED(rv))
@ -1933,8 +1947,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
* We also traverse into sublists created by nsDisplayWrapList or nsDisplayOpacity, so that
* we find all the correct children.
*/
if ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
disp->HasTransform() && !resultList.IsEmpty()) {
if (IsTransformed() && !resultList.IsEmpty()) {
if (Preserves3DChildren()) {
rv = WrapPreserve3DList(this, aBuilder, &resultList);
if (NS_FAILED(rv))
@ -1965,11 +1978,14 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
nsIFrame* child = aChild;
if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
return NS_OK;
bool isSVG = (child->GetStateBits() & NS_FRAME_SVG_LAYOUT);
// true if this is a real or pseudo stacking context
bool pseudoStackingContext =
(aFlags & DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT) != 0;
if ((aFlags & DISPLAY_CHILD_INLINE) &&
if (!isSVG &&
(aFlags & DISPLAY_CHILD_INLINE) &&
!child->IsFrameOfType(eLineParticipant)) {
// child is a non-inline frame in an inline context, i.e.,
// it acts like inline-block or inline-table. Therefore it is a
@ -2020,7 +2036,6 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
}
}
// Mark the display list items for absolutely positioned children
child->MarkAbsoluteFramesForDisplayList(aBuilder, dirty);
if (childType != nsGkAtoms::placeholderFrame &&
@ -2070,8 +2085,10 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|| child->IsTransformed()
|| nsSVGIntegrationUtils::UsingEffectsForFrame(child);
bool isPositioned = disp->IsPositioned();
if (isVisuallyAtomic || isPositioned || disp->IsFloating() ||
bool isPositioned = !isSVG && disp->IsPositioned();
if (isVisuallyAtomic || isPositioned || (!isSVG && disp->IsFloating()) ||
((disp->mClipFlags & NS_STYLE_CLIP_RECT) &&
IsSVGContentWithCSSClip(this)) ||
(aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
// If you change this, also change IsPseudoStackingContextFromStyle()
pseudoStackingContext = true;
@ -2178,16 +2195,20 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
// Make sure the root of a fixed position frame sub-tree gets the
// correct displaylist item type.
nsDisplayItem* item;
if (!child->GetParent()->GetParent() &&
if (!isSVG && !child->GetParent()->GetParent() &&
disp->mPosition == NS_STYLE_POSITION_FIXED) {
item = new (aBuilder) nsDisplayFixedPosition(aBuilder, child, &list);
} else {
item = new (aBuilder) nsDisplayWrapList(aBuilder, child, &list);
}
rv = aLists.PositionedDescendants()->AppendNewToTop(item);
if (isSVG) {
rv = aLists.Content()->AppendNewToTop(item);
} else {
rv = aLists.PositionedDescendants()->AppendNewToTop(item);
}
NS_ENSURE_SUCCESS(rv, rv);
}
} else if (disp->IsFloating()) {
} else if (!isSVG && disp->IsFloating()) {
if (!list.IsEmpty()) {
rv = aLists.Floats()->AppendNewToTop(new (aBuilder)
nsDisplayWrapList(aBuilder, child, &list));

View File

@ -571,11 +571,18 @@ public:
nsIAtom* type = aFrame->GetType();
if (type == nsGkAtoms::tableFrame ||
type == nsGkAtoms::tableCellFrame ||
type == nsGkAtoms::bcTableCellFrame) {
type == nsGkAtoms::bcTableCellFrame ||
type == nsGkAtoms::svgOuterSVGFrame ||
type == nsGkAtoms::svgInnerSVGFrame ||
type == nsGkAtoms::svgForeignObjectFrame) {
return true;
}
}
if ((aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
return false;
}
// If we're paginated and a block, and have NS_BLOCK_CLIP_PAGINATED_OVERFLOW
// set, then we want to clip our overflow.
return

View File

@ -2476,7 +2476,8 @@ public:
/**
* Determines whether this frame is a pseudo stacking context, looking
* only as style --- i.e., assuming that it's in-flow and not a replaced
* element.
* element and not an SVG element.
* XXX maybe check IsTransformed()?
*/
bool IsPseudoStackingContextFromStyle() {
const nsStyleDisplay* disp = GetStyleDisplay();

View File

@ -79,7 +79,7 @@ fails == filter-marked-line-01.svg pass.svg # bug 477704
== feDisplacementMap-colour-01.svg feDisplacementMap-colour-01-ref.svg
== feDisplacementMap-scale-01.svg pass.svg
== feDistantLight-filterRes-01.svg feDistantLight-filterRes-01-ref.svg
fuzzy-if(cocoaWidget&&layersGPUAccelerated,2,93) == feDistantLight-filterRes-01.svg feDistantLight-filterRes-01-ref.svg
== feMorphology-radius-negative-01.svg pass.svg
== feMorphology-radius-negative-02.svg pass.svg

View File

@ -4,7 +4,7 @@
== image-filter-01.svg image-filter-01-ref.svg
== image-load-01.svg ../pass.svg
== image-opacity-01.svg image-opacity-01-ref.svg
== image-opacity-02.svg image-opacity-02-ref.svg
fuzzy-if(Android,4,34) == image-opacity-02.svg image-opacity-02-ref.svg # Bug 776039 for Android
== image-rotate-01.svg image-rotate-01-ref.svg
== image-rotate-02a.svg image-rotate-02-ref.svg
== image-rotate-02b.svg image-rotate-02-ref.svg

View File

@ -96,8 +96,8 @@ fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu),1,2) == clipPath-and-shape-re
== dynamic-small-object-scaled-up-02.svg pass.svg
== dynamic-switch-01.svg pass.svg
== dynamic-text-01.svg dynamic-text-01-ref.svg
== dynamic-text-02.svg dynamic-text-02-ref.svg
== dynamic-text-03.svg dynamic-text-03-ref.svg
fuzzy-if(d2d&&layersGPUAccelerated,2,12739) == dynamic-text-02.svg dynamic-text-02-ref.svg # bug 776038 for Win7
fuzzy-if(d2d&&layersGPUAccelerated,2,10539) == dynamic-text-03.svg dynamic-text-03-ref.svg # bug 776038 for Win7
random-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) == dynamic-text-04.svg dynamic-text-04-ref.svg # bug 421587 for WinXP
== dynamic-text-05.svg pass.svg
== dynamic-text-06.svg pass.svg

View File

@ -230,7 +230,7 @@ random == anim-text-x-y-dx-dy-01.svg anim-text-x-y-dx-dy-01-ref.svg # bug 579588
== anim-pattern-attr-presence-01.svg anim-pattern-attr-presence-01-ref.svg
fails == anim-pattern-attr-presence-02.svg anim-pattern-attr-presence-02-ref.svg
# ^ bug 621651
== anim-gradient-attr-presence-01.svg anim-gradient-attr-presence-01-ref.svg
fuzzy-if(cocoaWidget&&layersGPUAccelerated,1,2) == anim-gradient-attr-presence-01.svg anim-gradient-attr-presence-01-ref.svg
== api-sanity-1.svg lime.svg

View File

@ -93,6 +93,17 @@ nsSVGDisplayContainerFrame::Init(nsIContent* aContent,
return rv;
}
NS_IMETHODIMP
nsSVGDisplayContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists)
{
if (!static_cast<const nsSVGElement*>(mContent)->HasValidDimensions()) {
return NS_OK;
}
return BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists);
}
NS_IMETHODIMP
nsSVGDisplayContainerFrame::InsertFrames(ChildListID aListID,
nsIFrame* aPrevFrame,
@ -167,8 +178,7 @@ nsSVGDisplayContainerFrame::IsSVGTransformed(gfxMatrix *aOwnTransform,
}
nsSVGElement *content = static_cast<nsSVGElement*>(mContent);
const SVGAnimatedTransformList *list = content->GetAnimatedTransformList();
if ((list && !list->GetAnimValue().IsEmpty()) ||
if (content->GetAnimatedTransformList() ||
content->GetAnimateMotionTransform()) {
if (aOwnTransform) {
*aOwnTransform = content->PrependLocalTransformsTo(gfxMatrix(),
@ -186,6 +196,11 @@ NS_IMETHODIMP
nsSVGDisplayContainerFrame::PaintSVG(nsRenderingContext* aContext,
const nsIntRect *aDirtyRect)
{
NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
(mState & NS_STATE_SVG_NONDISPLAY_CHILD),
"If display lists are enabled, only painting of non-display "
"SVG should take this code path");
const nsStyleDisplay *display = mStyleContext->GetStyleDisplay();
if (display->mOpacity == 0.0)
return NS_OK;
@ -201,6 +216,10 @@ nsSVGDisplayContainerFrame::PaintSVG(nsRenderingContext* aContext,
NS_IMETHODIMP_(nsIFrame*)
nsSVGDisplayContainerFrame::GetFrameForPoint(const nsPoint &aPoint)
{
NS_ASSERTION(!NS_SVGDisplayListHitTestingEnabled() ||
(mState & NS_STATE_SVG_NONDISPLAY_CHILD),
"If display lists are enabled, only hit-testing of a "
"clipPath's contents should take this code path");
return nsSVGUtils::HitTestChildren(this, aPoint);
}

View File

@ -118,6 +118,10 @@ public:
nsIFrame* aParent,
nsIFrame* aPrevInFlow);
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists);
virtual bool IsSVGTransformed(gfxMatrix *aOwnTransform = nsnull,
gfxMatrix *aFromParentTransform = nsnull) const;

View File

@ -167,6 +167,17 @@ nsSVGForeignObjectFrame::Reflow(nsPresContext* aPresContext,
return NS_OK;
}
NS_IMETHODIMP
nsSVGForeignObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists)
{
if (!static_cast<const nsSVGElement*>(mContent)->HasValidDimensions()) {
return NS_OK;
}
return BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists);
}
void
nsSVGForeignObjectFrame::InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY,
@ -198,6 +209,31 @@ nsSVGForeignObjectFrame::InvalidateInternal(const nsRect& aDamageRect,
region->Or(*region, aDamageRect + nsPoint(aX, aY));
}
bool
nsSVGForeignObjectFrame::IsSVGTransformed(gfxMatrix *aOwnTransform,
gfxMatrix *aFromParentTransform) const
{
bool foundTransform = false;
// Check if our parent has children-only transforms:
nsIFrame *parent = GetParent();
if (parent &&
parent->IsFrameOfType(nsIFrame::eSVG | nsIFrame::eSVGContainer)) {
foundTransform = static_cast<nsSVGContainerFrame*>(parent)->
HasChildrenOnlyTransform(aFromParentTransform);
}
nsSVGElement *content = static_cast<nsSVGElement*>(mContent);
if (content->GetAnimatedTransformList()) {
if (aOwnTransform) {
*aOwnTransform = content->PrependLocalTransformsTo(gfxMatrix(),
nsSVGElement::eUserSpaceToParent);
}
foundTransform = true;
}
return foundTransform;
}
/**
* Returns the app unit canvas bounds of a userspace rect.
@ -218,6 +254,11 @@ NS_IMETHODIMP
nsSVGForeignObjectFrame::PaintSVG(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect)
{
NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
(mState & NS_STATE_SVG_NONDISPLAY_CHILD),
"If display lists are enabled, only painting of non-display "
"SVG should take this code path");
if (IsDisabled())
return NS_OK;
@ -236,6 +277,9 @@ nsSVGForeignObjectFrame::PaintSVG(nsRenderingContext *aContext,
/* Check if we need to draw anything. */
if (aDirtyRect) {
NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
(mState & NS_STATE_SVG_NONDISPLAY_CHILD),
"Display lists handle dirty rect intersection test");
// Transform the dirty rect into app units in our userspace.
gfxMatrix invmatrix = canvasTM;
invmatrix.Invert();
@ -297,6 +341,11 @@ nsSVGForeignObjectFrame::PaintSVG(nsRenderingContext *aContext,
NS_IMETHODIMP_(nsIFrame*)
nsSVGForeignObjectFrame::GetFrameForPoint(const nsPoint &aPoint)
{
NS_ASSERTION(!NS_SVGDisplayListHitTestingEnabled() ||
(mState & NS_STATE_SVG_NONDISPLAY_CHILD),
"If display lists are enabled, only hit-testing of a "
"clipPath's contents should take this code path");
if (IsDisabled() || (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD))
return nsnull;

View File

@ -49,6 +49,10 @@ public:
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists);
/**
* Get the "type" of the frame
*
@ -66,6 +70,9 @@ public:
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRUint32 aFlags);
virtual bool IsSVGTransformed(gfxMatrix *aOwnTransform,
gfxMatrix *aFromParentTransform) const;
#ifdef DEBUG
NS_IMETHOD GetFrameName(nsAString& aResult) const
{

View File

@ -13,6 +13,7 @@
#include "gfxPlatform.h"
#include "mozilla/LookAndFeel.h"
#include "nsBidiPresUtils.h"
#include "nsDisplayList.h"
#include "nsDOMError.h"
#include "nsIDOMSVGRect.h"
#include "nsRenderingContext.h"
@ -198,6 +199,59 @@ private:
bool mInError;
};
class nsDisplaySVGGlyphs : public nsDisplayItem {
public:
nsDisplaySVGGlyphs(nsDisplayListBuilder* aBuilder,
nsSVGGlyphFrame* aFrame)
: nsDisplayItem(aBuilder, aFrame)
{
MOZ_COUNT_CTOR(nsDisplaySVGGlyphs);
NS_ABORT_IF_FALSE(aFrame, "Must have a frame!");
}
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplaySVGGlyphs() {
MOZ_COUNT_DTOR(nsDisplaySVGGlyphs);
}
#endif
NS_DISPLAY_DECL_NAME("nsDisplaySVGGlyphs", TYPE_SVG_GLYPHS)
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames);
virtual void Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx);
};
void
nsDisplaySVGGlyphs::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
{
nsSVGGlyphFrame *frame = static_cast<nsSVGGlyphFrame*>(mFrame);
nsPoint pointRelativeToReferenceFrame = aRect.Center();
// ToReferenceFrame() includes frame->GetPosition(), our user space position.
nsPoint userSpacePt = pointRelativeToReferenceFrame -
(ToReferenceFrame() - frame->GetPosition());
if (frame->GetFrameForPoint(userSpacePt)) {
aOutFrames->AppendElement(frame);
}
}
void
nsDisplaySVGGlyphs::Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx)
{
// ToReferenceFrame includes our mRect offset, but painting takes
// account of that too. To avoid double counting, we subtract that
// here.
nsPoint offset = ToReferenceFrame() - mFrame->GetPosition();
aCtx->PushState();
aCtx->Translate(offset);
static_cast<nsSVGGlyphFrame*>(mFrame)->PaintSVG(aCtx, nsnull);
aCtx->PopState();
}
//----------------------------------------------------------------------
// Implementation
@ -295,6 +349,18 @@ nsSVGGlyphFrame::GetType() const
return nsGkAtoms::svgGlyphFrame;
}
NS_IMETHODIMP
nsSVGGlyphFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists)
{
if (GetStyleFont()->mFont.size <= 0) {
return NS_OK;
}
return aLists.Content()->AppendNewToTop(
new (aBuilder) nsDisplaySVGGlyphs(aBuilder, this));
}
//----------------------------------------------------------------------
// nsISVGChildFrame methods

View File

@ -15,6 +15,7 @@
class CharacterIterator;
class gfxContext;
class nsDisplaySVGGlyphs;
class nsIDOMSVGRect;
class nsRenderingContext;
class nsSVGGlyphFrame;
@ -144,6 +145,10 @@ public:
}
#endif
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists);
// nsISVGChildFrame interface:
// These four always use the global transform, even if NS_STATE_NONDISPLAY_CHILD
NS_IMETHOD PaintSVG(nsRenderingContext *aContext,

View File

@ -341,6 +341,9 @@ nsSVGImageFrame::PaintSVG(nsRenderingContext *aContext,
nscoord appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel();
nsRect dirtyRect; // only used if aDirtyRect is non-null
if (aDirtyRect) {
NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
(mState & NS_STATE_SVG_NONDISPLAY_CHILD),
"Display lists handle dirty rect intersection test");
dirtyRect = aDirtyRect->ToAppUnits(appUnitsPerDevPx);
// Adjust dirtyRect to match our local coordinate system.
nsRect rootRect =

View File

@ -57,6 +57,11 @@ NS_IMETHODIMP
nsSVGInnerSVGFrame::PaintSVG(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect)
{
NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
(mState & NS_STATE_SVG_NONDISPLAY_CHILD),
"If display lists are enabled, only painting of non-display "
"SVG should take this code path");
gfxContextAutoSaveRestore autoSR;
if (GetStyleDisplay()->IsScrollableOverflow()) {
@ -211,6 +216,11 @@ nsSVGInnerSVGFrame::AttributeChanged(PRInt32 aNameSpaceID,
NS_IMETHODIMP_(nsIFrame*)
nsSVGInnerSVGFrame::GetFrameForPoint(const nsPoint &aPoint)
{
NS_ASSERTION(!NS_SVGDisplayListHitTestingEnabled() ||
(mState & NS_STATE_SVG_NONDISPLAY_CHILD),
"If display lists are enabled, only hit-testing of non-display "
"SVG should take this code path");
if (GetStyleDisplay()->IsScrollableOverflow()) {
nsSVGElement *content = static_cast<nsSVGElement*>(mContent);
nsSVGContainerFrame *parent = static_cast<nsSVGContainerFrame*>(mParent);

View File

@ -13,6 +13,7 @@
#include "nsRenderingContext.h"
#include "nsSVGClipPathFrame.h"
#include "nsSVGEffects.h"
#include "nsSVGElement.h"
#include "nsSVGFilterFrame.h"
#include "nsSVGFilterPaintCallback.h"
#include "nsSVGMaskFrame.h"
@ -143,9 +144,10 @@ GetPreEffectsVisualOverflowUnion(nsIFrame* aFirstContinuation,
bool
nsSVGIntegrationUtils::UsingEffectsForFrame(const nsIFrame* aFrame)
{
if (aFrame->IsFrameOfType(nsIFrame::eSVG)) {
return false;
}
// Even when SVG display lists are disabled, returning true for SVG frames
// does not adversely affect any of our callers. Therefore we don't bother
// checking the SDL prefs here, since we don't know if we're being called for
// painting or hit-testing anyway.
const nsStyleSVGReset *style = aFrame->GetStyleSVGReset();
return (style->mFilter || style->mClipPath || style->mMask);
}
@ -153,6 +155,13 @@ nsSVGIntegrationUtils::UsingEffectsForFrame(const nsIFrame* aFrame)
/* static */ nsPoint
nsSVGIntegrationUtils::GetOffsetToUserSpace(nsIFrame* aFrame)
{
if ((aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
// Do NOT call GetAllInFlowRectsUnion for SVG - it will get the
// covered region relative to the nsSVGOuterSVGFrame, which is absolutely
// not what we want. SVG frames are always in user space, so they have
// no offset adjustment to make.
return nsPoint();
}
// We could allow aFrame to be any continuation, but since that would require
// a GetPrevContinuation() virtual call and conditional returns, and since
// all our current consumers always pass in the first continuation, we don't
@ -375,7 +384,10 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx,
{
#ifdef DEBUG
nsISVGChildFrame *svgChildFrame = do_QueryFrame(aFrame);
NS_ASSERTION(!svgChildFrame, "Should never be called on an SVG frame");
NS_ASSERTION(!svgChildFrame ||
(NS_SVGDisplayListPaintingEnabled() &&
!(aFrame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)),
"Should not use nsSVGIntegrationUtils on this SVG frame");
#endif
/* SVG defines the following rendering model:
@ -392,10 +404,27 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx,
* + Merge opacity and masking if both used together.
*/
const nsIContent* content = aFrame->GetContent();
bool hasSVGLayout = (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
if (hasSVGLayout) {
nsISVGChildFrame *svgChildFrame = do_QueryFrame(aFrame);
if (!svgChildFrame || !aFrame->GetContent()->IsSVG()) {
NS_ASSERTION(false, "why?");
return;
}
if (!static_cast<const nsSVGElement*>(content)->HasValidDimensions()) {
return; // The SVG spec says not to draw _anything_
}
}
float opacity = aFrame->GetStyleDisplay()->mOpacity;
if (opacity == 0.0f) {
return;
}
if (opacity != 1.0f &&
hasSVGLayout && nsSVGUtils::CanOptimizeOpacity(aFrame)) {
opacity = 1.0f;
}
/* Properties are added lazily and may have been removed by a restyle,
so make sure all applicable ones are set again. */
@ -420,10 +449,17 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx,
PRInt32 appUnitsPerDevPixel =
aFrame->PresContext()->AppUnitsPerDevPixel();
nsPoint firstFrameOffset = GetOffsetToUserSpace(firstFrame);
nsPoint offset = (aBuilder->ToReferenceFrame(firstFrame) - firstFrameOffset).
ToNearestPixels(appUnitsPerDevPixel).
ToAppUnits(appUnitsPerDevPixel);
aCtx->Translate(offset);
nsPoint offset = aBuilder->ToReferenceFrame(firstFrame) - firstFrameOffset;
nsPoint offsetWithoutSVGGeomFramePos = offset;
nsPoint svgGeomFramePos;
if (aFrame->IsFrameOfType(nsIFrame::eSVGGeometry)) {
// SVG leaf frames apply their offset themselves, we need to unapply it at
// various points below to prevent it being double counted.
svgGeomFramePos = aFrame->GetPosition();
offsetWithoutSVGGeomFramePos -= svgGeomFramePos;
}
aCtx->Translate(offsetWithoutSVGGeomFramePos);
gfxMatrix cssPxToDevPxMatrix = GetCSSPxToDevPxMatrix(aFrame);
@ -433,7 +469,7 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx,
if (opacity != 1.0f || maskFrame || (clipPathFrame && !isTrivialClip)) {
complexEffects = true;
gfx->Save();
aCtx->IntersectClip(aFrame->GetVisualOverflowRect());
aCtx->IntersectClip(aFrame->GetVisualOverflowRect() + svgGeomFramePos);
gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
}
@ -448,13 +484,13 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx,
/* Paint the child */
if (filterFrame) {
RegularFramePaintCallback callback(aBuilder, aLayerManager,
offset);
offsetWithoutSVGGeomFramePos);
nsRect dirtyRect = aDirtyRect - offset;
filterFrame->PaintFilteredFrame(aCtx, aFrame, &callback, &dirtyRect);
} else {
gfx->SetMatrix(matrixAutoSaveRestore.Matrix());
aLayerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer, aBuilder);
aCtx->Translate(offset);
aCtx->Translate(offsetWithoutSVGGeomFramePos);
}
if (clipPathFrame && isTrivialClip) {

View File

@ -28,7 +28,7 @@ class nsSVGIntegrationUtils MOZ_FINAL
{
public:
/**
* Returns true if a non-SVG frame has SVG effects.
* Returns true if SVG effects are currently applied to this frame.
*/
static bool
UsingEffectsForFrame(const nsIFrame* aFrame);

View File

@ -396,6 +396,17 @@ nsSVGOuterSVGFrame::Reflow(nsPresContext* aPresContext,
NS_ASSERTION(!GetPrevInFlow(), "SVG can't currently be broken across pages.");
nsSVGSVGElement *svgElem = static_cast<nsSVGSVGElement*>(mContent);
nsSVGOuterSVGAnonChildFrame *anonKid =
static_cast<nsSVGOuterSVGAnonChildFrame*>(GetFirstPrincipalChild());
if (mState & NS_FRAME_FIRST_REFLOW) {
// Initialize
svgElem->mHasChildrenOnlyTransform =
anonKid->HasChildrenOnlyTransform(nsnull);
}
// If our SVG viewport has changed, update our content and notify.
// http://www.w3.org/TR/SVG11/coords.html#ViewportSpace
@ -403,8 +414,6 @@ nsSVGOuterSVGFrame::Reflow(nsPresContext* aPresContext,
nsPresContext::AppUnitsToFloatCSSPixels(aReflowState.ComputedWidth()),
nsPresContext::AppUnitsToFloatCSSPixels(aReflowState.ComputedHeight()));
nsSVGSVGElement *svgElem = static_cast<nsSVGSVGElement*>(mContent);
PRUint32 changeBits = 0;
if (newViewportSize != svgElem->GetViewportSize()) {
changeBits |= COORD_CONTEXT_CHANGED;
@ -419,9 +428,6 @@ nsSVGOuterSVGFrame::Reflow(nsPresContext* aPresContext,
NotifyViewportOrTransformChanged(changeBits);
}
nsSVGOuterSVGAnonChildFrame *anonKid =
static_cast<nsSVGOuterSVGAnonChildFrame*>(GetFirstPrincipalChild());
if (!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) {
// Now that we've marked the necessary children as dirty, call
// UpdateBounds() on them:
@ -469,6 +475,9 @@ nsSVGOuterSVGFrame::DidReflow(nsPresContext* aPresContext,
//----------------------------------------------------------------------
// container methods
/**
* Used to paint/hit-test SVG when SVG display lists are disabled.
*/
class nsDisplayOuterSVG : public nsDisplayItem {
public:
nsDisplayOuterSVG(nsDisplayListBuilder* aBuilder,
@ -630,9 +639,20 @@ nsSVGOuterSVGFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
nsDisplayList childItems;
rv = childItems.AppendNewToTop(
new (aBuilder) nsDisplayOuterSVG(aBuilder, this));
NS_ENSURE_SUCCESS(rv, rv);
if ((aBuilder->IsForEventDelivery() &&
NS_SVGDisplayListHitTestingEnabled()) ||
NS_SVGDisplayListPaintingEnabled()) {
nsDisplayList *nonContentList = &childItems;
nsDisplayListSet set(nonContentList, nonContentList, nonContentList,
&childItems, nonContentList, nonContentList);
nsresult rv =
BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, set);
NS_ENSURE_SUCCESS(rv, rv);
} else {
rv = childItems.AppendNewToTop(
new (aBuilder) nsDisplayOuterSVG(aBuilder, this));
NS_ENSURE_SUCCESS(rv, rv);
}
// Clip to our _content_ box:
nsRect clipRect =

View File

@ -9,6 +9,7 @@
// Keep others in (case-insensitive) order:
#include "gfxContext.h"
#include "gfxPlatform.h"
#include "nsDisplayList.h"
#include "nsGkAtoms.h"
#include "nsRenderingContext.h"
#include "nsSVGEffects.h"
@ -40,6 +41,61 @@ NS_QUERYFRAME_HEAD(nsSVGPathGeometryFrame)
NS_QUERYFRAME_ENTRY(nsISVGChildFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsSVGPathGeometryFrameBase)
//----------------------------------------------------------------------
// Display list item:
class nsDisplaySVGPathGeometry : public nsDisplayItem {
public:
nsDisplaySVGPathGeometry(nsDisplayListBuilder* aBuilder,
nsSVGPathGeometryFrame* aFrame)
: nsDisplayItem(aBuilder, aFrame)
{
MOZ_COUNT_CTOR(nsDisplaySVGPathGeometry);
NS_ABORT_IF_FALSE(aFrame, "Must have a frame!");
}
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplaySVGPathGeometry() {
MOZ_COUNT_DTOR(nsDisplaySVGPathGeometry);
}
#endif
NS_DISPLAY_DECL_NAME("nsDisplaySVGPathGeometry", TYPE_SVG_PATH_GEOMETRY)
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames);
virtual void Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx);
};
void
nsDisplaySVGPathGeometry::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
{
nsSVGPathGeometryFrame *frame = static_cast<nsSVGPathGeometryFrame*>(mFrame);
nsPoint pointRelativeToReferenceFrame = aRect.Center();
// ToReferenceFrame() includes frame->GetPosition(), our user space position.
nsPoint userSpacePt = pointRelativeToReferenceFrame -
(ToReferenceFrame() - frame->GetPosition());
if (frame->GetFrameForPoint(userSpacePt)) {
aOutFrames->AppendElement(frame);
}
}
void
nsDisplaySVGPathGeometry::Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx)
{
// ToReferenceFrame includes our mRect offset, but painting takes
// account of that too. To avoid double counting, we subtract that
// here.
nsPoint offset = ToReferenceFrame() - mFrame->GetPosition();
aCtx->PushState();
aCtx->Translate(offset);
static_cast<nsSVGPathGeometryFrame*>(mFrame)->PaintSVG(aCtx, nsnull);
aCtx->PopState();
}
//----------------------------------------------------------------------
// nsIFrame methods
@ -92,8 +148,7 @@ nsSVGPathGeometryFrame::IsSVGTransformed(gfxMatrix *aOwnTransform,
}
nsSVGElement *content = static_cast<nsSVGElement*>(mContent);
const SVGAnimatedTransformList *list = content->GetAnimatedTransformList();
if ((list && !list->GetAnimValue().IsEmpty()) ||
if (content->GetAnimatedTransformList() ||
content->GetAnimateMotionTransform()) {
if (aOwnTransform) {
*aOwnTransform = content->PrependLocalTransformsTo(gfxMatrix(),
@ -104,6 +159,18 @@ nsSVGPathGeometryFrame::IsSVGTransformed(gfxMatrix *aOwnTransform,
return foundTransform;
}
NS_IMETHODIMP
nsSVGPathGeometryFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists)
{
if (!static_cast<const nsSVGElement*>(mContent)->HasValidDimensions()) {
return NS_OK;
}
return aLists.Content()->AppendNewToTop(
new (aBuilder) nsDisplaySVGPathGeometry(aBuilder, this));
}
//----------------------------------------------------------------------
// nsISVGChildFrame methods
@ -154,6 +221,9 @@ NS_IMETHODIMP_(nsIFrame*)
nsSVGPathGeometryFrame::GetFrameForPoint(const nsPoint &aPoint)
{
gfxMatrix canvasTM = GetCanvasTM(FOR_HIT_TESTING);
if (canvasTM.IsSingular()) {
return nsnull;
}
PRUint16 fillRule, hitTestFlags;
if (GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD) {
hitTestFlags = SVG_HIT_TEST_FILL;
@ -162,9 +232,6 @@ nsSVGPathGeometryFrame::GetFrameForPoint(const nsPoint &aPoint)
hitTestFlags = GetHitTestFlags();
// XXX once bug 614732 is fixed, aPoint won't need any conversion in order
// to compare it with mRect.
if (canvasTM.IsSingular()) {
return nsnull;
}
nsPoint point =
nsSVGUtils::TransformOuterSVGPointToChildFrame(aPoint, canvasTM, PresContext());
if (!hitTestFlags || ((hitTestFlags & SVG_HIT_TEST_CHECK_MRECT) &&

View File

@ -17,6 +17,7 @@
#include "nsSVGUtils.h"
class gfxContext;
class nsDisplaySVGPathGeometry;
class nsIAtom;
class nsIFrame;
class nsIPresShell;
@ -34,6 +35,9 @@ class nsSVGPathGeometryFrame : public nsSVGPathGeometryFrameBase,
{
friend nsIFrame*
NS_NewSVGPathGeometryFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
friend class nsDisplaySVGPathGeometry;
protected:
nsSVGPathGeometryFrame(nsStyleContext* aContext)
: nsSVGPathGeometryFrameBase(aContext)
@ -69,6 +73,10 @@ public:
}
#endif
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists);
// nsSVGGeometryFrame methods
gfxMatrix GetCanvasTM(PRUint32 aFor);

View File

@ -46,6 +46,10 @@ public:
}
#endif
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists);
// nsISVGChildFrame interface:
NS_IMETHOD PaintSVG(nsRenderingContext* aContext, const nsIntRect *aDirtyRect);
NS_IMETHODIMP_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint);
@ -88,10 +92,27 @@ nsSVGSwitchFrame::GetType() const
return nsGkAtoms::svgSwitchFrame;
}
NS_IMETHODIMP
nsSVGSwitchFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists)
{
nsIFrame* kid = GetActiveChildFrame();
if (kid) {
return BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
}
return NS_OK;
}
NS_IMETHODIMP
nsSVGSwitchFrame::PaintSVG(nsRenderingContext* aContext,
const nsIntRect *aDirtyRect)
{
NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
(mState & NS_STATE_SVG_NONDISPLAY_CHILD),
"If display lists are enabled, only painting of non-display "
"SVG should take this code path");
const nsStyleDisplay *display = mStyleContext->GetStyleDisplay();
if (display->mOpacity == 0.0)
return NS_OK;
@ -107,6 +128,11 @@ nsSVGSwitchFrame::PaintSVG(nsRenderingContext* aContext,
NS_IMETHODIMP_(nsIFrame*)
nsSVGSwitchFrame::GetFrameForPoint(const nsPoint &aPoint)
{
NS_ASSERTION(!NS_SVGDisplayListHitTestingEnabled() ||
(mState & NS_STATE_SVG_NONDISPLAY_CHILD),
"If display lists are enabled, only hit-testing of non-display "
"SVG should take this code path");
nsIFrame *kid = GetActiveChildFrame();
if (kid) {
nsISVGChildFrame* svgFrame = do_QueryFrame(kid);

View File

@ -76,6 +76,15 @@ nsSVGTextFrame::GetType() const
return nsGkAtoms::svgTextFrame;
}
NS_IMETHODIMP
nsSVGTextFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists)
{
UpdateGlyphPositioning(true);
return nsSVGTextFrameBase::BuildDisplayList(aBuilder, aDirtyRect, aLists);
}
//----------------------------------------------------------------------
// nsSVGTextContainerFrame
PRUint32
@ -197,6 +206,11 @@ NS_IMETHODIMP
nsSVGTextFrame::PaintSVG(nsRenderingContext* aContext,
const nsIntRect *aDirtyRect)
{
NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
(mState & NS_STATE_SVG_NONDISPLAY_CHILD),
"If display lists are enabled, only painting of non-display "
"SVG should take this code path");
UpdateGlyphPositioning(true);
return nsSVGTextFrameBase::PaintSVG(aContext, aDirtyRect);
@ -205,6 +219,11 @@ nsSVGTextFrame::PaintSVG(nsRenderingContext* aContext,
NS_IMETHODIMP_(nsIFrame*)
nsSVGTextFrame::GetFrameForPoint(const nsPoint &aPoint)
{
NS_ASSERTION(!NS_SVGDisplayListHitTestingEnabled() ||
(mState & NS_STATE_SVG_NONDISPLAY_CHILD),
"If display lists are enabled, only hit-testing of non-display "
"SVG should take this code path");
UpdateGlyphPositioning(true);
return nsSVGTextFrameBase::GetFrameForPoint(aPoint);

View File

@ -51,6 +51,10 @@ public:
}
#endif
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists);
// nsISVGChildFrame interface:
virtual void NotifySVGChanged(PRUint32 aFlags);
// Override these four to ensure that UpdateGlyphPositioning is called

View File

@ -1118,6 +1118,11 @@ nsSVGUtils::PaintFrameWithEffects(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect,
nsIFrame *aFrame)
{
NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
(aFrame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD),
"If display lists are enabled, only painting of non-display "
"SVG should take this code path");
nsISVGChildFrame *svgChildFrame = do_QueryFrame(aFrame);
if (!svgChildFrame)
return;
@ -1618,6 +1623,9 @@ nsSVGUtils::GetRelativeRect(PRUint16 aUnits, const nsSVGLength2 *aXYWH,
bool
nsSVGUtils::CanOptimizeOpacity(nsIFrame *aFrame)
{
if (!(aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
return false;
}
nsIAtom *type = aFrame->GetType();
if (type != nsGkAtoms::svgImageFrame &&
type != nsGkAtoms::svgPathGeometryFrame) {