mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-23 12:53:07 +09:00
Bug 1331322 - Allow tagging of pseudo-implementing native anonymous content with the pseudo type at creation time
* Stop using a node bit for HasExplicitBaseURI * Move MAY_HAVE_CLASS to mBoolFlags * Add a flag to indicate that a node is native anonymous content * Allow tagging of pseudo-implementing native anonymous content with the pseudo type at creation time, and eliminate explicit style contexts in nsIAnonymousContentCreator::ContentInfo Tag #1375
This commit is contained in:
parent
31048968fd
commit
b723a5c8c4
25 changed files with 267 additions and 128 deletions
|
|
@ -1865,6 +1865,7 @@ nsCSSFrameConstructor::CreateGeneratedContentItem(nsFrameConstructorState& aStat
|
|||
if (NS_FAILED(rv))
|
||||
return;
|
||||
container->SetIsNativeAnonymousRoot();
|
||||
container->SetPseudoElementType(aPseudoElement);
|
||||
|
||||
// If the parent is in a shadow tree, make sure we don't
|
||||
// bind with a document because shadow roots and its descendants
|
||||
|
|
@ -4161,6 +4162,13 @@ ConnectAnonymousTreeDescendants(nsIContent* aParent,
|
|||
}
|
||||
}
|
||||
|
||||
void SetNativeAnonymousBitOnDescendants(nsIContent *aRoot)
|
||||
{
|
||||
for (nsIContent* curr = aRoot; curr; curr = curr->GetNextNode(aRoot)) {
|
||||
curr->SetFlags(NODE_IS_NATIVE_ANONYMOUS);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent,
|
||||
nsIFrame* aParentFrame,
|
||||
|
|
@ -4182,16 +4190,17 @@ nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent,
|
|||
nsIContent* content = aContent[i].mContent;
|
||||
NS_ASSERTION(content, "null anonymous content?");
|
||||
|
||||
ConnectAnonymousTreeDescendants(content, aContent[i].mChildren);
|
||||
|
||||
// least-surprise CSS binding until we do the SVG specified
|
||||
// cascading rules for <svg:use> - bug 265894
|
||||
if (aParentFrame->GetType() == nsGkAtoms::svgUseFrame) {
|
||||
content->SetFlags(NODE_IS_ANONYMOUS_ROOT);
|
||||
} else {
|
||||
content->SetIsNativeAnonymousRoot();
|
||||
SetNativeAnonymousBitOnDescendants(content);
|
||||
}
|
||||
|
||||
ConnectAnonymousTreeDescendants(content, aContent[i].mChildren);
|
||||
|
||||
bool anonContentIsEditable = content->HasFlag(NODE_IS_EDITABLE);
|
||||
|
||||
// If the parent is in a shadow tree, make sure we don't
|
||||
|
|
@ -4216,11 +4225,9 @@ nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent,
|
|||
}
|
||||
|
||||
if (ServoStyleSet* styleSet = mPresShell->StyleSet()->GetAsServo()) {
|
||||
// Eagerly compute styles for the anonymous content tree, but only do so
|
||||
// if the content doesn't have an explicit style context (if it does, we
|
||||
// don't need the normal computed values).
|
||||
// Eagerly compute styles for the anonymous content tree.
|
||||
for (auto& info : aContent) {
|
||||
if (!info.mStyleContext) {
|
||||
if (info.mContent->IsElement()) {
|
||||
styleSet->StyleNewSubtree(info.mContent);
|
||||
}
|
||||
}
|
||||
|
|
@ -4999,22 +5006,35 @@ nsCSSFrameConstructor::ResolveStyleContext(const InsertionPoint& aInsertion,
|
|||
already_AddRefed<nsStyleContext>
|
||||
nsCSSFrameConstructor::ResolveStyleContext(nsStyleContext* aParentStyleContext,
|
||||
nsIContent* aContent,
|
||||
nsFrameConstructorState* aState)
|
||||
nsFrameConstructorState* aState,
|
||||
Element* aOriginatingElementOrNull)
|
||||
{
|
||||
StyleSetHandle styleSet = mPresShell->StyleSet();
|
||||
aContent->OwnerDoc()->FlushPendingLinkUpdates();
|
||||
|
||||
RefPtr<nsStyleContext> result;
|
||||
if (aContent->IsElement()) {
|
||||
if (aState) {
|
||||
result = styleSet->ResolveStyleFor(aContent->AsElement(),
|
||||
aParentStyleContext,
|
||||
aState->mTreeMatchContext);
|
||||
auto pseudoType = aContent->AsElement()->GetPseudoElementType();
|
||||
if (pseudoType == CSSPseudoElementType::NotPseudo) {
|
||||
MOZ_ASSERT(!aOriginatingElementOrNull);
|
||||
if (aState) {
|
||||
result = styleSet->ResolveStyleFor(aContent->AsElement(),
|
||||
aParentStyleContext,
|
||||
aState->mTreeMatchContext);
|
||||
} else {
|
||||
result = styleSet->ResolveStyleFor(aContent->AsElement(),
|
||||
aParentStyleContext);
|
||||
}
|
||||
} else {
|
||||
result = styleSet->ResolveStyleFor(aContent->AsElement(),
|
||||
aParentStyleContext);
|
||||
MOZ_ASSERT(aOriginatingElementOrNull);
|
||||
MOZ_ASSERT(aContent->IsInNativeAnonymousSubtree());
|
||||
result = styleSet->ResolvePseudoElementStyle(aOriginatingElementOrNull,
|
||||
pseudoType,
|
||||
aParentStyleContext,
|
||||
aContent->AsElement());
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(!aOriginatingElementOrNull);
|
||||
NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
|
||||
"shouldn't waste time creating style contexts for "
|
||||
"comments and processing instructions");
|
||||
|
|
@ -10643,24 +10663,96 @@ nsCSSFrameConstructor::AddFCItemsForAnonymousContent(
|
|||
RefPtr<nsStyleContext> styleContext;
|
||||
TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper
|
||||
parentDisplayBasedStyleFixupSkipper(aState.mTreeMatchContext);
|
||||
if (aAnonymousItems[i].mStyleContext) {
|
||||
// If we have an explicit style context, that means that the anonymous
|
||||
// content creator had its own plan for the style, and doesn't need the
|
||||
// computed style obtained by cascading this content as a normal node.
|
||||
// This happens when a native anonymous node is used to implement a
|
||||
// pseudo-element. Allowing Servo to traverse these nodes would be wasted
|
||||
// work, so assert that we didn't do that.
|
||||
MOZ_ASSERT_IF(content->IsStyledByServo(), !content->HasServoData());
|
||||
styleContext = aAnonymousItems[i].mStyleContext.forget();
|
||||
} else {
|
||||
// If we don't have an explicit style context, that means we need the
|
||||
// ordinary computed values. Make sure we eagerly cascaded them when the
|
||||
// anonymous nodes were created.
|
||||
MOZ_ASSERT_IF(content->IsStyledByServo() && content->IsElement(),
|
||||
content->HasServoData());
|
||||
styleContext = ResolveStyleContext(aFrame, content, &aState);
|
||||
|
||||
// Make sure we eagerly performed the servo cascade when the anonymous
|
||||
// nodes were created.
|
||||
MOZ_ASSERT_IF(content->IsStyledByServo() && content->IsElement(),
|
||||
content->AsElement()->HasServoData());
|
||||
|
||||
// Determine whether this NAC is pseudo-implementing.
|
||||
nsIAtom* pseudo = nullptr;
|
||||
if (content->IsElement()) {
|
||||
auto pseudoType = content->AsElement()->GetPseudoElementType();
|
||||
if (pseudoType != CSSPseudoElementType::NotPseudo) {
|
||||
pseudo = nsCSSPseudoElements::GetPseudoAtom(pseudoType);
|
||||
}
|
||||
}
|
||||
|
||||
// Determine the appropriate parent style for this NAC, and if the NAC
|
||||
// implements a pseudo-element, the appropriate originating element
|
||||
// (that is to say, the element to the left of the ::pseudo-element in
|
||||
// the selector). This is all rather tricky, and merits some discussion.
|
||||
//
|
||||
// First, it's important to note that author stylesheets generally do not
|
||||
// apply to elements in native-anonymous subtrees. The exceptions to
|
||||
// this are web-exposed pseudo-elements, where authors can style the
|
||||
// pseudo-implementing NAC if the originating element is not itself in a NAC
|
||||
// subtree.
|
||||
//
|
||||
// For this reason, it's very important that we avoid using a style parent
|
||||
// that is inside a NAC subtree together with an originating element that
|
||||
// is not inside a NAC subtree, since that would allow authors to
|
||||
// explicitly inherit styles from internal elements, potentially making
|
||||
// the NAC hierarchy observable. To ensure this, and generally simplify
|
||||
// things, we always set the originating element to the style parent.
|
||||
//
|
||||
// As a consequence of the above, all web-exposed pseudo-elements (which,
|
||||
// by definition, must have a content-accessible originating element) must
|
||||
// also inherit style from that same content-accessible element. To avoid
|
||||
// unintuitive behavior differences between NAC elements that do and don't
|
||||
// correspond to web-exposed pseudo-elements, we follow this protocol for
|
||||
// all NAC, pseudo-implementing or not.
|
||||
//
|
||||
// However, things get tricky with the <video> element, where we have a
|
||||
// bunch of XBL-generated anonymous content descending from a native-
|
||||
// anonymous XULElement. The XBL elements inherit style from their
|
||||
// flattened tree parent, because that's how XBL works. But then we need
|
||||
// to figure out what to do when one of those anonymous XBL elements
|
||||
// (like an <input> element) generates its own (possibly pseudo-element-
|
||||
// implementing) NAC.
|
||||
//
|
||||
// In this case, we inherit style from the XBL-generated NAC-creating
|
||||
// element, rather than the <video> element. There are a number of good
|
||||
// reasons for this. First, inheriting from the great-grandparent while
|
||||
// the parent inherits from the grandparent would be bizarre at best.
|
||||
// Second, exposing pseudo-elements from elements within our particular
|
||||
// XBL implementation would allow content styles to (un)intentionally
|
||||
// alter the video controls, which would be very bad. Third, our UA
|
||||
// stylesheets have selectors like:
|
||||
//
|
||||
// input[type=range][orient=horizontal]::-moz-range-track
|
||||
//
|
||||
// and we need to make sure that the originating element is the <input>,
|
||||
// not the <video>, because that's where the |orient| attribute lives.
|
||||
//
|
||||
// The upshot of all of this is that, to find the style parent (and
|
||||
// originating element, if applicable), we walk up our parent chain to the
|
||||
// first element that is not itself NAC (distinct from whether it happens
|
||||
// to be in a NAC subtree).
|
||||
//
|
||||
// To implement all this, we need to pass the correct parent style context
|
||||
// here because SetPrimaryFrame() may not have been called on the content
|
||||
// yet and thus ResolveStyleContext can't find it otherwise.
|
||||
//
|
||||
// We don't need to worry about display:contents here, because such
|
||||
// elements don't get a frame and thus can't generate NAC. But we do need
|
||||
// to worry about anonymous boxes, which CorrectStyleParentFrame handles
|
||||
// for us.
|
||||
nsIFrame* inheritFrame = aFrame;
|
||||
while (inheritFrame->GetContent()->IsNativeAnonymous()) {
|
||||
inheritFrame = inheritFrame->GetParent();
|
||||
}
|
||||
if (inheritFrame->GetType() == nsGkAtoms::canvasFrame) {
|
||||
// CorrectStyleParentFrame returns nullptr if the prospective parent is
|
||||
// the canvas frame, so avoid calling it in that situation.
|
||||
} else {
|
||||
inheritFrame = nsFrame::CorrectStyleParentFrame(inheritFrame, pseudo);
|
||||
}
|
||||
Element* originating = pseudo ? inheritFrame->GetContent()->AsElement() : nullptr;
|
||||
|
||||
styleContext =
|
||||
ResolveStyleContext(inheritFrame->StyleContext(), content, &aState, originating);
|
||||
|
||||
nsTArray<nsIAnonymousContentCreator::ContentInfo>* anonChildren = nullptr;
|
||||
if (!aAnonymousItems[i].mChildren.IsEmpty()) {
|
||||
anonChildren = &aAnonymousItems[i].mChildren;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue