Bug 333481. Sort table-part event-handling display items to ensure that the table comes before all row-groups, which come before all rows, which come before all cells. r=bernd

This commit is contained in:
roc+%cs.cmu.edu 2006-04-17 22:16:24 +00:00
parent e93572b185
commit ee089f28b9
6 changed files with 70 additions and 19 deletions

View File

@ -228,10 +228,8 @@ nsIFrame* nsDisplayList::HitTest(nsDisplayListBuilder* aBuilder, nsPoint aPt) co
return nsnull;
}
typedef PRBool (* SortLEQ)(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
void* aClosure);
static void Sort(nsDisplayList* aList, PRInt32 aCount, SortLEQ aCmp, void* aClosure) {
static void Sort(nsDisplayList* aList, PRInt32 aCount, nsDisplayList::SortLEQ aCmp,
void* aClosure) {
if (aCount < 2)
return;
@ -326,13 +324,17 @@ void nsDisplayList::ExplodeAnonymousChildLists(nsDisplayListBuilder* aBuilder) {
void nsDisplayList::SortByZOrder(nsDisplayListBuilder* aBuilder,
nsIContent* aCommonAncestor) {
ExplodeAnonymousChildLists(aBuilder);
Sort(this, Count(), IsZOrderLEQ, aCommonAncestor);
Sort(IsZOrderLEQ, aCommonAncestor);
}
void nsDisplayList::SortByContentOrder(nsDisplayListBuilder* aBuilder,
nsIContent* aCommonAncestor) {
ExplodeAnonymousChildLists(aBuilder);
Sort(this, Count(), IsContentLEQ, aCommonAncestor);
Sort(IsContentLEQ, aCommonAncestor);
}
void nsDisplayList::Sort(SortLEQ aCmp, void* aClosure) {
::Sort(this, Count(), aCmp, aClosure);
}
static PRBool

View File

@ -551,6 +551,16 @@ public:
*/
void SortByContentOrder(nsDisplayListBuilder* aBuilder, nsIContent* aCommonAncestor);
/**
* Generic stable sort. Take care, because some of the items might be nsDisplayLists
* themselves.
* aCmp(item1, item2) should return true if item1 <= item2. We sort the items
* into increasing order.
*/
typedef PRBool (* SortLEQ)(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
void* aClosure);
void Sort(SortLEQ aCmp, void* aClosure);
/**
* Optimize the display list for visibility, removing any elements that
* are not visible. We put this logic here so it can be shared by top-level

View File

@ -1379,18 +1379,45 @@ nsDisplayTableBorderBackground::Paint(nsDisplayListBuilder* aBuilder,
aBuilder->ToReferenceFrame(mFrame));
}
static PRInt32 GetTablePartRank(nsDisplayItem* aItem)
{
nsIAtom* type = aItem->GetUnderlyingFrame()->GetType();
if (type == nsGkAtoms::tableFrame)
return 0;
if (type == nsGkAtoms::tableRowGroupFrame)
return 1;
if (type == nsGkAtoms::tableRowFrame)
return 2;
return 3;
}
static PRBool CompareByTablePartRank(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
void* aClosure)
{
return GetTablePartRank(aItem1) <= GetTablePartRank(aItem2);
}
/* static */ nsresult
nsTableFrame::DisplayGenericTablePart(nsDisplayListBuilder* aBuilder,
nsFrame* aFrame,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists)
const nsDisplayListSet& aLists,
PRBool aIsRoot)
{
nsDisplayList eventsBorderBackground;
// If we need to sort the event backgrounds, then we'll put descendant
// border-backgrounds into their own list so we don't accidentally sort
// some ancestor's border-background.
PRBool sortEventBackgrounds = aIsRoot && aBuilder->IsForEventDelivery();
nsDisplayListSet lists(aLists,
sortEventBackgrounds ? &eventsBorderBackground : aLists.BorderBackground());
// Create dedicated background display items per-frame when we're
// handling events.
// XXX how to handle collapsed borders?
if (aBuilder->IsForEventDelivery() &&
aFrame->IsVisibleForPainting(aBuilder)) {
nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
nsresult rv = lists.BorderBackground()->AppendNewToTop(new (aBuilder)
nsDisplayBackground(aFrame));
NS_ENSURE_SUCCESS(rv, rv);
}
@ -1405,12 +1432,20 @@ nsTableFrame::DisplayGenericTablePart(nsDisplayListBuilder* aBuilder,
// lets us get cell borders into the nsTableFrame's BorderBackground list.
nsIFrame* kid = aFrame->GetFirstChild(nsnull);
while (kid) {
nsresult rv = aFrame->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
nsresult rv = aFrame->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, lists);
NS_ENSURE_SUCCESS(rv, rv);
kid = kid->GetNextSibling();
}
return aFrame->DisplayOutline(aBuilder, aLists);
if (sortEventBackgrounds) {
// Ensure that the table frame event background goes before the
// table rowgroups event backgrounds, before the table row event backgrounds,
// before everything else (cells and their blocks)
eventsBorderBackground.Sort(CompareByTablePartRank, nsnull);
aLists.BorderBackground()->AppendToTop(&eventsBorderBackground);
}
return aFrame->DisplayOutline(aBuilder, lists);
}
// table paint code is concerned primarily with borders and bg color
@ -1430,7 +1465,7 @@ nsTableFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
nsDisplayTableBorderBackground(this));
NS_ENSURE_SUCCESS(rv, rv);
return DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists);
return DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists, PR_TRUE);
}
// XXX We don't put the borders and backgrounds in tree order like we should.

View File

@ -263,11 +263,14 @@ public:
* and row frames. It creates a background display item for handling events
* if necessary, an outline display item if necessary, and displays
* all the the frame's children.
* @param aIsRoot true if aFrame is the table frame or a table part which
* happens to be the root of a stacking context
*/
static nsresult DisplayGenericTablePart(nsDisplayListBuilder* aBuilder,
nsFrame* aFrame,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists);
nsFrame* aFrame,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists,
PRBool aIsRoot);
// Return the closest sibling of aPriorChildFrame (including aPriroChildFrame)
// of type aChildType.

View File

@ -582,7 +582,6 @@ nsDisplayTableRowBackground::Paint(nsDisplayListBuilder* aBuilder,
nsIRenderingContext* aCtx, const nsRect& aDirtyRect) {
nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(mFrame);
nsPoint pt = aBuilder->ToReferenceFrame(mFrame);
nsIRenderingContext::AutoPushTranslation translate(aCtx, pt.x, pt.y);
TableBackgroundPainter painter(tableFrame,
@ -600,7 +599,8 @@ nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
if (!IsVisibleInSelection(aBuilder))
return NS_OK;
if (aBuilder->IsAtRootOfPseudoStackingContext()) {
PRBool isRoot = aBuilder->IsAtRootOfPseudoStackingContext();
if (isRoot) {
// This background is created regardless of whether this frame is
// visible or not. Visibility decisions are delegated to the
// table background painter.
@ -612,7 +612,7 @@ nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
NS_ENSURE_SUCCESS(rv, rv);
}
return nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists);
return nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists, isRoot);
}
PRIntn

View File

@ -210,7 +210,8 @@ nsTableRowGroupFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
if (!IsVisibleInSelection(aBuilder))
return NS_OK;
if (aBuilder->IsAtRootOfPseudoStackingContext()) {
PRBool isRoot = aBuilder->IsAtRootOfPseudoStackingContext();
if (isRoot) {
// This background is created regardless of whether this frame is
// visible or not. Visibility decisions are delegated to the
// table background painter.
@ -219,7 +220,7 @@ nsTableRowGroupFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
NS_ENSURE_SUCCESS(rv, rv);
}
return nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists);
return nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists, isRoot);
}
PRIntn