Make percentage width and height work inside of foreignObject by fixing up the way foreignObject initiates the reflow process, and also partly fixing incremental change issues with foreignObject. b=328550 r+sr=roc
git-svn-id: svn://10.0.0.236/trunk@191383 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -85,6 +85,8 @@ NS_NewSVGForeignObjectFrame(nsIPresShell* aPresShell, nsIContent* aContent)
|
||||
nsSVGForeignObjectFrame::nsSVGForeignObjectFrame()
|
||||
: mIsDirty(PR_TRUE), mPropagateTransform(PR_TRUE), mFilter(nsnull)
|
||||
{
|
||||
AddStateBits(NS_BLOCK_SPACE_MGR | NS_BLOCK_MARGIN_ROOT |
|
||||
NS_FRAME_REFLOW_ROOT);
|
||||
}
|
||||
|
||||
nsSVGForeignObjectFrame::~nsSVGForeignObjectFrame()
|
||||
@@ -213,39 +215,30 @@ nsSVGForeignObjectFrame::Reflow(nsPresContext* aPresContext,
|
||||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("nsSVGForeignObjectFrame(%p)::Reflow\n", this);
|
||||
#endif
|
||||
|
||||
float twipsPerPx = GetTwipsPerPx();
|
||||
|
||||
NS_ENSURE_TRUE(mX && mY && mWidth && mHeight, NS_ERROR_FAILURE);
|
||||
nsHTMLReflowState &reflowState =
|
||||
NS_CONST_CAST(nsHTMLReflowState&, aReflowState);
|
||||
|
||||
float width, height;
|
||||
mWidth->GetValue(&width);
|
||||
mHeight->GetValue(&height);
|
||||
// We could do this in DoReflow, except that we set
|
||||
// NS_FRAME_REFLOW_ROOT, so we also need to do it when the pres shell
|
||||
// calls us directly.
|
||||
reflowState.mComputedHeight = mRect.height;
|
||||
reflowState.mComputedWidth = mRect.width;
|
||||
|
||||
// move our frame to (0, 0), set our size to the untransformed
|
||||
// width and height. Our frame size and position are meaningless
|
||||
// given the possibility of non-rectilinear transforms; our size
|
||||
// is only useful for reflowing our content
|
||||
SetPosition(nsPoint(0, 0));
|
||||
|
||||
// create a new reflow state, setting our max size to (width,height):
|
||||
nsSize availableSpace((nscoord)(width*twipsPerPx), (nscoord)(height*twipsPerPx));
|
||||
nsHTMLReflowState sizedReflowState(aPresContext,
|
||||
aReflowState,
|
||||
this,
|
||||
availableSpace);
|
||||
nsSpaceManager* spaceManager =
|
||||
new nsSpaceManager(aPresContext->PresShell(), this);
|
||||
if (!spaceManager) {
|
||||
NS_ERROR("Could not create space manager");
|
||||
return nsnull;
|
||||
}
|
||||
reflowState.mSpaceManager = spaceManager;
|
||||
|
||||
nsresult rv = nsSVGForeignObjectFrameBase::Reflow(aPresContext, aDesiredSize,
|
||||
aReflowState, aStatus);
|
||||
|
||||
// XXX Not sure the dirty-state should be cleared here. We should
|
||||
// re-examine how the reflow is driven from nsSVGOuterSVGFrame. I
|
||||
// think we're missing a call to DidReflow somewhere ?
|
||||
mState &= ~NS_FRAME_IS_DIRTY;
|
||||
|
||||
// leverage our base class' reflow function to do all the work:
|
||||
return nsSVGForeignObjectFrameBase::Reflow(aPresContext, aDesiredSize,
|
||||
sizedReflowState, aStatus);
|
||||
reflowState.mSpaceManager = nsnull;
|
||||
delete spaceManager;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@@ -742,24 +735,41 @@ nsSVGForeignObjectFrame::DoReflow()
|
||||
nsIPresShell* presShell = presContext->PresShell();
|
||||
NS_ASSERTION(presShell, "null presShell");
|
||||
presShell->CreateRenderingContext(this,getter_AddRefs(renderingContext));
|
||||
NS_ENSURE_TRUE(renderingContext, nsnull);
|
||||
|
||||
// XXX we always pass this off as an initial reflow. is that a problem?
|
||||
nsHTMLReflowState reflowState(presContext, this, eReflowReason_Initial,
|
||||
renderingContext, availableSpace);
|
||||
float twipsPerPx = GetTwipsPerPx();
|
||||
|
||||
NS_ENSURE_TRUE(mX && mY && mWidth && mHeight, nsnull);
|
||||
|
||||
nsSpaceManager* spaceManager = new nsSpaceManager(presShell, this);
|
||||
if (!spaceManager) {
|
||||
NS_ERROR("Could not create space manager");
|
||||
return nsnull;
|
||||
}
|
||||
reflowState.mSpaceManager = spaceManager;
|
||||
|
||||
float width, height;
|
||||
mWidth->GetValue(&width);
|
||||
mHeight->GetValue(&height);
|
||||
|
||||
nsSize size(NSFloatPixelsToTwips(width, twipsPerPx),
|
||||
NSFloatPixelsToTwips(height, twipsPerPx));
|
||||
|
||||
// move our frame to (0, 0), set our size to the untransformed
|
||||
// width and height. Our frame size and position are meaningless
|
||||
// given the possibility of non-rectilinear transforms; our size
|
||||
// is only useful for reflowing our content
|
||||
SetPosition(nsPoint(0, 0));
|
||||
SetSize(size);
|
||||
|
||||
// create a new reflow state, setting our max size to (width,height):
|
||||
// Make up a potentially reasonable but perhaps too destructive reflow
|
||||
// reason.
|
||||
nsReflowReason reason = (GetStateBits() & NS_FRAME_FIRST_REFLOW)
|
||||
? eReflowReason_Initial
|
||||
: eReflowReason_StyleChange;
|
||||
nsHTMLReflowState reflowState(presContext, this, reason,
|
||||
renderingContext, size);
|
||||
nsHTMLReflowMetrics desiredSize(nsnull);
|
||||
nsReflowStatus status;
|
||||
|
||||
WillReflow(presContext);
|
||||
Reflow(presContext, desiredSize, reflowState, status);
|
||||
SetSize(nsSize(desiredSize.width, desiredSize.height));
|
||||
NS_ASSERTION(size.width == desiredSize.width &&
|
||||
size.height == desiredSize.height, "unexpected size");
|
||||
DidReflow(presContext, &reflowState, NS_FRAME_REFLOW_FINISHED);
|
||||
|
||||
mIsDirty = PR_FALSE;
|
||||
|
||||
@@ -408,45 +408,18 @@ nsSVGOuterSVGFrame::Reflow(nsPresContext* aPresContext,
|
||||
}
|
||||
#endif
|
||||
|
||||
// check whether this reflow request is targeted at us or a child
|
||||
// frame (e.g. a foreignObject):
|
||||
if (aReflowState.reason == eReflowReason_Incremental) {
|
||||
nsReflowPath::iterator iter = aReflowState.path->FirstChild();
|
||||
nsReflowPath::iterator end = aReflowState.path->EndChildren();
|
||||
if (aReflowState.reason == eReflowReason_Incremental &&
|
||||
!aReflowState.path->mReflowCommand) {
|
||||
// We're not the target of the incremental reflow, so just bail.
|
||||
// This means that something happened to one of our descendants
|
||||
// (excluding those inside svg:foreignObject, since
|
||||
// nsSVGForeignObjectFrame is a reflow root).
|
||||
|
||||
for ( ; iter != end; ++iter) {
|
||||
// The actual target of this reflow is one of our child
|
||||
// frames. Since SVG as such doesn't use reflow, this will
|
||||
// probably be the child of a <foreignObject>. Some HTML|XUL
|
||||
// content frames target reflow events at themselves when they
|
||||
// need to be redrawn in response to e.g. a style change. For
|
||||
// correct visual updating, we must make sure the reflow
|
||||
// reaches its intended target.
|
||||
|
||||
// Since it is an svg frame (probably an nsSVGForeignObjectFrame),
|
||||
// we might as well pass in our aDesiredSize and aReflowState
|
||||
// objects - they are ignored by svg frames:
|
||||
nsSize availSpace(0, 0); // XXXwaterson probably wrong!
|
||||
nsHTMLReflowState state(aPresContext, aReflowState, *iter, availSpace);
|
||||
(*iter)->Reflow (aPresContext,
|
||||
aDesiredSize,
|
||||
state,
|
||||
aStatus);
|
||||
|
||||
// XXX do we really have to return our metrics although we're
|
||||
// not affected by the reflow? Is there a way of telling our
|
||||
// parent that we don't want anything changed?
|
||||
aDesiredSize.width = mRect.width;
|
||||
aDesiredSize.height = mRect.height;
|
||||
aDesiredSize.ascent = aDesiredSize.height;
|
||||
aDesiredSize.descent = 0;
|
||||
}
|
||||
|
||||
if (! aReflowState.path->mReflowCommand) {
|
||||
// We're not the target of the incremental reflow, so just bail.
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
return NS_OK;
|
||||
}
|
||||
// XXXldb If this incremental reflow was the result of a style
|
||||
// change to something that *contains* a foreignObject, then we're
|
||||
// dropping the change completely on the floor!
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// SVG CR 20001102: When the SVG content is embedded inline within
|
||||
|
||||
@@ -62,3 +62,9 @@ switch {
|
||||
svg:not(:root), symbol, image, marker, pattern, foreignObject {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
foreignObject {
|
||||
margin: 0 ! important;
|
||||
padding: 0 ! important;
|
||||
border: none ! important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user