зеркало из https://github.com/mozilla/gecko-dev.git
Bug 205202 part 1 - [css-lists][css-pseudo] Add support for the ::marker pseudo element on list items. Alias :-moz-list-bullet/number to that in the parser. r=emilio
This commit is contained in:
Родитель
bff6f8a4d5
Коммит
53f517142f
|
@ -10224,6 +10224,7 @@ exports.CSS_PROPERTIES = {
|
|||
exports.PSEUDO_ELEMENTS = [
|
||||
":after",
|
||||
":before",
|
||||
":marker",
|
||||
":backdrop",
|
||||
":cue",
|
||||
":first-letter",
|
||||
|
@ -10231,8 +10232,6 @@ exports.PSEUDO_ELEMENTS = [
|
|||
":selection",
|
||||
":-moz-focus-inner",
|
||||
":-moz-focus-outer",
|
||||
":-moz-list-bullet",
|
||||
":-moz-list-number",
|
||||
":-moz-progress-bar",
|
||||
":-moz-range-track",
|
||||
":-moz-range-progress",
|
||||
|
|
|
@ -295,6 +295,12 @@ nsIContent* ExplicitChildIterator::GetPreviousChild() {
|
|||
|
||||
nsIContent* AllChildrenIterator::Get() const {
|
||||
switch (mPhase) {
|
||||
case eAtMarkerKid: {
|
||||
Element* marker = nsLayoutUtils::GetMarkerPseudo(mOriginalContent);
|
||||
MOZ_ASSERT(marker, "No content marker frame at eAtMarkerKid phase");
|
||||
return marker;
|
||||
}
|
||||
|
||||
case eAtBeforeKid: {
|
||||
Element* before = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
|
||||
MOZ_ASSERT(before, "No content before frame at eAtBeforeKid phase");
|
||||
|
@ -319,7 +325,15 @@ nsIContent* AllChildrenIterator::Get() const {
|
|||
}
|
||||
|
||||
bool AllChildrenIterator::Seek(const nsIContent* aChildToFind) {
|
||||
if (mPhase == eAtBegin || mPhase == eAtBeforeKid) {
|
||||
if (mPhase == eAtBegin || mPhase == eAtMarkerKid) {
|
||||
mPhase = eAtBeforeKid;
|
||||
Element* markerPseudo = nsLayoutUtils::GetMarkerPseudo(mOriginalContent);
|
||||
if (markerPseudo && markerPseudo == aChildToFind) {
|
||||
mPhase = eAtMarkerKid;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (mPhase == eAtBeforeKid) {
|
||||
mPhase = eAtExplicitKids;
|
||||
Element* beforePseudo = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
|
||||
if (beforePseudo && beforePseudo == aChildToFind) {
|
||||
|
@ -350,6 +364,14 @@ void AllChildrenIterator::AppendNativeAnonymousChildren() {
|
|||
|
||||
nsIContent* AllChildrenIterator::GetNextChild() {
|
||||
if (mPhase == eAtBegin) {
|
||||
Element* markerContent = nsLayoutUtils::GetMarkerPseudo(mOriginalContent);
|
||||
if (markerContent) {
|
||||
mPhase = eAtMarkerKid;
|
||||
return markerContent;
|
||||
}
|
||||
}
|
||||
|
||||
if (mPhase == eAtBegin || mPhase == eAtMarkerKid) {
|
||||
mPhase = eAtExplicitKids;
|
||||
Element* beforeContent = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
|
||||
if (beforeContent) {
|
||||
|
@ -442,6 +464,14 @@ nsIContent* AllChildrenIterator::GetPreviousChild() {
|
|||
}
|
||||
}
|
||||
|
||||
if (mPhase == eAtExplicitKids || mPhase == eAtBeforeKid) {
|
||||
Element* markerContent = nsLayoutUtils::GetMarkerPseudo(mOriginalContent);
|
||||
if (markerContent) {
|
||||
mPhase = eAtMarkerKid;
|
||||
return markerContent;
|
||||
}
|
||||
}
|
||||
|
||||
mPhase = eAtBegin;
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -236,6 +236,7 @@ class AllChildrenIterator : private FlattenedChildIterator {
|
|||
|
||||
enum IteratorPhase {
|
||||
eAtBegin,
|
||||
eAtMarkerKid,
|
||||
eAtBeforeKid,
|
||||
eAtExplicitKids,
|
||||
eAtAnonKids,
|
||||
|
|
|
@ -303,6 +303,11 @@ class nsIContent : public nsINode {
|
|||
mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentafter;
|
||||
}
|
||||
|
||||
bool IsGeneratedContentContainerForMarker() const {
|
||||
return IsRootOfNativeAnonymousSubtree() &&
|
||||
mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentmarker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get direct access (but read only) to the text in the text content.
|
||||
* NOTE: For elements this is *not* the concatenation of all text children,
|
||||
|
|
|
@ -26,21 +26,24 @@ JSObject* nsXMLElement::WrapNode(JSContext* aCx,
|
|||
}
|
||||
|
||||
void nsXMLElement::UnbindFromTree(bool aDeep, bool aNullParent) {
|
||||
PseudoStyleType pseudoType = GetPseudoElementType();
|
||||
bool isBefore = pseudoType == PseudoStyleType::before;
|
||||
nsAtom* property = isBefore ? nsGkAtoms::beforePseudoProperty
|
||||
: nsGkAtoms::afterPseudoProperty;
|
||||
|
||||
switch (pseudoType) {
|
||||
nsAtom* property;
|
||||
switch (GetPseudoElementType()) {
|
||||
case PseudoStyleType::marker:
|
||||
property = nsGkAtoms::markerPseudoProperty;
|
||||
break;
|
||||
case PseudoStyleType::before:
|
||||
case PseudoStyleType::after: {
|
||||
MOZ_ASSERT(GetParent());
|
||||
MOZ_ASSERT(GetParent()->IsElement());
|
||||
GetParent()->DeleteProperty(property);
|
||||
property = nsGkAtoms::beforePseudoProperty;
|
||||
break;
|
||||
case PseudoStyleType::after:
|
||||
property = nsGkAtoms::afterPseudoProperty;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
property = nullptr;
|
||||
}
|
||||
if (property) {
|
||||
MOZ_ASSERT(GetParent());
|
||||
MOZ_ASSERT(GetParent()->IsElement());
|
||||
GetParent()->DeleteProperty(property);
|
||||
}
|
||||
Element::UnbindFromTree(aDeep, aNullParent);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
list-style-type: '−';
|
||||
}
|
||||
|
||||
.expandable-opening::-moz-list-bullet {
|
||||
.expandable-opening::marker {
|
||||
cursor: pointer;
|
||||
padding-inline-end: 2px;
|
||||
/* Don't want to inherit the styling from pi and comment elements */
|
||||
|
|
|
@ -2050,10 +2050,6 @@ static const nsIFrame* ExpectedOwnerForChild(const nsIFrame* aFrame) {
|
|||
: FirstContinuationOrPartOfIBSplit(parent);
|
||||
}
|
||||
|
||||
if (aFrame->IsBulletFrame()) {
|
||||
return FirstContinuationOrPartOfIBSplit(parent);
|
||||
}
|
||||
|
||||
if (aFrame->IsLineFrame()) {
|
||||
// A ::first-line always ends up here via its block, which is therefore the
|
||||
// right expected owner. That block can be an
|
||||
|
@ -2744,6 +2740,20 @@ bool RestyleManager::ProcessPostTraversal(Element* aElement,
|
|||
aRestyleState.AddPendingWrapperRestyle(
|
||||
ServoRestyleState::TableAwareParentFor(maybeAnonBoxChild));
|
||||
}
|
||||
|
||||
// If we don't have a ::marker pseudo-element, but need it, then
|
||||
// reconstruct the frame. (The opposite situation implies 'display'
|
||||
// changes so doesn't need to be handled explicitly here.)
|
||||
if (styleFrame->StyleDisplay()->mDisplay == StyleDisplay::ListItem &&
|
||||
styleFrame->IsBlockFrameOrSubclass() &&
|
||||
!nsLayoutUtils::GetMarkerPseudo(aElement)) {
|
||||
RefPtr<ComputedStyle> pseudoStyle =
|
||||
aRestyleState.StyleSet().ProbePseudoElementStyle(
|
||||
*aElement, PseudoStyleType::marker, styleFrame->Style());
|
||||
if (pseudoStyle) {
|
||||
changeHint |= nsChangeHint_ReconstructFrame;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Although we shouldn't generate non-ReconstructFrame hints for elements with
|
||||
|
|
|
@ -1706,20 +1706,20 @@ already_AddRefed<nsIContent> nsCSSFrameConstructor::CreateGeneratedContent(
|
|||
*
|
||||
* Any items created are added to aItems.
|
||||
*
|
||||
* We create an XML element (tag _moz_generated_content_before or
|
||||
* _moz_generated_content_after) representing the pseudoelement. We
|
||||
* create a DOM node for each 'content' item and make those nodes the
|
||||
* children of the XML element. Then we create a frame subtree for
|
||||
* the XML element as if it were a regular child of
|
||||
* aParentFrame/aParentContent, giving the XML element the ::before or
|
||||
* ::after style.
|
||||
* We create an XML element (tag _moz_generated_content_before/after/marker)
|
||||
* representing the pseudoelement. We create a DOM node for each 'content'
|
||||
* item and make those nodes the children of the XML element. Then we create
|
||||
* a frame subtree for the XML element as if it were a regular child of
|
||||
* aParentFrame/aParentContent, giving the XML element the ::before, ::after
|
||||
* or ::marker style.
|
||||
*/
|
||||
void nsCSSFrameConstructor::CreateGeneratedContentItem(
|
||||
nsFrameConstructorState& aState, nsContainerFrame* aParentFrame,
|
||||
Element& aOriginatingElement, ComputedStyle& aStyle,
|
||||
PseudoStyleType aPseudoElement, FrameConstructionItemList& aItems) {
|
||||
MOZ_ASSERT(aPseudoElement == PseudoStyleType::before ||
|
||||
aPseudoElement == PseudoStyleType::after,
|
||||
aPseudoElement == PseudoStyleType::after ||
|
||||
aPseudoElement == PseudoStyleType::marker,
|
||||
"unexpected aPseudoElement");
|
||||
|
||||
if (aParentFrame && (aParentFrame->IsHTMLVideoFrame() ||
|
||||
|
@ -1738,12 +1738,27 @@ void nsCSSFrameConstructor::CreateGeneratedContentItem(
|
|||
return;
|
||||
}
|
||||
|
||||
bool isBefore = aPseudoElement == PseudoStyleType::before;
|
||||
nsAtom* elemName = nullptr;
|
||||
nsAtom* property = nullptr;
|
||||
switch (aPseudoElement) {
|
||||
case PseudoStyleType::before:
|
||||
elemName = nsGkAtoms::mozgeneratedcontentbefore;
|
||||
property = nsGkAtoms::beforePseudoProperty;
|
||||
break;
|
||||
case PseudoStyleType::after:
|
||||
elemName = nsGkAtoms::mozgeneratedcontentafter;
|
||||
property = nsGkAtoms::afterPseudoProperty;
|
||||
break;
|
||||
case PseudoStyleType::marker:
|
||||
elemName = nsGkAtoms::mozgeneratedcontentmarker;
|
||||
property = nsGkAtoms::markerPseudoProperty;
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("unexpected aPseudoElement");
|
||||
}
|
||||
|
||||
// |ProbePseudoStyleFor| checked the 'display' property and the
|
||||
// |ContentCount()| of the 'content' property for us.
|
||||
nsAtom* elemName = isBefore ? nsGkAtoms::mozgeneratedcontentbefore
|
||||
: nsGkAtoms::mozgeneratedcontentafter;
|
||||
RefPtr<NodeInfo> nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo(
|
||||
elemName, nullptr, kNameSpaceID_None, nsINode::ELEMENT_NODE);
|
||||
RefPtr<Element> container;
|
||||
|
@ -1754,8 +1769,6 @@ void nsCSSFrameConstructor::CreateGeneratedContentItem(
|
|||
|
||||
// Cleared when the pseudo is unbound from the tree, so no need to store a
|
||||
// strong reference, nor a destructor.
|
||||
nsAtom* property = isBefore ? nsGkAtoms::beforePseudoProperty
|
||||
: nsGkAtoms::afterPseudoProperty;
|
||||
aOriginatingElement.SetProperty(property, container.get());
|
||||
|
||||
container->SetIsNativeAnonymousRoot();
|
||||
|
@ -3223,7 +3236,8 @@ static nsIFrame* FindAncestorWithGeneratedContentPseudo(nsIFrame* aFrame) {
|
|||
NS_ASSERTION(f->IsGeneratedContentFrame(),
|
||||
"should not have exited generated content");
|
||||
auto pseudo = f->Style()->GetPseudoType();
|
||||
if (pseudo == PseudoStyleType::before || pseudo == PseudoStyleType::after)
|
||||
if (pseudo == PseudoStyleType::before || pseudo == PseudoStyleType::after ||
|
||||
pseudo == PseudoStyleType::marker)
|
||||
return f;
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -3409,8 +3423,7 @@ nsCSSFrameConstructor::FindHTMLData(const Element& aElement,
|
|||
COMPLEX_TAG_CREATE(fieldset,
|
||||
&nsCSSFrameConstructor::ConstructFieldSetFrame),
|
||||
{nsGkAtoms::legend,
|
||||
FCDATA_DECL(FCDATA_ALLOW_BLOCK_STYLES | FCDATA_MAY_NEED_SCROLLFRAME |
|
||||
FCDATA_MAY_NEED_BULLET,
|
||||
FCDATA_DECL(FCDATA_ALLOW_BLOCK_STYLES | FCDATA_MAY_NEED_SCROLLFRAME,
|
||||
NS_NewLegendFrame)},
|
||||
SIMPLE_TAG_CREATE(frameset, NS_NewHTMLFramesetFrame),
|
||||
SIMPLE_TAG_CREATE(iframe, NS_NewSubDocumentFrame),
|
||||
|
@ -3855,14 +3868,6 @@ void nsCSSFrameConstructor::ConstructFrameFromItemInternal(
|
|||
columnSpanSiblings);
|
||||
}
|
||||
}
|
||||
|
||||
if (bits & FCDATA_MAY_NEED_BULLET) {
|
||||
nsBlockFrame* block = do_QueryFrame(newFrameAsContainer);
|
||||
MOZ_ASSERT(block,
|
||||
"FCDATA_MAY_NEED_BULLET should not be set on "
|
||||
"non-block type!");
|
||||
CreateBulletFrameForListItemIfNeeded(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5257,7 +5262,9 @@ static bool ShouldSuppressFrameInSelect(const nsIContent* aParent,
|
|||
}
|
||||
|
||||
static bool ShouldSuppressFrameInNonOpenDetails(
|
||||
const HTMLDetailsElement* aDetails, const nsIContent& aChild) {
|
||||
const HTMLDetailsElement* aDetails,
|
||||
ComputedStyle* aComputedStyle,
|
||||
const nsIContent& aChild) {
|
||||
if (!aDetails || aDetails->Open()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -5271,8 +5278,11 @@ static bool ShouldSuppressFrameInNonOpenDetails(
|
|||
return false;
|
||||
}
|
||||
|
||||
// Don't suppress NAC, unless it's ::before or ::after.
|
||||
// Don't suppress NAC, unless it's a ::before, inside ::marker, or ::after.
|
||||
if (aChild.IsRootOfAnonymousSubtree() &&
|
||||
!(aChild.IsGeneratedContentContainerForMarker() &&
|
||||
aComputedStyle->StyleList()->mListStylePosition ==
|
||||
NS_STYLE_LIST_STYLE_POSITION_INSIDE) &&
|
||||
!aChild.IsGeneratedContentContainerForBefore() &&
|
||||
!aChild.IsGeneratedContentContainerForAfter()) {
|
||||
return false;
|
||||
|
@ -5338,6 +5348,15 @@ nsCSSFrameConstructor::FindElementTagData(const Element& aElement,
|
|||
ComputedStyle& aStyle,
|
||||
nsIFrame* aParentFrame,
|
||||
uint32_t aFlags) {
|
||||
// A ::marker pseudo creates a nsBulletFrame.
|
||||
if (aStyle.GetPseudoType() == PseudoStyleType::marker) {
|
||||
static const FrameConstructionData data = FCDATA_DECL(
|
||||
FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH |
|
||||
FCDATA_DISALLOW_GENERATED_CONTENT | FCDATA_IS_LINE_PARTICIPANT |
|
||||
FCDATA_IS_INLINE | FCDATA_USE_CHILD_ITEMS,
|
||||
NS_NewBulletFrame);
|
||||
return &data;
|
||||
}
|
||||
switch (aElement.GetNameSpaceID()) {
|
||||
case kNameSpaceID_XHTML:
|
||||
return FindHTMLData(aElement, aParentFrame, aStyle);
|
||||
|
@ -5486,7 +5505,7 @@ void nsCSSFrameConstructor::AddFrameConstructionItemsInternal(
|
|||
// ::before and ::after); we always want to create "internal" anonymous
|
||||
// content.
|
||||
auto* details = HTMLDetailsElement::FromNodeOrNull(parent);
|
||||
if (ShouldSuppressFrameInNonOpenDetails(details, *aContent)) {
|
||||
if (ShouldSuppressFrameInNonOpenDetails(details, aComputedStyle, *aContent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -9715,6 +9734,8 @@ void nsCSSFrameConstructor::ProcessChildren(
|
|||
AddFCItemsForAnonymousContent(aState, aFrame, anonymousItems,
|
||||
itemsToConstruct);
|
||||
|
||||
nsBlockFrame* listItem = nullptr;
|
||||
bool isOutsideMarker = false;
|
||||
if (!aPossiblyLeafFrame->IsLeaf()) {
|
||||
// :before/:after content should have the same style parent as normal kids.
|
||||
//
|
||||
|
@ -9724,9 +9745,18 @@ void nsCSSFrameConstructor::ProcessChildren(
|
|||
ComputedStyle* computedStyle;
|
||||
|
||||
if (aCanHaveGeneratedContent) {
|
||||
computedStyle =
|
||||
nsFrame::CorrectStyleParentFrame(aFrame, PseudoStyleType::NotPseudo)
|
||||
->Style();
|
||||
auto* styleParentFrame =
|
||||
nsFrame::CorrectStyleParentFrame(aFrame, PseudoStyleType::NotPseudo);
|
||||
computedStyle = styleParentFrame->Style();
|
||||
if (computedStyle->StyleDisplay()->mDisplay == StyleDisplay::ListItem &&
|
||||
(listItem = do_QueryFrame(aFrame)) &&
|
||||
!styleParentFrame->IsFieldSetFrame()) {
|
||||
isOutsideMarker = computedStyle->StyleList()->mListStylePosition ==
|
||||
NS_STYLE_LIST_STYLE_POSITION_OUTSIDE;
|
||||
CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
|
||||
*computedStyle, PseudoStyleType::marker,
|
||||
itemsToConstruct);
|
||||
}
|
||||
// Probe for generated content before
|
||||
CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
|
||||
*computedStyle, PseudoStyleType::before,
|
||||
|
@ -9770,6 +9800,30 @@ void nsCSSFrameConstructor::ProcessChildren(
|
|||
NS_ASSERTION(!allowFirstPseudos || !aFrame->IsXULBoxFrame(),
|
||||
"can't be both block and box");
|
||||
|
||||
if (listItem) {
|
||||
if (auto* markerFrame = nsLayoutUtils::GetMarkerFrame(aContent)) {
|
||||
for (auto* childFrame : aFrameItems) {
|
||||
if (markerFrame == childFrame) {
|
||||
if (isOutsideMarker) {
|
||||
// SetMarkerFrameForListItem will add childFrame to the kBulletList
|
||||
aFrameItems.RemoveFrame(childFrame);
|
||||
auto* grandParent = listItem->GetParent()->GetParent();
|
||||
if (listItem->Style()->GetPseudoType() == PseudoStyleType::columnContent &&
|
||||
grandParent &&
|
||||
grandParent->IsColumnSetWrapperFrame()) {
|
||||
listItem = do_QueryFrame(grandParent);
|
||||
MOZ_ASSERT(listItem, "ColumnSetWrapperFrame is expected to be "
|
||||
"a nsBlockFrame subclass");
|
||||
}
|
||||
}
|
||||
listItem->SetMarkerFrameForListItem(childFrame);
|
||||
MOZ_ASSERT(listItem->HasAnyStateBits(NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET) == isOutsideMarker);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (haveFirstLetterStyle) {
|
||||
WrapFramesInFirstLetterFrame(aFrame, aFrameItems);
|
||||
}
|
||||
|
@ -10647,14 +10701,12 @@ void nsCSSFrameConstructor::ConstructBlock(
|
|||
if (!StaticPrefs::layout_css_column_span_enabled()) {
|
||||
// Set the frame's initial child list
|
||||
blockFrame->SetInitialChildList(kPrincipalList, childItems);
|
||||
CreateBulletFrameForListItemIfNeeded(blockFrame);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!MayNeedToCreateColumnSpanSiblings(blockFrame, childItems)) {
|
||||
// No need to create column-span siblings.
|
||||
blockFrame->SetInitialChildList(kPrincipalList, childItems);
|
||||
CreateBulletFrameForListItemIfNeeded(blockFrame);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -10664,16 +10716,6 @@ void nsCSSFrameConstructor::ConstructBlock(
|
|||
childItems.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
|
||||
blockFrame->SetInitialChildList(kPrincipalList, initialNonColumnSpanKids);
|
||||
|
||||
nsBlockFrame* blockFrameToCreateBullet = blockFrame;
|
||||
if (needsColumn && (*aNewFrame)->StyleList()->mListStylePosition ==
|
||||
NS_STYLE_LIST_STYLE_POSITION_OUTSIDE) {
|
||||
// Create the outside bullet on ColumnSetWrapper so that the position of
|
||||
// the bullet is correct.
|
||||
blockFrameToCreateBullet = static_cast<nsBlockFrame*>(*aNewFrame);
|
||||
}
|
||||
|
||||
CreateBulletFrameForListItemIfNeeded(blockFrameToCreateBullet);
|
||||
|
||||
if (childItems.IsEmpty()) {
|
||||
// No more kids to process (there weren't any column-span kids).
|
||||
return;
|
||||
|
@ -10706,33 +10748,6 @@ void nsCSSFrameConstructor::ConstructBlock(
|
|||
"The column-span siblings should be moved to the proper place!");
|
||||
}
|
||||
|
||||
void nsCSSFrameConstructor::CreateBulletFrameForListItemIfNeeded(
|
||||
nsBlockFrame* aBlockFrame) {
|
||||
// Create a list bullet if this is a list-item. Note that this is
|
||||
// done here so that RenumberList will work (it needs the bullets
|
||||
// to store the bullet numbers). Also note that due to various
|
||||
// wrapper frames (scrollframes, columns) we want to use the
|
||||
// outermost (primary, ideally, but it's not set yet when we get
|
||||
// here) frame of our content for the display check. On the other
|
||||
// hand, we look at ourselves for the GetPrevInFlow() check, since
|
||||
// for a columnset we don't want a bullet per column. Note that
|
||||
// the outermost frame for the content is the primary frame in
|
||||
// most cases; the ones when it's not (like tables) can't be
|
||||
// StyleDisplay::ListItem).
|
||||
nsIFrame* possibleListItem = aBlockFrame;
|
||||
while (true) {
|
||||
nsIFrame* parent = possibleListItem->GetParent();
|
||||
if (parent->GetContent() != aBlockFrame->GetContent()) {
|
||||
break;
|
||||
}
|
||||
possibleListItem = parent;
|
||||
}
|
||||
|
||||
if (possibleListItem->StyleDisplay()->mDisplay == StyleDisplay::ListItem) {
|
||||
aBlockFrame->CreateBulletFrameForListItem();
|
||||
}
|
||||
}
|
||||
|
||||
nsContainerFrame* nsCSSFrameConstructor::BeginBuildingColumns(
|
||||
nsFrameConstructorState& aState, nsIContent* aContent,
|
||||
nsContainerFrame* aParentFrame, nsContainerFrame* aColumnContent,
|
||||
|
|
|
@ -699,12 +699,6 @@ class nsCSSFrameConstructor final : public nsFrameManager {
|
|||
* FCDATA_USE_CHILD_ITEMS is set.
|
||||
*/
|
||||
#define FCDATA_IS_WRAPPER_ANON_BOX 0x400000
|
||||
/**
|
||||
* If FCDATA_MAY_NEED_BULLET is set, then the frame will be checked
|
||||
* whether an nsBulletFrame needs to be created for it or not. Only the
|
||||
* frames inherited from nsBlockFrame should have this bit set.
|
||||
*/
|
||||
#define FCDATA_MAY_NEED_BULLET 0x800000
|
||||
|
||||
/* Structure representing information about how a frame should be
|
||||
constructed. */
|
||||
|
@ -1802,8 +1796,6 @@ class nsCSSFrameConstructor final : public nsFrameManager {
|
|||
nsIFrame* aPositionedFrameForAbsPosContainer,
|
||||
PendingBinding* aPendingBinding);
|
||||
|
||||
void CreateBulletFrameForListItemIfNeeded(nsBlockFrame* aBlockFrame);
|
||||
|
||||
// Build the initial column hierarchy around aColumnContent. This function
|
||||
// should be called before constructing aColumnContent's children.
|
||||
//
|
||||
|
|
|
@ -48,12 +48,16 @@ bool nsGenConList::DestroyNodesFor(nsIFrame* aFrame) {
|
|||
* Compute the type of the pseudo and the content for the pseudo that
|
||||
* we'll use for comparison purposes.
|
||||
* @param aContent the content to use is stored here; it's the element
|
||||
* that generated the ::before or ::after content, or (if not for generated
|
||||
* content), the frame's own element
|
||||
* @return -1 for ::before, +1 for ::after, and 0 otherwise.
|
||||
* that generated the pseudo, or (if not for generated content), the frame's
|
||||
* own element
|
||||
* @return -2 for ::marker, -1 for ::before, +1 for ::after, and 0 otherwise.
|
||||
*/
|
||||
inline int32_t PseudoCompareType(nsIFrame* aFrame, nsIContent** aContent) {
|
||||
auto pseudo = aFrame->Style()->GetPseudoType();
|
||||
if (pseudo == mozilla::PseudoStyleType::marker) {
|
||||
*aContent = aFrame->GetContent()->GetParent();
|
||||
return -2;
|
||||
}
|
||||
if (pseudo == mozilla::PseudoStyleType::before) {
|
||||
*aContent = aFrame->GetContent()->GetParent();
|
||||
return -1;
|
||||
|
@ -84,14 +88,30 @@ bool nsGenConList::NodeAfter(const nsGenConNode* aNode1,
|
|||
NS_ASSERTION(pseudoType1 != pseudoType2, "identical");
|
||||
return pseudoType2 == 0;
|
||||
}
|
||||
// We want to treat an element as coming before its :before (preorder
|
||||
// traversal), so treating both as :before now works.
|
||||
if (pseudoType1 == 0) pseudoType1 = -1;
|
||||
if (pseudoType2 == 0) pseudoType2 = -1;
|
||||
// We want to treat an element as coming before its :before and ::marker
|
||||
// (preorder traversal), so treating both as :before now works.
|
||||
if (pseudoType1 == 0) {
|
||||
pseudoType1 = -1;
|
||||
if (pseudoType2 == -2) {
|
||||
pseudoType2 = -1;
|
||||
}
|
||||
}
|
||||
if (pseudoType2 == 0) {
|
||||
pseudoType2 = -1;
|
||||
if (pseudoType1 == -2) {
|
||||
pseudoType1 = -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (content1 == content2) {
|
||||
NS_ASSERTION(pseudoType1 != pseudoType2, "identical");
|
||||
return pseudoType1 == 1;
|
||||
return pseudoType1 > pseudoType2;
|
||||
}
|
||||
if (pseudoType1 == -2) {
|
||||
pseudoType1 = -1;
|
||||
}
|
||||
if (pseudoType2 == -2) {
|
||||
pseudoType2 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,8 +71,10 @@ struct nsGenConNode : public mozilla::LinkedListElement<nsGenConNode> {
|
|||
mPseudoFrame->Style()->GetPseudoType() ==
|
||||
mozilla::PseudoStyleType::before ||
|
||||
mPseudoFrame->Style()->GetPseudoType() ==
|
||||
mozilla::PseudoStyleType::after,
|
||||
"not :before/:after generated content and not counter change");
|
||||
mozilla::PseudoStyleType::after ||
|
||||
mPseudoFrame->Style()->GetPseudoType() ==
|
||||
mozilla::PseudoStyleType::marker,
|
||||
"not CSS generated content and not counter change");
|
||||
NS_ASSERTION(mContentIndex < 0 ||
|
||||
mPseudoFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT,
|
||||
"not generated content and not counter change");
|
||||
|
|
|
@ -1381,7 +1381,8 @@ FrameChildListID nsLayoutUtils::GetChildListNameFor(nsIFrame* aChildFrame) {
|
|||
|
||||
static Element* GetPseudo(const nsIContent* aContent, nsAtom* aPseudoProperty) {
|
||||
MOZ_ASSERT(aPseudoProperty == nsGkAtoms::beforePseudoProperty ||
|
||||
aPseudoProperty == nsGkAtoms::afterPseudoProperty);
|
||||
aPseudoProperty == nsGkAtoms::afterPseudoProperty ||
|
||||
aPseudoProperty == nsGkAtoms::markerPseudoProperty);
|
||||
if (!aContent->MayHaveAnonymousChildren()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1410,6 +1411,17 @@ nsIFrame* nsLayoutUtils::GetAfterFrame(const nsIContent* aContent) {
|
|||
return pseudo ? pseudo->GetPrimaryFrame() : nullptr;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
Element* nsLayoutUtils::GetMarkerPseudo(const nsIContent* aContent) {
|
||||
return GetPseudo(aContent, nsGkAtoms::markerPseudoProperty);
|
||||
}
|
||||
|
||||
/*static*/
|
||||
nsIFrame* nsLayoutUtils::GetMarkerFrame(const nsIContent* aContent) {
|
||||
Element* pseudo = GetMarkerPseudo(aContent);
|
||||
return pseudo ? pseudo->GetPrimaryFrame() : nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
nsIFrame* nsLayoutUtils::GetClosestFrameOfType(nsIFrame* aFrame,
|
||||
LayoutFrameType aFrameType,
|
||||
|
@ -1555,6 +1567,8 @@ bool nsLayoutUtils::IsProperAncestorFrame(const nsIFrame* aAncestorFrame,
|
|||
int32_t nsLayoutUtils::DoCompareTreePosition(
|
||||
nsIContent* aContent1, nsIContent* aContent2, int32_t aIf1Ancestor,
|
||||
int32_t aIf2Ancestor, const nsIContent* aCommonAncestor) {
|
||||
MOZ_ASSERT(aIf1Ancestor == -1 || aIf1Ancestor == 0 || aIf1Ancestor == 1);
|
||||
MOZ_ASSERT(aIf2Ancestor == -1 || aIf2Ancestor == 0 || aIf2Ancestor == 1);
|
||||
MOZ_ASSERT(aContent1, "aContent1 must not be null");
|
||||
MOZ_ASSERT(aContent2, "aContent2 must not be null");
|
||||
|
||||
|
@ -1688,6 +1702,8 @@ int32_t nsLayoutUtils::DoCompareTreePosition(nsIFrame* aFrame1,
|
|||
int32_t aIf1Ancestor,
|
||||
int32_t aIf2Ancestor,
|
||||
nsIFrame* aCommonAncestor) {
|
||||
MOZ_ASSERT(aIf1Ancestor == -1 || aIf1Ancestor == 0 || aIf1Ancestor == 1);
|
||||
MOZ_ASSERT(aIf2Ancestor == -1 || aIf2Ancestor == 0 || aIf2Ancestor == 1);
|
||||
MOZ_ASSERT(aFrame1, "aFrame1 must not be null");
|
||||
MOZ_ASSERT(aFrame2, "aFrame2 must not be null");
|
||||
|
||||
|
@ -1704,6 +1720,8 @@ int32_t nsLayoutUtils::DoCompareTreePosition(nsIFrame* aFrame1,
|
|||
int32_t nsLayoutUtils::DoCompareTreePosition(
|
||||
nsIFrame* aFrame1, nsIFrame* aFrame2, nsTArray<nsIFrame*>& aFrame2Ancestors,
|
||||
int32_t aIf1Ancestor, int32_t aIf2Ancestor, nsIFrame* aCommonAncestor) {
|
||||
MOZ_ASSERT(aIf1Ancestor == -1 || aIf1Ancestor == 0 || aIf1Ancestor == 1);
|
||||
MOZ_ASSERT(aIf2Ancestor == -1 || aIf2Ancestor == 0 || aIf2Ancestor == 1);
|
||||
MOZ_ASSERT(aFrame1, "aFrame1 must not be null");
|
||||
MOZ_ASSERT(aFrame2, "aFrame2 must not be null");
|
||||
|
||||
|
|
|
@ -348,6 +348,17 @@ class nsLayoutUtils {
|
|||
*/
|
||||
static nsIFrame* GetAfterFrame(const nsIContent* aContent);
|
||||
|
||||
/**
|
||||
* Returns the ::marker pseudo-element for aContent, if any.
|
||||
*/
|
||||
static mozilla::dom::Element* GetMarkerPseudo(const nsIContent* aContent);
|
||||
|
||||
/**
|
||||
* Returns the frame corresponding to the ::marker pseudo-element for
|
||||
* aContent, if any.
|
||||
*/
|
||||
static nsIFrame* GetMarkerFrame(const nsIContent* aContent);
|
||||
|
||||
/**
|
||||
* Given a frame, search up the frame tree until we find an
|
||||
* ancestor that (or the frame itself) is of type aFrameType, if any.
|
||||
|
|
|
@ -49,9 +49,11 @@ void DetailsFrame::SetInitialChildList(ChildListID aListID,
|
|||
#ifdef DEBUG
|
||||
bool DetailsFrame::CheckValidMainSummary(const nsFrameList& aFrameList) const {
|
||||
for (nsIFrame* child : aFrameList) {
|
||||
if (child->IsGeneratedContentFrame()) {
|
||||
continue;
|
||||
}
|
||||
HTMLSummaryElement* summary =
|
||||
HTMLSummaryElement::FromNode(child->GetContent());
|
||||
|
||||
if (child == aFrameList.FirstChild()) {
|
||||
if (summary && summary->IsMainSummary()) {
|
||||
return true;
|
||||
|
@ -125,7 +127,7 @@ bool DetailsFrame::HasMainSummaryFrame(nsIFrame* aSummaryFrame) {
|
|||
child = nsPlaceholderFrame::GetRealFrameFor(child);
|
||||
// We skip any non-primary frames such as a list-style-position:inside
|
||||
// bullet frame for the <details> itself.
|
||||
if (child->IsPrimaryFrame()) {
|
||||
if (!child->IsGeneratedContentFrame()) {
|
||||
return aSummaryFrame == child;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2534,11 +2534,13 @@ void ReflowInput::InitConstraints(nsPresContext* aPresContext,
|
|||
ComputedBSize() == NS_UNCONSTRAINEDSIZE || ComputedBSize() >= 0,
|
||||
"Bogus block-size");
|
||||
|
||||
// Exclude inline tables, side captions, flex and grid items from block
|
||||
// margin calculations.
|
||||
// Exclude inline tables, side captions, outside ::markers, flex and grid
|
||||
// items from block margin calculations.
|
||||
if (isBlock && !IsSideCaption(mFrame, mStyleDisplay, cbwm) &&
|
||||
mStyleDisplay->mDisplay != StyleDisplay::InlineTable &&
|
||||
!alignCB->IsFlexOrGridContainer()) {
|
||||
!alignCB->IsFlexOrGridContainer() &&
|
||||
!(mFrame->Style()->GetPseudoType() == PseudoStyleType::marker &&
|
||||
mFrame->GetParent()->StyleList()->mListStylePosition == NS_STYLE_LIST_STYLE_POSITION_OUTSIDE)) {
|
||||
CalculateBlockSideMargins(aFrameType);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1243,10 +1243,9 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
|
|||
#endif
|
||||
}
|
||||
|
||||
// Place the "marker" (bullet) frame if it is placed next to a block
|
||||
// child.
|
||||
// Place the ::marker's frame if it is placed next to a block child.
|
||||
//
|
||||
// According to the CSS2 spec, section 12.6.1, the "marker" box
|
||||
// According to the CSS2 spec, section 12.6.1, the ::marker's box
|
||||
// participates in the height calculation of the list-item box's
|
||||
// first line box.
|
||||
//
|
||||
|
@ -5159,12 +5158,6 @@ void nsBlockFrame::AddFrames(nsFrameList& aFrameList, nsIFrame* aPrevSibling) {
|
|||
return;
|
||||
}
|
||||
|
||||
// If we're inserting at the beginning of our list and we have an
|
||||
// inside bullet, insert after that bullet.
|
||||
if (!aPrevSibling && HasInsideBullet()) {
|
||||
aPrevSibling = GetInsideBullet();
|
||||
}
|
||||
|
||||
// Attempt to find the line that contains the previous sibling
|
||||
nsLineList* lineList = &mLines;
|
||||
nsFrameList* frames = &mFrames;
|
||||
|
@ -6747,38 +6740,19 @@ void nsBlockFrame::SetInitialChildList(ChildListID aListID,
|
|||
}
|
||||
}
|
||||
|
||||
void nsBlockFrame::CreateBulletFrameForListItem() {
|
||||
void nsBlockFrame::SetMarkerFrameForListItem(nsIFrame* aMarkerFrame) {
|
||||
MOZ_ASSERT(aMarkerFrame && aMarkerFrame->IsBulletFrame());
|
||||
MOZ_ASSERT((GetStateBits() & (NS_BLOCK_FRAME_HAS_INSIDE_BULLET |
|
||||
NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET)) == 0,
|
||||
"How can we have a bullet already?");
|
||||
|
||||
nsPresContext* pc = PresContext();
|
||||
nsIPresShell* shell = pc->PresShell();
|
||||
const nsStyleList* styleList = StyleList();
|
||||
CounterStyle* style =
|
||||
pc->CounterStyleManager()->ResolveCounterStyle(styleList->mCounterStyle);
|
||||
|
||||
PseudoStyleType pseudoType = style->IsBullet()
|
||||
? PseudoStyleType::mozListBullet
|
||||
: PseudoStyleType::mozListNumber;
|
||||
|
||||
RefPtr<ComputedStyle> kidSC =
|
||||
ResolveBulletStyle(pseudoType, shell->StyleSet());
|
||||
|
||||
// Create bullet frame
|
||||
nsBulletFrame* bullet = new (shell) nsBulletFrame(kidSC, pc);
|
||||
bullet->Init(mContent, this, nullptr);
|
||||
|
||||
// If the list bullet frame should be positioned inside then add
|
||||
// it to the flow now.
|
||||
if (styleList->mListStylePosition == NS_STYLE_LIST_STYLE_POSITION_INSIDE) {
|
||||
nsFrameList bulletList(bullet, bullet);
|
||||
AddFrames(bulletList, nullptr);
|
||||
auto bullet = static_cast<nsBulletFrame*>(aMarkerFrame);
|
||||
if (StyleList()->mListStylePosition == NS_STYLE_LIST_STYLE_POSITION_INSIDE) {
|
||||
SetProperty(InsideBulletProperty(), bullet);
|
||||
AddStateBits(NS_BLOCK_FRAME_HAS_INSIDE_BULLET);
|
||||
} else {
|
||||
nsFrameList* bulletList = new (shell) nsFrameList(bullet, bullet);
|
||||
SetProperty(OutsideBulletProperty(), bulletList);
|
||||
SetProperty(OutsideBulletProperty(),
|
||||
new (PresShell()) nsFrameList(bullet, bullet));
|
||||
AddStateBits(NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET);
|
||||
}
|
||||
}
|
||||
|
@ -6819,10 +6793,8 @@ void nsBlockFrame::ReflowBullet(nsIFrame* aBulletFrame,
|
|||
availSize.ISize(bulletWM) = aState.ContentISize();
|
||||
availSize.BSize(bulletWM) = NS_UNCONSTRAINEDSIZE;
|
||||
|
||||
// Get the reason right.
|
||||
// XXXwaterson Should this look just like the logic in
|
||||
// nsBlockReflowContext::ReflowBlock and nsLineLayout::ReflowFrame?
|
||||
ReflowInput reflowInput(aState.mPresContext, ri, aBulletFrame, availSize);
|
||||
ReflowInput reflowInput(aState.mPresContext, ri, aBulletFrame, availSize,
|
||||
nullptr, ReflowInput::COMPUTE_SIZE_SHRINK_WRAP);
|
||||
nsReflowStatus status;
|
||||
aBulletFrame->Reflow(aState.mPresContext, aMetrics, reflowInput, status);
|
||||
|
||||
|
@ -7134,13 +7106,6 @@ void nsBlockFrame::UpdatePseudoElementStyles(ServoRestyleState& aRestyleState) {
|
|||
UpdateFirstLetterStyle(aRestyleState);
|
||||
}
|
||||
|
||||
if (nsBulletFrame* bullet = GetBullet()) {
|
||||
PseudoStyleType type = bullet->Style()->GetPseudoType();
|
||||
RefPtr<ComputedStyle> newBulletStyle =
|
||||
ResolveBulletStyle(type, &aRestyleState.StyleSet());
|
||||
UpdateStyleOfOwnedChildFrame(bullet, newBulletStyle, aRestyleState);
|
||||
}
|
||||
|
||||
if (nsIFrame* firstLineFrame = GetFirstLineFrame()) {
|
||||
nsIFrame* styleParent = CorrectStyleParentFrame(firstLineFrame->GetParent(),
|
||||
PseudoStyleType::firstLine);
|
||||
|
@ -7170,13 +7135,6 @@ void nsBlockFrame::UpdatePseudoElementStyles(ServoRestyleState& aRestyleState) {
|
|||
}
|
||||
}
|
||||
|
||||
already_AddRefed<ComputedStyle> nsBlockFrame::ResolveBulletStyle(
|
||||
PseudoStyleType aType, ServoStyleSet* aStyleSet) {
|
||||
ComputedStyle* parentStyle = CorrectStyleParentFrame(this, aType)->Style();
|
||||
return aStyleSet->ResolvePseudoElementStyle(mContent->AsElement(), aType,
|
||||
parentStyle, nullptr);
|
||||
}
|
||||
|
||||
nsIFrame* nsBlockFrame::GetFirstLetter() const {
|
||||
if (!(GetStateBits() & NS_BLOCK_HAS_FIRST_LETTER_STYLE)) {
|
||||
// Certainly no first-letter frame.
|
||||
|
@ -7187,16 +7145,7 @@ nsIFrame* nsBlockFrame::GetFirstLetter() const {
|
|||
}
|
||||
|
||||
nsIFrame* nsBlockFrame::GetFirstLineFrame() const {
|
||||
// Our ::first-line frame is either the first thing on our principal child
|
||||
// list, or the second one if we have an inside bullet.
|
||||
nsIFrame* bullet = GetInsideBullet();
|
||||
nsIFrame* maybeFirstLine;
|
||||
if (bullet) {
|
||||
maybeFirstLine = bullet->GetNextSibling();
|
||||
} else {
|
||||
maybeFirstLine = PrincipalChildList().FirstChild();
|
||||
}
|
||||
|
||||
nsIFrame* maybeFirstLine = PrincipalChildList().FirstChild();
|
||||
if (maybeFirstLine && maybeFirstLine->IsLineFrame()) {
|
||||
return maybeFirstLine;
|
||||
}
|
||||
|
|
|
@ -501,9 +501,9 @@ class nsBlockFrame : public nsContainerFrame {
|
|||
|
||||
public:
|
||||
/**
|
||||
* Helper function to create bullet frame.
|
||||
* Helper function for the frame ctor to register a ::marker frame.
|
||||
*/
|
||||
void CreateBulletFrameForListItem();
|
||||
void SetMarkerFrameForListItem(nsIFrame* aMarkerFrame);
|
||||
|
||||
/**
|
||||
* Does all the real work for removing aDeletedFrame
|
||||
|
@ -896,12 +896,6 @@ class nsBlockFrame : public nsContainerFrame {
|
|||
// Remove and return the pushed floats list.
|
||||
nsFrameList* RemovePushedFloats();
|
||||
|
||||
// Resolve a ComputedStyle for our bullet frame. aType should be
|
||||
// mozListBullet or mozListNumber. Passing in the style set is an
|
||||
// optimization, because all callsites have it.
|
||||
already_AddRefed<ComputedStyle> ResolveBulletStyle(
|
||||
mozilla::PseudoStyleType aType, mozilla::ServoStyleSet* aStyleSet);
|
||||
|
||||
#ifdef DEBUG
|
||||
void VerifyLines(bool aFinalCheckOK);
|
||||
void VerifyOverflowSituation();
|
||||
|
|
|
@ -54,6 +54,10 @@ using namespace mozilla::image;
|
|||
using namespace mozilla::layout;
|
||||
using mozilla::dom::Document;
|
||||
|
||||
nsIFrame* NS_NewBulletFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle) {
|
||||
return new (aPresShell) nsBulletFrame(aStyle, aPresShell->GetPresContext());
|
||||
}
|
||||
|
||||
NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(FontSizeInflationProperty, float)
|
||||
|
||||
NS_IMPL_FRAMEARENA_HELPERS(nsBulletFrame)
|
||||
|
@ -159,8 +163,9 @@ void nsBulletFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
|
|||
!newStyleList->mCounterStyle.IsNone();
|
||||
|
||||
if (hadBullet != hasBullet) {
|
||||
accService->UpdateListBullet(PresContext()->GetPresShell(), mContent,
|
||||
hasBullet);
|
||||
nsIContent* listItem = mContent->GetParent();
|
||||
accService->UpdateListBullet(PresContext()->GetPresShell(), listItem,
|
||||
hasBullet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ class nsBulletFrame final : public nsFrame {
|
|||
if (aFlags & (eSupportsCSSTransforms | eSupportsContainLayoutAndPaint)) {
|
||||
return false;
|
||||
}
|
||||
return nsFrame::IsFrameOfType(aFlags);
|
||||
return nsFrame::IsFrameOfType(aFlags & ~nsIFrame::eLineParticipant);
|
||||
}
|
||||
|
||||
// nsBulletFrame
|
||||
|
|
|
@ -166,6 +166,8 @@ nsIFrame* NS_NewDateTimeControlFrame(nsIPresShell* aPresShell,
|
|||
mozilla::ComputedStyle* aStyle);
|
||||
nsBlockFrame* NS_NewDetailsFrame(nsIPresShell* aPresShell,
|
||||
mozilla::ComputedStyle* aStyle);
|
||||
nsIFrame* NS_NewBulletFrame(nsIPresShell* aPresShell,
|
||||
mozilla::ComputedStyle* aStyle);
|
||||
|
||||
// Table frame factories
|
||||
class nsTableWrapperFrame;
|
||||
|
|
|
@ -1384,7 +1384,7 @@ void nsLineLayout::PlaceFrame(PerFrameData* pfd, ReflowOutput& aMetrics) {
|
|||
}
|
||||
}
|
||||
|
||||
void nsLineLayout::AddBulletFrame(nsBulletFrame* aFrame,
|
||||
void nsLineLayout::AddBulletFrame(nsIFrame* aFrame,
|
||||
const ReflowOutput& aMetrics) {
|
||||
NS_ASSERTION(mCurrentSpan == mRootSpan, "bad linelayout user");
|
||||
NS_ASSERTION(mGotLineBox, "must have line box");
|
||||
|
@ -1418,7 +1418,7 @@ void nsLineLayout::AddBulletFrame(nsBulletFrame* aFrame,
|
|||
pfd->mOverflowAreas = aMetrics.mOverflowAreas;
|
||||
}
|
||||
|
||||
void nsLineLayout::RemoveBulletFrame(nsBulletFrame* aFrame) {
|
||||
void nsLineLayout::RemoveBulletFrame(nsIFrame* aFrame) {
|
||||
PerSpanData* psd = mCurrentSpan;
|
||||
MOZ_ASSERT(psd == mRootSpan, "bullet on non-root span?");
|
||||
MOZ_ASSERT(psd->mFirstFrame->mFrame == aFrame,
|
||||
|
|
|
@ -93,9 +93,9 @@ class nsLineLayout {
|
|||
void ReflowFrame(nsIFrame* aFrame, nsReflowStatus& aReflowStatus,
|
||||
ReflowOutput* aMetrics, bool& aPushedFrame);
|
||||
|
||||
void AddBulletFrame(nsBulletFrame* aFrame, const ReflowOutput& aMetrics);
|
||||
void AddBulletFrame(nsIFrame* aFrame, const ReflowOutput& aMetrics);
|
||||
|
||||
void RemoveBulletFrame(nsBulletFrame* aFrame);
|
||||
void RemoveBulletFrame(nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Place frames in the block direction (CSS property vertical-align)
|
||||
|
|
|
@ -158,6 +158,13 @@ const Element* Gecko_GetBeforeOrAfterPseudo(const Element* aElement,
|
|||
: nsLayoutUtils::GetAfterPseudo(aElement);
|
||||
}
|
||||
|
||||
const Element* Gecko_GetMarkerPseudo(const Element* aElement) {
|
||||
MOZ_ASSERT(aElement);
|
||||
MOZ_ASSERT(aElement->HasProperties());
|
||||
|
||||
return nsLayoutUtils::GetMarkerPseudo(aElement);
|
||||
}
|
||||
|
||||
nsTArray<nsIContent*>* Gecko_GetAnonymousContentForElement(
|
||||
const Element* aElement) {
|
||||
nsIAnonymousContentCreator* ac = do_QueryFrame(aElement->GetPrimaryFrame());
|
||||
|
|
|
@ -77,6 +77,8 @@ const nsINode* Gecko_GetPreviousSibling(const nsINode*);
|
|||
const nsINode* Gecko_GetFlattenedTreeParentNode(const nsINode*);
|
||||
const mozilla::dom::Element* Gecko_GetBeforeOrAfterPseudo(
|
||||
const mozilla::dom::Element*, bool is_before);
|
||||
const mozilla::dom::Element* Gecko_GetMarkerPseudo(
|
||||
const mozilla::dom::Element*);
|
||||
|
||||
nsTArray<nsIContent*>* Gecko_GetAnonymousContentForElement(
|
||||
const mozilla::dom::Element*);
|
||||
|
|
|
@ -828,6 +828,17 @@ already_AddRefed<ComputedStyle> ServoStyleSet::ProbePseudoElementStyle(
|
|||
}
|
||||
}
|
||||
|
||||
if (aType == PseudoStyleType::marker) {
|
||||
// ::marker only exist for list items (for now).
|
||||
if (aParentStyle->StyleDisplay()->mDisplay != StyleDisplay::ListItem) {
|
||||
return nullptr;
|
||||
}
|
||||
// display:none is equivalent to not having the pseudo-element at all.
|
||||
if (computedValues->StyleDisplay()->mDisplay == StyleDisplay::None) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// For :before and :after pseudo-elements, having display: none or no
|
||||
// 'content' property is equivalent to not having the pseudo-element
|
||||
// at all.
|
||||
|
|
|
@ -33,6 +33,7 @@ CSS_PSEUDO_ELEMENT(after, ":after", CSS_PSEUDO_ELEMENT_IS_CSS2 |
|
|||
CSS_PSEUDO_ELEMENT_IS_FLEX_OR_GRID_ITEM)
|
||||
CSS_PSEUDO_ELEMENT(before, ":before", CSS_PSEUDO_ELEMENT_IS_CSS2 |
|
||||
CSS_PSEUDO_ELEMENT_IS_FLEX_OR_GRID_ITEM)
|
||||
CSS_PSEUDO_ELEMENT(marker, ":marker", 0)
|
||||
|
||||
CSS_PSEUDO_ELEMENT(backdrop, ":backdrop", 0)
|
||||
|
||||
|
@ -54,11 +55,6 @@ CSS_PSEUDO_ELEMENT(selection, ":selection",
|
|||
CSS_PSEUDO_ELEMENT(mozFocusInner, ":-moz-focus-inner", 0)
|
||||
CSS_PSEUDO_ELEMENT(mozFocusOuter, ":-moz-focus-outer", 0)
|
||||
|
||||
// XXXbz should we really allow random content to style these? Maybe
|
||||
// use our flags to prevent that?
|
||||
CSS_PSEUDO_ELEMENT(mozListBullet, ":-moz-list-bullet", 0)
|
||||
CSS_PSEUDO_ELEMENT(mozListNumber, ":-moz-list-number", 0)
|
||||
|
||||
// FIXME(emilio): It's unclear why this needs to exist at all, we don't ever
|
||||
// style them.
|
||||
//
|
||||
|
|
|
@ -526,6 +526,8 @@ already_AddRefed<ComputedStyle> nsComputedDOMStyle::DoGetComputedStyleNoFlush(
|
|||
element = nsLayoutUtils::GetBeforePseudo(aElement);
|
||||
} else if (aPseudo == nsCSSPseudoElements::after()) {
|
||||
element = nsLayoutUtils::GetAfterPseudo(aElement);
|
||||
} else if (aPseudo == nsCSSPseudoElements::marker()) {
|
||||
element = nsLayoutUtils::GetMarkerPseudo(aElement);
|
||||
} else if (!aPseudo) {
|
||||
element = aElement;
|
||||
}
|
||||
|
@ -863,14 +865,19 @@ void nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush) {
|
|||
|
||||
if (!mPseudo) {
|
||||
mOuterFrame = mElement->GetPrimaryFrame();
|
||||
} else if (mPseudo == nsCSSPseudoElements::before() ||
|
||||
mPseudo == nsCSSPseudoElements::after()) {
|
||||
nsAtom* property = mPseudo == nsCSSPseudoElements::before()
|
||||
? nsGkAtoms::beforePseudoProperty
|
||||
: nsGkAtoms::afterPseudoProperty;
|
||||
|
||||
auto* pseudo = static_cast<Element*>(mElement->GetProperty(property));
|
||||
mOuterFrame = pseudo ? pseudo->GetPrimaryFrame() : nullptr;
|
||||
} else {
|
||||
nsAtom* property = nullptr;
|
||||
if (mPseudo == nsCSSPseudoElements::before()) {
|
||||
property = nsGkAtoms::beforePseudoProperty;
|
||||
} else if (mPseudo == nsCSSPseudoElements::after()) {
|
||||
property = nsGkAtoms::afterPseudoProperty;
|
||||
} else if (mPseudo == nsCSSPseudoElements::marker()) {
|
||||
property = nsGkAtoms::markerPseudoProperty;
|
||||
}
|
||||
if (property) {
|
||||
auto* pseudo = static_cast<Element*>(mElement->GetProperty(property));
|
||||
mOuterFrame = pseudo ? pseudo->GetPrimaryFrame() : nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
mInnerFrame = mOuterFrame;
|
||||
|
|
|
@ -126,14 +126,11 @@
|
|||
unicode-bidi: isolate;
|
||||
}
|
||||
|
||||
/* Lists */
|
||||
|
||||
*|*::-moz-list-bullet, *|*::-moz-list-number {
|
||||
display: inline;
|
||||
vertical-align: baseline;
|
||||
/* https://drafts.csswg.org/css-lists-3/#ua-stylesheet */
|
||||
*|*::marker {
|
||||
text-align: end;
|
||||
unicode-bidi: isolate;
|
||||
font-variant-numeric: tabular-nums;
|
||||
/* Prevent the element from being selected when clicking on the marker. */
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
/* SVG documents don't always load this file but they do have links.
|
||||
|
|
|
@ -441,6 +441,11 @@ pub trait TElement:
|
|||
None
|
||||
}
|
||||
|
||||
/// The ::marker pseudo-element of this element, if it exists.
|
||||
fn marker_pseudo_element(&self) -> Option<Self> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Execute `f` for each anonymous content child (apart from ::before and
|
||||
/// ::after) whose originating element is `self`.
|
||||
fn each_anonymous_content_child<F>(&self, _f: F)
|
||||
|
|
|
@ -33,7 +33,7 @@ impl ::selectors::parser::PseudoElement for PseudoElement {
|
|||
fn valid_after_slotted(&self) -> bool {
|
||||
matches!(
|
||||
*self,
|
||||
PseudoElement::Before | PseudoElement::After | PseudoElement::Placeholder
|
||||
PseudoElement::Before | PseudoElement::After | PseudoElement::Marker | PseudoElement::Placeholder
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -180,6 +180,8 @@ impl PseudoElement {
|
|||
/// Whether this pseudo-element should actually exist if it has
|
||||
/// the given styles.
|
||||
pub fn should_exist(&self, style: &ComputedValues) -> bool {
|
||||
debug_assert!(self.is_eager());
|
||||
|
||||
if style.get_box().clone_display() == Display::None {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -195,13 +195,16 @@ impl PseudoElement {
|
|||
return Some(${pseudo_element_variant(pseudo)})
|
||||
}
|
||||
% endfor
|
||||
// Alias "-moz-selection" to "selection" at parse time.
|
||||
// Alias some legacy prefixed pseudos to their standardized name at parse time:
|
||||
"-moz-selection" => {
|
||||
return Some(PseudoElement::Selection);
|
||||
}
|
||||
"-moz-placeholder" => {
|
||||
return Some(PseudoElement::Placeholder);
|
||||
}
|
||||
"-moz-list-bullet" | "-moz-list-number" => {
|
||||
return Some(PseudoElement::Marker);
|
||||
}
|
||||
_ => {
|
||||
if starts_with_ignore_ascii_case(name, "-moz-tree-") {
|
||||
return PseudoElement::tree_pseudo_element(name, Box::new([]))
|
||||
|
|
|
@ -1137,6 +1137,14 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
self.before_or_after_pseudo(/* is_before = */ false)
|
||||
}
|
||||
|
||||
fn marker_pseudo_element(&self) -> Option<Self> {
|
||||
if !self.has_properties() {
|
||||
return None;
|
||||
}
|
||||
|
||||
unsafe { bindings::Gecko_GetMarkerPseudo(self.0).as_ref().map(GeckoElement) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_html_element(&self) -> bool {
|
||||
self.namespace_id() == structs::kNameSpaceID_XHTML as i32
|
||||
|
|
|
@ -542,6 +542,10 @@ where
|
|||
any_descendant |= self.invalidate_dom_descendants_of(anon_content, invalidations);
|
||||
}
|
||||
|
||||
if let Some(marker) = self.element.marker_pseudo_element() {
|
||||
any_descendant |= self.invalidate_pseudo_element_or_nac(marker, invalidations);
|
||||
}
|
||||
|
||||
if let Some(before) = self.element.before_pseudo_element() {
|
||||
any_descendant |= self.invalidate_pseudo_element_or_nac(before, invalidations);
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ STATIC_ATOMS = [
|
|||
Atom("mozeditorbogusnode", "_moz_editor_bogus_node"),
|
||||
Atom("mozgeneratedcontentbefore", "_moz_generated_content_before"),
|
||||
Atom("mozgeneratedcontentafter", "_moz_generated_content_after"),
|
||||
Atom("mozgeneratedcontentmarker", "_moz_generated_content_marker"),
|
||||
Atom("mozgeneratedcontentimage", "_moz_generated_content_image"),
|
||||
Atom("mozquote", "_moz_quote"),
|
||||
Atom("mozsignature", "moz-signature"),
|
||||
|
@ -2066,6 +2067,7 @@ STATIC_ATOMS = [
|
|||
Atom("paintRequestTime", "PaintRequestTime"),
|
||||
Atom("pseudoProperty", "PseudoProperty"), # PseudoStyleType
|
||||
Atom("manualNACProperty", "ManualNACProperty"), # ManualNAC*
|
||||
Atom("markerPseudoProperty", "markerPseudoProperty"), # nsXMLElement*
|
||||
|
||||
# Languages for lang-specific transforms
|
||||
Atom("Japanese", "ja"),
|
||||
|
@ -2381,6 +2383,7 @@ STATIC_ATOMS = [
|
|||
# in nsCSSPseudoElementList.h
|
||||
PseudoElementAtom("PseudoElement_after", ":after"),
|
||||
PseudoElementAtom("PseudoElement_before", ":before"),
|
||||
PseudoElementAtom("PseudoElement_marker", ":marker"),
|
||||
PseudoElementAtom("PseudoElement_backdrop", ":backdrop"),
|
||||
PseudoElementAtom("PseudoElement_cue", ":cue"),
|
||||
PseudoElementAtom("PseudoElement_firstLetter", ":first-letter"),
|
||||
|
@ -2388,8 +2391,6 @@ STATIC_ATOMS = [
|
|||
PseudoElementAtom("PseudoElement_selection", ":selection"),
|
||||
PseudoElementAtom("PseudoElement_mozFocusInner", ":-moz-focus-inner"),
|
||||
PseudoElementAtom("PseudoElement_mozFocusOuter", ":-moz-focus-outer"),
|
||||
PseudoElementAtom("PseudoElement_mozListBullet", ":-moz-list-bullet"),
|
||||
PseudoElementAtom("PseudoElement_mozListNumber", ":-moz-list-number"),
|
||||
PseudoElementAtom("PseudoElement_mozMathAnonymous", ":-moz-math-anonymous"),
|
||||
PseudoElementAtom("PseudoElement_mozNumberWrapper", ":-moz-number-wrapper"),
|
||||
PseudoElementAtom("PseudoElement_mozNumberText", ":-moz-number-text"),
|
||||
|
|
Загрузка…
Ссылка в новой задаче