Make boxes that have non-box non-block children wrap all their children in a block. b=321402 r+sr=roc, a=blocking1.9+/M9

This commit is contained in:
dbaron%dbaron.org 2007-10-25 23:31:04 +00:00
Родитель c426a2f29e
Коммит dfc1afb90e
18 изменённых файлов: 297 добавлений и 73 удалений

Просмотреть файл

@ -35,3 +35,4 @@
MissingOverlay=Failed to load overlay from %1$S.
PINotInProlog=<?%1$S?> processing instruction does not have any effect outside the prolog anymore (see bug 360119).
NeededToWrapXUL=XUL box for %1$S element contained an inline %2$S child, forcing all its children to be wrapped in a block.

Просмотреть файл

@ -101,6 +101,7 @@
#include "nsITheme.h"
#include "nsContentCID.h"
#include "nsContentUtils.h"
#include "nsIScriptError.h"
#include "nsIDocShell.h"
#include "nsIDocShellTreeItem.h"
#include "nsObjectFrame.h"
@ -461,6 +462,43 @@ IsInlineFrame(const nsIFrame* aFrame)
return aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
}
/**
* If any children require a block parent, return the first such child.
* Otherwise return null.
*/
static nsIContent*
AnyKidsNeedBlockParent(nsIFrame *aFrameList)
{
for (nsIFrame *k = aFrameList; k; k = k->GetNextSibling()) {
// Line participants, such as text and inline frames, can't be
// directly inside a XUL box; they must be wrapped in an
// intermediate block.
if (k->IsFrameOfType(nsIFrame::eLineParticipant)) {
return k->GetContent();
}
}
return nsnull;
}
// Reparent a frame into a wrapper frame that is a child of its old parent.
static void
ReparentFrame(nsFrameManager* aFrameManager,
nsIFrame* aNewParentFrame,
nsIFrame* aFrame)
{
aFrame->SetParent(aNewParentFrame);
aFrameManager->ReParentStyleContext(aFrame);
if (aFrame->GetStateBits() &
(NS_FRAME_HAS_VIEW | NS_FRAME_HAS_CHILD_WITH_VIEW)) {
// No need to walk up the tree, since the bits are already set
// right on the parent of aNewParentFrame.
NS_ASSERTION(aNewParentFrame->GetParent()->GetStateBits() &
NS_FRAME_HAS_CHILD_WITH_VIEW,
"aNewParentFrame's parent should have this bit set!");
aNewParentFrame->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
}
}
//----------------------------------------------------------------------
//
// When inline frames get weird and have block frames in them, we
@ -6187,9 +6225,48 @@ nsCSSFrameConstructor::ConstructXULFrame(nsFrameConstructorState& aState,
if (mDocument->BindingManager()->ShouldBuildChildFrames(aContent)) {
rv = ProcessChildren(aState, aContent, newFrame, PR_FALSE,
childItems, PR_FALSE);
nsIContent *badKid;
if (newFrame->IsBoxFrame() &&
(badKid = AnyKidsNeedBlockParent(childItems.childList))) {
nsAutoString parentTag, kidTag;
aContent->Tag()->ToString(parentTag);
badKid->Tag()->ToString(kidTag);
const PRUnichar* params[] = { parentTag.get(), kidTag.get() };
nsContentUtils::ReportToConsole(nsContentUtils::eXUL_PROPERTIES,
"NeededToWrapXUL",
params, NS_ARRAY_LENGTH(params),
mDocument->GetDocumentURI(),
EmptyString(), 0, 0, // not useful
nsIScriptError::warningFlag,
"FrameConstructor");
nsRefPtr<nsStyleContext> blockSC = mPresShell->StyleSet()->
ResolvePseudoStyleFor(aContent,
nsCSSAnonBoxes::mozXULAnonymousBlock,
aStyleContext);
nsIFrame *blockFrame = NS_NewBlockFrame(mPresShell, blockSC);
// We might, in theory, want to set NS_BLOCK_SPACE_MGR and
// NS_BLOCK_MARGIN_ROOT, but I think it's a bad idea given that
// a real block placed here wouldn't get those set on it.
InitAndRestoreFrame(aState, aContent, newFrame, nsnull,
blockFrame, PR_FALSE);
NS_ASSERTION(!blockFrame->HasView(), "need to do view reparenting");
for (nsIFrame *f = childItems.childList; f; f = f->GetNextSibling()) {
ReparentFrame(aState.mFrameManager, blockFrame, f);
}
blockFrame->AppendFrames(nsnull, childItems.childList);
childItems = nsFrameItems();
childItems.AddChild(blockFrame);
newFrame->AddStateBits(NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK);
}
}
}
// XXX These should go after the wrapper!
CreateAnonymousFrames(aTag, aState, aContent, newFrame, PR_FALSE,
childItems);
@ -6744,24 +6821,6 @@ nsCSSFrameConstructor::ResolveStyleContext(nsIFrame* aParentFrame,
}
}
static void
ReparentFrame(nsFrameManager* aFrameManager,
nsIFrame* aNewParentFrame,
nsIFrame* aFrame)
{
aFrame->SetParent(aNewParentFrame);
aFrameManager->ReParentStyleContext(aFrame);
if (aFrame->GetStateBits() &
(NS_FRAME_HAS_VIEW | NS_FRAME_HAS_CHILD_WITH_VIEW)) {
// No need to walk up the tree, since the bits are already set
// right on the parent of aNewParentFrame.
NS_ASSERTION(aNewParentFrame->GetParent()->GetStateBits() &
NS_FRAME_HAS_CHILD_WITH_VIEW,
"aNewParentFrame's parent should have this bit set!");
aNewParentFrame->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
}
}
// MathML Mod - RBS
#ifdef MOZ_MATHML
nsresult
@ -7475,8 +7534,7 @@ nsCSSFrameConstructor::ConstructSVGFrame(nsFrameConstructorState& aState,
// absolute containing block.
nsFrameConstructorSaveState saveState;
aState.PushFloatContainingBlock(nsnull, saveState, PR_FALSE, PR_FALSE);
const nsStyleDisplay* disp = innerPseudoStyle->GetStyleDisplay();
rv = ConstructBlock(aState, disp, aContent,
rv = ConstructBlock(aState, innerPseudoStyle->GetStyleDisplay(), aContent,
newFrame, newFrame, innerPseudoStyle,
&blockFrame, childItems, PR_TRUE);
// Give the blockFrame a view so that GetOffsetTo works for descendants
@ -9579,6 +9637,18 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
if (possibleMathMLAncestor->IsFrameOfType(nsIFrame::eMathML))
return RecreateFramesForContent(possibleMathMLAncestor->GetContent());
#endif
// Undo XUL wrapping if it's no longer needed.
// (If we're in the XUL block-wrapping situation, parentFrame is the
// wrapper frame.)
nsIFrame* grandparentFrame = parentFrame->GetParent();
if (grandparentFrame && grandparentFrame->IsBoxFrame() &&
(grandparentFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
// check if this frame is the only one needing wrapping
aChild == AnyKidsNeedBlockParent(parentFrame->GetFirstChild(nsnull)) &&
!AnyKidsNeedBlockParent(childFrame->GetNextSibling())) {
return RecreateFramesForContent(grandparentFrame->GetContent());
}
// Examine the containing-block for the removed content and see if
// :first-letter style applies.
@ -12508,8 +12578,8 @@ nsCSSFrameConstructor::ConstructBlock(nsFrameConstructorState& aState,
return rv;
}
PRBool
nsCSSFrameConstructor::AreAllKidsInline(nsIFrame* aFrameList)
static PRBool
AreAllKidsInline(nsIFrame* aFrameList)
{
nsIFrame* kid = aFrameList;
while (kid) {
@ -12835,6 +12905,55 @@ nsCSSFrameConstructor::ProcessInlineChildren(nsFrameConstructorState& aState,
return rv;
}
static void
DestroyNewlyCreatedFrames(nsFrameConstructorState& aState,
nsIFrame* aParentFrame,
const nsFrameItems& aFrameList)
{
// Ok, reverse tracks: wipe out the frames we just created
nsFrameManager *frameManager = aState.mFrameManager;
// Destroy the frames. As we do make sure any content to frame mappings
// or entries in the undisplayed content map are removed
frameManager->ClearAllUndisplayedContentIn(aParentFrame->GetContent());
CleanupFrameReferences(frameManager, aFrameList.childList);
if (aState.mAbsoluteItems.childList) {
CleanupFrameReferences(frameManager, aState.mAbsoluteItems.childList);
}
if (aState.mFixedItems.childList) {
CleanupFrameReferences(frameManager, aState.mFixedItems.childList);
}
if (aState.mFloatedItems.childList) {
CleanupFrameReferences(frameManager, aState.mFloatedItems.childList);
}
#ifdef MOZ_XUL
if (aState.mPopupItems.childList) {
CleanupFrameReferences(frameManager, aState.mPopupItems.childList);
}
#endif
nsFrameList tmp(aFrameList.childList);
tmp.DestroyFrames();
tmp.SetFrames(aState.mAbsoluteItems.childList);
tmp.DestroyFrames();
aState.mAbsoluteItems.childList = nsnull;
tmp.SetFrames(aState.mFixedItems.childList);
tmp.DestroyFrames();
aState.mFixedItems.childList = nsnull;
tmp.SetFrames(aState.mFloatedItems.childList);
tmp.DestroyFrames();
aState.mFloatedItems.childList = nsnull;
#ifdef MOZ_XUL
tmp.SetFrames(aState.mPopupItems.childList);
tmp.DestroyFrames();
aState.mPopupItems.childList = nsnull;
#endif
}
PRBool
nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
nsIFrame* aContainingBlock,
@ -12847,8 +12966,20 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
return PR_FALSE;
}
// Before we go and append the frames, check for a special
// situation: an inline frame that will now contain block
// Before we go and append the frames, we must check for two
// special situations.
// Situation #1 is a XUL frame that contains frames that are required
// to be wrapped in blocks.
if (aFrame->IsBoxFrame() &&
!(aFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
AnyKidsNeedBlockParent(aFrameList.childList)) {
DestroyNewlyCreatedFrames(aState, aFrame, aFrameList);
RecreateFramesForContent(aFrame->GetContent());
return PR_TRUE;
}
// Situation #2 is an inline frame that will now contain block
// frames. This is a no-no and the frame construction logic knows
// how to fix this. See defition of IsInlineFrame() for what "an
// inline" is. Whether we have "a block" is tested for by
@ -12910,48 +13041,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
}
}
// Ok, reverse tracks: wipe out the frames we just created
nsFrameManager *frameManager = aState.mFrameManager;
// Destroy the frames. As we do make sure any content to frame mappings
// or entries in the undisplayed content map are removed
frameManager->ClearAllUndisplayedContentIn(aFrame->GetContent());
CleanupFrameReferences(frameManager, aFrameList.childList);
if (aState.mAbsoluteItems.childList) {
CleanupFrameReferences(frameManager, aState.mAbsoluteItems.childList);
}
if (aState.mFixedItems.childList) {
CleanupFrameReferences(frameManager, aState.mFixedItems.childList);
}
if (aState.mFloatedItems.childList) {
CleanupFrameReferences(frameManager, aState.mFloatedItems.childList);
}
#ifdef MOZ_XUL
if (aState.mPopupItems.childList) {
CleanupFrameReferences(frameManager, aState.mPopupItems.childList);
}
#endif
nsFrameList tmp(aFrameList.childList);
tmp.DestroyFrames();
tmp.SetFrames(aState.mAbsoluteItems.childList);
tmp.DestroyFrames();
aState.mAbsoluteItems.childList = nsnull;
tmp.SetFrames(aState.mFixedItems.childList);
tmp.DestroyFrames();
aState.mFixedItems.childList = nsnull;
tmp.SetFrames(aState.mFloatedItems.childList);
tmp.DestroyFrames();
aState.mFloatedItems.childList = nsnull;
#ifdef MOZ_XUL
tmp.SetFrames(aState.mPopupItems.childList);
tmp.DestroyFrames();
aState.mPopupItems.childList = nsnull;
#endif
DestroyNewlyCreatedFrames(aState, aFrame, aFrameList);
// If we don't have a containing block, start with aFrame and look for one.
if (!aContainingBlock) {

Просмотреть файл

@ -885,8 +885,6 @@ private:
nsFrameItems& aFrameItems,
PRBool* aKidsAllInline);
PRBool AreAllKidsInline(nsIFrame* aFrameList);
// Determine whether we need to wipe out what we just did and start over
// because we're doing something like adding block kids to an inline frame
// (and therefore need an {ib} split). If aIsAppend is true, aPrevSibling is

Просмотреть файл

@ -0,0 +1,2 @@
<!DOCTYPE HTML>
<span style="display:-moz-inline-box">hello world</span>

Просмотреть файл

@ -0,0 +1,2 @@
<!DOCTYPE HTML>
<span style="display:-moz-inline-box"><span style="background:green">&nbsp;</span></span>

Просмотреть файл

@ -0,0 +1,6 @@
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml">
<vbox flex="1">
<label value="hello world" />
</vbox>
</window>

Просмотреть файл

@ -0,0 +1,8 @@
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml">
<vbox flex="1">
<html:span style="display:inline" flex="1" /> <!-- causes block wrapping -->
<box flex="1" />
<label value="hello world" />
</vbox>
</window>

Просмотреть файл

@ -0,0 +1,8 @@
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml">
<vbox flex="1">
<html:span style="display:inline" flex="1" /> <!-- causes block wrapping -->
<box flex="1" />
<label value="hello world" />
</vbox>
</window>

Просмотреть файл

@ -0,0 +1,25 @@
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml">
class="reftest-wait">
<script type="text/javascript"><![CDATA[
function run() {
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const HTML_NS = "http://www.w3.org/1999/xhtml";
var vbox = document.getElementsByTagName("vbox")[0];
var span = document.createElementNS(HTML_NS, "html:span");
vbox.insertBefore(span, vbox.firstChild); // causes block wrapping
setTimeout(finish, 0);
}
function finish() {
document.documentElement.removeAttribute("class");
}
function load(event) {
setTimeout(run, 0);
}
window.addEventListener("load", load, false);
]]></script>
<vbox flex="1">
<box flex="1" />
<label value="hello world" />
</vbox>
</window>

Просмотреть файл

@ -0,0 +1,8 @@
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml">
<vbox flex="1">
<box flex="1" />
<label value="hello world" />
<html:span style="display:inline" flex="1" /> <!-- causes block wrapping -->
</vbox>
</window>

Просмотреть файл

@ -0,0 +1,25 @@
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml">
class="reftest-wait">
<script type="text/javascript"><![CDATA[
function run() {
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const HTML_NS = "http://www.w3.org/1999/xhtml";
var vbox = document.getElementsByTagName("vbox")[0];
var span = document.createElementNS(HTML_NS, "html:span");
vbox.appendChild(span); // causes block wrapping
setTimeout(finish, 0);
}
function finish() {
document.documentElement.removeAttribute("class");
}
function load(event) {
setTimeout(run, 0);
}
window.addEventListener("load", load, false);
]]></script>
<vbox flex="1">
<box flex="1" />
<label value="hello world" />
</vbox>
</window>

Просмотреть файл

@ -0,0 +1,7 @@
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml">
<vbox flex="1">
<box flex="1" />
<label value="hello world" />
</vbox>
</window>

Просмотреть файл

@ -0,0 +1,25 @@
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml">
class="reftest-wait">
<script type="text/javascript"><![CDATA[
function run() {
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const HTML_NS = "http://www.w3.org/1999/xhtml";
var span = document.getElementsByTagNameNS(HTML_NS, "span")[0];
span.parentNode.removeChild(span);
setTimeout(finish, 0);
}
function finish() {
document.documentElement.removeAttribute("class");
}
function load(event) {
setTimeout(run, 0);
}
window.addEventListener("load", load, false);
]]></script>
<vbox flex="1">
<html:span style="display:inline" flex="1" /> <!-- causes block wrapping -->
<box flex="1" />
<label value="hello world" />
</vbox>
</window>

Просмотреть файл

@ -130,6 +130,10 @@ fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == 28811-2a.html 28811-2-ref.html # bug 38
!= 315620-1b.html 315620-1-ref.html
== 315620-2a.xhtml 315620-2-ref.xhtml
!= 315620-2b.xhtml 315620-2-ref.xhtml
!= 321402-1.html about:blank
!= 321402-2.html about:blank
== 321402-3.xul 321402-3-ref.xul
== 321402-4.xul 321402-4-ref.xul
== 322461-1.xml 322461-1-ref.html
== 323656-1.html 323656-1-ref.html
== 323656-2.html 323656-2-ref.html

Просмотреть файл

@ -57,6 +57,7 @@ CSS_ANON_BOX(mozNonElement, ":-moz-non-element")
CSS_ANON_BOX(mozAnonymousBlock, ":-moz-anonymous-block")
CSS_ANON_BOX(mozAnonymousPositionedBlock, ":-moz-anonymous-positioned-block")
CSS_ANON_BOX(mozMathMLAnonymousBlock, ":-moz-mathml-anonymous-block")
CSS_ANON_BOX(mozXULAnonymousBlock, ":-moz-xul-anonymous-block")
CSS_ANON_BOX(mozLineFrame, ":-moz-line-frame")

Просмотреть файл

@ -128,6 +128,12 @@
position: static !important;
}
*|*::-moz-xul-anonymous-block {
display: block ! important;
position: static ! important;
float: none ! important;
}
*|*::-moz-scrolled-content, *|*::-moz-scrolled-canvas,
*|*::-moz-scrolled-page-sequence {
/* e.g., text inputs, select boxes */

Просмотреть файл

@ -1086,7 +1086,13 @@ nsBoxFrame::AppendFrames(nsIAtom* aListName,
return NS_OK;
}
/* virtual */ nsIFrame*
nsBoxFrame::GetContentInsertionFrame()
{
if (GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK)
return GetFirstChild(nsnull)->GetContentInsertionFrame();
return nsContainerFrame::GetContentInsertionFrame();
}
NS_IMETHODIMP
nsBoxFrame::AttributeChanged(PRInt32 aNameSpaceID,

Просмотреть файл

@ -55,12 +55,12 @@ class nsBoxLayoutState;
#define NS_STATE_STACK_NOT_POSITIONED 0x00200000
//#define NS_STATE_IS_HORIZONTAL 0x00400000 moved to nsIFrame.h
#define NS_STATE_AUTO_STRETCH 0x00800000
//#define NS_STATE_IS_ROOT 0x01000000 moved to nsIFrame.h
//#define NS_STATE_IS_ROOT 0x01000000 moved to nsBox.h
#define NS_STATE_CURRENTLY_IN_DEBUG 0x02000000
//#define NS_STATE_SET_TO_DEBUG 0x04000000 moved to nsIFrame.h
//#define NS_STATE_DEBUG_WAS_SET 0x08000000 moved to nsIFrame.h
//#define NS_STATE_SET_TO_DEBUG 0x04000000 moved to nsBox.h
//#define NS_STATE_DEBUG_WAS_SET 0x08000000 moved to nsBox.h
#define NS_STATE_IS_COLLAPSED 0x10000000
//#define NS_STATE_STYLE_CHANGE 0x20000000 moved to nsIFrame.h
#define NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK 0x20000000
#define NS_STATE_EQUAL_SIZE 0x40000000
//#define NS_STATE_IS_DIRECTION_NORMAL 0x80000000 moved to nsIFrame.h
@ -134,6 +134,8 @@ public:
NS_IMETHOD RemoveFrame(nsIAtom* aListName,
nsIFrame* aOldFrame);
virtual nsIFrame* GetContentInsertionFrame();
NS_IMETHOD SetInitialChildList(nsIAtom* aListName,
nsIFrame* aChildList);