2007-03-22 10:30:00 -07:00
|
|
|
/* -*- 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
|
|
|
|
* Crocodile Clips Ltd..
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2001
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
|
|
|
|
*
|
|
|
|
* 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 "nsSVGForeignObjectFrame.h"
|
|
|
|
|
|
|
|
#include "nsIDOMSVGForeignObjectElem.h"
|
|
|
|
#include "nsIDOMSVGSVGElement.h"
|
|
|
|
#include "nsSVGOuterSVGFrame.h"
|
|
|
|
#include "nsRegion.h"
|
|
|
|
#include "nsGkAtoms.h"
|
|
|
|
#include "nsLayoutUtils.h"
|
|
|
|
#include "nsSVGUtils.h"
|
|
|
|
#include "nsIURI.h"
|
|
|
|
#include "nsSVGRect.h"
|
|
|
|
#include "nsSVGMatrix.h"
|
|
|
|
#include "nsINameSpaceManager.h"
|
|
|
|
#include "nsSVGForeignObjectElement.h"
|
|
|
|
#include "nsSVGContainerFrame.h"
|
|
|
|
#include "gfxContext.h"
|
|
|
|
#include "gfxMatrix.h"
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Implementation
|
|
|
|
|
|
|
|
nsIFrame*
|
2007-06-21 16:01:10 -07:00
|
|
|
NS_NewSVGForeignObjectFrame(nsIPresShell *aPresShell,
|
|
|
|
nsStyleContext *aContext)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
return new (aPresShell) nsSVGForeignObjectFrame(aContext);
|
|
|
|
}
|
|
|
|
|
2009-09-12 09:49:24 -07:00
|
|
|
NS_IMPL_FRAMEARENA_HELPERS(nsSVGForeignObjectFrame)
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsSVGForeignObjectFrame::nsSVGForeignObjectFrame(nsStyleContext* aContext)
|
|
|
|
: nsSVGForeignObjectFrameBase(aContext),
|
2007-06-21 16:01:10 -07:00
|
|
|
mInReflow(PR_FALSE)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2010-08-13 06:31:31 -07:00
|
|
|
AddStateBits(NS_FRAME_REFLOW_ROOT | NS_FRAME_MAY_BE_TRANSFORMED);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-01-09 08:35:24 -08:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsIFrame methods
|
2008-11-05 11:25:30 -08:00
|
|
|
|
2009-01-12 11:20:59 -08:00
|
|
|
NS_QUERYFRAME_HEAD(nsSVGForeignObjectFrame)
|
|
|
|
NS_QUERYFRAME_ENTRY(nsISVGChildFrame)
|
|
|
|
NS_QUERYFRAME_TAIL_INHERITING(nsSVGForeignObjectFrameBase)
|
|
|
|
|
2007-11-20 01:10:18 -08:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSVGForeignObjectFrame::Init(nsIContent* aContent,
|
|
|
|
nsIFrame* aParent,
|
|
|
|
nsIFrame* aPrevInFlow)
|
|
|
|
{
|
2009-01-19 10:31:34 -08:00
|
|
|
#ifdef DEBUG
|
|
|
|
nsCOMPtr<nsIDOMSVGForeignObjectElement> foreignObject = do_QueryInterface(aContent);
|
|
|
|
NS_ASSERTION(foreignObject, "Content is not an SVG foreignObject!");
|
|
|
|
#endif
|
|
|
|
|
2007-11-20 01:10:18 -08:00
|
|
|
nsresult rv = nsSVGForeignObjectFrameBase::Init(aContent, aParent, aPrevInFlow);
|
2011-04-20 02:16:01 -07:00
|
|
|
AddStateBits(aParent->GetStateBits() &
|
|
|
|
(NS_STATE_SVG_NONDISPLAY_CHILD | NS_STATE_SVG_CLIPPATH_CHILD));
|
2007-11-20 01:10:18 -08:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
nsSVGUtils::GetOuterSVGFrame(this)->RegisterForeignObject(this);
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2009-12-23 21:21:15 -08:00
|
|
|
void nsSVGForeignObjectFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-11-20 01:10:18 -08:00
|
|
|
nsSVGUtils::GetOuterSVGFrame(this)->UnregisterForeignObject(this);
|
2009-12-23 21:21:15 -08:00
|
|
|
nsSVGForeignObjectFrameBase::DestroyFrom(aDestructRoot);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsIAtom *
|
|
|
|
nsSVGForeignObjectFrame::GetType() const
|
|
|
|
{
|
|
|
|
return nsGkAtoms::svgForeignObjectFrame;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2007-06-21 16:01:10 -07:00
|
|
|
nsSVGForeignObjectFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
|
|
|
nsIAtom *aAttribute,
|
|
|
|
PRInt32 aModType)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (aNameSpaceID == kNameSpaceID_None) {
|
|
|
|
if (aAttribute == nsGkAtoms::width ||
|
|
|
|
aAttribute == nsGkAtoms::height) {
|
2007-06-21 16:01:10 -07:00
|
|
|
UpdateGraphic(); // update mRect before requesting reflow
|
2007-11-20 01:10:18 -08:00
|
|
|
// XXXjwatt: why mark intrinsic widths dirty? can't we just use eResize?
|
2007-05-05 04:11:07 -07:00
|
|
|
RequestReflow(nsIPresShell::eStyleChange);
|
2007-03-22 10:30:00 -07:00
|
|
|
} else if (aAttribute == nsGkAtoms::x ||
|
2009-06-18 04:31:25 -07:00
|
|
|
aAttribute == nsGkAtoms::y ||
|
|
|
|
aAttribute == nsGkAtoms::transform) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// make sure our cached transform matrix gets (lazily) updated
|
|
|
|
mCanvasTM = nsnull;
|
|
|
|
UpdateGraphic();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSVGForeignObjectFrame::Reflow(nsPresContext* aPresContext,
|
|
|
|
nsHTMLReflowMetrics& aDesiredSize,
|
|
|
|
const nsHTMLReflowState& aReflowState,
|
|
|
|
nsReflowStatus& aStatus)
|
|
|
|
{
|
2007-06-21 16:01:10 -07:00
|
|
|
// InitialUpdate and AttributeChanged make sure mRect is up to date before
|
|
|
|
// we're called (UpdateCoveredRegion sets mRect).
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ASSERTION(!aReflowState.parentReflowState,
|
|
|
|
"should only get reflow from being reflow root");
|
|
|
|
NS_ASSERTION(aReflowState.ComputedWidth() == GetSize().width &&
|
2007-08-02 11:08:05 -07:00
|
|
|
aReflowState.ComputedHeight() == GetSize().height,
|
2009-07-27 01:47:02 -07:00
|
|
|
"reflow roots should be reflowed at existing size and "
|
2007-03-22 10:30:00 -07:00
|
|
|
"svg.css should ensure we have no padding/border/margin");
|
|
|
|
|
|
|
|
DoReflow();
|
|
|
|
|
|
|
|
aDesiredSize.width = aReflowState.ComputedWidth();
|
2007-08-02 11:08:05 -07:00
|
|
|
aDesiredSize.height = aReflowState.ComputedHeight();
|
2010-10-06 21:25:46 -07:00
|
|
|
aDesiredSize.SetOverflowAreasToDesiredBounds();
|
2007-03-22 10:30:00 -07:00
|
|
|
aStatus = NS_FRAME_COMPLETE;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-06-21 16:01:10 -07:00
|
|
|
void
|
|
|
|
nsSVGForeignObjectFrame::InvalidateInternal(const nsRect& aDamageRect,
|
|
|
|
nscoord aX, nscoord aY,
|
|
|
|
nsIFrame* aForChild,
|
2008-09-18 02:47:21 -07:00
|
|
|
PRUint32 aFlags)
|
2007-06-21 16:01:10 -07:00
|
|
|
{
|
2009-06-18 04:31:25 -07:00
|
|
|
// This is called by our descendants when they change.
|
|
|
|
|
2008-10-24 00:47:04 -07:00
|
|
|
if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)
|
2007-06-21 16:01:10 -07:00
|
|
|
return;
|
|
|
|
|
2008-09-18 02:47:21 -07:00
|
|
|
nsRegion* region = (aFlags & INVALIDATE_CROSS_DOC)
|
2009-06-11 08:23:43 -07:00
|
|
|
? &mSubDocDirtyRegion : &mSameDocDirtyRegion;
|
2008-09-18 02:47:21 -07:00
|
|
|
region->Or(*region, aDamageRect + nsPoint(aX, aY));
|
2010-10-14 18:03:45 -07:00
|
|
|
FlushDirtyRegion(aFlags);
|
2007-06-21 16:01:10 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
/**
|
2009-06-18 04:31:25 -07:00
|
|
|
* Returns the app unit canvas bounds of a userspace rect.
|
|
|
|
*
|
|
|
|
* @param aToCanvas Transform from userspace to canvas device space.
|
2007-03-22 10:30:00 -07:00
|
|
|
*/
|
2007-06-21 16:01:10 -07:00
|
|
|
static nsRect
|
2009-06-18 04:31:25 -07:00
|
|
|
ToCanvasBounds(const gfxRect &aUserspaceRect,
|
|
|
|
const gfxMatrix &aToCanvas,
|
|
|
|
const nsPresContext *presContext)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-06-18 04:31:25 -07:00
|
|
|
return nsLayoutUtils::RoundGfxRectToAppRect(
|
|
|
|
aToCanvas.TransformBounds(aUserspaceRect),
|
|
|
|
presContext->AppUnitsPerDevPixel());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSVGForeignObjectFrame::PaintSVG(nsSVGRenderState *aContext,
|
2008-10-20 01:42:03 -07:00
|
|
|
const nsIntRect *aDirtyRect)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-04-24 12:55:58 -07:00
|
|
|
NS_ABORT_IF_FALSE(aDirtyRect, "We expect aDirtyRect to be non-null");
|
|
|
|
|
2007-06-25 01:31:31 -07:00
|
|
|
if (IsDisabled())
|
|
|
|
return NS_OK;
|
|
|
|
|
2011-08-24 13:54:30 -07:00
|
|
|
nsIFrame* kid = GetFirstPrincipalChild();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!kid)
|
|
|
|
return NS_OK;
|
|
|
|
|
2010-01-30 11:28:02 -08:00
|
|
|
gfxMatrix matrixForChildren = GetCanvasTMForChildren();
|
|
|
|
gfxMatrix matrix = GetCanvasTM();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-04-07 18:04:40 -07:00
|
|
|
nsRenderingContext *ctx = aContext->GetRenderingContext(this);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-01-30 11:28:02 -08:00
|
|
|
if (!ctx || matrixForChildren.IsSingular()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_WARNING("Can't render foreignObject element!");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2008-12-06 07:22:01 -08:00
|
|
|
/* Check if we need to draw anything. */
|
2011-04-24 12:55:58 -07:00
|
|
|
PRInt32 appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel();
|
|
|
|
if (!mRect.ToOutsidePixels(appUnitsPerDevPx).Intersects(*aDirtyRect))
|
|
|
|
return NS_OK;
|
2008-12-06 07:22:01 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
gfxContext *gfx = aContext->GetGfxContext();
|
|
|
|
|
|
|
|
gfx->Save();
|
2007-04-30 02:02:38 -07:00
|
|
|
|
|
|
|
if (GetStyleDisplay()->IsScrollableOverflow()) {
|
2007-05-23 01:39:00 -07:00
|
|
|
float x, y, width, height;
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsSVGElement*>(mContent)->
|
2007-05-23 01:39:00 -07:00
|
|
|
GetAnimatedLengthValues(&x, &y, &width, &height, nsnull);
|
2007-04-30 02:02:38 -07:00
|
|
|
|
2009-06-17 13:51:40 -07:00
|
|
|
gfxRect clipRect =
|
2009-06-18 04:31:25 -07:00
|
|
|
nsSVGUtils::GetClipRectForFrame(this, 0.0f, 0.0f, width, height);
|
2010-01-30 11:28:02 -08:00
|
|
|
nsSVGUtils::SetClipRect(gfx, matrix, clipRect);
|
2007-04-30 02:02:38 -07:00
|
|
|
}
|
|
|
|
|
2010-01-30 11:28:02 -08:00
|
|
|
gfx->Multiply(matrixForChildren);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-01-30 11:28:02 -08:00
|
|
|
// Transform the dirty rect into the rectangle containing the
|
|
|
|
// transformed dirty rect.
|
|
|
|
gfxMatrix invmatrix = matrix.Invert();
|
|
|
|
NS_ASSERTION(!invmatrix.IsSingular(),
|
|
|
|
"inverse of non-singular matrix should be non-singular");
|
|
|
|
|
|
|
|
gfxRect transDirtyRect = gfxRect(aDirtyRect->x, aDirtyRect->y,
|
|
|
|
aDirtyRect->width, aDirtyRect->height);
|
|
|
|
transDirtyRect = invmatrix.TransformBounds(transDirtyRect);
|
|
|
|
|
|
|
|
transDirtyRect.Scale(nsPresContext::AppUnitsPerCSSPixel());
|
|
|
|
nsPoint tl(NSToCoordFloor(transDirtyRect.X()),
|
|
|
|
NSToCoordFloor(transDirtyRect.Y()));
|
|
|
|
nsPoint br(NSToCoordCeil(transDirtyRect.XMost()),
|
|
|
|
NSToCoordCeil(transDirtyRect.YMost()));
|
|
|
|
nsRect kidDirtyRect(tl.x, tl.y, br.x - tl.x, br.y - tl.y);
|
|
|
|
|
|
|
|
kidDirtyRect.IntersectRect(kidDirtyRect, kid->GetRect());
|
|
|
|
|
2010-10-14 18:03:45 -07:00
|
|
|
PRUint32 flags = nsLayoutUtils::PAINT_IN_TRANSFORM;
|
|
|
|
if (aContext->IsPaintingToWindow()) {
|
|
|
|
flags |= nsLayoutUtils::PAINT_TO_WINDOW;
|
|
|
|
}
|
2010-01-30 11:28:02 -08:00
|
|
|
nsresult rv = nsLayoutUtils::PaintFrame(ctx, kid, nsRegion(kidDirtyRect),
|
2010-10-14 18:03:45 -07:00
|
|
|
NS_RGBA(0,0,0,0), flags);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
gfx->Restore();
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2011-07-22 15:28:51 -07:00
|
|
|
gfx3DMatrix
|
2008-09-13 02:42:11 -07:00
|
|
|
nsSVGForeignObjectFrame::GetTransformMatrix(nsIFrame **aOutAncestor)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aOutAncestor, "We need an ancestor to write to!");
|
|
|
|
|
|
|
|
/* Set the ancestor to be the outer frame. */
|
|
|
|
*aOutAncestor = nsSVGUtils::GetOuterSVGFrame(this);
|
|
|
|
NS_ASSERTION(*aOutAncestor, "How did we end up without an outer frame?");
|
|
|
|
|
|
|
|
/* Return the matrix back to the root, factoring in the x and y offsets. */
|
2011-07-22 15:28:51 -07:00
|
|
|
return gfx3DMatrix::From2D(GetCanvasTMForChildren());
|
2008-09-13 02:42:11 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-25 02:23:54 -07:00
|
|
|
NS_IMETHODIMP_(nsIFrame*)
|
|
|
|
nsSVGForeignObjectFrame::GetFrameForPoint(const nsPoint &aPoint)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-06-18 04:31:25 -07:00
|
|
|
if (IsDisabled() || (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD))
|
|
|
|
return nsnull;
|
2007-06-25 01:31:31 -07:00
|
|
|
|
2011-08-24 13:54:30 -07:00
|
|
|
nsIFrame* kid = GetFirstPrincipalChild();
|
2009-06-18 04:31:25 -07:00
|
|
|
if (!kid)
|
2008-08-25 02:23:54 -07:00
|
|
|
return nsnull;
|
2009-06-18 04:31:25 -07:00
|
|
|
|
|
|
|
float x, y, width, height;
|
|
|
|
static_cast<nsSVGElement*>(mContent)->
|
|
|
|
GetAnimatedLengthValues(&x, &y, &width, &height, nsnull);
|
|
|
|
|
|
|
|
gfxMatrix tm = GetCanvasTM().Invert();
|
|
|
|
if (tm.IsSingular())
|
2008-08-25 02:23:54 -07:00
|
|
|
return nsnull;
|
2009-06-18 04:31:25 -07:00
|
|
|
|
|
|
|
// Convert aPoint from app units in canvas space to user space:
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-06-18 04:31:25 -07:00
|
|
|
gfxPoint pt = gfxPoint(aPoint.x, aPoint.y) / PresContext()->AppUnitsPerDevPixel();
|
|
|
|
pt = tm.Transform(pt);
|
|
|
|
|
|
|
|
if (!gfxRect(0.0f, 0.0f, width, height).Contains(pt))
|
|
|
|
return nsnull;
|
|
|
|
|
|
|
|
// Convert pt to app units in *local* space:
|
|
|
|
|
|
|
|
pt = pt * nsPresContext::AppUnitsPerCSSPixel();
|
|
|
|
nsPoint point = nsPoint(NSToIntRound(pt.x), NSToIntRound(pt.y));
|
|
|
|
|
2010-07-15 01:10:59 -07:00
|
|
|
nsIFrame *frame = nsLayoutUtils::GetFrameForPoint(kid, point);
|
|
|
|
if (frame && nsSVGUtils::HitTestClip(this, aPoint))
|
|
|
|
return frame;
|
|
|
|
|
|
|
|
return nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP_(nsRect)
|
|
|
|
nsSVGForeignObjectFrame::GetCoveredRegion()
|
|
|
|
{
|
|
|
|
return mRect;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSVGForeignObjectFrame::UpdateCoveredRegion()
|
|
|
|
{
|
2008-10-24 00:47:04 -07:00
|
|
|
if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2007-06-21 16:01:10 -07:00
|
|
|
float x, y, w, h;
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsSVGForeignObjectElement*>(mContent)->
|
2007-06-21 16:01:10 -07:00
|
|
|
GetAnimatedLengthValues(&x, &y, &w, &h, nsnull);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-06-25 01:31:31 -07:00
|
|
|
// If mRect's width or height are negative, reflow blows up! We must clamp!
|
|
|
|
if (w < 0.0f) w = 0.0f;
|
|
|
|
if (h < 0.0f) h = 0.0f;
|
|
|
|
|
2009-06-18 04:31:25 -07:00
|
|
|
// GetCanvasTM includes the x,y translation
|
|
|
|
mRect = ToCanvasBounds(gfxRect(0.0, 0.0, w, h), GetCanvasTM(), PresContext());
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSVGForeignObjectFrame::InitialUpdate()
|
|
|
|
{
|
2007-10-19 04:07:08 -07:00
|
|
|
NS_ASSERTION(GetStateBits() & NS_FRAME_FIRST_REFLOW,
|
|
|
|
"Yikes! We've been called already! Hopefully we weren't called "
|
|
|
|
"before our nsSVGOuterSVGFrame's initial Reflow()!!!");
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
UpdateCoveredRegion();
|
2009-04-21 16:53:52 -07:00
|
|
|
|
|
|
|
// Make sure to not allow interrupts if we're not being reflown as a root
|
|
|
|
nsPresContext::InterruptPreventer noInterrupts(PresContext());
|
2007-03-22 10:30:00 -07:00
|
|
|
DoReflow();
|
|
|
|
|
|
|
|
NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW),
|
|
|
|
"We don't actually participate in reflow");
|
|
|
|
|
|
|
|
// Do unset the various reflow bits, though.
|
|
|
|
mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
|
|
|
|
NS_FRAME_HAS_DIRTY_CHILDREN);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-01-25 01:27:03 -08:00
|
|
|
void
|
|
|
|
nsSVGForeignObjectFrame::NotifySVGChanged(PRUint32 aFlags)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-01-25 01:27:03 -08:00
|
|
|
PRBool reflow = PR_FALSE;
|
|
|
|
|
|
|
|
if (aFlags & TRANSFORM_CHANGED) {
|
2008-03-19 14:27:33 -07:00
|
|
|
// In an ideal world we would reflow when our CTM changes. This is because
|
2008-01-25 01:27:03 -08:00
|
|
|
// glyph metrics do not necessarily scale uniformly with change in scale
|
|
|
|
// and, as a result, CTM changes may require text to break at different
|
2008-03-19 14:27:33 -07:00
|
|
|
// points. The problem would be how to keep performance acceptable when
|
|
|
|
// e.g. the transform of an ancestor is animated.
|
|
|
|
// We also seem to get some sort of infinite loop post bug 421584 if we
|
|
|
|
// reflow.
|
2008-01-25 01:27:03 -08:00
|
|
|
mCanvasTM = nsnull;
|
2008-04-07 03:32:41 -07:00
|
|
|
if (!(aFlags & SUPPRESS_INVALIDATION)) {
|
|
|
|
UpdateGraphic();
|
|
|
|
}
|
2008-01-25 01:27:03 -08:00
|
|
|
|
|
|
|
} else if (aFlags & COORD_CONTEXT_CHANGED) {
|
|
|
|
// Our coordinate context's width/height has changed. If we have a
|
|
|
|
// percentage width/height our dimensions will change so we must reflow.
|
|
|
|
nsSVGForeignObjectElement *fO =
|
|
|
|
static_cast<nsSVGForeignObjectElement*>(mContent);
|
|
|
|
if (fO->mLengthAttributes[nsSVGForeignObjectElement::WIDTH].IsPercentage() ||
|
|
|
|
fO->mLengthAttributes[nsSVGForeignObjectElement::HEIGHT].IsPercentage()) {
|
|
|
|
reflow = PR_TRUE;
|
|
|
|
}
|
2007-11-20 01:10:18 -08:00
|
|
|
}
|
|
|
|
|
2008-01-25 01:27:03 -08:00
|
|
|
if (reflow) {
|
|
|
|
// If we're called while the PresShell is handling reflow events then we
|
|
|
|
// must have been called as a result of the NotifyViewportChange() call in
|
|
|
|
// our nsSVGOuterSVGFrame's Reflow() method. We must not call RequestReflow
|
|
|
|
// at this point (i.e. during reflow) because it could confuse the
|
|
|
|
// PresShell and prevent it from reflowing us properly in future. Besides
|
|
|
|
// that, nsSVGOuterSVGFrame::DidReflow will take care of reflowing us
|
|
|
|
// synchronously, so there's no need.
|
2010-03-31 05:43:27 -07:00
|
|
|
if (!PresContext()->PresShell()->IsReflowLocked()) {
|
2008-01-25 01:27:03 -08:00
|
|
|
UpdateGraphic(); // update mRect before requesting reflow
|
|
|
|
RequestReflow(nsIPresShell::eResize);
|
|
|
|
}
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSVGForeignObjectFrame::NotifyRedrawSuspended()
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSVGForeignObjectFrame::NotifyRedrawUnsuspended()
|
|
|
|
{
|
2008-10-24 00:47:04 -07:00
|
|
|
if (!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
if (GetStateBits() & NS_STATE_SVG_DIRTY) {
|
2009-06-11 08:23:43 -07:00
|
|
|
UpdateGraphic(); // invalidate our entire area
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
2010-10-14 18:03:45 -07:00
|
|
|
FlushDirtyRegion(0); // only invalidate areas dirtied by our descendants
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-04-28 21:31:34 -07:00
|
|
|
gfxRect
|
|
|
|
nsSVGForeignObjectFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-04-28 21:31:34 -07:00
|
|
|
NS_ASSERTION(!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD),
|
|
|
|
"Should not be calling this on a non-display child");
|
2008-08-15 03:24:01 -07:00
|
|
|
|
2009-04-28 21:31:34 -07:00
|
|
|
nsSVGForeignObjectElement *content =
|
|
|
|
static_cast<nsSVGForeignObjectElement*>(mContent);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
float x, y, w, h;
|
2009-04-28 21:31:34 -07:00
|
|
|
content->GetAnimatedLengthValues(&x, &y, &w, &h, nsnull);
|
2007-06-21 16:01:10 -07:00
|
|
|
|
2007-06-25 01:31:31 -07:00
|
|
|
if (w < 0.0f) w = 0.0f;
|
|
|
|
if (h < 0.0f) h = 0.0f;
|
|
|
|
|
2009-04-28 21:31:34 -07:00
|
|
|
if (aToBBoxUserspace.IsSingular()) {
|
|
|
|
// XXX ReportToConsole
|
|
|
|
return gfxRect(0.0, 0.0, 0.0, 0.0);
|
|
|
|
}
|
2009-06-18 04:31:25 -07:00
|
|
|
return aToBBoxUserspace.TransformBounds(gfxRect(0.0, 0.0, w, h));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
2009-04-28 21:31:34 -07:00
|
|
|
gfxMatrix
|
2007-03-22 10:30:00 -07:00
|
|
|
nsSVGForeignObjectFrame::GetCanvasTM()
|
|
|
|
{
|
|
|
|
if (!mCanvasTM) {
|
|
|
|
NS_ASSERTION(mParent, "null parent");
|
|
|
|
|
2009-04-28 21:31:34 -07:00
|
|
|
nsSVGContainerFrame *parent = static_cast<nsSVGContainerFrame*>(mParent);
|
|
|
|
nsSVGForeignObjectElement *content =
|
|
|
|
static_cast<nsSVGForeignObjectElement*>(mContent);
|
|
|
|
|
|
|
|
gfxMatrix tm = content->PrependLocalTransformTo(parent->GetCanvasTM());
|
|
|
|
|
|
|
|
mCanvasTM = NS_NewSVGMatrix(tm);
|
|
|
|
}
|
|
|
|
return nsSVGUtils::ConvertSVGMatrixToThebes(mCanvasTM);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Implementation helpers
|
|
|
|
|
2009-06-18 04:31:25 -07:00
|
|
|
gfxMatrix
|
|
|
|
nsSVGForeignObjectFrame::GetCanvasTMForChildren()
|
2009-03-29 06:58:09 -07:00
|
|
|
{
|
2009-06-18 04:31:25 -07:00
|
|
|
float cssPxPerDevPx = PresContext()->
|
|
|
|
AppUnitsToFloatCSSPixels(PresContext()->AppUnitsPerDevPixel());
|
2009-03-29 06:58:09 -07:00
|
|
|
|
2009-06-18 04:31:25 -07:00
|
|
|
return GetCanvasTM().Scale(cssPxPerDevPx, cssPxPerDevPx);
|
2009-03-29 06:58:09 -07:00
|
|
|
}
|
|
|
|
|
2007-05-05 04:11:07 -07:00
|
|
|
void nsSVGForeignObjectFrame::RequestReflow(nsIPresShell::IntrinsicDirty aType)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-05-05 04:11:07 -07:00
|
|
|
if (GetStateBits() & NS_FRAME_FIRST_REFLOW)
|
|
|
|
// If we haven't had an InitialUpdate yet, nothing to do.
|
|
|
|
return;
|
|
|
|
|
2011-08-24 13:54:30 -07:00
|
|
|
nsIFrame* kid = GetFirstPrincipalChild();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!kid)
|
|
|
|
return;
|
2007-05-05 04:11:07 -07:00
|
|
|
|
2007-05-06 12:16:51 -07:00
|
|
|
PresContext()->PresShell()->FrameNeedsReflow(kid, aType, NS_FRAME_IS_DIRTY);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void nsSVGForeignObjectFrame::UpdateGraphic()
|
|
|
|
{
|
2008-04-08 05:51:19 -07:00
|
|
|
nsSVGUtils::UpdateGraphic(this);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-06-11 08:23:43 -07:00
|
|
|
// We just invalidated our entire area, so clear the caches of areas dirtied
|
|
|
|
// by our descendants:
|
2008-09-18 02:47:21 -07:00
|
|
|
mSameDocDirtyRegion.SetEmpty();
|
2009-06-11 08:23:43 -07:00
|
|
|
mSubDocDirtyRegion.SetEmpty();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-11-20 01:10:18 -08:00
|
|
|
void
|
|
|
|
nsSVGForeignObjectFrame::MaybeReflowFromOuterSVGFrame()
|
|
|
|
{
|
2011-02-17 16:33:31 -08:00
|
|
|
// If IsDisabled() is true, then we know that our DoReflow() call will return
|
|
|
|
// early, leaving us with a marked-dirty but not-reflowed kid. That'd be bad;
|
|
|
|
// it'd mean that all future calls to this method would be doomed to take the
|
|
|
|
// NS_FRAME_IS_DIRTY early-return below. To avoid that problem, we need to
|
|
|
|
// bail out *before* we mark our kid as dirty.
|
|
|
|
if (IsDisabled()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-08-24 13:54:30 -07:00
|
|
|
nsIFrame* kid = GetFirstPrincipalChild();
|
2009-06-18 04:31:25 -07:00
|
|
|
|
|
|
|
// If we're already scheduled to reflow (if we or our kid is dirty) we don't
|
2007-11-20 01:10:18 -08:00
|
|
|
// want to reflow now or else our presShell will do extra work trying to
|
|
|
|
// reflow us a second time. (It will also complain if it finds that a reflow
|
|
|
|
// root scheduled for reflow isn't dirty).
|
|
|
|
|
|
|
|
if (kid->GetStateBits() & NS_FRAME_IS_DIRTY) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
kid->AddStateBits(NS_FRAME_IS_DIRTY); // we must be fully marked dirty
|
|
|
|
if (kid->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN) {
|
|
|
|
return;
|
|
|
|
}
|
2009-04-21 16:53:52 -07:00
|
|
|
|
|
|
|
// Make sure to not allow interrupts if we're not being reflown as a root
|
|
|
|
nsPresContext::InterruptPreventer noInterrupts(PresContext());
|
2007-11-20 01:10:18 -08:00
|
|
|
DoReflow();
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
|
|
|
nsSVGForeignObjectFrame::DoReflow()
|
|
|
|
{
|
2007-10-19 04:07:08 -07:00
|
|
|
NS_ASSERTION(!(nsSVGUtils::GetOuterSVGFrame(this)->
|
|
|
|
GetStateBits() & NS_FRAME_FIRST_REFLOW),
|
|
|
|
"Calling InitialUpdate too early - must not call DoReflow!!!");
|
|
|
|
|
2011-02-17 16:33:30 -08:00
|
|
|
// Skip reflow if we're zero-sized, unless this is our first reflow.
|
|
|
|
if (IsDisabled() &&
|
|
|
|
!(GetStateBits() & NS_FRAME_FIRST_REFLOW))
|
2007-06-25 01:31:31 -07:00
|
|
|
return;
|
|
|
|
|
2008-10-24 00:47:04 -07:00
|
|
|
if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)
|
2007-03-22 10:30:00 -07:00
|
|
|
return;
|
|
|
|
|
2007-03-30 14:11:41 -07:00
|
|
|
nsPresContext *presContext = PresContext();
|
2011-08-24 13:54:30 -07:00
|
|
|
nsIFrame* kid = GetFirstPrincipalChild();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!kid)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// initiate a synchronous reflow here and now:
|
|
|
|
nsSize availableSpace(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
|
|
|
nsIPresShell* presShell = presContext->PresShell();
|
|
|
|
NS_ASSERTION(presShell, "null presShell");
|
2011-04-07 18:04:40 -07:00
|
|
|
nsRefPtr<nsRenderingContext> renderingContext =
|
2010-08-20 12:29:01 -07:00
|
|
|
presShell->GetReferenceRenderingContext();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!renderingContext)
|
|
|
|
return;
|
|
|
|
|
2007-07-08 00:08:04 -07:00
|
|
|
nsSVGForeignObjectElement *fO = static_cast<nsSVGForeignObjectElement*>
|
|
|
|
(mContent);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
float width =
|
|
|
|
fO->mLengthAttributes[nsSVGForeignObjectElement::WIDTH].GetAnimValue(fO);
|
|
|
|
float height =
|
|
|
|
fO->mLengthAttributes[nsSVGForeignObjectElement::HEIGHT].GetAnimValue(fO);
|
|
|
|
|
2011-02-17 16:33:30 -08:00
|
|
|
// Clamp height & width to be non-negative (to match UpdateCoveredRegion).
|
|
|
|
width = NS_MAX(width, 0.0f);
|
|
|
|
height = NS_MAX(height, 0.0f);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsSize size(nsPresContext::CSSPixelsToAppUnits(width),
|
|
|
|
nsPresContext::CSSPixelsToAppUnits(height));
|
|
|
|
|
|
|
|
mInReflow = PR_TRUE;
|
|
|
|
|
|
|
|
nsHTMLReflowState reflowState(presContext, kid,
|
|
|
|
renderingContext,
|
|
|
|
nsSize(size.width, NS_UNCONSTRAINEDSIZE));
|
|
|
|
nsHTMLReflowMetrics desiredSize;
|
|
|
|
nsReflowStatus status;
|
|
|
|
|
|
|
|
// We don't use size.height above because that tells the child to do
|
|
|
|
// page/column breaking at that height.
|
|
|
|
NS_ASSERTION(reflowState.mComputedBorderPadding == nsMargin(0, 0, 0, 0) &&
|
|
|
|
reflowState.mComputedMargin == nsMargin(0, 0, 0, 0),
|
|
|
|
"style system should ensure that :-moz-svg-foreign content "
|
|
|
|
"does not get styled");
|
|
|
|
NS_ASSERTION(reflowState.ComputedWidth() == size.width,
|
|
|
|
"reflow state made child wrong size");
|
2007-08-02 11:08:05 -07:00
|
|
|
reflowState.SetComputedHeight(size.height);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
ReflowChild(kid, presContext, desiredSize, reflowState, 0, 0,
|
|
|
|
NS_FRAME_NO_MOVE_FRAME, status);
|
|
|
|
NS_ASSERTION(size.width == desiredSize.width &&
|
|
|
|
size.height == desiredSize.height, "unexpected size");
|
|
|
|
FinishReflowChild(kid, presContext, &reflowState, desiredSize, 0, 0,
|
|
|
|
NS_FRAME_NO_MOVE_FRAME);
|
|
|
|
|
|
|
|
mInReflow = PR_FALSE;
|
2010-10-14 18:03:45 -07:00
|
|
|
FlushDirtyRegion(0);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-09-18 02:47:21 -07:00
|
|
|
void
|
|
|
|
nsSVGForeignObjectFrame::InvalidateDirtyRect(nsSVGOuterSVGFrame* aOuter,
|
|
|
|
const nsRect& aRect, PRUint32 aFlags)
|
|
|
|
{
|
|
|
|
if (aRect.IsEmpty())
|
|
|
|
return;
|
|
|
|
|
2009-06-18 04:31:25 -07:00
|
|
|
// The areas dirtied by children are in app units, relative to this frame.
|
|
|
|
// We need to convert the rect to userspace to use IntersectRect.
|
2009-03-29 06:58:09 -07:00
|
|
|
|
2009-06-18 04:31:25 -07:00
|
|
|
gfxRect r(aRect.x, aRect.y, aRect.width, aRect.height);
|
|
|
|
r.Scale(1.0 / nsPresContext::AppUnitsPerCSSPixel());
|
2009-03-29 06:58:09 -07:00
|
|
|
|
2009-06-18 04:31:25 -07:00
|
|
|
nsRect rect = ToCanvasBounds(r, GetCanvasTM(), PresContext());
|
2008-09-18 02:47:21 -07:00
|
|
|
|
2009-06-18 04:31:25 -07:00
|
|
|
// Don't invalidate areas outside our bounds:
|
2009-06-11 08:23:43 -07:00
|
|
|
rect.IntersectRect(rect, mRect);
|
|
|
|
if (rect.IsEmpty())
|
|
|
|
return;
|
|
|
|
|
2008-09-18 02:47:21 -07:00
|
|
|
rect = nsSVGUtils::FindFilterInvalidation(this, rect);
|
|
|
|
aOuter->InvalidateWithFlags(rect, aFlags);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
2010-10-14 18:03:45 -07:00
|
|
|
nsSVGForeignObjectFrame::FlushDirtyRegion(PRUint32 aFlags)
|
2007-06-21 16:01:10 -07:00
|
|
|
{
|
2009-06-11 08:23:43 -07:00
|
|
|
if ((mSameDocDirtyRegion.IsEmpty() && mSubDocDirtyRegion.IsEmpty()) ||
|
2008-09-18 02:47:21 -07:00
|
|
|
mInReflow)
|
2007-03-22 10:30:00 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(this);
|
|
|
|
if (!outerSVGFrame) {
|
|
|
|
NS_ERROR("null outerSVGFrame");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-03-28 02:41:46 -07:00
|
|
|
if (outerSVGFrame->IsRedrawSuspended())
|
2007-03-22 10:30:00 -07:00
|
|
|
return;
|
|
|
|
|
2010-10-14 18:03:45 -07:00
|
|
|
InvalidateDirtyRect(outerSVGFrame, mSameDocDirtyRegion.GetBounds(), aFlags);
|
|
|
|
InvalidateDirtyRect(outerSVGFrame, mSubDocDirtyRegion.GetBounds(),
|
|
|
|
aFlags | INVALIDATE_CROSS_DOC);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-09-18 02:47:21 -07:00
|
|
|
mSameDocDirtyRegion.SetEmpty();
|
2009-06-11 08:23:43 -07:00
|
|
|
mSubDocDirtyRegion.SetEmpty();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|