--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -788,16 +788,35 @@ public:
GetElementsByTagName(const nsAString& aQualifiedName);
already_AddRefed<nsIHTMLCollection>
GetElementsByTagNameNS(const nsAString& aNamespaceURI,
const nsAString& aLocalName,
ErrorResult& aError);
already_AddRefed<nsIHTMLCollection>
GetElementsByClassName(const nsAString& aClassNames);
+ CSSPseudoElementType GetPseudoElementType() const {
+ if (!HasProperties()) {
+ return CSSPseudoElementType::NotPseudo;
+ }
+ nsresult rv = NS_OK;
+ auto raw = GetProperty(nsGkAtoms::pseudoProperty, &rv);
+ if (rv == NS_PROPTABLE_PROP_NOT_THERE) {
+ return CSSPseudoElementType::NotPseudo;
+ }
+ return CSSPseudoElementType(reinterpret_cast<uintptr_t>(raw));
+ }
+
+ void SetPseudoElementType(CSSPseudoElementType aPseudo) {
+ static_assert(sizeof(CSSPseudoElementType) <= sizeof(uintptr_t),
+ "Need to be able to store this in a void*");
+ MOZ_ASSERT(aPseudo != CSSPseudoElementType::NotPseudo);
+ SetProperty(nsGkAtoms::pseudoProperty, reinterpret_cast<void*>(aPseudo));
+ }
+
private:
/**
* Implement the algorithm specified at
* https://dom.spec.whatwg.org/#insert-adjacent for both
* |insertAdjacentElement()| and |insertAdjacentText()| APIs.
*/
nsINode* InsertAdjacent(const nsAString& aWhere,
nsINode* aNode,
--- a/dom/base/crashtests/crashtests.list
+++ b/dom/base/crashtests/crashtests.list
@@ -188,17 +188,17 @@ load 852381.html
load 863950.html
load 864448.html
load 886213.html
load 898906.html
load 930250.html
load 942979.html
load 973401.html
load 978646.html
-asserts-if(stylo,1-11) pref(dom.webcomponents.enabled,true) load 1024428-1.html # bug 1324671
+skip-if(stylo) pref(dom.webcomponents.enabled,true) load 1024428-1.html # bug 1340009
load 1026714.html
pref(dom.webcomponents.enabled,true) load 1027461-1.html
pref(dom.webcomponents.enabled,true) load 1029710.html
load 1154598.xhtml
load 1157995.html
load 1158412.html
load 1181619.html
load structured_clone_container_throws.html
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -2147,16 +2147,17 @@ GK_ATOM(transitionsOfBeforeProperty, "Tr
GK_ATOM(transitionsOfAfterProperty, "TransitionsOfAfterProperty") // FrameTransitions*
GK_ATOM(genConInitializerProperty, "QuoteNodeProperty")
GK_ATOM(labelMouseDownPtProperty, "LabelMouseDownPtProperty")
GK_ATOM(baseURIProperty, "baseURIProperty")
GK_ATOM(lockedStyleStates, "lockedStyleStates")
GK_ATOM(apzCallbackTransform, "apzCallbackTransform")
GK_ATOM(restylableAnonymousNode, "restylableAnonymousNode")
GK_ATOM(paintRequestTime, "PaintRequestTime")
+GK_ATOM(pseudoProperty, "PseudoProperty") // CSSPseudoElementType
// Languages for lang-specific transforms
GK_ATOM(Japanese, "ja")
GK_ATOM(Chinese, "zh-CN")
GK_ATOM(Taiwanese, "zh-TW")
GK_ATOM(HongKongChinese, "zh-HK")
GK_ATOM(Unicode, "x-unicode")
--- a/layout/base/GeckoRestyleManager.cpp
+++ b/layout/base/GeckoRestyleManager.cpp
@@ -2007,16 +2007,26 @@ ElementRestyler::ComputeRestyleResultFro
// style contexts.
if (aSelf->GetAdditionalStyleContext(0)) {
LOG_RESTYLE_CONTINUE("there are additional style contexts");
aRestyleResult = RestyleResult::eContinue;
aCanStopWithStyleChange = false;
return;
}
+ // Each NAC element inherits from the first non-NAC ancestor, so child
+ // NAC may inherit from our parent instead of us. That means we can't
+ // cull traversal if our style context didn't change.
+ if (aSelf->GetContent() && aSelf->GetContent()->IsNativeAnonymous()) {
+ LOG_RESTYLE_CONTINUE("native anonymous content");
+ aRestyleResult = RestyleResult::eContinue;
+ aCanStopWithStyleChange = false;
+ return;
+ }
+
// Style changes might have moved children between the two nsLetterFrames
// (the one matching ::first-letter and the one containing the rest of the
// content). Continue restyling to the children of the nsLetterFrame so
// that they get the correct style context parent. Similarly for
// nsLineFrames.
nsIAtom* type = aSelf->GetType();
if (type == nsGkAtoms::letterFrame) {
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -1862,16 +1862,17 @@ nsCSSFrameConstructor::CreateGeneratedCo
nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo(elemName, nullptr,
kNameSpaceID_None,
nsIDOMNode::ELEMENT_NODE);
nsCOMPtr<Element> container;
nsresult rv = NS_NewXMLElement(getter_AddRefs(container), nodeInfo.forget());
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
// are not in document.
nsIDocument* bindDocument =
aParentContent->HasFlag(NODE_IS_IN_SHADOW_TREE) ? nullptr : mDocument;
rv = container->BindToTree(bindDocument, aParentContent, aParentContent, true);
if (NS_FAILED(rv)) {
@@ -4245,21 +4246,19 @@ nsCSSFrameConstructor::GetAnonymousConte
}
if (NS_FAILED(rv)) {
content->UnbindFromTree();
return rv;
}
}
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 && info.mContent->IsElement()) {
+ if (info.mContent->IsElement()) {
styleSet->StyleNewSubtree(info.mContent->AsElement());
}
}
}
return NS_OK;
}
@@ -5029,34 +5028,47 @@ nsCSSFrameConstructor::ResolveStyleConte
{
return ResolveStyleContext(aInsertion.mParentFrame, aInsertion.mContainer,
aChild, aState);
}
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,
- LazyComputeBehavior::Assert,
- aState->mTreeMatchContext);
+ auto pseudoType = aContent->AsElement()->GetPseudoElementType();
+ if (pseudoType == CSSPseudoElementType::NotPseudo) {
+ MOZ_ASSERT(!aOriginatingElementOrNull);
+ if (aState) {
+ result = styleSet->ResolveStyleFor(aContent->AsElement(),
+ aParentStyleContext,
+ LazyComputeBehavior::Assert,
+ aState->mTreeMatchContext);
+ } else {
+ result = styleSet->ResolveStyleFor(aContent->AsElement(),
+ aParentStyleContext,
+ LazyComputeBehavior::Assert);
+ }
} else {
- result = styleSet->ResolveStyleFor(aContent->AsElement(),
- aParentStyleContext,
- LazyComputeBehavior::Assert);
+ 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");
result = styleSet->ResolveStyleForText(aContent, aParentStyleContext);
}
// ServoRestyleManager does not handle transitions yet, and when it does
// it probably won't need to track reframed style contexts to start
@@ -10720,34 +10732,105 @@ nsCSSFrameConstructor::AddFCItemsForAnon
"Should have no existing frame");
MOZ_ASSERT(!content->IsNodeOfType(nsINode::eCOMMENT) &&
!content->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION),
"Why is someone creating garbage anonymous content");
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->IsElement() || !content->AsElement()->HasServoData());
- styleContext = aAnonymousItems[i].mStyleContext.forget();
+
+ // 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 {
- // 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->AsElement()->HasServoData());
- styleContext = ResolveStyleContext(aFrame, content, &aState);
- }
+ 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;
}
uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK |
ITEM_IS_ANONYMOUSCONTENTCREATOR_CONTENT | aExtraFlags;
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -359,17 +359,18 @@ private:
nsFrameConstructorState* aState);
already_AddRefed<nsStyleContext>
ResolveStyleContext(const InsertionPoint& aInsertion,
nsIContent* aChild,
nsFrameConstructorState* aState);
already_AddRefed<nsStyleContext>
ResolveStyleContext(nsStyleContext* aParentStyleContext,
nsIContent* aContent,
- nsFrameConstructorState* aState);
+ nsFrameConstructorState* aState,
+ Element* aOriginatingElementOrNull = nullptr);
// Add the frame construction items for the given aContent and aParentFrame
// to the list. This might add more than one item in some rare cases.
// If aSuppressWhiteSpaceOptimizations is true, optimizations that
// may suppress the construction of white-space-only text frames
// must be skipped for these items and items around them.
void AddFrameConstructionItems(nsFrameConstructorState& aState,
nsIContent* aContent,
--- a/layout/forms/nsColorControlFrame.cpp
+++ b/layout/forms/nsColorControlFrame.cpp
@@ -64,28 +64,25 @@ nsColorControlFrame::GetFrameName(nsAStr
// Create the color area for the button.
// The frame will be generated by the frame constructor.
nsresult
nsColorControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
{
nsCOMPtr<nsIDocument> doc = mContent->GetComposedDoc();
mColorContent = doc->CreateHTMLElement(nsGkAtoms::div);
+ mColorContent->SetPseudoElementType(CSSPseudoElementType::mozColorSwatch);
// Mark the element to be native anonymous before setting any attributes.
mColorContent->SetIsNativeAnonymousRoot();
nsresult rv = UpdateColor();
NS_ENSURE_SUCCESS(rv, rv);
- CSSPseudoElementType pseudoType = CSSPseudoElementType::mozColorSwatch;
- RefPtr<nsStyleContext> newStyleContext = PresContext()->StyleSet()->
- ResolvePseudoElementStyle(mContent->AsElement(), pseudoType,
- StyleContext(), mColorContent->AsElement());
- if (!aElements.AppendElement(ContentInfo(mColorContent, newStyleContext))) {
+ if (!aElements.AppendElement(mColorContent)) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
void
nsColorControlFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
--- a/layout/forms/nsMeterFrame.cpp
+++ b/layout/forms/nsMeterFrame.cpp
@@ -70,24 +70,19 @@ nsMeterFrame::CreateAnonymousContent(nsT
{
// Get the NodeInfoManager and tag necessary to create the meter bar div.
nsCOMPtr<nsIDocument> doc = mContent->GetComposedDoc();
// Create the div.
mBarDiv = doc->CreateHTMLElement(nsGkAtoms::div);
// Associate ::-moz-meter-bar pseudo-element to the anonymous child.
- CSSPseudoElementType pseudoType = CSSPseudoElementType::mozMeterBar;
- RefPtr<nsStyleContext> newStyleContext = PresContext()->StyleSet()->
- ResolvePseudoElementStyle(mContent->AsElement(), pseudoType,
- StyleContext(), mBarDiv->AsElement());
+ mBarDiv->SetPseudoElementType(CSSPseudoElementType::mozMeterBar);
- if (!aElements.AppendElement(ContentInfo(mBarDiv, newStyleContext))) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
+ aElements.AppendElement(mBarDiv);
return NS_OK;
}
void
nsMeterFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
uint32_t aFilter)
{
--- a/layout/forms/nsNumberControlFrame.cpp
+++ b/layout/forms/nsNumberControlFrame.cpp
@@ -320,37 +320,25 @@ private:
nsCOMPtr<nsIContent> mNumber;
nsCOMPtr<nsIContent> mTextField;
};
nsresult
nsNumberControlFrame::MakeAnonymousElement(Element** aResult,
nsTArray<ContentInfo>& aElements,
nsIAtom* aTagName,
- CSSPseudoElementType aPseudoType,
- nsStyleContext* aParentContext)
+ CSSPseudoElementType aPseudoType)
{
// Get the NodeInfoManager and tag necessary to create the anonymous divs.
nsCOMPtr<nsIDocument> doc = mContent->GetComposedDoc();
RefPtr<Element> resultElement = doc->CreateHTMLElement(aTagName);
+ resultElement->SetPseudoElementType(aPseudoType);
- // If we legitimately fail this assertion and need to allow
- // non-pseudo-element anonymous children, then we'll need to add a branch
- // that calls ResolveStyleFor((*aResult)->AsElement(), aParentContext)") to
- // set newStyleContext.
- NS_ASSERTION(aPseudoType != CSSPseudoElementType::NotPseudo,
- "Expecting anonymous children to all be pseudo-elements");
// Associate the pseudo-element with the anonymous child
- RefPtr<nsStyleContext> newStyleContext =
- PresContext()->StyleSet()->ResolvePseudoElementStyle(mContent->AsElement(),
- aPseudoType,
- aParentContext,
- resultElement);
-
- if (!aElements.AppendElement(ContentInfo(resultElement, newStyleContext))) {
+ if (!aElements.AppendElement(resultElement)) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (aPseudoType == CSSPseudoElementType::mozNumberSpinDown ||
aPseudoType == CSSPseudoElementType::mozNumberSpinUp) {
resultElement->SetAttr(kNameSpaceID_None, nsGkAtoms::role,
NS_LITERAL_STRING("button"), false);
}
@@ -377,28 +365,26 @@ nsNumberControlFrame::CreateAnonymousCon
// If you change this, be careful to change the destruction order in
// nsNumberControlFrame::DestroyFrom.
// Create the anonymous outer wrapper:
rv = MakeAnonymousElement(getter_AddRefs(mOuterWrapper),
aElements,
nsGkAtoms::div,
- CSSPseudoElementType::mozNumberWrapper,
- mStyleContext);
+ CSSPseudoElementType::mozNumberWrapper);
NS_ENSURE_SUCCESS(rv, rv);
ContentInfo& outerWrapperCI = aElements.LastElement();
// Create the ::-moz-number-text pseudo-element:
rv = MakeAnonymousElement(getter_AddRefs(mTextField),
outerWrapperCI.mChildren,
nsGkAtoms::input,
- CSSPseudoElementType::mozNumberText,
- outerWrapperCI.mStyleContext);
+ CSSPseudoElementType::mozNumberText);
NS_ENSURE_SUCCESS(rv, rv);
mTextField->SetAttr(kNameSpaceID_None, nsGkAtoms::type,
NS_LITERAL_STRING("text"), PR_FALSE);
HTMLInputElement* content = HTMLInputElement::FromContent(mContent);
HTMLInputElement* textField = HTMLInputElement::FromContent(mTextField);
@@ -435,36 +421,33 @@ nsNumberControlFrame::CreateAnonymousCon
// -moz-appearance. We will reframe if it changes.
return rv;
}
// Create the ::-moz-number-spin-box pseudo-element:
rv = MakeAnonymousElement(getter_AddRefs(mSpinBox),
outerWrapperCI.mChildren,
nsGkAtoms::div,
- CSSPseudoElementType::mozNumberSpinBox,
- outerWrapperCI.mStyleContext);
+ CSSPseudoElementType::mozNumberSpinBox);
NS_ENSURE_SUCCESS(rv, rv);
ContentInfo& spinBoxCI = outerWrapperCI.mChildren.LastElement();
// Create the ::-moz-number-spin-up pseudo-element:
rv = MakeAnonymousElement(getter_AddRefs(mSpinUp),
spinBoxCI.mChildren,
nsGkAtoms::div,
- CSSPseudoElementType::mozNumberSpinUp,
- spinBoxCI.mStyleContext);
+ CSSPseudoElementType::mozNumberSpinUp);
NS_ENSURE_SUCCESS(rv, rv);
// Create the ::-moz-number-spin-down pseudo-element:
rv = MakeAnonymousElement(getter_AddRefs(mSpinDown),
spinBoxCI.mChildren,
nsGkAtoms::div,
- CSSPseudoElementType::mozNumberSpinDown,
- spinBoxCI.mStyleContext);
+ CSSPseudoElementType::mozNumberSpinDown);
SyncDisabledState();
return rv;
}
nsIAtom*
nsNumberControlFrame::GetType() const
--- a/layout/forms/nsNumberControlFrame.h
+++ b/layout/forms/nsNumberControlFrame.h
@@ -165,18 +165,17 @@ public:
bool ShouldUseNativeStyleForSpinner() const;
private:
nsITextControlFrame* GetTextFieldFrame();
nsresult MakeAnonymousElement(Element** aResult,
nsTArray<ContentInfo>& aElements,
nsIAtom* aTagName,
- CSSPseudoElementType aPseudoType,
- nsStyleContext* aParentContext);
+ CSSPseudoElementType aPseudoType);
class SyncDisabledStateEvent;
friend class SyncDisabledStateEvent;
class SyncDisabledStateEvent : public mozilla::Runnable
{
public:
explicit SyncDisabledStateEvent(nsNumberControlFrame* aFrame)
: mFrame(aFrame)
--- a/layout/forms/nsProgressFrame.cpp
+++ b/layout/forms/nsProgressFrame.cpp
@@ -67,22 +67,19 @@ nsProgressFrame::GetType() const
nsresult
nsProgressFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
{
// Create the progress bar div.
nsCOMPtr<nsIDocument> doc = mContent->GetComposedDoc();
mBarDiv = doc->CreateHTMLElement(nsGkAtoms::div);
// Associate ::-moz-progress-bar pseudo-element to the anonymous child.
- CSSPseudoElementType pseudoType = CSSPseudoElementType::mozProgressBar;
- RefPtr<nsStyleContext> newStyleContext = PresContext()->StyleSet()->
- ResolvePseudoElementStyle(mContent->AsElement(), pseudoType,
- StyleContext(), mBarDiv->AsElement());
+ mBarDiv->SetPseudoElementType(CSSPseudoElementType::mozProgressBar);
- if (!aElements.AppendElement(ContentInfo(mBarDiv, newStyleContext))) {
+ if (!aElements.AppendElement(mBarDiv)) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
void
nsProgressFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
--- a/layout/forms/nsRangeFrame.cpp
+++ b/layout/forms/nsRangeFrame.cpp
@@ -114,23 +114,19 @@ nsresult
nsRangeFrame::MakeAnonymousDiv(Element** aResult,
CSSPseudoElementType aPseudoType,
nsTArray<ContentInfo>& aElements)
{
nsCOMPtr<nsIDocument> doc = mContent->GetComposedDoc();
RefPtr<Element> resultElement = doc->CreateHTMLElement(nsGkAtoms::div);
// Associate the pseudo-element with the anonymous child.
- RefPtr<nsStyleContext> newStyleContext =
- PresContext()->StyleSet()->ResolvePseudoElementStyle(mContent->AsElement(),
- aPseudoType,
- StyleContext(),
- resultElement);
+ resultElement->SetPseudoElementType(aPseudoType);
- if (!aElements.AppendElement(ContentInfo(resultElement, newStyleContext))) {
+ if (!aElements.AppendElement(resultElement)) {
return NS_ERROR_OUT_OF_MEMORY;
}
resultElement.forget(aResult);
return NS_OK;
}
nsresult
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -342,42 +342,22 @@ nsTextControlFrame::CreateAnonymousConte
nsAutoString placeholderTxt;
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::placeholder,
placeholderTxt);
nsContentUtils::RemoveNewlines(placeholderTxt);
mUsePlaceholder = !placeholderTxt.IsEmpty();
// Create the placeholder anonymous content if needed.
if (mUsePlaceholder) {
- nsIContent* placeholderNode = txtCtrl->CreatePlaceholderNode();
+ Element* placeholderNode = txtCtrl->CreatePlaceholderNode();
NS_ENSURE_TRUE(placeholderNode, NS_ERROR_OUT_OF_MEMORY);
// Associate ::placeholder pseudo-element with the placeholder node.
- CSSPseudoElementType pseudoType = CSSPseudoElementType::placeholder;
-
- // If this is a text input inside a number input then we want to use the
- // main number input as the source of style for the placeholder frame.
- nsIFrame* mainInputFrame = this;
- if (StyleContext()->GetPseudoType() == CSSPseudoElementType::mozNumberText) {
- do {
- mainInputFrame = mainInputFrame->GetParent();
- } while (mainInputFrame &&
- mainInputFrame->GetType() != nsGkAtoms::numberControlFrame);
- MOZ_ASSERT(mainInputFrame);
- }
-
- RefPtr<nsStyleContext> placeholderStyleContext =
- PresContext()->StyleSet()->ResolvePseudoElementStyle(
- mainInputFrame->GetContent()->AsElement(), pseudoType, StyleContext(),
- placeholderNode->AsElement());
-
- if (!aElements.AppendElement(ContentInfo(placeholderNode,
- placeholderStyleContext))) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
+ placeholderNode->SetPseudoElementType(CSSPseudoElementType::placeholder);
+ aElements.AppendElement(placeholderNode);
if (!IsSingleLineTextControl()) {
// For textareas, UpdateValueDisplay doesn't initialize the visibility
// status of the placeholder because it returns early, so we have to
// do that manually here.
txtCtrl->UpdatePlaceholderVisibility(true);
}
}
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -9060,16 +9060,18 @@ GetIBSplitSiblingForAnonymousBlock(const
* Get the parent, corrected for the mangled frame tree resulting from
* having a block within an inline. The result only differs from the
* result of |GetParent| when |GetParent| returns an anonymous block
* that was created for an element that was 'display: inline' because
* that element contained a block.
*
* Also skip anonymous scrolled-content parents; inherit directly from the
* outer scroll frame.
+ *
+ * Also skip NAC parents if the child frame is NAC.
*/
static nsIFrame*
GetCorrectedParent(const nsIFrame* aFrame)
{
nsIFrame* parent = aFrame->GetParent();
if (!parent) {
return nullptr;
}
@@ -9085,16 +9087,41 @@ GetCorrectedParent(const nsIFrame* aFram
// Table wrappers are always anon boxes; if we're in here for an outer
// table, that actually means its the _inner_ table that wants to
// know its parent. So get the pseudo of the inner in that case.
nsIAtom* pseudo = aFrame->StyleContext()->GetPseudo();
if (pseudo == nsCSSAnonBoxes::tableWrapper) {
pseudo = aFrame->PrincipalChildList().FirstChild()->StyleContext()->GetPseudo();
}
+
+ // Prevent NAC from inheriting NAC. This partially duplicates the logic
+ // implemented in nsCSSFrameConstructor::AddFCItemsForAnonymousContent, and is
+ // necessary so that restyle inherits style contexts in the same way as the
+ // initial styling performed in frame construction.
+ //
+ // It would be nice to put it in CorrectStyleParentFrame and therefore share
+ // it, but that would lose the information of whether the _child_ is NAC,
+ // since CorrectStyleParentFrame only knows about the prospective _parent_.
+ // This duplication and complexity will go away when we fully switch to the
+ // Servo style system, where all this can be handled much more naturally.
+ //
+ // We need to take special care not to disrupt the style inheritance of frames
+ // whose content is NAC but who implement a pseudo (like an anonymous
+ // box, or a non-NAC-backed pseudo like ::first-line) that does not match the
+ // one that the NAC implements, if any.
+ nsIContent* content = aFrame->GetContent();
+ Element* element = content->IsElement() ? content->AsElement() : nullptr;
+ if (element && element->IsNativeAnonymous() &&
+ element->GetPseudoElementType() == aFrame->StyleContext()->GetPseudoType()) {
+ while (parent->GetContent() && parent->GetContent()->IsNativeAnonymous()) {
+ parent = parent->GetParent();
+ }
+ }
+
return nsFrame::CorrectStyleParentFrame(parent, pseudo);
}
/* static */
nsIFrame*
nsFrame::CorrectStyleParentFrame(nsIFrame* aProspectiveParent,
nsIAtom* aChildPseudo)
{
@@ -9155,16 +9182,19 @@ nsFrame::CorrectStyleParentFrame(nsIFram
return nullptr;
}
nsStyleContext*
nsFrame::DoGetParentStyleContext(nsIFrame** aProviderFrame) const
{
*aProviderFrame = nullptr;
nsFrameManager* fm = PresContext()->FrameManager();
+
+ // Handle display:contents and the root frame, when there's no parent frame
+ // to inherit from.
if (MOZ_LIKELY(mContent)) {
nsIContent* parentContent = mContent->GetFlattenedTreeParent();
if (MOZ_LIKELY(parentContent)) {
nsIAtom* pseudo = StyleContext()->GetPseudo();
if (!pseudo || !mContent->IsElement() ||
(!nsCSSAnonBoxes::IsAnonBox(pseudo) &&
// Ensure that we don't return the display:contents style
// of the parent content for pseudos that have the same content
--- a/layout/generic/nsIAnonymousContentCreator.h
+++ b/layout/generic/nsIAnonymousContentCreator.h
@@ -29,22 +29,17 @@ class nsIAnonymousContentCreator
public:
NS_DECL_QUERYFRAME_TARGET(nsIAnonymousContentCreator)
struct ContentInfo {
explicit ContentInfo(nsIContent* aContent) :
mContent(aContent)
{}
- ContentInfo(nsIContent* aContent, nsStyleContext* aStyleContext) :
- mContent(aContent), mStyleContext(aStyleContext)
- {}
-
nsIContent* mContent;
- RefPtr<nsStyleContext> mStyleContext;
nsTArray<ContentInfo> mChildren;
};
/**
* Creates "native" anonymous content and adds the created content to
* the aElements array. None of the returned elements can be nullptr.
*
* If the anonymous content creator sets the editable flag on some
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/input/number/number-style-inheritance-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+ <body>
+ <input type="text" style="width: 100px; text-decoration: underline;" value="1234">
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/input/number/number-style-inheritance.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+ <body>
+ <input type="number" style="width: 100px; -moz-appearance: textfield; text-decoration: underline;" value="1234">
+ </body>
+</html>
--- a/layout/reftests/forms/input/number/reftest.list
+++ b/layout/reftests/forms/input/number/reftest.list
@@ -47,8 +47,11 @@ fuzzy-if(skiaContent,2,5) needs-focus ==
== number-placeholder.html number-placeholder-ref.html
# check that if the anonymous text control is reframed, we reframe the whole
# number control (the fuzzy is for the top-right and bottom-left of the border
# bevel which gets slightly different antialiasing after invalidation):
fuzzy(128,4) == number-reframe-anon-text-field.html number-reframe-anon-text-field-ref.html
== pseudo-classes.html about:blank
+
+# Style inheritance:
+== number-style-inheritance.html number-style-inheritance-ref.html
--- a/layout/style/res/forms.css
+++ b/layout/style/res/forms.css
@@ -1167,16 +1167,17 @@ input[type=number]::-moz-number-spin-box
* if the font-size is made substantially larger or smaller. (Bug 1175074.)
*/
max-height: 1em;
align-self: center;
justify-content: center;
}
input[type=number]::-moz-number-spin-up {
+ writing-mode: horizontal-tb;
-moz-appearance: spinner-upbutton;
display: block; /* bug 926670 */
flex: none;
cursor: default;
/* Style for when native theming is off: */
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="6" height="5"><path d="M1,4 L3,0 5,4" fill="dimgrey"/></svg>');
background-repeat: no-repeat;
background-position: center bottom;
@@ -1184,16 +1185,17 @@ input[type=number]::-moz-number-spin-up
border-bottom: none;
/* [JK] I think the border-*-*-radius properties here can remain physical,
as we probably don't want to turn the spinner sideways in vertical writing mode */
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
input[type=number]::-moz-number-spin-down {
+ writing-mode: horizontal-tb;
-moz-appearance: spinner-downbutton;
display: block; /* bug 926670 */
flex: none;
cursor: default;
/* Style for when native theming is off: */
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="6" height="5"><path d="M1,1 L3,5 5,1" fill="dimgrey"/></svg>');
background-repeat: no-repeat;
background-position: center top;