Bug 288704 part 3 - Make nsBulletFrame use the built-in 'list-item' CSS counter and remove the old implementation. r=emilio

This commit is contained in:
Mats Palmgren 2019-03-24 23:13:53 +01:00
Родитель c750eaac07
Коммит bff6f8a4d5
9 изменённых файлов: 20 добавлений и 370 удалений

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

@ -350,6 +350,9 @@ class nsCSSFrameConstructor final : public nsFrameManager {
void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
// temporary - please don't add external uses outside of nsBulletFrame
nsCounterManager* CounterManager() { return &mCounterManager; }
private:
struct FrameConstructionItem;
class FrameConstructionItemList;

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

@ -741,9 +741,6 @@ nscoord nsBlockFrame::GetMinISize(gfxContext* aRenderingContext) {
curFrame->LazyMarkLinesDirty();
}
if (RenumberList()) {
AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
}
if (GetStateBits() & NS_BLOCK_NEEDS_BIDI_RESOLUTION) ResolveBidi();
InlineMinISizeData data;
for (nsBlockFrame* curFrame = this; curFrame;
@ -822,9 +819,6 @@ nscoord nsBlockFrame::GetPrefISize(gfxContext* aRenderingContext) {
curFrame->LazyMarkLinesDirty();
}
if (RenumberList()) {
AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
}
if (GetStateBits() & NS_BLOCK_NEEDS_BIDI_RESOLUTION) ResolveBidi();
InlinePrefISizeData data;
for (nsBlockFrame* curFrame = this; curFrame;
@ -1161,10 +1155,6 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
if (GetStateBits() & NS_BLOCK_NEEDS_BIDI_RESOLUTION)
static_cast<nsBlockFrame*>(FirstContinuation())->ResolveBidi();
if (RenumberList()) {
AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
}
// Handle paginated overflow (see nsContainerFrame.h)
nsOverflowAreas ocBounds;
nsReflowStatus ocStatus;
@ -2982,42 +2972,6 @@ void nsBlockFrame::MoveChildFramesOfLine(nsLineBox* aLine,
}
}
nsresult nsBlockFrame::AttributeChanged(int32_t aNameSpaceID,
nsAtom* aAttribute, int32_t aModType) {
nsresult rv =
nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
if (NS_FAILED(rv)) {
return rv;
}
if (nsGkAtoms::value == aAttribute) {
const nsStyleDisplay* styleDisplay = StyleDisplay();
if (mozilla::StyleDisplay::ListItem == styleDisplay->mDisplay) {
// Search for the closest ancestor that's a block frame. We
// make the assumption that all related list items share a
// common block/grid/flex ancestor.
// XXXldb I think that's a bad assumption.
nsContainerFrame* ancestor = GetParent();
for (; ancestor; ancestor = ancestor->GetParent()) {
auto frameType = ancestor->Type();
if (frameType == LayoutFrameType::Block ||
frameType == LayoutFrameType::FlexContainer ||
frameType == LayoutFrameType::GridContainer) {
break;
}
}
// Tell the ancestor to renumber list items within itself.
if (ancestor) {
// XXX Not sure if this is necessary anymore
if (ancestor->RenumberList()) {
PresShell()->FrameNeedsReflow(ancestor, nsIPresShell::eStyleChange,
NS_FRAME_HAS_DIRTY_CHILDREN);
}
}
}
}
return rv;
}
static inline bool IsNonAutoNonZeroBSize(const StyleSize& aCoord) {
// The "extremum length" values (see ExtremumLength) were originally aimed at
// inline-size (or width, as it was before logicalization). For now, let them
@ -6853,43 +6807,6 @@ void nsBlockFrame::GetSpokenBulletText(nsAString& aText) const {
}
}
bool nsBlockFrame::RenumberChildFrames(int32_t* aOrdinal, int32_t aDepth,
int32_t aIncrement, bool aForCounting) {
// Examine each line in the block
bool foundValidLine;
nsBlockInFlowLineIterator bifLineIter(this, &foundValidLine);
if (!foundValidLine) {
return false;
}
bool renumberedABullet = false;
do {
nsLineList::iterator line = bifLineIter.GetLine();
nsIFrame* kid = line->mFirstChild;
int32_t n = line->GetChildCount();
while (--n >= 0) {
bool kidRenumberedABullet = kid->RenumberFrameAndDescendants(
aOrdinal, aDepth, aIncrement, aForCounting);
if (!aForCounting && kidRenumberedABullet) {
line->MarkDirty();
renumberedABullet = true;
}
kid = kid->GetNextSibling();
}
} while (bifLineIter.Next());
// We need to set NS_FRAME_HAS_DIRTY_CHILDREN bits up the tree between
// the bullet and the caller of RenumberList. But the caller itself
// has to be responsible for setting the bit itself, since that caller
// might be making a FrameNeedsReflow call, which requires that the
// bit not be set yet.
if (renumberedABullet && aDepth != 0) {
AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
}
return renumberedABullet;
}
void nsBlockFrame::ReflowBullet(nsIFrame* aBulletFrame,
BlockReflowInput& aState,
ReflowOutput& aMetrics, nscoord aLineTop) {

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

@ -317,9 +317,6 @@ class nsBlockFrame : public nsContainerFrame {
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) override;
nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
int32_t aModType) override;
/**
* Move any frames on our overflow list to the end of our principal list.
* @return true if there were any overflow frames
@ -577,10 +574,6 @@ class nsBlockFrame : public nsContainerFrame {
return false;
}
virtual bool RenumberChildFrames(int32_t* aOrdinal, int32_t aDepth,
int32_t aIncrement,
bool aForCounting) override;
// @see nsIFrame::AddSizeOfExcludingThisForTree
void AddSizeOfExcludingThisForTree(nsWindowSizes&) const override;

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

@ -175,7 +175,7 @@ class nsDisplayBulletGeometry
: nsDisplayItemGenericGeometry(aItem, aBuilder),
nsImageGeometryMixin(aItem, aBuilder) {
nsBulletFrame* f = static_cast<nsBulletFrame*>(aItem->Frame());
mOrdinal = f->GetOrdinal();
mOrdinal = f->Ordinal();
}
virtual bool InvalidateForSyncDecodeImages() const override {
@ -581,7 +581,7 @@ class nsDisplayBullet final : public nsDisplayItem {
static_cast<const nsDisplayBulletGeometry*>(aGeometry);
nsBulletFrame* f = static_cast<nsBulletFrame*>(mFrame);
if (f->GetOrdinal() != geometry->mOrdinal) {
if (f->Ordinal() != geometry->mOrdinal) {
bool snap;
aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &snap));
return;
@ -770,8 +770,8 @@ Maybe<BulletRenderer> nsBulletFrame::CreateBulletRenderer(
RefPtr<nsFontMetrics> fm =
nsLayoutUtils::GetFontMetricsForFrame(this, GetFontSizeInflation());
nsAutoString text;
GetListItemText(listStyleType, GetWritingMode(), GetOrdinal(), text);
WritingMode wm = GetWritingMode();
GetListItemText(listStyleType, wm, Ordinal(), text);
nscoord ascent = wm.IsLineInverted() ? fm->MaxDescent() : fm->MaxAscent();
aPt.MoveBy(padding.left, padding.top);
if (wm.IsVertical()) {
@ -810,33 +810,19 @@ ImgDrawResult nsBulletFrame::PaintBullet(gfxContext& aRenderingContext,
aDisableSubpixelAA, this);
}
int32_t nsBulletFrame::SetListItemOrdinal(int32_t aNextOrdinal, bool* aChanged,
int32_t aIncrement) {
MOZ_ASSERT(aIncrement == 1 || aIncrement == -1,
"We shouldn't have weird increments here");
// Assume that the ordinal comes from the caller
int32_t oldOrdinal = mOrdinal;
mOrdinal = aNextOrdinal;
// Try to get value directly from the list-item, if it specifies a
// value attribute. Note: we do this with our parent's content
// because our parent is the list-item.
nsIContent* parentContent = GetParent()->GetContent();
if (parentContent) {
nsGenericHTMLElement* hc = nsGenericHTMLElement::FromNode(parentContent);
if (hc) {
const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::value);
if (attr && attr->Type() == nsAttrValue::eInteger) {
// Use ordinal specified by the value attribute
mOrdinal = attr->GetIntegerValue();
}
int32_t nsBulletFrame::Ordinal() const {
auto* fc = PresShell()->FrameConstructor();
auto* cm = fc->CounterManager();
auto* list = cm->CounterListFor(NS_LITERAL_STRING("list-item"));
MOZ_ASSERT(list && !list->IsDirty());
nsIFrame* listItem = GetParent()->GetContent()->GetPrimaryFrame();
int32_t value = 0;
for (auto* node = list->First(); node; node = list->Next(node)) {
if (node->mPseudoFrame == listItem) {
value = node->mValueAfter;
}
}
*aChanged = oldOrdinal != mOrdinal;
return nsCounterManager::IncrementCounter(mOrdinal, aIncrement);
return value;
}
void nsBulletFrame::GetListItemText(CounterStyle* aStyle,
@ -959,7 +945,7 @@ void nsBulletFrame::GetDesiredSize(nsPresContext* aCX,
break;
default:
GetListItemText(style, GetWritingMode(), GetOrdinal(), text);
GetListItemText(style, wm, Ordinal(), text);
finalSize.BSize(wm) = fm->MaxHeight();
finalSize.ISize(wm) = nsLayoutUtils::AppUnitWidthOfStringBidi(
text, this, *fm, *aRenderingContext);
@ -1267,7 +1253,7 @@ void nsBulletFrame::GetSpokenText(nsAString& aText) {
PresContext()->CounterStyleManager()->ResolveCounterStyle(
StyleList()->mCounterStyle);
bool isBullet;
style->GetSpokenCounterText(mOrdinal, GetWritingMode(), aText, isBullet);
style->GetSpokenCounterText(Ordinal(), GetWritingMode(), aText, isBullet);
if (isBullet) {
if (!style->IsNone()) {
aText.Append(' ');

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

@ -53,7 +53,6 @@ class nsBulletFrame final : public nsFrame {
: nsFrame(aStyle, aPresContext, kClassID),
mPadding(GetWritingMode()),
mIntrinsicSize(GetWritingMode()),
mOrdinal(0),
mRequestRegistered(false) {}
virtual ~nsBulletFrame();
@ -89,8 +88,6 @@ class nsBulletFrame final : public nsFrame {
}
// nsBulletFrame
int32_t SetListItemOrdinal(int32_t aNextOrdinal, bool* aChanged,
int32_t aIncrement);
/* get list item text, with prefix & suffix */
static void GetListItemText(mozilla::CounterStyle*, mozilla::WritingMode,
@ -115,7 +112,7 @@ class nsBulletFrame final : public nsFrame {
}
void SetFontSizeInflation(float aInflation);
int32_t GetOrdinal() { return mOrdinal; }
int32_t Ordinal() const;
already_AddRefed<imgIContainer> GetImage() const;
@ -137,7 +134,6 @@ class nsBulletFrame final : public nsFrame {
RefPtr<nsBulletListener> mListener;
mozilla::LogicalSize mIntrinsicSize;
int32_t mOrdinal;
private:
mozilla::CounterStyle* ResolveCounterStyle();

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

@ -1692,177 +1692,6 @@ bool nsContainerFrame::ResolvedOrientationIsVertical() {
return false;
}
// static
bool nsContainerFrame::FrameStartsCounterScope(nsIFrame* aFrame) {
nsIContent* content = aFrame->GetContent();
if (!content || !content->IsHTMLElement()) return false;
nsAtom* localName = content->NodeInfo()->NameAtom();
return localName == nsGkAtoms::ol || localName == nsGkAtoms::ul ||
localName == nsGkAtoms::dir || localName == nsGkAtoms::menu;
}
bool nsContainerFrame::RenumberList() {
if (!FrameStartsCounterScope(this)) {
// If this frame doesn't start a counter scope then we don't need
// to renumber child list items.
return false;
}
MOZ_ASSERT(
mContent->IsHTMLElement(),
"FrameStartsCounterScope should only return true for HTML elements");
// Setup initial list ordinal value
// XXX Map html's start property to counter-reset style
int32_t ordinal = 1;
int32_t increment;
if (mContent->IsHTMLElement(nsGkAtoms::ol) &&
mContent->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::reversed)) {
increment = -1;
} else {
increment = 1;
}
nsGenericHTMLElement* hc = nsGenericHTMLElement::FromNode(mContent);
// Must be non-null, since FrameStartsCounterScope only returns true
// for HTML elements.
MOZ_ASSERT(hc, "How is mContent not HTML?");
const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::start);
nsContainerFrame* fif = static_cast<nsContainerFrame*>(FirstInFlow());
if (attr && attr->Type() == nsAttrValue::eInteger) {
ordinal = attr->GetIntegerValue();
} else if (increment < 0) {
// <ol reversed> case, or some other case with a negative increment: count
// up the child list
ordinal = 0;
fif->RenumberChildFrames(&ordinal, 0, -increment, true);
}
return fif->RenumberChildFrames(&ordinal, 0, increment, false);
}
// add in a sanity check for absurdly deep frame trees. See bug 42138
// can't just use IsFrameTreeTooDeep() because that method has side effects we
// don't want
// 200 open displayable tags is pretty unrealistic
#define MAX_DEPTH_FOR_LIST_RENUMBERING 200
bool nsContainerFrame::RenumberFrameAndDescendants(int32_t* aOrdinal,
int32_t aDepth,
int32_t aIncrement,
bool aForCounting) {
MOZ_ASSERT(aOrdinal, "null params are immoral!");
// add in a sanity check for absurdly deep frame trees. See bug 42138
if (MAX_DEPTH_FOR_LIST_RENUMBERING < aDepth) {
return false;
}
const nsStyleDisplay* display = StyleDisplay();
// drill down through any wrappers to the real frame
nsIFrame* kid = GetContentInsertionFrame();
if (!kid) {
return false;
}
// Do not renumber list for summary elements.
HTMLSummaryElement* summary = HTMLSummaryElement::FromNode(kid->GetContent());
if (summary && summary->IsMainSummary()) {
return false;
}
bool kidRenumberedABullet = false;
// If the frame is a list-item and the frame implements our
// block frame API then get its bullet and set the list item
// ordinal.
if (mozilla::StyleDisplay::ListItem == display->mDisplay) {
// Make certain that the frame is a block frame in case
// something foreign has crept in.
nsBlockFrame* listItem = do_QueryFrame(kid);
if (listItem) {
nsBulletFrame* bullet = listItem->GetBullet();
if (bullet) {
if (!aForCounting) {
bool changed;
*aOrdinal =
bullet->SetListItemOrdinal(*aOrdinal, &changed, aIncrement);
if (changed) {
kidRenumberedABullet = true;
// The ordinal changed - mark the bullet frame, and any
// intermediate frames between it and the block (are there
// ever any?), dirty.
// The calling code will make the necessary FrameNeedsReflow
// call for the list ancestor.
bullet->AddStateBits(NS_FRAME_IS_DIRTY);
nsIFrame* f = bullet;
do {
nsIFrame* parent = f->GetParent();
parent->ChildIsDirty(f);
f = parent;
} while (f != listItem);
}
} else {
// We're only counting the number of children,
// not restyling them. Don't take |value|
// into account when incrementing the ordinal
// or dirty the bullet.
*aOrdinal += aIncrement;
}
}
// XXX temporary? if the list-item has child list-items they
// should be numbered too; especially since the list-item is
// itself (ASSUMED!) not to be a counter-resetter.
bool meToo = listItem->RenumberChildFrames(aOrdinal, aDepth + 1,
aIncrement, aForCounting);
if (meToo) {
kidRenumberedABullet = true;
}
}
} else if (display->mDisplay == mozilla::StyleDisplay::Block ||
display->mDisplay == mozilla::StyleDisplay::Flex ||
display->mDisplay == mozilla::StyleDisplay::Grid) {
if (FrameStartsCounterScope(kid)) {
// Don't bother recursing into a frame that is a new counter scope.
// Any list-items in there will be handled by it.
} else {
nsContainerFrame* container = do_QueryFrame(kid);
if (container) {
kidRenumberedABullet = container->RenumberChildFrames(
aOrdinal, aDepth + 1, aIncrement, aForCounting);
}
}
}
return kidRenumberedABullet;
}
bool nsContainerFrame::RenumberChildFrames(int32_t* aOrdinal, int32_t aDepth,
int32_t aIncrement,
bool aForCounting) {
bool renumbered = false;
for (auto kid : mFrames) {
bool kidRenumbered = kid->RenumberFrameAndDescendants(
aOrdinal, aDepth, aIncrement, aForCounting);
if (!aForCounting && kidRenumbered) {
renumbered = true;
}
}
// We need to set NS_FRAME_HAS_DIRTY_CHILDREN bits up the tree between
// the bullet and the caller of RenumberList. But the caller itself
// has to be responsible for setting the bit itself, since that caller
// might be making a FrameNeedsReflow call, which requires that the
// bit not be set yet.
if (renumbered && aDepth != 0) {
AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
}
return renumbered;
}
uint16_t nsContainerFrame::CSSAlignmentForAbsPosChild(
const ReflowInput& aChildRI, LogicalAxis aLogicalAxis) const {
MOZ_ASSERT(aChildRI.mFrame->IsAbsolutelyPositioned(),
@ -1876,26 +1705,6 @@ uint16_t nsContainerFrame::CSSAlignmentForAbsPosChild(
return NS_STYLE_ALIGN_START;
}
nsresult nsContainerFrame::AttributeChanged(int32_t aNameSpaceID,
nsAtom* aAttribute,
int32_t aModType) {
nsresult rv =
nsSplittableFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
if (NS_FAILED(rv)) {
return rv;
}
if (nsGkAtoms::start == aAttribute ||
(nsGkAtoms::reversed == aAttribute &&
mContent->IsHTMLElement(nsGkAtoms::ol))) {
// XXX Not sure if this is necessary anymore
if (RenumberList()) {
PresShell()->FrameNeedsReflow(this, nsIPresShell::eStyleChange,
NS_FRAME_HAS_DIRTY_CHILDREN);
}
}
return rv;
}
nsOverflowContinuationTracker::nsOverflowContinuationTracker(
nsContainerFrame* aFrame, bool aWalkOOFFrames,
bool aSkipOverflowContainerChildren)

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

@ -66,9 +66,6 @@ class nsContainerFrame : public nsSplittableFrame {
PeekOffsetCharacterOptions aOptions =
PeekOffsetCharacterOptions()) override;
virtual nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
int32_t aModType) override;
#ifdef DEBUG_FRAME_DUMP
void List(FILE* out = stderr, const char* aPrefix = "",
uint32_t aFlags = 0) const override;
@ -415,49 +412,6 @@ class nsContainerFrame : public nsSplittableFrame {
nsContainerFrame::PositionChildViews(aFrame);
}
static bool FrameStartsCounterScope(nsIFrame* aFrame);
/**
* Renumber the list of the counter scope started by this frame, if any.
* If this returns true, the frame it's called on should get the
* NS_FRAME_HAS_DIRTY_CHILDREN bit set on it by the caller; either directly
* if it's already in reflow, or via calling FrameNeedsReflow() to schedule
* a reflow.
*/
bool RenumberList();
/**
* Renumber this frame if it's a list-item, then call RenumberChildFrames.
* @param aOrdinal Ordinal number to start counting at.
* Modifies this number for each associated list
* item. Changes in the numbering due to setting
* the |value| attribute are included if |aForCounting|
* is false. This value is both an input and output
* of this function, with the output value being the
* next ordinal number to be used.
* @param aDepth Current depth in frame tree from root list element.
* @param aIncrement Amount to increase by after visiting each associated
* list item, unless overridden by |value|.
* @param aForCounting Whether we are counting the elements or actually
* restyling them. When true, this simply visits all children,
* ignoring |<li value="..">| changes, effectively counting them
* and storing the result in |aOrdinal|. This is useful for
* |<ol reversed>|, where we need to count the number of
* applicable child list elements before numbering. When false,
* this will restyle all applicable descendants, and the next
* ordinal value will be stored in |aOrdinal|, taking into account
* any changes from |<li value="..">|.
*/
bool RenumberFrameAndDescendants(int32_t* aOrdinal, int32_t aDepth,
int32_t aIncrement,
bool aForCounting) override;
/**
* Renumber the child frames using RenumberFrameAndDescendants.
* See RenumberFrameAndDescendants for description of parameters.
*/
virtual bool RenumberChildFrames(int32_t* aOrdinal, int32_t aDepth,
int32_t aIncrement, bool aForCounting);
/**
* Returns a CSS Box Alignment constant which the caller can use to align
* the absolutely-positioned child (whose ReflowInput is aChildRI) within

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

@ -4208,8 +4208,6 @@ void nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
}
RenumberList();
const FlexboxAxisTracker axisTracker(this, aReflowInput.GetWritingMode());
// Check to see if we need to create a computed info structure, to
@ -5147,8 +5145,6 @@ void nsFlexContainerFrame::ReflowPlaceholders(
nscoord nsFlexContainerFrame::IntrinsicISize(gfxContext* aRenderingContext,
IntrinsicISizeType aType) {
nscoord containerISize = 0;
RenumberList();
const nsStylePosition* stylePos = StylePosition();
const FlexboxAxisTracker axisTracker(this, GetWritingMode());

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

@ -5718,8 +5718,6 @@ void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
::MergeSortedFrameLists(mFrames, items, GetContent());
}
RenumberList();
#ifdef DEBUG
mDidPushItemsBitMayLie = false;
SanityCheckGridItemsBeforeReflow();
@ -6151,8 +6149,6 @@ void nsGridContainerFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
nscoord nsGridContainerFrame::IntrinsicISize(gfxContext* aRenderingContext,
IntrinsicISizeType aType) {
RenumberList();
// Calculate the sum of column sizes under intrinsic sizing.
// http://dev.w3.org/csswg/css-grid/#intrinsic-sizes
GridReflowInput state(this, *aRenderingContext);