diff --git a/accessible/html/HTMLListAccessible.cpp b/accessible/html/HTMLListAccessible.cpp index bc506053865d..7df3bbf3748c 100644 --- a/accessible/html/HTMLListAccessible.cpp +++ b/accessible/html/HTMLListAccessible.cpp @@ -39,7 +39,7 @@ HTMLLIAccessible::HTMLLIAccessible(nsIContent* aContent, DocAccessible* aDoc) mType = eHTMLLiType; nsBlockFrame* blockFrame = do_QueryFrame(GetFrame()); - if (blockFrame && blockFrame->HasBullet()) { + if (blockFrame && blockFrame->HasMarker()) { mBullet = new HTMLListBulletAccessible(mContent, mDoc); Document()->BindToDocument(mBullet, nullptr); AppendChild(mBullet); @@ -120,7 +120,7 @@ HTMLListBulletAccessible::HTMLListBulletAccessible(nsIContent* aContent, nsIFrame* HTMLListBulletAccessible::GetFrame() const { nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame()); - return blockFrame ? blockFrame->GetBullet() : nullptr; + return blockFrame ? blockFrame->GetMarker() : nullptr; } ENameValueFlag HTMLListBulletAccessible::Name(nsString& aName) const { @@ -129,7 +129,7 @@ ENameValueFlag HTMLListBulletAccessible::Name(nsString& aName) const { // Native anonymous content, ARIA can't be used. Get list bullet text. nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame()); if (blockFrame) { - blockFrame->GetSpokenBulletText(aName); + blockFrame->GetSpokenMarkerText(aName); } return eNameOK; @@ -146,7 +146,7 @@ void HTMLListBulletAccessible::AppendTextTo(nsAString& aText, uint32_t aLength) { nsAutoString bulletText; nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame()); - if (blockFrame) blockFrame->GetSpokenBulletText(bulletText); + if (blockFrame) blockFrame->GetSpokenMarkerText(bulletText); aText.Append(Substring(bulletText, aStartOffset, aLength)); } @@ -156,5 +156,5 @@ void HTMLListBulletAccessible::AppendTextTo(nsAString& aText, bool HTMLListBulletAccessible::IsInside() const { nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame()); - return blockFrame ? blockFrame->HasInsideBullet() : false; + return blockFrame ? blockFrame->HasInsideMarker() : false; } diff --git a/devtools/server/actors/animation-type-longhand.js b/devtools/server/actors/animation-type-longhand.js index 3283b831766e..ccec7550f966 100644 --- a/devtools/server/actors/animation-type-longhand.js +++ b/devtools/server/actors/animation-type-longhand.js @@ -48,6 +48,7 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [ "content", "counter-increment", "counter-reset", + "counter-set", "cursor", "direction", "dominant-baseline", @@ -92,6 +93,7 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [ "list-style-image", "list-style-position", "list-style-type", + "-moz-list-reversed", "marker-end", "marker-mid", "marker-start", diff --git a/devtools/server/tests/mochitest/test_css-logic-specificity.html b/devtools/server/tests/mochitest/test_css-logic-specificity.html index b8d573d042b8..5060618fdda5 100644 --- a/devtools/server/tests/mochitest/test_css-logic-specificity.html +++ b/devtools/server/tests/mochitest/test_css-logic-specificity.html @@ -32,7 +32,7 @@ Test that css-logic calculates CSS specificity properly {text: "* body#home div#warning p.message", expected: 2098179}, {text: "#footer :not(nav) li", expected: 1048578}, {text: "bar:nth-child(n)", expected: 1025}, - {text: "li::-moz-list-number", expected: 2}, + {text: "li::marker", expected: 2}, {text: "a:hover", expected: 1025}, ]; diff --git a/devtools/server/tests/mochitest/test_styles-applied.html b/devtools/server/tests/mochitest/test_styles-applied.html index 0773695084ed..4f75379c7726 100644 --- a/devtools/server/tests/mochitest/test_styles-applied.html +++ b/devtools/server/tests/mochitest/test_styles-applied.html @@ -82,7 +82,7 @@ addTest(function inheritedSystemStyles() { ok(!applied[1].rule.parentStyleSheet.system, "Entry 1 should be a system style"); is(applied[1].rule.type, 1, "Entry 1 should be a rule style"); - is(applied.length, 13, "Should have 13 rules."); + is(applied.length, 12, "Should have 12 rules."); }).then(runNextTest)); }); diff --git a/devtools/shared/css/generated/properties-db.js b/devtools/shared/css/generated/properties-db.js index a5ea0cf1efd4..e5ebfbe63618 100644 --- a/devtools/shared/css/generated/properties-db.js +++ b/devtools/shared/css/generated/properties-db.js @@ -3116,6 +3116,7 @@ exports.CSS_PROPERTIES = { "content", "counter-increment", "counter-reset", + "counter-set", "opacity", "box-shadow", "clip", @@ -5749,6 +5750,20 @@ exports.CSS_PROPERTIES = { "unset" ] }, + "counter-set": { + "isInherited": false, + "subproperties": [ + "counter-set" + ], + "supports": [], + "values": [ + "inherit", + "initial", + "none", + "revert", + "unset" + ] + }, "cursor": { "isInherited": true, "subproperties": [ @@ -10209,6 +10224,7 @@ exports.CSS_PROPERTIES = { exports.PSEUDO_ELEMENTS = [ ":after", ":before", + ":marker", ":backdrop", ":cue", ":first-letter", @@ -10216,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", diff --git a/dom/base/ChildIterator.cpp b/dom/base/ChildIterator.cpp index 85dc4dcd25b7..f38874447524 100644 --- a/dom/base/ChildIterator.cpp +++ b/dom/base/ChildIterator.cpp @@ -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; } diff --git a/dom/base/ChildIterator.h b/dom/base/ChildIterator.h index bcb3190e3991..0c192628deba 100644 --- a/dom/base/ChildIterator.h +++ b/dom/base/ChildIterator.h @@ -236,6 +236,7 @@ class AllChildrenIterator : private FlattenedChildIterator { enum IteratorPhase { eAtBegin, + eAtMarkerKid, eAtBeforeKid, eAtExplicitKids, eAtAnonKids, diff --git a/dom/base/nsIContent.h b/dom/base/nsIContent.h index 4123573a3a66..e4b0cb2b1fbb 100644 --- a/dom/base/nsIContent.h +++ b/dom/base/nsIContent.h @@ -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, diff --git a/dom/html/HTMLLIElement.cpp b/dom/html/HTMLLIElement.cpp index 8fb86d34986a..eb46688f7b53 100644 --- a/dom/html/HTMLLIElement.cpp +++ b/dom/html/HTMLLIElement.cpp @@ -67,6 +67,18 @@ void HTMLLIElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes, value->GetEnumValue()); } + // Map
  • to 'counter-set: list-item INTEGER; + // counter-increment: list-item 0;'. + const nsAttrValue* attrVal = aAttributes->GetAttr(nsGkAtoms::value); + if (attrVal && attrVal->Type() == nsAttrValue::eInteger) { + if (!aDecls.PropertyIsSet(eCSSProperty_counter_set)) { + aDecls.SetCounterSetListItem(attrVal->GetIntegerValue()); + } + if (!aDecls.PropertyIsSet(eCSSProperty_counter_increment)) { + aDecls.SetCounterIncrementListItem(0); + } + } + nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls); } @@ -74,6 +86,7 @@ NS_IMETHODIMP_(bool) HTMLLIElement::IsAttributeMapped(const nsAtom* aAttribute) const { static const MappedAttributeEntry attributes[] = { {nsGkAtoms::type}, + {nsGkAtoms::value}, {nullptr}, }; diff --git a/dom/html/HTMLSharedListElement.cpp b/dom/html/HTMLSharedListElement.cpp index c9d2213122e6..d92f67c514b9 100644 --- a/dom/html/HTMLSharedListElement.cpp +++ b/dom/html/HTMLSharedListElement.cpp @@ -59,6 +59,8 @@ bool HTMLSharedListElement::ParseAttribute( return aResult.ParseEnumValue(aValue, kListTypeTable, false) || aResult.ParseEnumValue(aValue, kOldListTypeTable, true); } + } + if (mNodeInfo->Equals(nsGkAtoms::ol)) { if (aAttribute == nsGkAtoms::start) { return aResult.ParseIntValue(aValue); } @@ -72,7 +74,6 @@ bool HTMLSharedListElement::ParseAttribute( void HTMLSharedListElement::MapAttributesIntoRule( const nsMappedAttributes* aAttributes, MappedDeclarations& aDecls) { if (!aDecls.PropertyIsSet(eCSSProperty_list_style_type)) { - // type: enum const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::type); if (value && value->Type() == nsAttrValue::eEnum) { aDecls.SetKeywordValue(eCSSProperty_list_style_type, @@ -83,9 +84,34 @@ void HTMLSharedListElement::MapAttributesIntoRule( nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls); } +void HTMLSharedListElement::MapOLAttributesIntoRule( + const nsMappedAttributes* aAttributes, MappedDeclarations& aDecls) { + if (!aDecls.PropertyIsSet(eCSSProperty_counter_reset)) { + const nsAttrValue* startAttr = aAttributes->GetAttr(nsGkAtoms::start); + bool haveStart = startAttr && startAttr->Type() == nsAttrValue::eInteger; + int32_t start = 0; + if (haveStart) { + start = startAttr->GetIntegerValue() - 1; + } + bool haveReversed = !!aAttributes->GetAttr(nsGkAtoms::reversed); + if (haveReversed) { + if (haveStart) { + start += 2; // i.e. the attr value + 1 + } else { + start = std::numeric_limits::min(); + } + } + if (haveStart || haveReversed) { + aDecls.SetCounterResetListItem(start); + } + } + + HTMLSharedListElement::MapAttributesIntoRule(aAttributes, aDecls); +} + NS_IMETHODIMP_(bool) HTMLSharedListElement::IsAttributeMapped(const nsAtom* aAttribute) const { - if (mNodeInfo->Equals(nsGkAtoms::ol) || mNodeInfo->Equals(nsGkAtoms::ul)) { + if (mNodeInfo->Equals(nsGkAtoms::ul)) { static const MappedAttributeEntry attributes[] = {{nsGkAtoms::type}, {nullptr}}; @@ -97,14 +123,31 @@ HTMLSharedListElement::IsAttributeMapped(const nsAtom* aAttribute) const { return FindAttributeDependence(aAttribute, map); } + if (mNodeInfo->Equals(nsGkAtoms::ol)) { + static const MappedAttributeEntry attributes[] = {{nsGkAtoms::type}, + {nsGkAtoms::start}, + {nsGkAtoms::reversed}, + {nullptr}}; + + static const MappedAttributeEntry* const map[] = { + attributes, + sCommonAttributeMap, + }; + + return FindAttributeDependence(aAttribute, map); + } + return nsGenericHTMLElement::IsAttributeMapped(aAttribute); } nsMapRuleToAttributesFunc HTMLSharedListElement::GetAttributeMappingFunction() const { - if (mNodeInfo->Equals(nsGkAtoms::ol) || mNodeInfo->Equals(nsGkAtoms::ul)) { + if (mNodeInfo->Equals(nsGkAtoms::ul)) { return &MapAttributesIntoRule; } + if (mNodeInfo->Equals(nsGkAtoms::ol)) { + return &MapOLAttributesIntoRule; + } return nsGenericHTMLElement::GetAttributeMappingFunction(); } diff --git a/dom/html/HTMLSharedListElement.h b/dom/html/HTMLSharedListElement.h index ac45eab69a32..af635c0ed808 100644 --- a/dom/html/HTMLSharedListElement.h +++ b/dom/html/HTMLSharedListElement.h @@ -58,6 +58,8 @@ class HTMLSharedListElement final : public nsGenericHTMLElement { private: static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes, MappedDeclarations&); + static void MapOLAttributesIntoRule(const nsMappedAttributes* aAttributes, + MappedDeclarations&); }; } // namespace dom diff --git a/dom/plugins/base/nsPluginInstanceOwner.cpp b/dom/plugins/base/nsPluginInstanceOwner.cpp index 3e2bc722192e..6d7268a54592 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.cpp +++ b/dom/plugins/base/nsPluginInstanceOwner.cpp @@ -2286,7 +2286,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent( event.subwindow = X11None; event.mode = -1; event.detail = NotifyDetailNone; - event.same_screen = True; + event.same_screen = X11True; event.focus = mContentFocused; } break; case eMouseMove: { @@ -2302,7 +2302,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent( // information lost event.subwindow = X11None; event.is_hint = NotifyNormal; - event.same_screen = True; + event.same_screen = X11True; } break; case eMouseDown: case eMouseUp: { @@ -2329,7 +2329,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent( } // information lost: event.subwindow = X11None; - event.same_screen = True; + event.same_screen = X11True; } break; default: break; @@ -2372,7 +2372,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent( event.y = 0; event.x_root = -1; event.y_root = -1; - event.same_screen = False; + event.same_screen = X11False; } else { // If we need to send synthesized key events, then // DOMKeyCodeToGdkKeyCode(keyEvent.keyCode) and @@ -2409,7 +2409,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent( event.window = X11None; // not a real window // information lost: event.serial = 0; - event.send_event = False; + event.send_event = X11False; int16_t response = kNPEventNotHandled; mInstance->HandleEvent(&pluginEvent, &response, @@ -2702,7 +2702,7 @@ nsresult nsPluginInstanceOwner::Renderer::DrawWithXlib( exposeEvent.count = 0; // information not set: exposeEvent.serial = 0; - exposeEvent.send_event = False; + exposeEvent.send_event = X11False; exposeEvent.major_code = 0; exposeEvent.minor_code = 0; diff --git a/dom/plugins/ipc/PluginInstanceChild.cpp b/dom/plugins/ipc/PluginInstanceChild.cpp index cb646e1b6df3..1dbbc4936b34 100644 --- a/dom/plugins/ipc/PluginInstanceChild.cpp +++ b/dom/plugins/ipc/PluginInstanceChild.cpp @@ -880,7 +880,7 @@ mozilla::ipc::IPCResult PluginInstanceChild::AnswerNPP_HandleEvent( // process does not need to wait; the parent is the process that needs // to wait. A possibly-slightly-better alternative would be to send // an X event to the parent that the parent would wait for. - XSync(mWsInfo.display, False); + XSync(mWsInfo.display, X11False); } #endif @@ -3171,7 +3171,7 @@ void PluginInstanceChild::PaintRectToPlatformSurface(const nsIntRect& aRect, exposeEvent.count = 0; // information not set: exposeEvent.serial = 0; - exposeEvent.send_event = False; + exposeEvent.send_event = X11False; exposeEvent.major_code = 0; exposeEvent.minor_code = 0; mPluginIface->event(&mData, reinterpret_cast(&exposeEvent)); @@ -3551,7 +3551,7 @@ bool PluginInstanceChild::ShowPluginFrame() { currSurf = SurfaceDescriptorX11(xsurf); // Need to sync all pending x-paint requests // before giving drawable to another process - XSync(mWsInfo.display, False); + XSync(mWsInfo.display, X11False); } else #endif #ifdef XP_WIN diff --git a/dom/plugins/ipc/PluginInstanceParent.cpp b/dom/plugins/ipc/PluginInstanceParent.cpp index 72469a137b92..4f6e1ca89c40 100644 --- a/dom/plugins/ipc/PluginInstanceParent.cpp +++ b/dom/plugins/ipc/PluginInstanceParent.cpp @@ -1075,7 +1075,7 @@ nsresult PluginInstanceParent::EndUpdateBackground(const nsIntRect& aRect) { // view of its background, but it does mean that the plugin is // drawing onto pixels no older than those in the latest // EndUpdateBackground(). - XSync(DefaultXDisplay(), False); + XSync(DefaultXDisplay(), X11False); #endif Unused << SendUpdateBackground(BackgroundDescriptor(), aRect); @@ -1494,7 +1494,7 @@ int16_t PluginInstanceParent::NPP_HandleEvent(void* event) { XUngrabPointer(dpy, npevent->xbutton.time); # endif // Wait for the ungrab to complete. - XSync(dpy, False); + XSync(dpy, X11False); break; } #endif diff --git a/dom/plugins/ipc/PluginModuleChild.cpp b/dom/plugins/ipc/PluginModuleChild.cpp index 09cb9065a06b..5606b48ba0cb 100644 --- a/dom/plugins/ipc/PluginModuleChild.cpp +++ b/dom/plugins/ipc/PluginModuleChild.cpp @@ -432,15 +432,15 @@ static gboolean gtk_plug_scroll_event(GtkWidget* widget, xevent.xbutton.y_root = gdk_event->y_root; xevent.xbutton.state = gdk_event->state; xevent.xbutton.button = button; - xevent.xbutton.same_screen = True; + xevent.xbutton.same_screen = X11True; gdk_error_trap_push(); - XSendEvent(dpy, xevent.xbutton.window, True, ButtonPressMask, &xevent); + XSendEvent(dpy, xevent.xbutton.window, X11True, ButtonPressMask, &xevent); xevent.xbutton.type = ButtonRelease; xevent.xbutton.state |= button_mask; - XSendEvent(dpy, xevent.xbutton.window, True, ButtonReleaseMask, &xevent); + XSendEvent(dpy, xevent.xbutton.window, X11True, ButtonReleaseMask, &xevent); gdk_display_sync(gdk_screen_get_display(screen)); gdk_error_trap_pop(); diff --git a/dom/xml/nsXMLElement.cpp b/dom/xml/nsXMLElement.cpp index 352558c72178..9747b9d2cdc7 100644 --- a/dom/xml/nsXMLElement.cpp +++ b/dom/xml/nsXMLElement.cpp @@ -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); } diff --git a/dom/xml/resources/XMLPrettyPrint.css b/dom/xml/resources/XMLPrettyPrint.css index 50abee7d89ae..962b46d4ede6 100644 --- a/dom/xml/resources/XMLPrettyPrint.css +++ b/dom/xml/resources/XMLPrettyPrint.css @@ -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 */ diff --git a/gfx/gl/GLContextProviderGLX.cpp b/gfx/gl/GLContextProviderGLX.cpp index 682e8a893d96..44208ad26bcb 100644 --- a/gfx/gl/GLContextProviderGLX.cpp +++ b/gfx/gl/GLContextProviderGLX.cpp @@ -263,14 +263,14 @@ GLXPixmap GLXLibrary::CreatePixmap(gfxASurface* aSurface) { "Unexpected render format with non-adjacent alpha bits"); int attribs[] = {LOCAL_GLX_DOUBLEBUFFER, - False, + X11False, LOCAL_GLX_DRAWABLE_TYPE, LOCAL_GLX_PIXMAP_BIT, LOCAL_GLX_ALPHA_SIZE, alphaSize, (alphaSize ? LOCAL_GLX_BIND_TO_TEXTURE_RGBA_EXT : LOCAL_GLX_BIND_TO_TEXTURE_RGB_EXT), - True, + X11True, LOCAL_GLX_RENDER_TYPE, LOCAL_GLX_RGBA_BIT, X11None}; @@ -517,11 +517,11 @@ already_AddRefed GLContextGLX::CreateGLContext( }; attrib_list.AppendElement(0); - context = glx.fCreateContextAttribs(display, cfg, nullptr, True, + context = glx.fCreateContextAttribs(display, cfg, nullptr, X11True, attrib_list.Elements()); } else { context = glx.fCreateNewContext(display, cfg, LOCAL_GLX_RGBA_TYPE, - nullptr, True); + nullptr, X11True); } if (context) { @@ -778,7 +778,7 @@ static bool ChooseConfig(GLXLibrary* glx, Display* display, int screen, int attribs[] = {LOCAL_GLX_DRAWABLE_TYPE, LOCAL_GLX_PIXMAP_BIT, LOCAL_GLX_X_RENDERABLE, - True, + X11True, LOCAL_GLX_RED_SIZE, 8, LOCAL_GLX_GREEN_SIZE, @@ -918,7 +918,7 @@ bool GLContextGLX::FindFBConfigForWindow( LOCAL_GLX_DEPTH_SIZE, 24, LOCAL_GLX_DOUBLEBUFFER, - True, + X11True, 0}; if (aWebRender) { diff --git a/gfx/src/X11UndefineNone.h b/gfx/src/X11UndefineNone.h index 19cb0ea0fc03..a0776d4fb02b 100644 --- a/gfx/src/X11UndefineNone.h +++ b/gfx/src/X11UndefineNone.h @@ -26,3 +26,14 @@ #ifdef Always # undef Always #endif + +// X11/Xlib.h also defines True and False, get rid of those too for +// the same reasons as above... +#ifdef True +# undef True +# define X11True 1 +#endif +#ifdef False +# undef False +# define X11False 0 +#endif diff --git a/gfx/src/X11Util.cpp b/gfx/src/X11Util.cpp index f16c2f524401..709d652bae20 100644 --- a/gfx/src/X11Util.cpp +++ b/gfx/src/X11Util.cpp @@ -36,7 +36,7 @@ void FinishX(Display* aDisplay) { unsigned long lastRequest = NextRequest(aDisplay) - 1; if (lastRequest == LastKnownRequestProcessed(aDisplay)) return; - XSync(aDisplay, False); + XSync(aDisplay, X11False); } ScopedXErrorHandler::ErrorEvent* ScopedXErrorHandler::sXErrorPtr; diff --git a/gfx/thebes/gfxPlatformGtk.cpp b/gfx/thebes/gfxPlatformGtk.cpp index d431eb27828d..144af010f76a 100644 --- a/gfx/thebes/gfxPlatformGtk.cpp +++ b/gfx/thebes/gfxPlatformGtk.cpp @@ -362,7 +362,7 @@ void gfxPlatformGtk::GetPlatformCMSOutputProfile(void*& mem, size_t& size) { if (iccAtom) { // read once to get size, once for the data if (Success == XGetWindowProperty(dpy, root, iccAtom, 0, - INT_MAX /* length */, False, + INT_MAX /* length */, X11False, AnyPropertyType, &retAtom, &retFormat, &retLength, &retAfter, &retProperty)) { if (retLength > 0) { @@ -387,7 +387,7 @@ void gfxPlatformGtk::GetPlatformCMSOutputProfile(void*& mem, size_t& size) { edidAtom = XInternAtom(dpy, EDID1_ATOM_NAME, TRUE); if (edidAtom) { - if (Success == XGetWindowProperty(dpy, root, edidAtom, 0, 32, False, + if (Success == XGetWindowProperty(dpy, root, edidAtom, 0, 32, X11False, AnyPropertyType, &retAtom, &retFormat, &retLength, &retAfter, &retProperty)) { double gamma; diff --git a/js/src/builtin/Array.cpp b/js/src/builtin/Array.cpp index ffb9ec7c0071..8f93924ab69f 100644 --- a/js/src/builtin/Array.cpp +++ b/js/src/builtin/Array.cpp @@ -4077,10 +4077,9 @@ static MOZ_ALWAYS_INLINE ArrayObject* NewArray( } AutoSetNewObjectMetadata metadata(cx); - RootedArrayObject arr( - cx, ArrayObject::createArray( - cx, allocKind, GetInitialHeap(newKind, &ArrayObject::class_), - shape, group, length, metadata)); + RootedArrayObject arr(cx, ArrayObject::createArray( + cx, allocKind, GetInitialHeap(newKind, group), + shape, group, length, metadata)); if (!arr) { return nullptr; } @@ -4168,7 +4167,7 @@ ArrayObject* js::NewDenseFullyAllocatedArrayWithTemplate( RootedObjectGroup group(cx, templateObject->group()); RootedShape shape(cx, templateObject->as().lastProperty()); - gc::InitialHeap heap = GetInitialHeap(GenericObject, &ArrayObject::class_); + gc::InitialHeap heap = GetInitialHeap(GenericObject, group); Rooted arr( cx, ArrayObject::createArray(cx, allocKind, heap, shape, group, length, metadata)); @@ -4186,10 +4185,11 @@ ArrayObject* js::NewDenseFullyAllocatedArrayWithTemplate( } ArrayObject* js::NewDenseCopyOnWriteArray(JSContext* cx, - HandleArrayObject templateObject, - gc::InitialHeap heap) { + HandleArrayObject templateObject) { MOZ_ASSERT(!gc::IsInsideNursery(templateObject)); + gc::InitialHeap heap = GetInitialHeap(GenericObject, templateObject->group()); + ArrayObject* arr = ArrayObject::createCopyOnWriteArray(cx, heap, templateObject); if (!arr) { diff --git a/js/src/builtin/Array.h b/js/src/builtin/Array.h index be80883f52a7..9f00c5c5e5d4 100644 --- a/js/src/builtin/Array.h +++ b/js/src/builtin/Array.h @@ -79,8 +79,7 @@ extern ArrayObject* NewDenseFullyAllocatedArrayWithTemplate( // Create a dense array with the same copy-on-write elements as another object. extern ArrayObject* NewDenseCopyOnWriteArray(JSContext* cx, - HandleArrayObject templateObject, - gc::InitialHeap heap); + HandleArrayObject templateObject); extern ArrayObject* NewFullyAllocatedArrayTryUseGroup( JSContext* cx, HandleObjectGroup group, size_t length, diff --git a/js/src/builtin/Stream.cpp b/js/src/builtin/Stream.cpp index bc0e4200dd42..bbfea8203823 100644 --- a/js/src/builtin/Stream.cpp +++ b/js/src/builtin/Stream.cpp @@ -1552,8 +1552,7 @@ static MOZ_MUST_USE JSObject* ReadableStreamCreateReadResult( // Step 4: Let obj be ObjectCreate(prototype). NativeObject* obj; JS_TRY_VAR_OR_RETURN_NULL( - cx, obj, - NativeObject::createWithTemplate(cx, gc::DefaultHeap, templateObject)); + cx, obj, NativeObject::createWithTemplate(cx, templateObject)); // Step 5: Perform CreateDataProperty(obj, "value", value). obj->setSlot(Realm::IterResultObjectValueSlot, value); diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index 6c1256f64637..63dd3c863828 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -4434,11 +4434,9 @@ void CType::Trace(JSTracer* trc, JSObject* obj) { MOZ_ASSERT(fninfo); // Identify our objects to the tracer. - JS::TraceEdge(trc, &fninfo->mABI, "abi"); - JS::TraceEdge(trc, &fninfo->mReturnType, "returnType"); - for (auto& argType : fninfo->mArgTypes) { - JS::TraceEdge(trc, &argType, "argType"); - } + TraceEdge(trc, &fninfo->mABI, "abi"); + TraceEdge(trc, &fninfo->mReturnType, "returnType"); + fninfo->mArgTypes.trace(trc); break; } @@ -7228,13 +7226,10 @@ void CClosure::Trace(JSTracer* trc, JSObject* obj) { ClosureInfo* cinfo = static_cast(slot.toPrivate()); - // Identify our objects to the tracer. (There's no need to identify - // 'closureObj', since that's us.) - JS::TraceEdge(trc, &cinfo->typeObj, "typeObj"); - JS::TraceEdge(trc, &cinfo->jsfnObj, "jsfnObj"); - if (cinfo->thisObj) { - JS::TraceEdge(trc, &cinfo->thisObj, "thisObj"); - } + TraceEdge(trc, &cinfo->closureObj, "closureObj"); + TraceEdge(trc, &cinfo->typeObj, "typeObj"); + TraceEdge(trc, &cinfo->jsfnObj, "jsfnObj"); + TraceNullableEdge(trc, &cinfo->thisObj, "thisObj"); } void CClosure::Finalize(JSFreeOp* fop, JSObject* obj) { diff --git a/js/src/ctypes/CTypes.h b/js/src/ctypes/CTypes.h index c403ec670b38..80c69858a0f0 100644 --- a/js/src/ctypes/CTypes.h +++ b/js/src/ctypes/CTypes.h @@ -18,6 +18,7 @@ #include "js/GCHashTable.h" #include "js/UniquePtr.h" #include "js/Vector.h" +#include "vm/JSObject.h" #include "vm/StringType.h" namespace js { @@ -306,11 +307,11 @@ enum TypeCode { // Descriptor of one field in a StructType. The name of the field is stored // as the key to the hash entry. struct FieldInfo { - JS::Heap mType; // CType of the field + HeapPtr mType; // CType of the field size_t mIndex; // index of the field in the struct (first is 0) size_t mOffset; // offset of the field in the struct, in bytes - void trace(JSTracer* trc) { JS::TraceEdge(trc, &mType, "fieldType"); } + void trace(JSTracer* trc) { TraceEdge(trc, &mType, "fieldType"); } }; struct UnbarrieredFieldInfo { @@ -368,14 +369,14 @@ struct FunctionInfo { // Calling convention of the function. Convert to ffi_abi using GetABI // and ObjectValue. Stored as a JSObject* for ease of tracing. - JS::Heap mABI; + HeapPtr mABI; // The CType of the value returned by the function. - JS::Heap mReturnType; + HeapPtr mReturnType; // A fixed array of known parameter types, excluding any variadic // parameters (if mIsVariadic). - Vector, 0, SystemAllocPolicy> mArgTypes; + GCVector, 0, SystemAllocPolicy> mArgTypes; // A variable array of ffi_type*s corresponding to both known parameter // types and dynamic (variadic) parameter types. Longer than mArgTypes @@ -390,10 +391,10 @@ struct FunctionInfo { // Parameters necessary for invoking a JS function from a C closure. struct ClosureInfo { JSContext* cx; - JS::Heap closureObj; // CClosure object - JS::Heap typeObj; // FunctionType describing the C function - JS::Heap thisObj; // 'this' object to use for the JS function call - JS::Heap jsfnObj; // JS function + HeapPtr closureObj; // CClosure object + HeapPtr typeObj; // FunctionType describing the C function + HeapPtr thisObj; // 'this' object to use for the JS function call + HeapPtr jsfnObj; // JS function void* errResult; // Result that will be returned if the closure throws ffi_closure* closure; // The C closure itself diff --git a/js/src/jit-test/tests/gc/bug-1532376.js b/js/src/jit-test/tests/gc/bug-1532376.js new file mode 100644 index 000000000000..c523ba06b880 --- /dev/null +++ b/js/src/jit-test/tests/gc/bug-1532376.js @@ -0,0 +1,10 @@ +"use strict"; +function __f_276() { + this.getNameReallyHard = () => eval("eval('(() => this.name)()')") +} +for (var __v_1377 = 0; __v_1377 < 10000; __v_1377++) { + var __v_1378 = new __f_276(); + try { + __v_1376[__getRandomProperty()]; + } catch (e) {} +__v_1378.getNameReallyHard()} diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 590869c4b952..9887a417016b 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -2573,10 +2573,9 @@ bool BaselineCompilerCodeGen::emit_JSOP_NEWARRAY_COPYONWRITE() { prepareVMCall(); - pushArg(Imm32(gc::DefaultHeap)); pushArg(ImmGCPtr(obj)); - using Fn = ArrayObject* (*)(JSContext*, HandleArrayObject, gc::InitialHeap); + using Fn = ArrayObject* (*)(JSContext*, HandleArrayObject); if (!callVM()) { return false; } diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index bd52bd5c486c..14d5b9b6efb9 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -6434,10 +6434,9 @@ void CodeGenerator::visitNewArrayCopyOnWrite(LNewArrayCopyOnWrite* lir) { gc::InitialHeap initialHeap = lir->mir()->initialHeap(); // If we have a template object, we can inline call object creation. - using Fn = ArrayObject* (*)(JSContext*, HandleArrayObject, gc::InitialHeap); + using Fn = ArrayObject* (*)(JSContext*, HandleArrayObject); OutOfLineCode* ool = oolCallVM( - lir, ArgList(ImmGCPtr(templateObject), Imm32(initialHeap)), - StoreRegisterTo(objReg)); + lir, ArgList(ImmGCPtr(templateObject)), StoreRegisterTo(objReg)); TemplateObject templateObj(templateObject); templateObj.setDenseElementsAreCopyOnWrite(); diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index f24383e32cd9..da91a5b1bc9f 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -102,6 +102,7 @@ JitContext::JitContext(CompileRuntime* rt, CompileRealm* realm, realm_(realm), #ifdef DEBUG isCompilingWasm_(!realm), + oom_(false), #endif assemblerCount_(0) { SetJitContext(this); @@ -115,6 +116,7 @@ JitContext::JitContext(JSContext* cx, TempAllocator* temp) realm_(CompileRealm::get(cx->realm())), #ifdef DEBUG isCompilingWasm_(false), + oom_(false), #endif assemblerCount_(0) { SetJitContext(this); diff --git a/js/src/jit/Ion.h b/js/src/jit/Ion.h index b48b2849dbc2..70e9030d61cb 100644 --- a/js/src/jit/Ion.h +++ b/js/src/jit/Ion.h @@ -80,6 +80,8 @@ class JitContext { #ifdef DEBUG bool isCompilingWasm() { return isCompilingWasm_; } + bool hasOOM() { return oom_; } + void setOOM() { oom_ = true; } #endif private: @@ -87,6 +89,7 @@ class JitContext { CompileRealm* realm_; #ifdef DEBUG bool isCompilingWasm_; + bool oom_; #endif int assemblerCount_; }; diff --git a/js/src/jit/Label.h b/js/src/jit/Label.h index db4ff8d04343..9f0e10dea6fa 100644 --- a/js/src/jit/Label.h +++ b/js/src/jit/Label.h @@ -81,7 +81,8 @@ class Label : public LabelBase { JitContext* context = MaybeGetJitContext(); bool hadError = js::oom::HadSimulatedOOM() || - (context && context->runtime && context->runtime->hadOutOfMemory()); + (context && context->runtime && context->runtime->hadOutOfMemory()) || + (context && !context->runtime && context->hasOOM()); MOZ_ASSERT_IF(!hadError, !used()); #endif } diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index ab093f9ad8a5..64fc24caf5d3 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -3197,8 +3197,13 @@ class MOZ_RAII StackMacroAssembler : public MacroAssembler { // checking StackMacroAssembler has. class MOZ_RAII WasmMacroAssembler : public MacroAssembler { public: - explicit WasmMacroAssembler(TempAllocator& alloc) - : MacroAssembler(WasmToken(), alloc) {} + explicit WasmMacroAssembler(TempAllocator& alloc, bool limitedSize = true) + : MacroAssembler(WasmToken(), alloc) + { + if (!limitedSize) { + setUnlimitedBuffer(); + } + } ~WasmMacroAssembler() { assertNoGCThings(); } }; diff --git a/js/src/jit/ProcessExecutableMemory.h b/js/src/jit/ProcessExecutableMemory.h index 2eede3f5a09e..ae43624e753e 100644 --- a/js/src/jit/ProcessExecutableMemory.h +++ b/js/src/jit/ProcessExecutableMemory.h @@ -22,6 +22,39 @@ static const size_t MaxCodeBytesPerProcess = 140 * 1024 * 1024; static const size_t MaxCodeBytesPerProcess = 1 * 1024 * 1024 * 1024; #endif +// Limit on the number of bytes of code memory per buffer. This limit comes +// about because we encode an unresolved relative unconditional branch during +// assembly as a branch instruction that carries the absolute offset of the next +// branch instruction in the chain of branches that all reference the same +// unresolved label. For this architecture to work, no branch instruction may +// lie at an offset greater than the maximum forward branch distance. This is +// true on both ARM and ARM64. +// +// Notably, even though we know that the offsets thus encoded are always +// positive offsets, we use only the positive part of the signed range of the +// branch offset. +// +// On ARM-32, we are limited by BOffImm::IsInRange(), which checks that the +// offset is no greater than 2^25-4 in the offset's 26-bit signed field. +// +// On ARM-64, we are limited by Instruction::ImmBranchMaxForwardOffset(), which +// checks that the offset is no greater than 2^27-4 in the offset's 28-bit +// signed field. +// +// On MIPS, there are no limitations because the assembler has to implement +// jump chaining to be effective at all (jump offsets are quite small). +// +// On x86 and x64, there are no limitations here because the assembler +// MOZ_CRASHes if the 32-bit offset is exceeded. + +#if defined(JS_CODEGEN_ARM) +static const size_t MaxCodeBytesPerBuffer = (1 << 25) - 4; +#elif defined(JS_CODEGEN_ARM64) +static const size_t MaxCodeBytesPerBuffer = (1 << 27) - 4; +#else +static const size_t MaxCodeBytesPerBuffer = MaxCodeBytesPerProcess; +#endif + // Executable code is allocated in 64K chunks. ExecutableAllocator uses pools // that are at least this big. Code we allocate does not necessarily have 64K // alignment though. diff --git a/js/src/jit/Recover.cpp b/js/src/jit/Recover.cpp index adf0e3515ddc..12cafc7af866 100644 --- a/js/src/jit/Recover.cpp +++ b/js/src/jit/Recover.cpp @@ -1254,13 +1254,10 @@ bool RNewArray::recover(JSContext* cx, SnapshotIterator& iter) const { bool MNewArrayCopyOnWrite::writeRecoverData(CompactBufferWriter& writer) const { MOZ_ASSERT(canRecoverOnBailout()); writer.writeUnsigned(uint32_t(RInstruction::Recover_NewArrayCopyOnWrite)); - writer.writeByte(initialHeap()); return true; } -RNewArrayCopyOnWrite::RNewArrayCopyOnWrite(CompactBufferReader& reader) { - initialHeap_ = gc::InitialHeap(reader.readByte()); -} +RNewArrayCopyOnWrite::RNewArrayCopyOnWrite(CompactBufferReader& reader) {} bool RNewArrayCopyOnWrite::recover(JSContext* cx, SnapshotIterator& iter) const { @@ -1268,8 +1265,7 @@ bool RNewArrayCopyOnWrite::recover(JSContext* cx, &iter.read().toObject().as()); RootedValue result(cx); - ArrayObject* resultObject = - NewDenseCopyOnWriteArray(cx, templateObject, initialHeap_); + ArrayObject* resultObject = NewDenseCopyOnWriteArray(cx, templateObject); if (!resultObject) { return false; } diff --git a/js/src/jit/Recover.h b/js/src/jit/Recover.h index 4609b5fb097f..f95e7f342245 100644 --- a/js/src/jit/Recover.h +++ b/js/src/jit/Recover.h @@ -617,9 +617,6 @@ class RNewArray final : public RInstruction { }; class RNewArrayCopyOnWrite final : public RInstruction { - private: - gc::InitialHeap initialHeap_; - public: RINSTRUCTION_HEADER_NUM_OP_(NewArrayCopyOnWrite, 1) diff --git a/js/src/jit/arm/Assembler-arm.cpp b/js/src/jit/arm/Assembler-arm.cpp index b4b4564159da..b320f108a6d6 100644 --- a/js/src/jit/arm/Assembler-arm.cpp +++ b/js/src/jit/arm/Assembler-arm.cpp @@ -1619,10 +1619,8 @@ BufferOffset Assembler::as_BranchPool(uint32_t value, RepatchLabel* label, if (label->bound()) { BufferOffset dest(label); BOffImm offset = dest.diffB(ret); - if (offset.isInvalid()) { - m_buffer.fail_bail(); - return ret; - } + MOZ_RELEASE_ASSERT(!offset.isInvalid(), + "Buffer size limit should prevent this"); as_b(offset, c, ret); } else if (!oom()) { label->use(ret.getOffset()); @@ -1827,7 +1825,10 @@ BufferOffset Assembler::as_b(Label* l, Condition c) { return BufferOffset(); } - as_b(BufferOffset(l).diffB(ret), c, ret); + BOffImm offset = BufferOffset(l).diffB(ret); + MOZ_RELEASE_ASSERT(!offset.isInvalid(), + "Buffer size limit should prevent this"); + as_b(offset, c, ret); #ifdef JS_DISASM_ARM spewBranch(m_buffer.getInstOrNull(ret), refLabel(l)); #endif @@ -1841,12 +1842,8 @@ BufferOffset Assembler::as_b(Label* l, Condition c) { BufferOffset ret; if (l->used()) { int32_t old = l->offset(); - // This will currently throw an assertion if we couldn't actually - // encode the offset of the branch. - if (!BOffImm::IsInRange(old)) { - m_buffer.fail_bail(); - return ret; - } + MOZ_RELEASE_ASSERT(BOffImm::IsInRange(old), + "Buffer size limit should prevent this"); ret = as_b(BOffImm(old), c, l); } else { BOffImm inv; @@ -1894,10 +1891,8 @@ BufferOffset Assembler::as_bl(Label* l, Condition c) { } BOffImm offset = BufferOffset(l).diffB(ret); - if (offset.isInvalid()) { - m_buffer.fail_bail(); - return BufferOffset(); - } + MOZ_RELEASE_ASSERT(!offset.isInvalid(), + "Buffer size limit should prevent this"); as_bl(offset, c, ret); #ifdef JS_DISASM_ARM @@ -1913,13 +1908,9 @@ BufferOffset Assembler::as_bl(Label* l, Condition c) { BufferOffset ret; // See if the list was empty. if (l->used()) { - // This will currently throw an assertion if we couldn't actually encode - // the offset of the branch. int32_t old = l->offset(); - if (!BOffImm::IsInRange(old)) { - m_buffer.fail_bail(); - return ret; - } + MOZ_RELEASE_ASSERT(BOffImm::IsInRange(old), + "Buffer size limit should prevent this"); ret = as_bl(BOffImm(old), c, l); } else { BOffImm inv; @@ -2228,10 +2219,8 @@ void Assembler::bind(Label* label, BufferOffset boff) { Instruction branch = *editSrc(b); Condition c = branch.extractCond(); BOffImm offset = dest.diffB(b); - if (offset.isInvalid()) { - m_buffer.fail_bail(); - return; - } + MOZ_RELEASE_ASSERT(!offset.isInvalid(), + "Buffer size limit should prevent this"); if (branch.is()) { as_b(offset, c, b); } else if (branch.is()) { @@ -2268,10 +2257,8 @@ void Assembler::bind(RepatchLabel* label) { } BOffImm offset = dest.diffB(branchOff); - if (offset.isInvalid()) { - m_buffer.fail_bail(); - return; - } + MOZ_RELEASE_ASSERT(!offset.isInvalid(), + "Buffer size limit should prevent this"); as_b(offset, cond, branchOff); } label->bind(dest.getOffset()); diff --git a/js/src/jit/arm/Assembler-arm.h b/js/src/jit/arm/Assembler-arm.h index d016b4d37859..68574d7ff7ce 100644 --- a/js/src/jit/arm/Assembler-arm.h +++ b/js/src/jit/arm/Assembler-arm.h @@ -1251,6 +1251,10 @@ class Assembler : public AssemblerShared { // MacroAssembler, before allocating any space. void initWithAllocator() { m_buffer.initWithAllocator(); } + void setUnlimitedBuffer() { + m_buffer.setUnlimited(); + } + static Condition InvertCondition(Condition cond); static Condition UnsignedCondition(Condition cond); static Condition ConditionWithoutEqual(Condition cond); @@ -1878,8 +1882,6 @@ class Assembler : public AssemblerShared { void processCodeLabels(uint8_t* rawCode); - bool bailed() { return m_buffer.bail(); } - void verifyHeapAccessDisassembly(uint32_t begin, uint32_t end, const Disassembler::HeapAccess& heapAccess) { // Implement this if we implement a disassembler. diff --git a/js/src/jit/arm/CodeGenerator-arm.cpp b/js/src/jit/arm/CodeGenerator-arm.cpp index 1c1dc134fb61..0ee771b1af20 100644 --- a/js/src/jit/arm/CodeGenerator-arm.cpp +++ b/js/src/jit/arm/CodeGenerator-arm.cpp @@ -172,10 +172,6 @@ void CodeGeneratorARM::bailoutIf(Assembler::Condition condition, } void CodeGeneratorARM::bailoutFrom(Label* label, LSnapshot* snapshot) { - if (masm.bailed()) { - return; - } - MOZ_ASSERT_IF(!masm.oom(), label->used()); MOZ_ASSERT_IF(!masm.oom(), !label->bound()); diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index f0586208099f..67c08114e563 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -4242,7 +4242,10 @@ CodeOffset MacroAssembler::callWithPatch() { void MacroAssembler::patchCall(uint32_t callerOffset, uint32_t calleeOffset) { BufferOffset inst(callerOffset - 4); - as_bl(BufferOffset(calleeOffset).diffB(inst), Always, inst); + BOffImm off = BufferOffset(calleeOffset).diffB(inst); + MOZ_RELEASE_ASSERT(!off.isInvalid(), + "Failed to insert necessary far jump islands"); + as_bl(off, Always, inst); } CodeOffset MacroAssembler::farJumpWithPatch() { diff --git a/js/src/jit/arm64/Assembler-arm64.h b/js/src/jit/arm64/Assembler-arm64.h index 0c1c39b89a4a..f0171128afa3 100644 --- a/js/src/jit/arm64/Assembler-arm64.h +++ b/js/src/jit/arm64/Assembler-arm64.h @@ -224,6 +224,9 @@ class Assembler : public vixl::Assembler { void bind(RepatchLabel* label); void bind(CodeLabel* label) { label->target()->bind(currentOffset()); } + void setUnlimitedBuffer() { + armbuffer_.setUnlimited(); + } bool oom() const { return AssemblerShared::oom() || armbuffer_.oom() || jumpRelocations_.oom() || dataRelocations_.oom(); diff --git a/js/src/jit/mips-shared/Assembler-mips-shared.h b/js/src/jit/mips-shared/Assembler-mips-shared.h index efd6be411034..d5a4a1b665c8 100644 --- a/js/src/jit/mips-shared/Assembler-mips-shared.h +++ b/js/src/jit/mips-shared/Assembler-mips-shared.h @@ -814,6 +814,9 @@ class AssemblerMIPSShared : public AssemblerShared { } public: + void setUnlimitedBuffer() { + m_buffer.setUnlimited(); + } bool oom() const; void setPrinter(Sprinter* sp) { @@ -1217,8 +1220,6 @@ class AssemblerMIPSShared : public AssemblerShared { static void UpdateLuiOriValue(Instruction* inst0, Instruction* inst1, uint32_t value); - bool bailed() { return m_buffer.bail(); } - void verifyHeapAccessDisassembly(uint32_t begin, uint32_t end, const Disassembler::HeapAccess& heapAccess) { // Implement this if we implement a disassembler. diff --git a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp index ba825b1c4a8c..59acd950e873 100644 --- a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp +++ b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp @@ -191,10 +191,6 @@ bool CodeGeneratorMIPSShared::generateOutOfLineCode() { } void CodeGeneratorMIPSShared::bailoutFrom(Label* label, LSnapshot* snapshot) { - if (masm.bailed()) { - return; - } - MOZ_ASSERT_IF(!masm.oom(), label->used()); MOZ_ASSERT_IF(!masm.oom(), !label->bound()); diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index e4f7410b5a87..c8fd06874566 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -170,6 +170,10 @@ class Assembler : public AssemblerShared { const Disassembler::HeapAccess& heapAccess) { MOZ_CRASH(); } + + void setUnlimitedBuffer() { + MOZ_CRASH(); + } }; class Operand { diff --git a/js/src/jit/shared/IonAssemblerBuffer.h b/js/src/jit/shared/IonAssemblerBuffer.h index 20e734ab87d2..f098c274049c 100644 --- a/js/src/jit/shared/IonAssemblerBuffer.h +++ b/js/src/jit/shared/IonAssemblerBuffer.h @@ -141,12 +141,16 @@ class AssemblerBuffer { Slice* tail; bool m_oom; - bool m_bail; // How many bytes has been committed to the buffer thus far. // Does not include tail. uint32_t bufferSize; + // How many bytes can be in the buffer. Normally this is + // MaxCodeBytesPerBuffer, but for pasteup buffers where we handle far jumps + // explicitly it can be larger. + uint32_t maxSize; + // Finger for speeding up accesses. Slice* finger; int finger_offset; @@ -158,8 +162,8 @@ class AssemblerBuffer { : head(nullptr), tail(nullptr), m_oom(false), - m_bail(false), bufferSize(0), + maxSize(MaxCodeBytesPerBuffer), finger(nullptr), finger_offset(0), lifoAlloc_(8192) {} @@ -170,9 +174,13 @@ class AssemblerBuffer { return !(size() & (alignment - 1)); } + void setUnlimited() { + maxSize = MaxCodeBytesPerProcess; + } + private: Slice* newSlice(LifoAlloc& a) { - if (size() > MaxCodeBytesPerProcess - sizeof(Slice)) { + if (size() > maxSize - sizeof(Slice)) { fail_oom(); return nullptr; } @@ -281,15 +289,16 @@ class AssemblerBuffer { } BufferOffset nextOffset() const { return BufferOffset(size()); } - bool oom() const { return m_oom || m_bail; } - bool bail() const { return m_bail; } + bool oom() const { return m_oom; } bool fail_oom() { m_oom = true; - return false; - } - bool fail_bail() { - m_bail = true; +#ifdef DEBUG + JitContext* context = MaybeGetJitContext(); + if (context) { + context->setOOM(); + } +#endif return false; } diff --git a/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h b/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h index e391818fec64..c75332a0840f 100644 --- a/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h +++ b/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h @@ -826,7 +826,7 @@ struct AssemblerBufferWithConstantPools // check. MOZ_ASSERT_IF(numPoolEntries, !canNotPlacePool_); - if (this->oom() && !this->bail()) { + if (this->oom()) { return BufferOffset(); } diff --git a/js/src/jit/x86-shared/Assembler-x86-shared.h b/js/src/jit/x86-shared/Assembler-x86-shared.h index b9c5d3f3bc7c..24729fd8dc66 100644 --- a/js/src/jit/x86-shared/Assembler-x86-shared.h +++ b/js/src/jit/x86-shared/Assembler-x86-shared.h @@ -409,6 +409,9 @@ class AssemblerX86Shared : public AssemblerShared { #endif } + void setUnlimitedBuffer() { + // No-op on this platform + } bool oom() const { return AssemblerShared::oom() || masm.oom() || jumpRelocations_.oom() || dataRelocations_.oom(); diff --git a/js/src/jsapi-tests/testAssemblerBuffer.cpp b/js/src/jsapi-tests/testAssemblerBuffer.cpp index a6bcbb936890..4f4828c1834a 100644 --- a/js/src/jsapi-tests/testAssemblerBuffer.cpp +++ b/js/src/jsapi-tests/testAssemblerBuffer.cpp @@ -50,7 +50,6 @@ BEGIN_TEST(testAssemblerBuffer_AssemblerBuffer) { CHECK_EQUAL(ab.size(), 0u); CHECK_EQUAL(ab.nextOffset().getOffset(), 0); CHECK(!ab.oom()); - CHECK(!ab.bail()); BufferOffset off1 = ab.putInt(1000017); CHECK_EQUAL(off1.getOffset(), 0); @@ -317,7 +316,6 @@ BEGIN_TEST(testAssemblerBuffer_AssemblerBufferWithConstantPools) { CHECK_EQUAL(ab.size(), 0u); CHECK_EQUAL(ab.nextOffset().getOffset(), 0); CHECK(!ab.oom()); - CHECK(!ab.bail()); // Each slice holds 5 instructions. Trigger a constant pool inside the slice. uint32_t poolLoad[] = {0xc0cc0000}; diff --git a/js/src/vm/ArrayObject-inl.h b/js/src/vm/ArrayObject-inl.h index f4a259bf989f..c2032395ef7d 100644 --- a/js/src/vm/ArrayObject-inl.h +++ b/js/src/vm/ArrayObject-inl.h @@ -42,6 +42,8 @@ inline void ArrayObject::setLength(JSContext* cx, uint32_t length) { MOZ_ASSERT_IF(clasp->hasFinalize(), heap == gc::TenuredHeap); MOZ_ASSERT_IF(group->hasUnanalyzedPreliminaryObjects(), heap == js::gc::TenuredHeap); + MOZ_ASSERT_IF(group->shouldPreTenureDontCheckGeneration(), + heap == gc::TenuredHeap); // Arrays can use their fixed slots to store elements, so can't have shapes // which allow named properties to be stored in the fixed slots. diff --git a/js/src/vm/EnvironmentObject.cpp b/js/src/vm/EnvironmentObject.cpp index 6d3d2e4fe56c..f6f7c10c2e74 100644 --- a/js/src/vm/EnvironmentObject.cpp +++ b/js/src/vm/EnvironmentObject.cpp @@ -79,9 +79,11 @@ CallObject* CallObject::create(JSContext* cx, HandleShape shape, MOZ_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_)); kind = gc::GetBackgroundAllocKind(kind); + gc::InitialHeap heap = GetInitialHeap(GenericObject, group); + JSObject* obj; - JS_TRY_VAR_OR_RETURN_NULL( - cx, obj, NativeObject::create(cx, kind, gc::DefaultHeap, shape, group)); + JS_TRY_VAR_OR_RETURN_NULL(cx, obj, + NativeObject::create(cx, kind, heap, shape, group)); return &obj->as(); } @@ -108,6 +110,9 @@ CallObject* CallObject::createTemplateObject(JSContext* cx, HandleScript script, MOZ_ASSERT(CanBeFinalizedInBackground(kind, &class_)); kind = gc::GetBackgroundAllocKind(kind); + // The JITs assume the result is nursery allocated unless we collected the + // nursery, so don't change |heap| here. + JSObject* obj; JS_TRY_VAR_OR_RETURN_NULL(cx, obj, NativeObject::create(cx, kind, heap, shape, group)); @@ -243,6 +248,13 @@ VarEnvironmentObject* VarEnvironmentObject::create(JSContext* cx, MOZ_ASSERT(CanBeFinalizedInBackground(kind, &class_)); kind = gc::GetBackgroundAllocKind(kind); + { + AutoSweepObjectGroup sweep(group); + if (group->shouldPreTenure(sweep)) { + heap = gc::TenuredHeap; + } + } + JSObject* obj; JS_TRY_VAR_OR_RETURN_NULL(cx, obj, NativeObject::create(cx, kind, heap, shape, group)); @@ -277,9 +289,8 @@ VarEnvironmentObject* VarEnvironmentObject::create(JSContext* cx, RootedScript script(cx, frame.script()); RootedObject envChain(cx, frame.environmentChain()); - gc::InitialHeap heap = gc::DefaultHeap; RootedShape shape(cx, scope->environmentShape()); - VarEnvironmentObject* env = create(cx, shape, envChain, heap); + VarEnvironmentObject* env = create(cx, shape, envChain, gc::DefaultHeap); if (!env) { return nullptr; } @@ -887,6 +898,9 @@ LexicalEnvironmentObject* LexicalEnvironmentObject::createTemplateObject( return nullptr; } + // The JITs assume the result is nursery allocated unless we collected the + // nursery, so don't change |heap| here. + gc::AllocKind allocKind = gc::GetGCObjectKind(shape->numFixedSlots()); MOZ_ASSERT( CanBeFinalizedInBackground(allocKind, &LexicalEnvironmentObject::class_)); diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 8b5d82cac26b..78043d36f96a 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -5284,7 +5284,7 @@ ArrayObject* js::NewArrayCopyOnWriteOperation(JSContext* cx, return nullptr; } - return NewDenseCopyOnWriteArray(cx, baseobj, gc::DefaultHeap); + return NewDenseCopyOnWriteArray(cx, baseobj); } void js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber, diff --git a/js/src/vm/Iteration.cpp b/js/src/vm/Iteration.cpp index 70d0732cd30a..dfbd02ae0737 100644 --- a/js/src/vm/Iteration.cpp +++ b/js/src/vm/Iteration.cpp @@ -580,7 +580,7 @@ static PropertyIteratorObject* NewPropertyIteratorObject(JSContext* cx) { JS_TRY_VAR_OR_RETURN_NULL( cx, obj, NativeObject::create(cx, ITERATOR_FINALIZE_KIND, - GetInitialHeap(GenericObject, clasp), shape, group)); + GetInitialHeap(GenericObject, group), shape, group)); PropertyIteratorObject* res = &obj->as(); @@ -947,8 +947,7 @@ JSObject* js::CreateIterResultObject(JSContext* cx, HandleValue value, NativeObject* resultObj; JS_TRY_VAR_OR_RETURN_NULL( - cx, resultObj, - NativeObject::createWithTemplate(cx, gc::DefaultHeap, templateObject)); + cx, resultObj, NativeObject::createWithTemplate(cx, templateObject)); // Step 3. resultObj->setSlot(Realm::IterResultObjectValueSlot, value); diff --git a/js/src/vm/JSObject-inl.h b/js/src/vm/JSObject-inl.h index 0c58b6515b29..49693459b04d 100644 --- a/js/src/vm/JSObject-inl.h +++ b/js/src/vm/JSObject-inl.h @@ -375,6 +375,33 @@ inline bool IsInternalFunctionObject(JSObject& funobj) { return fun.isInterpreted() && !fun.environment(); } +inline gc::InitialHeap GetInitialHeap(NewObjectKind newKind, + const Class* clasp) { + if (newKind == NurseryAllocatedProxy) { + MOZ_ASSERT(clasp->isProxy()); + MOZ_ASSERT(clasp->hasFinalize()); + MOZ_ASSERT(!CanNurseryAllocateFinalizedClass(clasp)); + return gc::DefaultHeap; + } + if (newKind != GenericObject) { + return gc::TenuredHeap; + } + if (clasp->hasFinalize() && !CanNurseryAllocateFinalizedClass(clasp)) { + return gc::TenuredHeap; + } + return gc::DefaultHeap; +} + +inline gc::InitialHeap GetInitialHeap(NewObjectKind newKind, + ObjectGroup* group) { + AutoSweepObjectGroup sweep(group); + if (group->shouldPreTenure(sweep)) { + return gc::TenuredHeap; + } + + return GetInitialHeap(newKind, group->clasp()); +} + /* * Make an object with the specified prototype. If parent is null, it will * default to the prototype's global if the prototype is non-null. diff --git a/js/src/vm/JSObject.cpp b/js/src/vm/JSObject.cpp index 708ecb0c8b96..4db5060f547e 100644 --- a/js/src/vm/JSObject.cpp +++ b/js/src/vm/JSObject.cpp @@ -792,7 +792,7 @@ static inline JSObject* NewObject(JSContext* cx, HandleObjectGroup group, return nullptr; } - gc::InitialHeap heap = GetInitialHeap(newKind, clasp); + gc::InitialHeap heap = GetInitialHeap(newKind, group); JSObject* obj; if (clasp->isJSFunction()) { @@ -974,8 +974,8 @@ JSObject* js::NewObjectWithGroupCommon(JSContext* cx, HandleObjectGroup group, NewObjectCache& cache = cx->caches().newObjectCache; NewObjectCache::EntryIndex entry = -1; if (cache.lookupGroup(group, allocKind, &entry)) { - JSObject* obj = cache.newObjectFromHit( - cx, entry, GetInitialHeap(newKind, group->clasp())); + JSObject* obj = + cache.newObjectFromHit(cx, entry, GetInitialHeap(newKind, group)); if (obj) { return obj; } @@ -4241,6 +4241,13 @@ void JSObject::debugCheckNewObject(ObjectGroup* group, Shape* shape, MOZ_ASSERT_IF(group->hasUnanalyzedPreliminaryObjects(), heap == gc::TenuredHeap); + // Check that the group's shouldPreTenure flag is respected but ignore + // environment objects that the JIT expects to be nursery allocated. + MOZ_ASSERT_IF(group->shouldPreTenureDontCheckGeneration() && + clasp != &CallObject::class_ && + clasp != &LexicalEnvironmentObject::class_, + heap == gc::TenuredHeap); + MOZ_ASSERT(!group->realm()->hasObjectPendingMetadata()); // Non-native classes manage their own data and slots, so numFixedSlots and diff --git a/js/src/vm/JSObject.h b/js/src/vm/JSObject.h index 2f2cd432a21c..2ce7924eef58 100644 --- a/js/src/vm/JSObject.h +++ b/js/src/vm/JSObject.h @@ -798,23 +798,6 @@ using ClassInitializerOp = JSObject* (*)(JSContext* cx, namespace js { -inline gc::InitialHeap GetInitialHeap(NewObjectKind newKind, - const Class* clasp) { - if (newKind == NurseryAllocatedProxy) { - MOZ_ASSERT(clasp->isProxy()); - MOZ_ASSERT(clasp->hasFinalize()); - MOZ_ASSERT(!CanNurseryAllocateFinalizedClass(clasp)); - return gc::DefaultHeap; - } - if (newKind != GenericObject) { - return gc::TenuredHeap; - } - if (clasp->hasFinalize() && !CanNurseryAllocateFinalizedClass(clasp)) { - return gc::TenuredHeap; - } - return gc::DefaultHeap; -} - bool NewObjectWithTaggedProtoIsCachable(JSContext* cx, Handle proto, NewObjectKind newKind, diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h index 2051510df10b..3a18b75383da 100644 --- a/js/src/vm/NativeObject-inl.h +++ b/js/src/vm/NativeObject-inl.h @@ -522,9 +522,11 @@ inline bool NativeObject::isInWholeCellBuffer() const { } /* static */ inline JS::Result -NativeObject::createWithTemplate(JSContext* cx, js::gc::InitialHeap heap, - HandleObject templateObject) { +NativeObject::createWithTemplate(JSContext* cx, HandleObject templateObject) { RootedObjectGroup group(cx, templateObject->group()); + + gc::InitialHeap heap = GetInitialHeap(GenericObject, group); + RootedShape shape(cx, templateObject->as().lastProperty()); gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots()); diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index 8465d8f5192f..0225e861ac09 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -559,7 +559,7 @@ class NativeObject : public ShapedObject { js::HandleShape shape, js::HandleObjectGroup group); static inline JS::Result createWithTemplate( - JSContext* cx, js::gc::InitialHeap heap, HandleObject templateObject); + JSContext* cx, HandleObject templateObject); #ifdef DEBUG static void enableShapeConsistencyChecks(); diff --git a/js/src/vm/ObjectGroup-inl.h b/js/src/vm/ObjectGroup-inl.h index 44ce612db72c..c87bd1097707 100644 --- a/js/src/vm/ObjectGroup-inl.h +++ b/js/src/vm/ObjectGroup-inl.h @@ -54,8 +54,13 @@ inline bool ObjectGroup::unknownProperties(const AutoSweepObjectGroup& sweep) { } inline bool ObjectGroup::shouldPreTenure(const AutoSweepObjectGroup& sweep) { - return hasAnyFlags(sweep, OBJECT_FLAG_PRE_TENURE) && - !unknownProperties(sweep); + MOZ_ASSERT(sweep.group() == this); + return shouldPreTenureDontCheckGeneration(); +} + +inline bool ObjectGroup::shouldPreTenureDontCheckGeneration() { + return hasAnyFlagsDontCheckGeneration(OBJECT_FLAG_PRE_TENURE) && + !unknownPropertiesDontCheckGeneration(); } inline bool ObjectGroup::canPreTenure(const AutoSweepObjectGroup& sweep) { diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h index 4471a4a3050c..df5574361b8e 100644 --- a/js/src/vm/ObjectGroup.h +++ b/js/src/vm/ObjectGroup.h @@ -349,6 +349,10 @@ class ObjectGroup : public gc::TenuredCell { inline bool hasAllFlags(const AutoSweepObjectGroup& sweep, ObjectGroupFlags flags); + bool hasAnyFlagsDontCheckGeneration(ObjectGroupFlags flags) { + MOZ_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags); + return !!(this->flagsDontCheckGeneration() & flags); + } bool hasAllFlagsDontCheckGeneration(ObjectGroupFlags flags) { MOZ_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags); return (this->flagsDontCheckGeneration() & flags) == flags; @@ -363,6 +367,7 @@ class ObjectGroup : public gc::TenuredCell { } inline bool shouldPreTenure(const AutoSweepObjectGroup& sweep); + inline bool shouldPreTenureDontCheckGeneration(); gc::InitialHeap initialHeap(CompilerConstraintList* constraints); diff --git a/js/src/vm/ProxyObject.cpp b/js/src/vm/ProxyObject.cpp index ea147062aeff..61c8404c8ca0 100644 --- a/js/src/vm/ProxyObject.cpp +++ b/js/src/vm/ProxyObject.cpp @@ -184,7 +184,7 @@ void ProxyObject::nuke() { realm->newProxyCache.add(group, shape); } - gc::InitialHeap heap = GetInitialHeap(newKind, clasp); + gc::InitialHeap heap = GetInitialHeap(newKind, group); debugCheckNewObject(group, shape, allocKind, heap); JSObject* obj = diff --git a/js/src/wasm/WasmGenerator.cpp b/js/src/wasm/WasmGenerator.cpp index a4c21ff70a0b..30fc7415e981 100644 --- a/js/src/wasm/WasmGenerator.cpp +++ b/js/src/wasm/WasmGenerator.cpp @@ -78,7 +78,7 @@ ModuleGenerator::ModuleGenerator(const CompileArgs& args, taskState_(mutexid::WasmCompileTaskState), lifo_(GENERATOR_LIFO_DEFAULT_CHUNK_SIZE), masmAlloc_(&lifo_), - masm_(masmAlloc_), + masm_(masmAlloc_, /* limitedSize= */ false), debugTrapCodeOffset_(), lastPatchedCallSite_(0), startOfUnpatchedCallsites_(0), @@ -618,6 +618,17 @@ static bool AppendForEach(Vec* dstVec, const Vec& srcVec, Op op) { } bool ModuleGenerator::linkCompiledCode(CompiledCode& code) { + // Before merging in new code, if calls in a prior code range might go out of + // range, insert far jumps to extend the range. + + if (!InRange(startOfUnpatchedCallsites_, + masm_.size() + code.bytes.length())) { + startOfUnpatchedCallsites_ = masm_.size(); + if (!linkCallSites()) { + return false; + } + } + // All code offsets in 'code' must be incremented by their position in the // overall module when the code was appended. @@ -766,16 +777,6 @@ bool ModuleGenerator::locallyCompileCurrentTask() { bool ModuleGenerator::finishTask(CompileTask* task) { masm_.haltingAlign(CodeAlignment); - // Before merging in the new function's code, if calls in a prior code range - // might go out of range, insert far jumps to extend the range. - if (!InRange(startOfUnpatchedCallsites_, - masm_.size() + task->output.bytes.length())) { - startOfUnpatchedCallsites_ = masm_.size(); - if (!linkCallSites()) { - return false; - } - } - if (!linkCompiledCode(task->output)) { return false; } @@ -843,21 +844,6 @@ bool ModuleGenerator::compileFuncDef(uint32_t funcIndex, MOZ_ASSERT(!finishedFuncDefs_); MOZ_ASSERT(funcIndex < env_->numFuncs()); - if (!currentTask_) { - if (freeTasks_.empty() && !finishOutstandingTask()) { - return false; - } - currentTask_ = freeTasks_.popCopy(); - } - - uint32_t funcBytecodeLength = end - begin; - - FuncCompileInputVector& inputs = currentTask_->inputs; - if (!inputs.emplaceBack(funcIndex, lineOrBytecode, begin, end, - std::move(lineNums))) { - return false; - } - uint32_t threshold; switch (tier()) { case Tier::Baseline: @@ -871,9 +857,36 @@ bool ModuleGenerator::compileFuncDef(uint32_t funcIndex, break; } + uint32_t funcBytecodeLength = end - begin; + + // Do not go over the threshold if we can avoid it: spin off the compilation + // before appending the function if we would go over. (Very large single + // functions may still exceed the threshold but this is fine; it'll be very + // uncommon and is in any case safely handled by the MacroAssembler's buffer + // limit logic.) + + if (currentTask_ && currentTask_->inputs.length() && + batchedBytecode_ + funcBytecodeLength > threshold) { + if (!launchBatchCompile()) { + return false; + } + } + + if (!currentTask_) { + if (freeTasks_.empty() && !finishOutstandingTask()) { + return false; + } + currentTask_ = freeTasks_.popCopy(); + } + + if (!currentTask_->inputs.emplaceBack(funcIndex, lineOrBytecode, begin, end, + std::move(lineNums))) { + return false; + } + batchedBytecode_ += funcBytecodeLength; MOZ_ASSERT(batchedBytecode_ <= MaxCodeSectionBytes); - return batchedBytecode_ <= threshold || launchBatchCompile(); + return true; } bool ModuleGenerator::finishFuncDefs() { diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index ef410e929284..d0cdcc39c9f0 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -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 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 diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 5b660b8829a6..7b6dcabb923b 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -18,6 +18,7 @@ #include "mozilla/dom/GeneratedImageContent.h" #include "mozilla/dom/HTMLDetailsElement.h" #include "mozilla/dom/HTMLSelectElement.h" +#include "mozilla/dom/HTMLSharedListElement.h" #include "mozilla/dom/HTMLSummaryElement.h" #include "mozilla/EventStates.h" #include "mozilla/Likely.h" @@ -1705,20 +1706,20 @@ already_AddRefed 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() || @@ -1737,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 = mDocument->NodeInfoManager()->GetNodeInfo( elemName, nullptr, kNameSpaceID_None, nsINode::ELEMENT_NODE); RefPtr container; @@ -1753,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(); @@ -3222,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; @@ -3408,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), @@ -3854,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); - } } } @@ -4680,8 +4686,7 @@ void nsCSSFrameConstructor::InitAndRestoreFrame( RestoreFrameStateFor(aNewFrame, aState.mFrameState); } - if (aAllowCounters && - mCounterManager.AddCounterResetsAndIncrements(aNewFrame)) { + if (aAllowCounters && mCounterManager.AddCounterChanges(aNewFrame)) { CountersDirty(); } } @@ -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,16 @@ nsCSSFrameConstructor::FindElementTagData(const Element& aElement, ComputedStyle& aStyle, nsIFrame* aParentFrame, uint32_t aFlags) { + // A ::marker pseudo creates a nsBulletFrame, unless 'content' was set. + if (aStyle.GetPseudoType() == PseudoStyleType::marker && + aStyle.StyleContent()->ContentCount() == 0) { + 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 +5506,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; } @@ -9590,9 +9610,21 @@ inline void nsCSSFrameConstructor::ConstructFramesFromItemList( CreateNeededPseudoInternalRubyBoxes(aState, aItems, aParentFrame); CreateNeededPseudoSiblings(aState, aItems, aParentFrame); + bool listItemListIsDirty = false; for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) { NS_ASSERTION(iter.item().DesiredParentType() == GetParentType(aParentFrame), "Needed pseudos didn't get created; expect bad things"); + // display:list-item boxes affects the start value of the "list-item" counter + // when an
      element doesn't have an explicit start value. + if (!listItemListIsDirty && + iter.item().mComputedStyle->StyleList()->mMozListReversed + == StyleMozListReversed::True && + iter.item().mComputedStyle->StyleDisplay()->mDisplay == StyleDisplay::ListItem) { + auto* list = mCounterManager.CounterListFor(NS_LITERAL_STRING("list-item")); + list->SetDirty(); + CountersDirty(); + listItemListIsDirty = true; + } ConstructFramesFromItem(aState, iter, aParentFrame, aFrameItems); } @@ -9703,6 +9735,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. // @@ -9712,9 +9746,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, @@ -9758,6 +9801,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_MARKER) == isOutsideMarker); + break; + } + } + } + } + if (haveFirstLetterStyle) { WrapFramesInFirstLetterFrame(aFrame, aFrameItems); } @@ -10635,14 +10702,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; } @@ -10652,16 +10717,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(*aNewFrame); - } - - CreateBulletFrameForListItemIfNeeded(blockFrameToCreateBullet); - if (childItems.IsEmpty()) { // No more kids to process (there weren't any column-span kids). return; @@ -10694,33 +10749,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, diff --git a/layout/base/nsCSSFrameConstructor.h b/layout/base/nsCSSFrameConstructor.h index f2c49465acf0..50f83948b837 100644 --- a/layout/base/nsCSSFrameConstructor.h +++ b/layout/base/nsCSSFrameConstructor.h @@ -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; @@ -696,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. */ @@ -1799,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. // diff --git a/layout/base/nsCounterManager.cpp b/layout/base/nsCounterManager.cpp index 8520e9fe3ac9..9e53969318a2 100644 --- a/layout/base/nsCounterManager.cpp +++ b/layout/base/nsCounterManager.cpp @@ -56,7 +56,9 @@ void nsCounterUseNode::Calc(nsCounterList* aList) { // Should be called immediately after calling |Insert|. void nsCounterChangeNode::Calc(nsCounterList* aList) { NS_ASSERTION(!aList->IsDirty(), "Why are we calculating with a dirty list?"); - if (mType == RESET) { + if (IsContentBasedReset()) { + // RecalcAll takes care of this case. + } else if (mType == RESET || mType == SET) { mValueAfter = mChangeValue; } else { NS_ASSERTION(mType == INCREMENT, "invalid type"); @@ -156,8 +158,21 @@ void nsCounterList::SetScope(nsCounterNode* aNode) { void nsCounterList::RecalcAll() { mDirty = false; + // Setup the scope and calculate the default start value for
        . for (nsCounterNode* node = First(); node; node = Next(node)) { SetScope(node); + if (node->IsContentBasedReset()) { + node->mValueAfter = 1; + } else if ((node->mType == nsCounterChangeNode::INCREMENT || + node->mType == nsCounterChangeNode::SET) && + node->mScopeStart && + node->mScopeStart->IsContentBasedReset()) { + ++node->mScopeStart->mValueAfter; + } + } + + for (nsCounterNode* node = First(); node; node = Next(node)) { + auto oldValue = node->mValueAfter; node->Calc(this); if (node->mType == nsCounterNode::USE) { @@ -171,13 +186,22 @@ void nsCounterList::RecalcAll() { useNode->mText->SetData(text, IgnoreErrors()); } } + + if (oldValue != node->mValueAfter && node->mPseudoFrame && + node->mPseudoFrame->StyleDisplay()->mDisplay == StyleDisplay::ListItem) { + auto* shell = node->mPseudoFrame->PresShell(); + shell->FrameNeedsReflow(node->mPseudoFrame, + nsIPresShell::eStyleChange, + NS_FRAME_IS_DIRTY); + } } } -bool nsCounterManager::AddCounterResetsAndIncrements(nsIFrame* aFrame) { +bool nsCounterManager::AddCounterChanges(nsIFrame* aFrame) { const nsStyleContent* styleContent = aFrame->StyleContent(); if (!styleContent->CounterIncrementCount() && - !styleContent->CounterResetCount()) { + !styleContent->CounterResetCount() && + !styleContent->CounterSetCount()) { MOZ_ASSERT(!aFrame->HasAnyStateBits(NS_FRAME_HAS_CSS_COUNTER_STYLE)); return false; } @@ -189,17 +213,21 @@ bool nsCounterManager::AddCounterResetsAndIncrements(nsIFrame* aFrame) { int32_t i, i_end; bool dirty = false; for (i = 0, i_end = styleContent->CounterResetCount(); i != i_end; ++i) { - dirty |= AddResetOrIncrement(aFrame, i, styleContent->CounterResetAt(i), - nsCounterChangeNode::RESET); + dirty |= AddCounterChangeNode(aFrame, i, styleContent->CounterResetAt(i), + nsCounterChangeNode::RESET); + } + for (i = 0, i_end = styleContent->CounterSetCount(); i != i_end; ++i) { + dirty |= AddCounterChangeNode(aFrame, i, styleContent->CounterSetAt(i), + nsCounterChangeNode::SET); } for (i = 0, i_end = styleContent->CounterIncrementCount(); i != i_end; ++i) { - dirty |= AddResetOrIncrement(aFrame, i, styleContent->CounterIncrementAt(i), - nsCounterChangeNode::INCREMENT); + dirty |= AddCounterChangeNode(aFrame, i, styleContent->CounterIncrementAt(i), + nsCounterChangeNode::INCREMENT); } return dirty; } -bool nsCounterManager::AddResetOrIncrement( +bool nsCounterManager::AddCounterChangeNode( nsIFrame* aFrame, int32_t aIndex, const nsStyleCounterData& aCounterData, nsCounterNode::Type aType) { nsCounterChangeNode* node = @@ -266,7 +294,7 @@ void nsCounterManager::Dump() { nsCounterList* list = iter.UserData(); int32_t i = 0; for (nsCounterNode* node = list->First(); node; node = list->Next(node)) { - const char* types[] = {"RESET", "INCREMENT", "USE"}; + const char* types[] = {"RESET", "SET", "INCREMENT", "USE"}; printf( " Node #%d @%p frame=%p index=%d type=%s valAfter=%d\n" " scope-start=%p scope-prev=%p", diff --git a/layout/base/nsCounterManager.h b/layout/base/nsCounterManager.h index 38038d0c3198..aa808fc82ef1 100644 --- a/layout/base/nsCounterManager.h +++ b/layout/base/nsCounterManager.h @@ -22,6 +22,7 @@ struct nsCounterChangeNode; struct nsCounterNode : public nsGenConNode { enum Type { RESET, // a "counter number" pair in 'counter-reset' + SET, // a "counter number" pair in 'counter-set' INCREMENT, // a "counter number" pair in 'counter-increment' USE // counter() or counters() in 'content' }; @@ -56,12 +57,12 @@ struct nsCounterNode : public nsGenConNode { inline nsCounterUseNode* UseNode(); inline nsCounterChangeNode* ChangeNode(); - // For RESET and INCREMENT nodes, aPseudoFrame need not be a + // For RESET, SET and INCREMENT nodes, aPseudoFrame need not be a // pseudo-element, and aContentIndex represents the index within the - // 'counter-reset' or 'counter-increment' property instead of within - // the 'content' property but offset to ensure that (reset, - // increment, use) sort in that order. (This slight weirdness - // allows sharing a lot of code with 'quotes'.) + // 'counter-reset', 'counter-set' or 'counter-increment' property + // instead of within the 'content' property but offset to ensure + // that (reset, set, increment, use) sort in that order. + // (This slight weirdness allows sharing a lot of code with 'quotes'.) nsCounterNode(int32_t aContentIndex, Type aType) : nsGenConNode(aContentIndex), mType(aType), @@ -71,6 +72,9 @@ struct nsCounterNode : public nsGenConNode { // to avoid virtual function calls in the common case inline void Calc(nsCounterList* aList); + + // Is this a
          RESET node? + inline bool IsContentBasedReset(); }; struct nsCounterUseNode : public nsCounterNode { @@ -102,24 +106,27 @@ struct nsCounterUseNode : public nsCounterNode { }; struct nsCounterChangeNode : public nsCounterNode { - int32_t mChangeValue; // the numeric value of the increment or reset + int32_t mChangeValue; // the numeric value of the increment, set or reset // |aPseudoFrame| is not necessarily a pseudo-element's frame, but // since it is for every other subclass of nsGenConNode, we follow // the naming convention here. // |aPropIndex| is the index of the value within the list in the - // 'counter-increment' or 'counter-reset' property. + // 'counter-increment', 'counter-set' or 'counter-reset' property. nsCounterChangeNode(nsIFrame* aPseudoFrame, nsCounterNode::Type aChangeType, int32_t aChangeValue, int32_t aPropIndex) - : nsCounterNode( // Fake a content index for resets and increments + : nsCounterNode( // Fake a content index for resets, sets and increments // that comes before all the real content, with - // the resets first, in order, and then the increments. - aPropIndex + (aChangeType == RESET ? (INT32_MIN) : (INT32_MIN / 2)), + // the resets first, in order, and then the sets and + // then the increments. + aPropIndex + (aChangeType == RESET ? (INT32_MIN) : + (aChangeType == SET ? ((INT32_MIN / 3) * 2) : INT32_MIN / 3)), aChangeType), mChangeValue(aChangeValue) { NS_ASSERTION(aPropIndex >= 0, "out of range"); - NS_ASSERTION(aChangeType == INCREMENT || aChangeType == RESET, "bad type"); + NS_ASSERTION(aChangeType == INCREMENT || aChangeType == SET + || aChangeType == RESET, "bad type"); mPseudoFrame = aPseudoFrame; CheckFrameAssertions(); } @@ -135,7 +142,7 @@ inline nsCounterUseNode* nsCounterNode::UseNode() { } inline nsCounterChangeNode* nsCounterNode::ChangeNode() { - NS_ASSERTION(mType == INCREMENT || mType == RESET, "wrong type"); + MOZ_ASSERT(mType == INCREMENT || mType == SET || mType == RESET); return static_cast(this); } @@ -146,6 +153,11 @@ inline void nsCounterNode::Calc(nsCounterList* aList) { ChangeNode()->Calc(aList); } +inline bool nsCounterNode::IsContentBasedReset() { + return mType == RESET && + ChangeNode()->mChangeValue == std::numeric_limits::min(); +} + class nsCounterList : public nsGenConList { public: nsCounterList() : nsGenConList(), mDirty(false) {} @@ -195,7 +207,7 @@ class nsCounterList : public nsGenConList { class nsCounterManager { public: // Returns true if dirty - bool AddCounterResetsAndIncrements(nsIFrame* aFrame); + bool AddCounterChanges(nsIFrame* aFrame); // Gets the appropriate counter list, creating it if necessary. // Guaranteed to return non-null. (Uses an infallible hashtable API.) @@ -242,10 +254,10 @@ class nsCounterManager { } private: - // for |AddCounterResetsAndIncrements| only - bool AddResetOrIncrement(nsIFrame* aFrame, int32_t aIndex, - const nsStyleCounterData& aCounterData, - nsCounterNode::Type aType); + // for |AddCounterChanges| only + bool AddCounterChangeNode(nsIFrame* aFrame, int32_t aIndex, + const nsStyleCounterData& aCounterData, + nsCounterNode::Type aType); nsClassHashtable mNames; }; diff --git a/layout/base/nsGenConList.cpp b/layout/base/nsGenConList.cpp index f499ccbfd2b1..b352fc57f372 100644 --- a/layout/base/nsGenConList.cpp +++ b/layout/base/nsGenConList.cpp @@ -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; } } diff --git a/layout/base/nsGenConList.h b/layout/base/nsGenConList.h index a07da4c553f5..5c7a011e9076 100644 --- a/layout/base/nsGenConList.h +++ b/layout/base/nsGenConList.h @@ -71,8 +71,10 @@ struct nsGenConNode : public mozilla::LinkedListElement { 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"); diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 7a4b5cb7ba52..7a3a93866c1c 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -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& 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"); diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index c8bb57becb96..0a291aadf9c4 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -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. diff --git a/layout/generic/DetailsFrame.cpp b/layout/generic/DetailsFrame.cpp index 4c49d28aa66c..9e9a6709e6ae 100644 --- a/layout/generic/DetailsFrame.cpp +++ b/layout/generic/DetailsFrame.cpp @@ -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
          itself. - if (child->IsPrimaryFrame()) { + if (!child->IsGeneratedContentFrame()) { return aSummaryFrame == child; } } diff --git a/layout/generic/ReflowInput.cpp b/layout/generic/ReflowInput.cpp index f2d1d5541597..0e0762c0a2eb 100644 --- a/layout/generic/ReflowInput.cpp +++ b/layout/generic/ReflowInput.cpp @@ -131,7 +131,7 @@ static nscoord FontSizeInflationListMarginAdjustment(const nsIFrame* aFrame) { // We only want to adjust the margins if we're dealing with an ordered list. const nsBlockFrame* blockFrame = static_cast(aFrame); - if (!blockFrame->HasBullet()) { + if (!blockFrame->HasMarker()) { return 0; } @@ -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); } } diff --git a/layout/generic/crashtests/1001233.html b/layout/generic/crashtests/1001233.html index ef592212227c..aa877b542034 100644 --- a/layout/generic/crashtests/1001233.html +++ b/layout/generic/crashtests/1001233.html @@ -3,7 +3,7 @@ diff --git a/layout/generic/crashtests/769120.html b/layout/generic/crashtests/769120.html index ddbeaf941048..980ef875303c 100644 --- a/layout/generic/crashtests/769120.html +++ b/layout/generic/crashtests/769120.html @@ -1,5 +1,5 @@ >> >> diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 41ed952f2f89..c93c85f72242 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -275,8 +275,8 @@ NS_DECLARE_FRAME_PROPERTY_WITH_DTOR_NEVER_CALLED(OverflowLinesProperty, nsBlockFrame::FrameLines) NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OverflowOutOfFlowsProperty) NS_DECLARE_FRAME_PROPERTY_FRAMELIST(PushedFloatProperty) -NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OutsideBulletProperty) -NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(InsideBulletProperty, nsBulletFrame) +NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OutsideMarkerProperty) +NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(InsideMarkerProperty, nsIFrame) NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BlockEndEdgeOfChildrenProperty, nscoord) //---------------------------------------------------------------------- @@ -346,10 +346,10 @@ void nsBlockFrame::DestroyFrom(nsIFrame* aDestructRoot, RemoveStateBits(NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS); } - if (HasOutsideBullet()) { + if (HasOutsideMarker()) { SafelyDestroyFrameListProp(aDestructRoot, aPostDestroyData, shell, - OutsideBulletProperty()); - RemoveStateBits(NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET); + OutsideMarkerProperty()); + RemoveStateBits(NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER); } nsContainerFrame::DestroyFrom(aDestructRoot, aPostDestroyData); @@ -546,7 +546,7 @@ const nsFrameList& nsBlockFrame::GetChildList(ChildListID aListID) const { return list ? *list : nsFrameList::EmptyList(); } case kBulletList: { - const nsFrameList* list = GetOutsideBulletList(); + const nsFrameList* list = GetOutsideMarkerList(); return list ? *list : nsFrameList::EmptyList(); } default: @@ -565,7 +565,7 @@ void nsBlockFrame::GetChildLists(nsTArray* aLists) const { list->AppendIfNonempty(aLists, kOverflowOutOfFlowList); } mFloats.AppendIfNonempty(aLists, kFloatList); - list = GetOutsideBulletList(); + list = GetOutsideMarkerList(); if (list) { list->AppendIfNonempty(aLists, kBulletList); } @@ -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(FirstContinuation())->ResolveBidi(); - if (RenumberList()) { - AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); - } - // Handle paginated overflow (see nsContainerFrame.h) nsOverflowAreas ocBounds; nsReflowStatus ocStatus; @@ -1253,23 +1243,22 @@ 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. // - // There are exactly two places a bullet can be placed: near the + // There are exactly two places a ::marker can be placed: near the // first or second line. It's only placed on the second line in a // rare case: an empty first line followed by a second line that // contains a block (example:
        1. \n

          ... ). This is where // the second case can happen. - if (HasOutsideBullet() && !mLines.empty() && + if (HasOutsideMarker() && !mLines.empty() && (mLines.front()->IsBlock() || (0 == mLines.front()->BSize() && mLines.front() != mLines.back() && mLines.begin().next()->IsBlock()))) { - // Reflow the bullet + // Reflow the ::marker's frame. ReflowOutput reflowOutput(aReflowInput); // XXX Use the entire line when we fix bug 25888. nsLayoutUtils::LinePosition position; @@ -1279,24 +1268,24 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics, nscoord lineBStart = havePosition ? position.mBStart : reflowInput->ComputedLogicalBorderPadding().BStart(wm); - nsIFrame* bullet = GetOutsideBullet(); - ReflowBullet(bullet, state, reflowOutput, lineBStart); - NS_ASSERTION(!BulletIsEmpty() || reflowOutput.BSize(wm) == 0, - "empty bullet took up space"); + nsIFrame* marker = GetOutsideMarker(); + ReflowOutsideMarker(marker, state, reflowOutput, lineBStart); + NS_ASSERTION(!MarkerIsEmpty() || reflowOutput.BSize(wm) == 0, + "empty ::marker frame took up space"); - if (havePosition && !BulletIsEmpty()) { - // We have some lines to align the bullet with. + if (havePosition && !MarkerIsEmpty()) { + // We have some lines to align the ::marker with. // Doing the alignment using the baseline will also cater for - // bullets that are placed next to a child block (bug 92896) + // ::markers that are placed next to a child block (bug 92896) - // Tall bullets won't look particularly nice here... + // Tall ::markers won't look particularly nice here... LogicalRect bbox = - bullet->GetLogicalRect(wm, reflowOutput.PhysicalSize()); + marker->GetLogicalRect(wm, reflowOutput.PhysicalSize()); bbox.BStart(wm) = position.mBaseline - reflowOutput.BlockStartAscent(); - bullet->SetRect(wm, bbox, reflowOutput.PhysicalSize()); + marker->SetRect(wm, bbox, reflowOutput.PhysicalSize()); } - // Otherwise just leave the bullet where it is, up against our + // Otherwise just leave the ::marker where it is, up against our // block-start padding. } @@ -1330,10 +1319,10 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics, nsPoint physicalDelta(deltaX, 0); f->MovePositionBy(physicalDelta); } - nsFrameList* bulletList = GetOutsideBulletList(); - if (bulletList) { + nsFrameList* markerList = GetOutsideMarkerList(); + if (markerList) { nsPoint physicalDelta(deltaX, 0); - for (nsIFrame* f : *bulletList) { + for (nsIFrame* f : *markerList) { f->MovePositionBy(physicalDelta); } } @@ -1777,14 +1766,13 @@ void nsBlockFrame::ComputeOverflowAreas(const nsRect& aBounds, } } - // Factor an outside bullet in; normally the bullet will be factored into - // the line-box's overflow areas. However, if the line is a block + // Factor an outside ::marker in; normally the ::marker will be factored + // into the line-box's overflow areas. However, if the line is a block // line then it won't; if there are no lines, it won't. So just // factor it in anyway (it can't hurt if it was already done). // XXXldb Can we just fix GetOverflowArea instead? - nsIFrame* outsideBullet = GetOutsideBullet(); - if (outsideBullet) { - areas.UnionAllWith(outsideBullet->GetRect()); + if (nsIFrame* outsideMarker = GetOutsideMarker()) { + areas.UnionAllWith(outsideMarker->GetRect()); } ConsiderBlockEndEdgeOfChildren(GetWritingMode(), aBEndEdgeOfChildren, areas, @@ -2672,23 +2660,23 @@ void nsBlockFrame::ReflowDirtyLines(BlockReflowInput& aState) { } // Handle an odd-ball case: a list-item with no lines - if (HasOutsideBullet() && mLines.empty()) { + if (HasOutsideMarker() && mLines.empty()) { ReflowOutput metrics(aState.mReflowInput); - nsIFrame* bullet = GetOutsideBullet(); + nsIFrame* marker = GetOutsideMarker(); WritingMode wm = aState.mReflowInput.GetWritingMode(); - ReflowBullet(bullet, aState, metrics, - aState.mReflowInput.ComputedPhysicalBorderPadding().top); - NS_ASSERTION(!BulletIsEmpty() || metrics.BSize(wm) == 0, - "empty bullet took up space"); + ReflowOutsideMarker(marker, aState, metrics, + aState.mReflowInput.ComputedPhysicalBorderPadding().top); + NS_ASSERTION(!MarkerIsEmpty() || metrics.BSize(wm) == 0, + "empty ::marker frame took up space"); - if (!BulletIsEmpty()) { + if (!MarkerIsEmpty()) { // There are no lines so we have to fake up some y motion so that // we end up with *some* height. if (metrics.BlockStartAscent() == ReflowOutput::ASK_FOR_BASELINE) { nscoord ascent; WritingMode wm = aState.mReflowInput.GetWritingMode(); - if (nsLayoutUtils::GetFirstLineBaseline(wm, bullet, &ascent)) { + if (nsLayoutUtils::GetFirstLineBaseline(wm, marker, &ascent)) { metrics.SetBlockStartAscent(ascent); } else { metrics.SetBlockStartAscent(metrics.BSize(wm)); @@ -2708,7 +2696,7 @@ void nsBlockFrame::ReflowDirtyLines(BlockReflowInput& aState) { nscoord offset = minAscent - metrics.BlockStartAscent(); if (offset > 0) { - bullet->SetRect(bullet->GetRect() + nsPoint(0, offset)); + marker->SetRect(marker->GetRect() + nsPoint(0, offset)); } } } @@ -2982,42 +2970,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 @@ -3071,7 +3023,7 @@ bool nsBlockFrame::IsSelfEmpty() { return false; } - if (HasOutsideBullet() && !BulletIsEmpty()) { + if (HasOutsideMarker() && !MarkerIsEmpty()) { return false; } @@ -4410,23 +4362,23 @@ bool nsBlockFrame::PlaceLine(BlockReflowInput& aState, // participates in the height calculation of the list-item box's // first line box. // - // There are exactly two places a bullet can be placed: near the + // There are exactly two places a ::marker can be placed: near the // first or second line. It's only placed on the second line in a // rare case: when the first line is empty. WritingMode wm = aState.mReflowInput.GetWritingMode(); - bool addedBullet = false; - if (HasOutsideBullet() && + bool addedMarker = false; + if (HasOutsideMarker() && ((aLine == mLines.front() && (!aLineLayout.IsZeroBSize() || (aLine == mLines.back()))) || (mLines.front() != mLines.back() && 0 == mLines.front()->BSize() && aLine == mLines.begin().next()))) { ReflowOutput metrics(aState.mReflowInput); - nsBulletFrame* bullet = GetOutsideBullet(); - ReflowBullet(bullet, aState, metrics, aState.mBCoord); - NS_ASSERTION(!BulletIsEmpty() || metrics.BSize(wm) == 0, - "empty bullet took up space"); - aLineLayout.AddBulletFrame(bullet, metrics); - addedBullet = true; + nsIFrame* marker = GetOutsideMarker(); + ReflowOutsideMarker(marker, aState, metrics, aState.mBCoord); + NS_ASSERTION(!MarkerIsEmpty() || metrics.BSize(wm) == 0, + "empty ::marker frame took up space"); + aLineLayout.AddMarkerFrame(marker, metrics); + addedMarker = true; } aLineLayout.VerticalAlignLine(); @@ -4537,8 +4489,8 @@ bool nsBlockFrame::PlaceLine(BlockReflowInput& aState, nsOverflowAreas overflowAreas; aLineLayout.RelativePositionFrames(overflowAreas); aLine->SetOverflowAreas(overflowAreas); - if (addedBullet) { - aLineLayout.RemoveBulletFrame(GetOutsideBullet()); + if (addedMarker) { + aLineLayout.RemoveMarkerFrame(GetOutsideMarker()); } // Inline lines do not have margins themselves; however they are @@ -5001,30 +4953,28 @@ void nsBlockFrame::SetOverflowOutOfFlows(const nsFrameList& aList, } } -nsBulletFrame* nsBlockFrame::GetInsideBullet() const { - if (!HasInsideBullet()) { +nsIFrame* nsBlockFrame::GetInsideMarker() const { + if (!HasInsideMarker()) { return nullptr; } - NS_ASSERTION(!HasOutsideBullet(), "invalid bullet state"); - nsBulletFrame* frame = GetProperty(InsideBulletProperty()); - NS_ASSERTION(frame && frame->IsBulletFrame(), "bogus inside bullet frame"); + NS_ASSERTION(!HasOutsideMarker(), "invalid marker state"); + nsIFrame* frame = GetProperty(InsideMarkerProperty()); + NS_ASSERTION(frame, "bogus inside ::marker frame"); return frame; } -nsBulletFrame* nsBlockFrame::GetOutsideBullet() const { - nsFrameList* list = GetOutsideBulletList(); - return list ? static_cast(list->FirstChild()) : nullptr; +nsIFrame* nsBlockFrame::GetOutsideMarker() const { + nsFrameList* list = GetOutsideMarkerList(); + return list ? list->FirstChild() : nullptr; } -nsFrameList* nsBlockFrame::GetOutsideBulletList() const { - if (!HasOutsideBullet()) { +nsFrameList* nsBlockFrame::GetOutsideMarkerList() const { + if (!HasOutsideMarker()) { return nullptr; } - NS_ASSERTION(!HasInsideBullet(), "invalid bullet state"); - nsFrameList* list = GetProperty(OutsideBulletProperty()); - NS_ASSERTION( - list && list->GetLength() == 1 && list->FirstChild()->IsBulletFrame(), - "bogus outside bullet list"); + NS_ASSERTION(!HasInsideMarker(), "invalid marker state"); + nsFrameList* list = GetProperty(OutsideMarkerProperty()); + NS_ASSERTION(list && list->GetLength() == 1, "bogus outside ::marker list"); return list; } @@ -5205,12 +5155,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; @@ -6541,10 +6485,9 @@ void nsBlockFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, aLists.Content()->AppendToTop(&textOverflow->GetMarkers()); } - if (HasOutsideBullet()) { - // Display outside bullets manually - nsIFrame* bullet = GetOutsideBullet(); - BuildDisplayListForChild(aBuilder, bullet, aLists); + if (HasOutsideMarker()) { + // Display outside ::marker manually. + BuildDisplayListForChild(aBuilder, GetOutsideMarker(), aLists); } #ifdef DEBUG @@ -6581,7 +6524,7 @@ a11y::AccType nsBlockFrame::AccessibleType() { return a11y::eHTMLHRType; } - if (!HasBullet() || !PresContext()) { + if (!HasMarker() || !PresContext()) { // XXXsmaug What if we're in the shadow dom? if (!mContent->GetParent()) { // Don't create accessible objects for the root content node, they are @@ -6596,11 +6539,11 @@ a11y::AccType nsBlockFrame::AccessibleType() { return a11y::eNoType; } - // Not a bullet, treat as normal HTML container + // Not a list item with a ::marker, treat as normal HTML container. return a11y::eHyperTextType; } - // Create special list bullet accessible + // Create special list item accessible since we have a ::marker. return a11y::eHTMLLiType; } #endif @@ -6656,21 +6599,21 @@ void nsBlockFrame::ChildIsDirty(nsIFrame* aChild) { if (aChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW && aChild->IsAbsolutelyPositioned()) { // do nothing - } else if (aChild == GetOutsideBullet()) { - // The bullet lives in the first line, unless the first line has + } else if (aChild == GetOutsideMarker()) { + // The ::marker lives in the first line, unless the first line has // height 0 and there is a second line, in which case it lives // in the second line. - LineIterator bulletLine = LinesBegin(); - if (bulletLine != LinesEnd() && bulletLine->BSize() == 0 && - bulletLine != mLines.back()) { - bulletLine = bulletLine.next(); + LineIterator markerLine = LinesBegin(); + if (markerLine != LinesEnd() && markerLine->BSize() == 0 && + markerLine != mLines.back()) { + markerLine = markerLine.next(); } - if (bulletLine != LinesEnd()) { - MarkLineDirty(bulletLine, &mLines); + if (markerLine != LinesEnd()) { + MarkLineDirty(markerLine, &mLines); } // otherwise we have an empty line list, and ReflowDirtyLines - // will handle reflowing the bullet. + // will handle reflowing the ::marker. } else { // Note that we should go through our children to mark lines dirty // before the next reflow. Doing it now could make things O(N^2) @@ -6793,121 +6736,70 @@ void nsBlockFrame::SetInitialChildList(ChildListID aListID, } } -void nsBlockFrame::CreateBulletFrameForListItem() { - MOZ_ASSERT((GetStateBits() & (NS_BLOCK_FRAME_HAS_INSIDE_BULLET | - NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET)) == 0, - "How can we have a bullet already?"); +void nsBlockFrame::SetMarkerFrameForListItem(nsIFrame* aMarkerFrame) { + MOZ_ASSERT(aMarkerFrame); + MOZ_ASSERT((GetStateBits() & (NS_BLOCK_FRAME_HAS_INSIDE_MARKER | + NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER)) == 0, + "How can we have a ::marker frame 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 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); - SetProperty(InsideBulletProperty(), bullet); - AddStateBits(NS_BLOCK_FRAME_HAS_INSIDE_BULLET); + if (StyleList()->mListStylePosition == NS_STYLE_LIST_STYLE_POSITION_INSIDE) { + SetProperty(InsideMarkerProperty(), aMarkerFrame); + AddStateBits(NS_BLOCK_FRAME_HAS_INSIDE_MARKER); } else { - nsFrameList* bulletList = new (shell) nsFrameList(bullet, bullet); - SetProperty(OutsideBulletProperty(), bulletList); - AddStateBits(NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET); + SetProperty(OutsideMarkerProperty(), + new (PresShell()) nsFrameList(aMarkerFrame, aMarkerFrame)); + AddStateBits(NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER); } } -bool nsBlockFrame::BulletIsEmpty() const { +bool nsBlockFrame::MarkerIsEmpty() const { NS_ASSERTION(mContent->GetPrimaryFrame()->StyleDisplay()->mDisplay == mozilla::StyleDisplay::ListItem && - HasOutsideBullet(), - "should only care when we have an outside bullet"); - const nsStyleList* list = StyleList(); - return list->mCounterStyle.IsNone() && !list->GetListStyleImage(); + HasOutsideMarker(), + "should only care when we have an outside ::marker"); + nsIFrame* marker = GetMarker(); + const nsStyleList* list = marker->StyleList(); + return list->mCounterStyle.IsNone() && !list->GetListStyleImage() && + marker->StyleContent()->ContentCount() == 0; } -void nsBlockFrame::GetSpokenBulletText(nsAString& aText) const { +void nsBlockFrame::GetSpokenMarkerText(nsAString& aText) const { const nsStyleList* myList = StyleList(); if (myList->GetListStyleImage()) { aText.Assign(kDiscCharacter); aText.Append(' '); } else { - nsBulletFrame* bullet = GetBullet(); - if (bullet) { - bullet->GetSpokenText(aText); + if (nsIFrame* marker = GetMarker()) { + if (nsBulletFrame* bullet = do_QueryFrame(marker)) { + bullet->GetSpokenText(aText); + } else { + ErrorResult err; + marker->GetContent()->GetTextContent(aText, err); + if (err.Failed()) { + aText.Truncate(); + } + } } else { aText.Truncate(); } } } -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) { +void nsBlockFrame::ReflowOutsideMarker(nsIFrame* aMarkerFrame, + BlockReflowInput& aState, + ReflowOutput& aMetrics, nscoord aLineTop) { const ReflowInput& ri = aState.mReflowInput; - // Reflow the bullet now - WritingMode bulletWM = aBulletFrame->GetWritingMode(); - LogicalSize availSize(bulletWM); + WritingMode markerWM = aMarkerFrame->GetWritingMode(); + LogicalSize availSize(markerWM); // Make up an inline-size since it doesn't really matter (XXX). - availSize.ISize(bulletWM) = aState.ContentISize(); - availSize.BSize(bulletWM) = NS_UNCONSTRAINEDSIZE; + availSize.ISize(markerWM) = aState.ContentISize(); + availSize.BSize(markerWM) = 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, aMarkerFrame, availSize, + nullptr, ReflowInput::COMPUTE_SIZE_SHRINK_WRAP); nsReflowStatus status; - aBulletFrame->Reflow(aState.mPresContext, aMetrics, reflowInput, status); + aMarkerFrame->Reflow(aState.mPresContext, aMetrics, reflowInput, status); // Get the float available space using our saved state from before we // started reflowing the block, so that we ignore any floats inside @@ -6922,36 +6814,36 @@ void nsBlockFrame::ReflowBullet(nsIFrame* aBulletFrame, // FIXME (bug 25888): need to check the entire region that the first // line overlaps, not just the top pixel. - // Place the bullet now. We want to place the bullet relative to the + // Place the ::marker now. We want to place the ::marker relative to the // border-box of the associated block (using the right/left margin of - // the bullet frame as separation). However, if a line box would be + // the ::marker frame as separation). However, if a line box would be // displaced by floats that are *outside* the associated block, we // want to displace it by the same amount. That is, we act as though // the edge of the floats is the content-edge of the block, and place - // the bullet at a position offset from there by the block's padding, - // the block's border, and the bullet frame's margin. + // the ::marker at a position offset from there by the block's padding, + // the block's border, and the ::marker frame's margin. // IStart from floatAvailSpace gives us the content/float start edge // in the current writing mode. Then we subtract out the start - // border/padding and the bullet's width and margin to offset the position. + // border/padding and the ::marker's width and margin to offset the position. WritingMode wm = ri.GetWritingMode(); - // Get the bullet's margin, converted to our writing mode so that we can + // Get the ::marker's margin, converted to our writing mode so that we can // combine it with other logical values here. - LogicalMargin bulletMargin = - reflowInput.ComputedLogicalMargin().ConvertTo(wm, bulletWM); + LogicalMargin markerMargin = + reflowInput.ComputedLogicalMargin().ConvertTo(wm, markerWM); nscoord iStart = floatAvailSpace.IStart(wm) - ri.ComputedLogicalBorderPadding().IStart(wm) - - bulletMargin.IEnd(wm) - aMetrics.ISize(wm); + markerMargin.IEnd(wm) - aMetrics.ISize(wm); - // Approximate the bullets position; vertical alignment will provide + // Approximate the ::marker's position; vertical alignment will provide // the final vertical location. We pass our writing-mode here, because - // it may be different from the bullet frame's mode. + // it may be different from the ::marker frame's mode. nscoord bStart = floatAvailSpace.BStart(wm); - aBulletFrame->SetRect( + aMarkerFrame->SetRect( wm, LogicalRect(wm, iStart, bStart, aMetrics.ISize(wm), aMetrics.BSize(wm)), aState.ContainerSize()); - aBulletFrame->DidReflow(aState.mPresContext, &aState.mReflowInput); + aMarkerFrame->DidReflow(aState.mPresContext, &aState.mReflowInput); } // This is used to scan frames for any float placeholders, add their @@ -7217,13 +7109,6 @@ void nsBlockFrame::UpdatePseudoElementStyles(ServoRestyleState& aRestyleState) { UpdateFirstLetterStyle(aRestyleState); } - if (nsBulletFrame* bullet = GetBullet()) { - PseudoStyleType type = bullet->Style()->GetPseudoType(); - RefPtr newBulletStyle = - ResolveBulletStyle(type, &aRestyleState.StyleSet()); - UpdateStyleOfOwnedChildFrame(bullet, newBulletStyle, aRestyleState); - } - if (nsIFrame* firstLineFrame = GetFirstLineFrame()) { nsIFrame* styleParent = CorrectStyleParentFrame(firstLineFrame->GetParent(), PseudoStyleType::firstLine); @@ -7253,13 +7138,6 @@ void nsBlockFrame::UpdatePseudoElementStyles(ServoRestyleState& aRestyleState) { } } -already_AddRefed 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. @@ -7270,16 +7148,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; } diff --git a/layout/generic/nsBlockFrame.h b/layout/generic/nsBlockFrame.h index b6a734b54133..91aa3e0c3a1a 100644 --- a/layout/generic/nsBlockFrame.h +++ b/layout/generic/nsBlockFrame.h @@ -42,7 +42,6 @@ enum class LineReflowStatus { }; class nsBlockInFlowLineIterator; -class nsBulletFrame; namespace mozilla { class BlockReflowInput; class ServoRestyleState; @@ -230,41 +229,41 @@ class nsBlockFrame : public nsContainerFrame { bool CachedIsEmpty() override; bool IsSelfEmpty() override; - // Given that we have a bullet, does it actually draw something, i.e., + // Given that we have a ::marker frame, does it actually draw something, i.e., // do we have either a 'list-style-type' or 'list-style-image' that is - // not 'none'? - bool BulletIsEmpty() const; + // not 'none', and no 'content'? + bool MarkerIsEmpty() const; /** - * Return the bullet text equivalent. + * Return the ::marker text equivalent. */ - void GetSpokenBulletText(nsAString& aText) const; + void GetSpokenMarkerText(nsAString& aText) const; /** - * Return true if there's a bullet. + * Return true if this frame has a ::marker frame. */ - bool HasBullet() const { return HasOutsideBullet() || HasInsideBullet(); } + bool HasMarker() const { return HasOutsideMarker() || HasInsideMarker(); } /** - * @return true if this frame has an inside bullet frame. + * @return true if this frame has an inside ::marker frame. */ - bool HasInsideBullet() const { - return 0 != (mState & NS_BLOCK_FRAME_HAS_INSIDE_BULLET); + bool HasInsideMarker() const { + return 0 != (mState & NS_BLOCK_FRAME_HAS_INSIDE_MARKER); } /** - * @return true if this frame has an outside bullet frame. + * @return true if this frame has an outside ::marker frame. */ - bool HasOutsideBullet() const { - return 0 != (mState & NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET); + bool HasOutsideMarker() const { + return 0 != (mState & NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER); } /** - * @return the bullet frame or nullptr if we don't have one. + * @return the ::marker frame or nullptr if we don't have one. */ - nsBulletFrame* GetBullet() const { - nsBulletFrame* outside = GetOutsideBullet(); - return outside ? outside : GetInsideBullet(); + nsIFrame* GetMarker() const { + nsIFrame* outside = GetOutsideMarker(); + return outside ? outside : GetInsideMarker(); } /** @@ -317,9 +316,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 @@ -399,7 +395,7 @@ class nsBlockFrame : public nsContainerFrame { }; /** - * Update the styles of our various pseudo-elements (bullets, first-line, + * Update the styles of our various pseudo-elements (marker, first-line, * etc, but _not_ first-letter). */ void UpdatePseudoElementStyles(mozilla::ServoRestyleState& aRestyleState); @@ -504,9 +500,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 @@ -577,10 +573,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; @@ -827,8 +819,8 @@ class nsBlockFrame : public nsContainerFrame { //---------------------------------------- // List handling kludge - void ReflowBullet(nsIFrame* aBulletFrame, BlockReflowInput& aState, - ReflowOutput& aMetrics, nscoord aLineTop); + void ReflowOutsideMarker(nsIFrame* aMarkerFrame, BlockReflowInput& aState, + ReflowOutput& aMetrics, nscoord aLineTop); //---------------------------------------- @@ -872,19 +864,19 @@ class nsBlockFrame : public nsContainerFrame { void SetOverflowOutOfFlows(const nsFrameList& aList, nsFrameList* aPropValue); /** - * @return the inside bullet frame or nullptr if we don't have one. + * @return the inside ::marker frame or nullptr if we don't have one. */ - nsBulletFrame* GetInsideBullet() const; + nsIFrame* GetInsideMarker() const; /** - * @return the outside bullet frame or nullptr if we don't have one. + * @return the outside ::marker frame or nullptr if we don't have one. */ - nsBulletFrame* GetOutsideBullet() const; + nsIFrame* GetOutsideMarker() const; /** - * @return the outside bullet frame list frame property. + * @return the outside ::marker frame list frame property. */ - nsFrameList* GetOutsideBulletList() const; + nsFrameList* GetOutsideMarkerList() const; /** * @return true if this frame has pushed floats. @@ -903,12 +895,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 ResolveBulletStyle( - mozilla::PseudoStyleType aType, mozilla::ServoStyleSet* aStyleSet); - #ifdef DEBUG void VerifyLines(bool aFinalCheckOK); void VerifyOverflowSituation(); diff --git a/layout/generic/nsBulletFrame.cpp b/layout/generic/nsBulletFrame.cpp index 0c7a628faa17..3fe8b8f0cfd9 100644 --- a/layout/generic/nsBulletFrame.cpp +++ b/layout/generic/nsBulletFrame.cpp @@ -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); } } } @@ -175,7 +180,7 @@ class nsDisplayBulletGeometry : nsDisplayItemGenericGeometry(aItem, aBuilder), nsImageGeometryMixin(aItem, aBuilder) { nsBulletFrame* f = static_cast(aItem->Frame()); - mOrdinal = f->GetOrdinal(); + mOrdinal = f->Ordinal(); } virtual bool InvalidateForSyncDecodeImages() const override { @@ -581,7 +586,7 @@ class nsDisplayBullet final : public nsDisplayItem { static_cast(aGeometry); nsBulletFrame* f = static_cast(mFrame); - if (f->GetOrdinal() != geometry->mOrdinal) { + if (f->Ordinal() != geometry->mOrdinal) { bool snap; aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &snap)); return; @@ -770,8 +775,8 @@ Maybe nsBulletFrame::CreateBulletRenderer( RefPtr 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 +815,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 +950,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 +1258,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(' '); diff --git a/layout/generic/nsBulletFrame.h b/layout/generic/nsBulletFrame.h index d982b0f93e1c..26687ca60eeb 100644 --- a/layout/generic/nsBulletFrame.h +++ b/layout/generic/nsBulletFrame.h @@ -53,7 +53,6 @@ class nsBulletFrame final : public nsFrame { : nsFrame(aStyle, aPresContext, kClassID), mPadding(GetWritingMode()), mIntrinsicSize(GetWritingMode()), - mOrdinal(0), mRequestRegistered(false) {} virtual ~nsBulletFrame(); @@ -85,12 +84,10 @@ class nsBulletFrame final : public nsFrame { if (aFlags & (eSupportsCSSTransforms | eSupportsContainLayoutAndPaint)) { return false; } - return nsFrame::IsFrameOfType(aFlags); + return nsFrame::IsFrameOfType(aFlags & ~nsIFrame::eLineParticipant); } // 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 GetImage() const; @@ -137,7 +134,6 @@ class nsBulletFrame final : public nsFrame { RefPtr mListener; mozilla::LogicalSize mIntrinsicSize; - int32_t mOrdinal; private: mozilla::CounterStyle* ResolveCounterStyle(); diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp index adce59d4d6d6..a27679c28e3c 100644 --- a/layout/generic/nsContainerFrame.cpp +++ b/layout/generic/nsContainerFrame.cpp @@ -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(FirstInFlow()); - if (attr && attr->Type() == nsAttrValue::eInteger) { - ordinal = attr->GetIntegerValue(); - } else if (increment < 0) { - //

            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) diff --git a/layout/generic/nsContainerFrame.h b/layout/generic/nsContainerFrame.h index d8518006c96b..afa2f3d0a8aa 100644 --- a/layout/generic/nsContainerFrame.h +++ b/layout/generic/nsContainerFrame.h @@ -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 |
          1. | changes, effectively counting them - * and storing the result in |aOrdinal|. This is useful for - * |
              |, 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 |
            1. |. - */ - 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 diff --git a/layout/generic/nsFlexContainerFrame.cpp b/layout/generic/nsFlexContainerFrame.cpp index 970202edc305..a05d982de9b8 100644 --- a/layout/generic/nsFlexContainerFrame.cpp +++ b/layout/generic/nsFlexContainerFrame.cpp @@ -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()); diff --git a/layout/generic/nsFrameStateBits.h b/layout/generic/nsFrameStateBits.h index 4c74845d5d86..52568c391ac5 100644 --- a/layout/generic/nsFrameStateBits.h +++ b/layout/generic/nsFrameStateBits.h @@ -562,10 +562,10 @@ FRAME_STATE_BIT(Block, 28, NS_BLOCK_CLIP_PAGINATED_OVERFLOW) // even if it has no actual first-letter frame among its descendants. FRAME_STATE_BIT(Block, 29, NS_BLOCK_HAS_FIRST_LETTER_STYLE) -// NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET and NS_BLOCK_FRAME_HAS_INSIDE_BULLET -// means the block has an associated bullet frame, they are mutually exclusive. -FRAME_STATE_BIT(Block, 30, NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET) -FRAME_STATE_BIT(Block, 31, NS_BLOCK_FRAME_HAS_INSIDE_BULLET) +// NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER and NS_BLOCK_FRAME_HAS_INSIDE_MARKER +// means the block has an associated ::marker frame, they are mutually exclusive. +FRAME_STATE_BIT(Block, 30, NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER) +FRAME_STATE_BIT(Block, 31, NS_BLOCK_FRAME_HAS_INSIDE_MARKER) // This block has had a child marked dirty, so before we reflow we need // to look through the lines to find any such children and mark diff --git a/layout/generic/nsGridContainerFrame.cpp b/layout/generic/nsGridContainerFrame.cpp index fdf50a695530..95a02c50dea5 100644 --- a/layout/generic/nsGridContainerFrame.cpp +++ b/layout/generic/nsGridContainerFrame.cpp @@ -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); diff --git a/layout/generic/nsHTMLParts.h b/layout/generic/nsHTMLParts.h index ad8282e6d20b..76a2009899d2 100644 --- a/layout/generic/nsHTMLParts.h +++ b/layout/generic/nsHTMLParts.h @@ -34,15 +34,15 @@ class ViewportFrame; // NS_BLOCK_FLAGS_NON_INHERITED_MASK bits below. #define NS_BLOCK_FLAGS_MASK \ (NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS | NS_BLOCK_CLIP_PAGINATED_OVERFLOW | \ - NS_BLOCK_HAS_FIRST_LETTER_STYLE | NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET | \ - NS_BLOCK_HAS_FIRST_LETTER_CHILD | NS_BLOCK_FRAME_HAS_INSIDE_BULLET) + NS_BLOCK_HAS_FIRST_LETTER_STYLE | NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER | \ + NS_BLOCK_HAS_FIRST_LETTER_CHILD | NS_BLOCK_FRAME_HAS_INSIDE_MARKER) // This is the subset of NS_BLOCK_FLAGS_MASK that is NOT inherited // by default. They should only be set on the first-in-flow. // See nsBlockFrame::Init. #define NS_BLOCK_FLAGS_NON_INHERITED_MASK \ - (NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET | NS_BLOCK_HAS_FIRST_LETTER_CHILD | \ - NS_BLOCK_FRAME_HAS_INSIDE_BULLET) + (NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER | NS_BLOCK_HAS_FIRST_LETTER_CHILD | \ + NS_BLOCK_FRAME_HAS_INSIDE_MARKER) // Factory methods for creating html layout objects @@ -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; diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 5fbae711771f..4ee1017718ab 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -331,6 +331,7 @@ void nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent, const nsStyleContent* styleContent = StyleContent(); if (mKind == Kind::ContentPropertyAtIndex) { MOZ_RELEASE_ASSERT( + aParent->GetContent()->IsGeneratedContentContainerForMarker() || aParent->GetContent()->IsGeneratedContentContainerForAfter() || aParent->GetContent()->IsGeneratedContentContainerForBefore()); MOZ_RELEASE_ASSERT( diff --git a/layout/generic/nsLineBox.cpp b/layout/generic/nsLineBox.cpp index 7f52028e6a0f..0443aca31d03 100644 --- a/layout/generic/nsLineBox.cpp +++ b/layout/generic/nsLineBox.cpp @@ -310,7 +310,7 @@ bool nsLineBox::IsEmpty() const { --n, kid = kid->GetNextSibling()) { if (!kid->IsEmpty()) return false; } - if (HasBullet()) { + if (HasMarker()) { return false; } return true; @@ -339,7 +339,7 @@ bool nsLineBox::CachedIsEmpty() { break; } } - if (HasBullet()) { + if (HasMarker()) { result = false; } } diff --git a/layout/generic/nsLineBox.h b/layout/generic/nsLineBox.h index 81342e8fc306..4765da159709 100644 --- a/layout/generic/nsLineBox.h +++ b/layout/generic/nsLineBox.h @@ -247,16 +247,16 @@ class nsLineBox final : public nsLineLink { return mFlags.mResizeReflowOptimizationDisabled; } - // mHasBullet bit - void SetHasBullet() { - mFlags.mHasBullet = true; + // mHasMarker bit + void SetHasMarker() { + mFlags.mHasMarker = true; InvalidateCachedIsEmpty(); } - void ClearHasBullet() { - mFlags.mHasBullet = false; + void ClearHasMarker() { + mFlags.mHasMarker = false; InvalidateCachedIsEmpty(); } - bool HasBullet() const { return mFlags.mHasBullet; } + bool HasMarker() const { return mFlags.mHasMarker; } // mHadFloatPushed bit void SetHadFloatPushed() { mFlags.mHadFloatPushed = true; } @@ -597,9 +597,9 @@ class nsLineBox final : public nsLineLink { bool mResizeReflowOptimizationDisabled : 1; bool mEmptyCacheValid : 1; bool mEmptyCacheState : 1; - // mHasBullet indicates that this is an inline line whose block's - // bullet is adjacent to this line and non-empty. - bool mHasBullet : 1; + // mHasMarker indicates that this is an inline line whose block's + // ::marker is adjacent to this line and non-empty. + bool mHasMarker : 1; // Indicates that this line *may* have a placeholder for a float // that was pushed to a later column or page. bool mHadFloatPushed : 1; diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp index f25d37134022..b8e17f6a2a3c 100644 --- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -13,7 +13,6 @@ #include "LayoutLogging.h" #include "SVGTextFrame.h" #include "nsBlockFrame.h" -#include "nsBulletFrame.h" #include "nsFontMetrics.h" #include "nsStyleConsts.h" #include "nsContainerFrame.h" @@ -76,7 +75,7 @@ nsLineLayout::nsLineLayout(nsPresContext* aPresContext, mInFirstLine(false), mGotLineBox(false), mInFirstLetter(false), - mHasBullet(false), + mHasMarker(false), mDirtyNextLine(false), mLineAtStart(false), mHasRuby(false), @@ -191,7 +190,7 @@ void nsLineLayout::BeginLineReflow(nscoord aICoord, nscoord aBCoord, mMaxStartBoxBSize = mMaxEndBoxBSize = 0; if (mGotLineBox) { - mLineBox->ClearHasBullet(); + mLineBox->ClearHasMarker(); } PerSpanData* psd = NewPerSpanData(); @@ -629,7 +628,7 @@ nsLineLayout::PerFrameData* nsLineLayout::NewPerFrameData(nsIFrame* aFrame) { pfd->mIsNonWhitespaceTextFrame = false; pfd->mIsLetterFrame = false; pfd->mRecomputeOverflow = false; - pfd->mIsBullet = false; + pfd->mIsMarker = false; pfd->mSkipWhenTrimmingWhitespace = false; pfd->mIsEmpty = false; pfd->mIsPlaceholder = false; @@ -907,7 +906,7 @@ void nsLineLayout::ReflowFrame(nsIFrame* aFrame, nsReflowStatus& aReflowStatus, !LineIsEmpty() && // We always place floating letter frames. This kinda sucks. They'd // usually fall into the LineIsEmpty() check anyway, except when - // there's something like a bullet before or what not. We actually + // there's something like a ::marker before or what not. We actually // need to place them now, because they're pretty nasty and they // create continuations that are in flow and not a kid of the // previous continuation's parent. We don't want the deferred reflow @@ -1384,29 +1383,29 @@ void nsLineLayout::PlaceFrame(PerFrameData* pfd, ReflowOutput& aMetrics) { } } -void nsLineLayout::AddBulletFrame(nsBulletFrame* aFrame, +void nsLineLayout::AddMarkerFrame(nsIFrame* aFrame, const ReflowOutput& aMetrics) { NS_ASSERTION(mCurrentSpan == mRootSpan, "bad linelayout user"); NS_ASSERTION(mGotLineBox, "must have line box"); nsBlockFrame* blockFrame = do_QueryFrame(mBlockReflowInput->mFrame); MOZ_ASSERT(blockFrame, "must be for block"); - if (!blockFrame->BulletIsEmpty()) { - mHasBullet = true; - mLineBox->SetHasBullet(); + if (!blockFrame->MarkerIsEmpty()) { + mHasMarker = true; + mLineBox->SetHasMarker(); } WritingMode lineWM = mRootSpan->mWritingMode; PerFrameData* pfd = NewPerFrameData(aFrame); PerSpanData* psd = mRootSpan; - MOZ_ASSERT(psd->mFirstFrame, "adding bullet to an empty line?"); - // Prepend the bullet frame to the line. + MOZ_ASSERT(psd->mFirstFrame, "adding marker to an empty line?"); + // Prepend the marker frame to the line. psd->mFirstFrame->mPrev = pfd; pfd->mNext = psd->mFirstFrame; psd->mFirstFrame = pfd; - pfd->mIsBullet = true; + pfd->mIsMarker = true; if (aMetrics.BlockStartAscent() == ReflowOutput::ASK_FOR_BASELINE) { pfd->mAscent = aFrame->GetLogicalBaseline(lineWM); } else { @@ -1418,13 +1417,13 @@ void nsLineLayout::AddBulletFrame(nsBulletFrame* aFrame, pfd->mOverflowAreas = aMetrics.mOverflowAreas; } -void nsLineLayout::RemoveBulletFrame(nsBulletFrame* aFrame) { +void nsLineLayout::RemoveMarkerFrame(nsIFrame* aFrame) { PerSpanData* psd = mCurrentSpan; - MOZ_ASSERT(psd == mRootSpan, "bullet on non-root span?"); + MOZ_ASSERT(psd == mRootSpan, "::marker on non-root span?"); MOZ_ASSERT(psd->mFirstFrame->mFrame == aFrame, - "bullet is not the first frame?"); + "::marker is not the first frame?"); PerFrameData* pfd = psd->mFirstFrame; - MOZ_ASSERT(pfd != psd->mLastFrame, "bullet is the only frame?"); + MOZ_ASSERT(pfd != psd->mLastFrame, "::marker is the only frame?"); pfd->mNext->mPrev = nullptr; psd->mFirstFrame = pfd->mNext; FreeFrame(pfd); @@ -2247,13 +2246,13 @@ void nsLineLayout::VerticalAlignFrames(PerSpanData* psd) { // in some cases in quirks mode: // (1) if the root span contains non-whitespace text directly (this // is handled by zeroEffectiveSpanBox - // (2) if this line has a bullet + // (2) if this line has a ::marker // (3) if this is the last line of an LI, DT, or DD element // (The last line before a block also counts, but not before a // BR) (NN4/IE5 quirk) // (1) and (2) above - bool applyMinLH = !zeroEffectiveSpanBox || mHasBullet; + bool applyMinLH = !zeroEffectiveSpanBox || mHasMarker; bool isLastLine = !mGotLineBox || (!mLineBox->IsLineWrapped() && !mLineEndsInBR); if (!applyMinLH && isLastLine) { @@ -2267,7 +2266,7 @@ void nsLineLayout::VerticalAlignFrames(PerSpanData* psd) { } } if (applyMinLH) { - if (psd->mHasNonemptyContent || preMode || mHasBullet) { + if (psd->mHasNonemptyContent || preMode || mHasMarker) { #ifdef NOISY_BLOCKDIR_ALIGN printf(" [span]==> adjusting min/maxBCoord: currentValues: %d,%d", minBCoord, maxBCoord); @@ -2619,8 +2618,8 @@ bool nsLineLayout::TrimTrailingWhiteSpace() { } bool nsLineLayout::PerFrameData::ParticipatesInJustification() const { - if (mIsBullet || mIsEmpty || mSkipWhenTrimmingWhitespace) { - // Skip bullets, empty frames, and placeholders + if (mIsMarker || mIsEmpty || mSkipWhenTrimmingWhitespace) { + // Skip ::markers, empty frames, and placeholders return false; } if (mIsTextFrame && !mIsNonWhitespaceTextFrame && @@ -3178,11 +3177,11 @@ void nsLineLayout::TextAlignLine(nsLineBox* aLine, bool aIsLastLine) { (!mPresContext->IsVisualMode() || !lineWM.IsBidiLTR())) { PerFrameData* startFrame = psd->mFirstFrame; MOZ_ASSERT(startFrame, "empty line?"); - if (startFrame->mIsBullet) { - // Bullet shouldn't participate in bidi reordering. + if (startFrame->mIsMarker) { + // ::marker shouldn't participate in bidi reordering. startFrame = startFrame->mNext; - MOZ_ASSERT(startFrame, "no frame after bullet?"); - MOZ_ASSERT(!startFrame->mIsBullet, "multiple bullets?"); + MOZ_ASSERT(startFrame, "no frame after ::marker?"); + MOZ_ASSERT(!startFrame->mIsMarker, "multiple ::markers?"); } nsBidiPresUtils::ReorderFrames(startFrame->mFrame, aLine->GetChildCount(), lineWM, mContainerSize, @@ -3240,7 +3239,7 @@ void nsLineLayout::RelativePositionFrames(PerSpanData* psd, if (psd != mRootSpan) { // The span's overflow areas come in three parts: // -- this frame's width and height - // -- pfd->mOverflowAreas, which is the area of a bullet or the union + // -- pfd->mOverflowAreas, which is the area of a ::marker or the union // of a relatively positioned frame's absolute children // -- the bounds of all inline descendants // The former two parts are computed right here, we gather the descendants diff --git a/layout/generic/nsLineLayout.h b/layout/generic/nsLineLayout.h index 7bea83c989f6..26a4eb439459 100644 --- a/layout/generic/nsLineLayout.h +++ b/layout/generic/nsLineLayout.h @@ -16,7 +16,6 @@ #include "BlockReflowInput.h" #include "nsLineBox.h" -class nsBulletFrame; class nsFloatManager; struct nsStyleText; @@ -93,9 +92,9 @@ class nsLineLayout { void ReflowFrame(nsIFrame* aFrame, nsReflowStatus& aReflowStatus, ReflowOutput* aMetrics, bool& aPushedFrame); - void AddBulletFrame(nsBulletFrame* aFrame, const ReflowOutput& aMetrics); + void AddMarkerFrame(nsIFrame* aFrame, const ReflowOutput& aMetrics); - void RemoveBulletFrame(nsBulletFrame* aFrame); + void RemoveMarkerFrame(nsIFrame* aFrame); /** * Place frames in the block direction (CSS property vertical-align) @@ -424,7 +423,7 @@ class nsLineLayout { bool mIsNonWhitespaceTextFrame : 1; bool mIsLetterFrame : 1; bool mRecomputeOverflow : 1; - bool mIsBullet : 1; + bool mIsMarker : 1; bool mSkipWhenTrimmingWhitespace : 1; bool mIsEmpty : 1; bool mIsPlaceholder : 1; @@ -570,7 +569,7 @@ class nsLineLayout { bool mInFirstLine : 1; bool mGotLineBox : 1; bool mInFirstLetter : 1; - bool mHasBullet : 1; + bool mHasMarker : 1; bool mDirtyNextLine : 1; bool mLineAtStart : 1; bool mHasRuby : 1; diff --git a/layout/inspector/tests/test_getCSSPseudoElementNames.html b/layout/inspector/tests/test_getCSSPseudoElementNames.html index a91c93f625f6..040f6ca50897 100644 --- a/layout/inspector/tests/test_getCSSPseudoElementNames.html +++ b/layout/inspector/tests/test_getCSSPseudoElementNames.html @@ -11,6 +11,7 @@ let expected = new Set([ ":after", ":before", + ":marker", ":backdrop", ":cue", ":first-letter", @@ -20,8 +21,6 @@ ":-moz-color-swatch", ":-moz-focus-inner", ":-moz-focus-outer", - ":-moz-list-bullet", - ":-moz-list-number", ":-moz-math-anonymous", ":-moz-meter-bar", ":-moz-placeholder", diff --git a/layout/reftests/bugs/1401317-ref.html b/layout/reftests/bugs/1401317-ref.html index 560920bf708f..395eab87d23e 100644 --- a/layout/reftests/bugs/1401317-ref.html +++ b/layout/reftests/bugs/1401317-ref.html @@ -2,7 +2,7 @@ diff --git a/layout/reftests/bugs/1401317.html b/layout/reftests/bugs/1401317.html index a52276c58fdc..82e17a8a2f7e 100644 --- a/layout/reftests/bugs/1401317.html +++ b/layout/reftests/bugs/1401317.html @@ -2,7 +2,7 @@ diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 7fe46b5acccc..b70bd35a8522 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -999,8 +999,8 @@ fuzzy-if(Android,0-11,0-17) fuzzy-if(webrender,0-1,0-10) == 413361-1.html 413361 == 417178-1.html 417178-1-ref.html == 417246-1.html 417246-1-ref.html == 417676.html 417676-ref.html -asserts(1) == 418574-1.html 418574-1-ref.html # bug 478135 -asserts(1) == 418574-2.html 418574-2-ref.html # bug 478135 +== 418574-1.html 418574-1-ref.html +== 418574-2.html 418574-2-ref.html == 418766-1a.html 418766-1-ref.html == 418766-1b.html 418766-1-ref.html == 419060.html 419060-ref.html diff --git a/layout/reftests/counters/counter-reset-integer-range-ref.html b/layout/reftests/counters/counter-reset-integer-range-ref.html index dfc950bc1c0e..44ac0af32889 100644 --- a/layout/reftests/counters/counter-reset-integer-range-ref.html +++ b/layout/reftests/counters/counter-reset-integer-range-ref.html @@ -5,5 +5,5 @@ 2147483647 2147483647 -2147483647 --2147483647 --2147483647 +0 +0 diff --git a/layout/reftests/counters/counter-reset-integer-range.html b/layout/reftests/counters/counter-reset-integer-range.html index 7867e09bd69a..ad080a1e25bf 100644 --- a/layout/reftests/counters/counter-reset-integer-range.html +++ b/layout/reftests/counters/counter-reset-integer-range.html @@ -10,5 +10,6 @@ span::after { content: counter(c); } + diff --git a/layout/reftests/details-summary/details-absolute-children.html b/layout/reftests/details-summary/details-absolute-children.html index af4396f9fa75..19a9c9c9d23e 100644 --- a/layout/reftests/details-summary/details-absolute-children.html +++ b/layout/reftests/details-summary/details-absolute-children.html @@ -9,7 +9,7 @@ width: 500px; height: 200px; } - summary::-moz-list-bullet { + summary::marker { /* Hide the triangle for comparing with div in reftest. */ list-style-type: none; } diff --git a/layout/reftests/details-summary/details-display-inline.html b/layout/reftests/details-summary/details-display-inline.html index 1f7b7c5da227..7a9150137a89 100644 --- a/layout/reftests/details-summary/details-display-inline.html +++ b/layout/reftests/details-summary/details-display-inline.html @@ -7,7 +7,7 @@ details { display: inline; } - summary::-moz-list-bullet { + summary::marker { /* Hide the triangle for comparing with div in reftest. */ list-style-type: none; } diff --git a/layout/reftests/details-summary/details-in-ol.html b/layout/reftests/details-summary/details-in-ol.html index 974c427761c9..434bbe9f6924 100644 --- a/layout/reftests/details-summary/details-in-ol.html +++ b/layout/reftests/details-summary/details-in-ol.html @@ -4,7 +4,7 @@ diff --git a/layout/style/nsCSSPseudoElementList.h b/layout/style/nsCSSPseudoElementList.h index b4110532297e..e914eb09f4a2 100644 --- a/layout/style/nsCSSPseudoElementList.h +++ b/layout/style/nsCSSPseudoElementList.h @@ -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. // diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index 907d0fe7e938..05d05007c937 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -526,6 +526,8 @@ already_AddRefed 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(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(mElement->GetProperty(property)); + mOuterFrame = pseudo ? pseudo->GetPrimaryFrame() : nullptr; + } } mInnerFrame = mOuterFrame; diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 25542603ae5a..1853e4eeaf27 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -454,7 +454,8 @@ nsChangeHint nsStyleOutline::CalcDifference( // nsStyleList // nsStyleList::nsStyleList(const Document& aDocument) - : mListStylePosition(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE) { + : mListStylePosition(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE), + mMozListReversed(StyleMozListReversed::False) { MOZ_COUNT_CTOR(nsStyleList); MOZ_ASSERT(NS_IsMainThread()); @@ -469,7 +470,8 @@ nsStyleList::nsStyleList(const nsStyleList& aSource) mListStyleImage(aSource.mListStyleImage), mCounterStyle(aSource.mCounterStyle), mQuotes(aSource.mQuotes), - mImageRegion(aSource.mImageRegion) { + mImageRegion(aSource.mImageRegion), + mMozListReversed(aSource.mMozListReversed) { MOZ_COUNT_CTOR(nsStyleList); } @@ -509,6 +511,11 @@ nsChangeHint nsStyleList::CalcDifference( mCounterStyle != aNewData.mCounterStyle) { hint = nsChangeHint_NeutralChange; } + // This is an internal UA-sheet property that is true only for
                + // so hopefully it changes rarely. + if (mMozListReversed != aNewData.mMozListReversed) { + return NS_STYLE_HINT_REFLOW; + } // list-style-image and -moz-image-region may affect some XUL elements // regardless of display value, so we still need to check them. if (!DefinitelyEqualImages(mListStyleImage, aNewData.mListStyleImage)) { diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 68a9ae498b41..a7132504e872 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -1110,6 +1110,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleList { public: RefPtr mQuotes; nsRect mImageRegion; // the rect to use within an image + mozilla::StyleMozListReversed mMozListReversed; // true in an
                  scope }; struct nsStyleGridLine { @@ -2485,10 +2486,27 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleContent { mResets[aIndex].mValue = aValue; } + uint32_t CounterSetCount() const { return mSets.Length(); } + const nsStyleCounterData& CounterSetAt(uint32_t aIndex) const { + return mSets[aIndex]; + } + + void AllocateCounterSets(uint32_t aCount) { + mSets.Clear(); + mSets.SetLength(aCount); + } + + void SetCounterSetAt(uint32_t aIndex, const nsString& aCounter, + int32_t aValue) { + mSets[aIndex].mCounter = aCounter; + mSets[aIndex].mValue = aValue; + } + protected: nsTArray mContents; nsTArray mIncrements; nsTArray mResets; + nsTArray mSets; }; struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUIReset { diff --git a/layout/style/res/html.css b/layout/style/res/html.css index 6682961748a3..7f84c34f6c8f 100644 --- a/layout/style/res/html.css +++ b/layout/style/res/html.css @@ -579,6 +579,15 @@ menu[type="context"] { display: none !important; } +ul, ol, menu { + counter-reset: list-item; + -moz-list-reversed: false; +} + +ol[reversed] { + -moz-list-reversed: true; +} + ol { display: block; list-style-type: decimal; @@ -775,6 +784,7 @@ video > .caption-box { details > summary:first-of-type, details > summary:-moz-native-anonymous { display: list-item; + counter-increment: list-item 0; list-style: disclosure-closed inside; } diff --git a/layout/style/res/ua.css b/layout/style/res/ua.css index a9121d0d340e..d41691cbf47f 100644 --- a/layout/style/res/ua.css +++ b/layout/style/res/ua.css @@ -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. diff --git a/layout/style/test/ListCSSProperties.cpp b/layout/style/test/ListCSSProperties.cpp index 773c9936bfb9..d2a143c80b5b 100644 --- a/layout/style/test/ListCSSProperties.cpp +++ b/layout/style/test/ListCSSProperties.cpp @@ -92,7 +92,8 @@ const char *gInaccessibleProperties[] = { "-x-text-zoom", "-moz-context-properties", "-moz-control-character-visibility", - "-moz-script-level", // parsed by UA sheets only + "-moz-list-reversed", // parsed by UA sheets only + "-moz-script-level", // parsed by UA sheets only "-moz-script-size-multiplier", "-moz-script-min-size", "-moz-math-variant", diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index d915764d37b8..efa5f6aea28f 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -3565,6 +3565,14 @@ var gCSSProperties = { other_values: [ "foo 1", "bar", "foo 3 bar baz 2", "\\32 1", "-\\32 1", "-c 1", "\\32 1", "-\\32 1", "\\2 1", "-\\2 1", "-c 1", "\\2 1", "-\\2 1", "-\\7f \\9e 1" ], invalid_values: [ "none foo", "none foo 3", "foo none", "foo 3 none" ] }, + "counter-set": { + domProp: "counterSet", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: [ "none" ], + other_values: [ "foo 1", "bar", "foo 3 bar baz 2", "\\32 1", "-\\32 1", "-c 1", "\\32 1", "-\\32 1", "\\2 1", "-\\2 1", "-c 1", "\\2 1", "-\\2 1", "-\\7f \\9e 1" ], + invalid_values: [ "none foo", "none foo 3", "foo none", "foo 3 none" ] + }, "cursor": { domProp: "cursor", inherited: true, diff --git a/layout/style/test/test_non_content_accessible_properties.html b/layout/style/test/test_non_content_accessible_properties.html index de879b64ee8d..a3e102cdbe96 100644 --- a/layout/style/test/test_non_content_accessible_properties.html +++ b/layout/style/test/test_non_content_accessible_properties.html @@ -8,6 +8,7 @@ const NON_CONTENT_ACCESSIBLE_PROPERTIES = [ "-x-span", "-x-lang", "-x-text-zoom", + "-moz-list-reversed", "-moz-window-shadow", "-moz-window-opacity", "-moz-window-transform", diff --git a/servo/components/style/cbindgen.toml b/servo/components/style/cbindgen.toml index b5d374d77bfe..54288dff7adb 100644 --- a/servo/components/style/cbindgen.toml +++ b/servo/components/style/cbindgen.toml @@ -108,6 +108,7 @@ include = [ "TouchAction", "WillChangeBits", "TextDecorationLine", + "MozListReversed", ] item_types = ["enums", "structs", "typedefs"] diff --git a/servo/components/style/dom.rs b/servo/components/style/dom.rs index 1c64543310c4..28798e280b61 100644 --- a/servo/components/style/dom.rs +++ b/servo/components/style/dom.rs @@ -441,6 +441,11 @@ pub trait TElement: None } + /// The ::marker pseudo-element of this element, if it exists. + fn marker_pseudo_element(&self) -> Option { + None + } + /// Execute `f` for each anonymous content child (apart from ::before and /// ::after) whose originating element is `self`. fn each_anonymous_content_child(&self, _f: F) diff --git a/servo/components/style/gecko/pseudo_element.rs b/servo/components/style/gecko/pseudo_element.rs index 8160ea2c9b8f..c49277409e03 100644 --- a/servo/components/style/gecko/pseudo_element.rs +++ b/servo/components/style/gecko/pseudo_element.rs @@ -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; } diff --git a/servo/components/style/gecko/pseudo_element_definition.mako.rs b/servo/components/style/gecko/pseudo_element_definition.mako.rs index be156b54a14f..e2dffcbdd742 100644 --- a/servo/components/style/gecko/pseudo_element_definition.mako.rs +++ b/servo/components/style/gecko/pseudo_element_definition.mako.rs @@ -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([])) diff --git a/servo/components/style/gecko/wrapper.rs b/servo/components/style/gecko/wrapper.rs index 93d3290c191d..dedfe7715e85 100644 --- a/servo/components/style/gecko/wrapper.rs +++ b/servo/components/style/gecko/wrapper.rs @@ -1137,6 +1137,14 @@ impl<'le> TElement for GeckoElement<'le> { self.before_or_after_pseudo(/* is_before = */ false) } + fn marker_pseudo_element(&self) -> Option { + 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 diff --git a/servo/components/style/invalidation/element/invalidator.rs b/servo/components/style/invalidation/element/invalidator.rs index 4640c7c0442a..7ed97c0b1972 100644 --- a/servo/components/style/invalidation/element/invalidator.rs +++ b/servo/components/style/invalidation/element/invalidator.rs @@ -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); } diff --git a/servo/components/style/properties/data.py b/servo/components/style/properties/data.py index 9347d9b94288..52cdcf15d22b 100644 --- a/servo/components/style/properties/data.py +++ b/servo/components/style/properties/data.py @@ -324,6 +324,7 @@ class Longhand(object): "JustifyItems", "JustifySelf", "MozForceBrokenImageIcon", + "MozListReversed", "MozScriptLevel", "MozScriptMinSize", "MozScriptSizeMultiplier", diff --git a/servo/components/style/properties/gecko.mako.rs b/servo/components/style/properties/gecko.mako.rs index 0879e5846c31..7c5f4a94c011 100644 --- a/servo/components/style/properties/gecko.mako.rs +++ b/servo/components/style/properties/gecko.mako.rs @@ -1247,6 +1247,7 @@ impl Clone for ${style_struct.gecko_struct_name} { "Length": impl_absolute_length, "LengthOrNormal": impl_style_coord, "LengthPercentageOrAuto": impl_style_coord, + "MozListReversed": impl_simple, "MozScriptMinSize": impl_absolute_length, "RGBAColor": impl_rgba_color, "SVGLength": impl_svg_length, @@ -4559,7 +4560,7 @@ clip-path <%self:impl_trait style_struct_name="Counters" - skip_longhands="content counter-increment counter-reset"> + skip_longhands="content counter-increment counter-reset counter-set"> pub fn ineffective_content_property(&self) -> bool { self.gecko.mContents.is_empty() } @@ -4788,7 +4789,7 @@ clip-path ) } - % for counter_property in ["Increment", "Reset"]: + % for counter_property in ["Increment", "Reset", "Set"]: pub fn set_counter_${counter_property.lower()}( &mut self, v: longhands::counter_${counter_property.lower()}::computed_value::T diff --git a/servo/components/style/properties/longhands/counters.mako.rs b/servo/components/style/properties/longhands/counters.mako.rs index b690eeb5c458..715aba1066e1 100644 --- a/servo/components/style/properties/longhands/counters.mako.rs +++ b/servo/components/style/properties/longhands/counters.mako.rs @@ -27,9 +27,18 @@ ${helpers.predefined_type( ${helpers.predefined_type( "counter-reset", - "CounterReset", + "CounterSetOrReset", initial_value="Default::default()", animation_value_type="discrete", spec="https://drafts.csswg.org/css-lists-3/#propdef-counter-reset", servo_restyle_damage="rebuild_and_reflow", )} + +${helpers.predefined_type( + "counter-set", + "CounterSetOrReset", + initial_value="Default::default()", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-lists-3/#propdef-counter-set", + servo_restyle_damage="rebuild_and_reflow", +)} diff --git a/servo/components/style/properties/longhands/list.mako.rs b/servo/components/style/properties/longhands/list.mako.rs index 4b368ea2ba52..6d79d3ad9ee7 100644 --- a/servo/components/style/properties/longhands/list.mako.rs +++ b/servo/components/style/properties/longhands/list.mako.rs @@ -68,3 +68,15 @@ ${helpers.predefined_type( boxed=True, spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-image-region)", )} + +${helpers.predefined_type( + "-moz-list-reversed", + "MozListReversed", + "computed::MozListReversed::False", + animation_value_type="discrete", + products="gecko", + enabled_in="ua", + needs_context=False, + spec="Internal implementation detail for
                    ", + servo_restyle_damage="rebuild_and_reflow", +)} diff --git a/servo/components/style/style_adjuster.rs b/servo/components/style/style_adjuster.rs index 8218e2706a3b..54b7dfc8a5ba 100644 --- a/servo/components/style/style_adjuster.rs +++ b/servo/components/style/style_adjuster.rs @@ -174,10 +174,15 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { /// Apply the blockification rules based on the table in CSS 2.2 section 9.7. /// + /// A ::marker pseudo-element with 'list-style-position:outside' needs to + /// have its 'display' blockified. fn blockify_if_necessary(&mut self, layout_parent_style: &ComputedValues, element: Option) where E: TElement, { + use crate::selector_parser::PseudoElement; + use crate::computed_values::list_style_position::T as ListStylePosition; + let mut blockify = false; macro_rules! blockify_if { ($if_what:expr) => { @@ -200,6 +205,8 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { blockify_if!(self.style.floated()); blockify_if!(self.style.out_of_flow_positioned()); + blockify_if!(self.style.pseudo == Some(&PseudoElement::Marker) && + self.style.get_parent_list().clone_list_style_position() == ListStylePosition::Outside); if !blockify { return; @@ -708,6 +715,47 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { } } + /// For HTML elements with 'display:list-item' we add a default 'counter-increment:list-item' + /// unless 'counter-increment' already has a value for 'list-item'. + /// + /// https://drafts.csswg.org/css-lists-3/#declaring-a-list-item + #[cfg(feature = "gecko")] + fn adjust_for_list_item(&mut self, element: Option) + where + E: TElement, + { + use crate::properties::longhands::counter_increment::computed_value::T as ComputedIncrement; + use crate::values::CustomIdent; + use crate::values::generics::counters::{CounterPair}; + use crate::values::specified::list::MozListReversed; + + if self.style.get_box().clone_display() != Display::ListItem { + return; + } + if self.style.pseudo.is_some() { + return; + } + if !element.map_or(false, |e| e.is_html_element()) { + return; + } + // Note that we map
                  1. to 'counter-set: list-item INTEGER; + // counter-increment: list-item 0;' so we'll return here unless the author + // explicitly specified something else. + let increments = self.style.get_counters().clone_counter_increment(); + if increments.iter().any(|i| i.name.0 == atom!("list-item")) { + return; + } + + let reversed = self.style.get_list().clone__moz_list_reversed() == MozListReversed::True; + let increment = if reversed { -1 } else { 1 }; + let list_increment = CounterPair { + name: CustomIdent(atom!("list-item")), + value: increment, + }; + let increments = increments.iter().cloned().chain(std::iter::once(list_increment)); + self.style.mutate_counters().set_counter_increment(ComputedIncrement::new(increments.collect())); + } + /// Adjusts the style to account for various fixups that don't fit naturally /// into the cascade. /// @@ -772,6 +820,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { #[cfg(feature = "gecko")] { self.adjust_for_appearance(element); + self.adjust_for_list_item(element); } self.set_bits(); } diff --git a/servo/components/style/values/computed/counters.rs b/servo/components/style/values/computed/counters.rs index aaf83afe485d..3a083632eb95 100644 --- a/servo/components/style/values/computed/counters.rs +++ b/servo/components/style/values/computed/counters.rs @@ -7,13 +7,13 @@ use crate::values::computed::url::ComputedImageUrl; use crate::values::generics::counters as generics; use crate::values::generics::counters::CounterIncrement as GenericCounterIncrement; -use crate::values::generics::counters::CounterReset as GenericCounterReset; +use crate::values::generics::counters::CounterSetOrReset as GenericCounterSetOrReset; /// A computed value for the `counter-increment` property. pub type CounterIncrement = GenericCounterIncrement; -/// A computed value for the `counter-increment` property. -pub type CounterReset = GenericCounterReset; +/// A computed value for the `counter-set` and `counter-reset` properties. +pub type CounterSetOrReset = GenericCounterSetOrReset; /// A computed value for the `content` property. pub type Content = generics::Content; diff --git a/servo/components/style/values/computed/list.rs b/servo/components/style/values/computed/list.rs index 622c021554ff..2bde35e3b6b3 100644 --- a/servo/components/style/values/computed/list.rs +++ b/servo/components/style/values/computed/list.rs @@ -6,6 +6,7 @@ #[cfg(feature = "gecko")] pub use crate::values::specified::list::ListStyleType; +pub use crate::values::specified::list::MozListReversed; pub use crate::values::specified::list::{QuotePair, Quotes}; use servo_arc::Arc; diff --git a/servo/components/style/values/computed/mod.rs b/servo/components/style/values/computed/mod.rs index 1f7d1e3eddcd..4c92218e69bb 100644 --- a/servo/components/style/values/computed/mod.rs +++ b/servo/components/style/values/computed/mod.rs @@ -45,7 +45,7 @@ pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective, Resize}; pub use self::box_::{ScrollSnapAlign, ScrollSnapType, TouchAction, VerticalAlign, WillChange}; pub use self::color::{Color, ColorOrAuto, ColorPropertyValue, RGBAColor}; pub use self::column::ColumnCount; -pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset}; +pub use self::counters::{Content, ContentItem, CounterIncrement, CounterSetOrReset}; pub use self::easing::TimingFunction; pub use self::effects::{BoxShadow, Filter, SimpleShadow}; pub use self::flex::FlexBasis; @@ -64,6 +64,7 @@ pub use self::length::{LengthOrAuto, LengthPercentageOrAuto, MaxSize, Size}; pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto}; #[cfg(feature = "gecko")] pub use self::list::ListStyleType; +pub use self::list::MozListReversed; pub use self::list::{QuotePair, Quotes}; pub use self::motion::OffsetPath; pub use self::outline::OutlineStyle; diff --git a/servo/components/style/values/generics/counters.rs b/servo/components/style/values/generics/counters.rs index 0f5d6bbb9392..7bab3c4bbc5f 100644 --- a/servo/components/style/values/generics/counters.rs +++ b/servo/components/style/values/generics/counters.rs @@ -45,21 +45,21 @@ impl Deref for CounterIncrement { } } -/// A generic value for the `counter-reset` property. +/// A generic value for the `counter-set` and `counter-reset` properties. #[derive( Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, )] -pub struct CounterReset(Counters); +pub struct CounterSetOrReset(Counters); -impl CounterReset { - /// Returns a new value for `counter-reset`. +impl CounterSetOrReset { + /// Returns a new value for `counter-set` / `counter-reset`. #[inline] pub fn new(counters: Vec>) -> Self { - CounterReset(Counters(counters.into_boxed_slice())) + CounterSetOrReset(Counters(counters.into_boxed_slice())) } } -impl Deref for CounterReset { +impl Deref for CounterSetOrReset { type Target = [CounterPair]; #[inline] diff --git a/servo/components/style/values/specified/counters.rs b/servo/components/style/values/specified/counters.rs index 6ee6575fc94d..262e7765a4a0 100644 --- a/servo/components/style/values/specified/counters.rs +++ b/servo/components/style/values/specified/counters.rs @@ -10,7 +10,7 @@ use crate::parser::{Parse, ParserContext}; use crate::values::generics::counters as generics; use crate::values::generics::counters::CounterIncrement as GenericCounterIncrement; use crate::values::generics::counters::CounterPair; -use crate::values::generics::counters::CounterReset as GenericCounterReset; +use crate::values::generics::counters::CounterSetOrReset as GenericCounterSetOrReset; #[cfg(feature = "gecko")] use crate::values::generics::CounterStyleOrNone; use crate::values::specified::url::SpecifiedImageUrl; @@ -34,10 +34,10 @@ impl Parse for CounterIncrement { } } -/// A specified value for the `counter-increment` property. -pub type CounterReset = GenericCounterReset; +/// A specified value for the `counter-set` and `counter-reset` properties. +pub type CounterSetOrReset = GenericCounterSetOrReset; -impl Parse for CounterReset { +impl Parse for CounterSetOrReset { fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, diff --git a/servo/components/style/values/specified/list.rs b/servo/components/style/values/specified/list.rs index b37ade47081a..d75455a1c71e 100644 --- a/servo/components/style/values/specified/list.rs +++ b/servo/components/style/values/specified/list.rs @@ -123,3 +123,13 @@ impl Parse for Quotes { } } } + +/// Specified and computed `-moz-list-reversed` property (for UA sheets only). +#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] +#[repr(u8)] +pub enum MozListReversed { + /// the initial value + False, + /// exclusively used for
                      in our html.css UA sheet + True, +} diff --git a/servo/components/style/values/specified/mod.rs b/servo/components/style/values/specified/mod.rs index 7295f0606976..919cb0cb3416 100644 --- a/servo/components/style/values/specified/mod.rs +++ b/servo/components/style/values/specified/mod.rs @@ -44,7 +44,7 @@ pub use self::box_::{ScrollSnapAlign, ScrollSnapType}; pub use self::box_::{TouchAction, TransitionProperty, VerticalAlign, WillChange}; pub use self::color::{Color, ColorOrAuto, ColorPropertyValue, RGBAColor}; pub use self::column::ColumnCount; -pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset}; +pub use self::counters::{Content, ContentItem, CounterIncrement, CounterSetOrReset}; pub use self::easing::TimingFunction; pub use self::effects::{BoxShadow, Filter, SimpleShadow}; pub use self::flex::FlexBasis; @@ -66,6 +66,7 @@ pub use self::length::{NoCalcLength, ViewportPercentageLength}; pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto}; #[cfg(feature = "gecko")] pub use self::list::ListStyleType; +pub use self::list::MozListReversed; pub use self::list::{QuotePair, Quotes}; pub use self::motion::OffsetPath; pub use self::outline::OutlineStyle; diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs index f52d7db49061..8b7e051125f1 100644 --- a/servo/ports/geckolib/glue.rs +++ b/servo/ports/geckolib/glue.rs @@ -4381,6 +4381,57 @@ pub extern "C" fn Servo_DeclarationBlock_SetIntValue( }) } +#[no_mangle] +pub extern "C" fn Servo_DeclarationBlock_SetCounterResetListItem( + declarations: &RawServoDeclarationBlock, + counter_value: i32, +) { + use style::values::generics::counters::{CounterPair, CounterSetOrReset}; + use style::properties::{PropertyDeclaration}; + + let prop = PropertyDeclaration::CounterReset(CounterSetOrReset::new(vec![CounterPair { + name: CustomIdent(atom!("list-item")), + value: style::values::specified::Integer::new(counter_value), + }])); + write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { + decls.push(prop, Importance::Normal); + }) +} + +#[no_mangle] +pub extern "C" fn Servo_DeclarationBlock_SetCounterSetListItem( + declarations: &RawServoDeclarationBlock, + counter_value: i32, +) { + use style::values::generics::counters::{CounterPair, CounterSetOrReset}; + use style::properties::{PropertyDeclaration}; + + let prop = PropertyDeclaration::CounterSet(CounterSetOrReset::new(vec![CounterPair { + name: CustomIdent(atom!("list-item")), + value: style::values::specified::Integer::new(counter_value), + }])); + write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { + decls.push(prop, Importance::Normal); + }) +} + +#[no_mangle] +pub extern "C" fn Servo_DeclarationBlock_SetCounterIncrementListItem( + declarations: &RawServoDeclarationBlock, + counter_value: i32, +) { + use style::values::generics::counters::{CounterPair, CounterIncrement}; + use style::properties::{PropertyDeclaration}; + + let prop = PropertyDeclaration::CounterIncrement(CounterIncrement::new(vec![CounterPair { + name: CustomIdent(atom!("list-item")), + value: style::values::specified::Integer::new(counter_value), + }])); + write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { + decls.push(prop, Importance::Normal); + }) +} + #[no_mangle] pub extern "C" fn Servo_DeclarationBlock_SetPixelValue( declarations: &RawServoDeclarationBlock, diff --git a/testing/web-platform/meta/css/CSS2/css1/c561-list-displ-000.xht.ini b/testing/web-platform/meta/css/CSS2/css1/c561-list-displ-000.xht.ini deleted file mode 100644 index b0dcccdb1534..000000000000 --- a/testing/web-platform/meta/css/CSS2/css1/c561-list-displ-000.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[c561-list-displ-000.xht] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-lists/inheritance.html.ini b/testing/web-platform/meta/css/css-lists/inheritance.html.ini new file mode 100644 index 000000000000..1e32d7c880d3 --- /dev/null +++ b/testing/web-platform/meta/css/css-lists/inheritance.html.ini @@ -0,0 +1,2 @@ +[inheritance.html] + disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1405176 diff --git a/testing/web-platform/meta/css/css-pseudo/marker-and-other-pseudo-elements.html.ini b/testing/web-platform/meta/css/css-pseudo/marker-and-other-pseudo-elements.html.ini deleted file mode 100644 index 4e08e3232dcd..000000000000 --- a/testing/web-platform/meta/css/css-pseudo/marker-and-other-pseudo-elements.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[marker-and-other-pseudo-elements.html] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-pseudo/marker-color.html.ini b/testing/web-platform/meta/css/css-pseudo/marker-color.html.ini deleted file mode 100644 index 030347fc02d8..000000000000 --- a/testing/web-platform/meta/css/css-pseudo/marker-color.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[marker-color.html] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-pseudo/marker-font-properties.html.ini b/testing/web-platform/meta/css/css-pseudo/marker-font-properties.html.ini index 41ad8b248c22..0323f4c0c35e 100644 --- a/testing/web-platform/meta/css/css-pseudo/marker-font-properties.html.ini +++ b/testing/web-platform/meta/css/css-pseudo/marker-font-properties.html.ini @@ -1,2 +1,4 @@ [marker-font-properties.html] - expected: FAIL + expected: + if os == "mac": FAIL + if os == "win": FAIL diff --git a/testing/web-platform/meta/css/css-scoping/slotted-parsing.html.ini b/testing/web-platform/meta/css/css-scoping/slotted-parsing.html.ini deleted file mode 100644 index 9c05af235f0f..000000000000 --- a/testing/web-platform/meta/css/css-scoping/slotted-parsing.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[slotted-parsing.html] - [Should be a valid selector: '::slotted(*)::marker'] - expected: FAIL - diff --git a/testing/web-platform/meta/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-list-item-numbering.html.ini b/testing/web-platform/meta/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-list-item-numbering.html.ini deleted file mode 100644 index 79683d568860..000000000000 --- a/testing/web-platform/meta/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-list-item-numbering.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[legend-list-item-numbering.html] - expected: FAIL diff --git a/testing/web-platform/meta/html/semantics/grouping-content/the-li-element/grouping-li-reftest-list-owner-mixed.html.ini b/testing/web-platform/meta/html/semantics/grouping-content/the-li-element/grouping-li-reftest-list-owner-mixed.html.ini deleted file mode 100644 index 3c6b9095830d..000000000000 --- a/testing/web-platform/meta/html/semantics/grouping-content/the-li-element/grouping-li-reftest-list-owner-mixed.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[grouping-li-reftest-list-owner-mixed.html] - expected: FAIL diff --git a/testing/web-platform/meta/html/semantics/grouping-content/the-li-element/grouping-li-reftest-list-owner-not-dir.html.ini b/testing/web-platform/meta/html/semantics/grouping-content/the-li-element/grouping-li-reftest-list-owner-not-dir.html.ini deleted file mode 100644 index 12ac5e2b5595..000000000000 --- a/testing/web-platform/meta/html/semantics/grouping-content/the-li-element/grouping-li-reftest-list-owner-not-dir.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[grouping-li-reftest-list-owner-not-dir.html] - expected: FAIL diff --git a/testing/web-platform/tests/css/CSS2/lists/counter-reset-increment-002.xht b/testing/web-platform/tests/css/CSS2/lists/counter-reset-increment-002.xht index bf422ba1eb89..8dc50ca60b24 100644 --- a/testing/web-platform/tests/css/CSS2/lists/counter-reset-increment-002.xht +++ b/testing/web-platform/tests/css/CSS2/lists/counter-reset-increment-002.xht @@ -29,7 +29,6 @@ li:before { content: counter(list-item) ". "; - counter-increment: list-item; } ]]> diff --git a/testing/web-platform/tests/css/css-lists/counter-reset-increment-display-contents.html b/testing/web-platform/tests/css/css-lists/counter-reset-increment-set-display-contents.html similarity index 78% rename from testing/web-platform/tests/css/css-lists/counter-reset-increment-display-contents.html rename to testing/web-platform/tests/css/css-lists/counter-reset-increment-set-display-contents.html index a59576b25345..6508df0da150 100644 --- a/testing/web-platform/tests/css/css-lists/counter-reset-increment-display-contents.html +++ b/testing/web-platform/tests/css/css-lists/counter-reset-increment-set-display-contents.html @@ -1,6 +1,6 @@ -CSS Lists: counter-reset and counter-increment on display:contents +CSS Lists: counter-reset, counter-set and counter-increment on display:contents @@ -8,6 +8,7 @@ .inc { counter-increment: x } .reset-6 { counter-reset: x 6 } .reset-666 { counter-reset: x 666 } + .set-666 { counter-set: x 666 } .contents { display: contents } .result::before { content: counter(x) } @@ -15,5 +16,6 @@
                      +
                      diff --git a/testing/web-platform/tests/css/css-lists/counter-reset-increment-display-none.html b/testing/web-platform/tests/css/css-lists/counter-reset-increment-set-display-none.html similarity index 78% rename from testing/web-platform/tests/css/css-lists/counter-reset-increment-display-none.html rename to testing/web-platform/tests/css/css-lists/counter-reset-increment-set-display-none.html index 3b344a751c1d..510fd8b6482b 100644 --- a/testing/web-platform/tests/css/css-lists/counter-reset-increment-display-none.html +++ b/testing/web-platform/tests/css/css-lists/counter-reset-increment-set-display-none.html @@ -1,6 +1,6 @@ -CSS Lists: counter-reset and counter-increment on display:none +CSS Lists: counter-reset, counter-set and counter-increment on display:none @@ -8,6 +8,7 @@ .inc { counter-increment: x } .reset-6 { counter-reset: x 6 } .reset-666 { counter-reset: x 666 } + .set-666 { counter-set: x 666 } .none { display: none } .result::before { content: counter(x) } @@ -15,5 +16,6 @@
                      +
                      diff --git a/testing/web-platform/tests/css/css-lists/counter-set-001-ref.html b/testing/web-platform/tests/css/css-lists/counter-set-001-ref.html new file mode 100644 index 000000000000..be06ea1dc948 --- /dev/null +++ b/testing/web-platform/tests/css/css-lists/counter-set-001-ref.html @@ -0,0 +1,37 @@ + + + + + CSS Lists: basic tests for 'counter-set' + + + + + +7 +0 +7 +8 +2 + + 2 + +3 + + 0 + 2 + + 2.5 + + +3 + + + diff --git a/testing/web-platform/tests/css/css-lists/counter-set-001.html b/testing/web-platform/tests/css/css-lists/counter-set-001.html new file mode 100644 index 000000000000..3be4c737c2ba --- /dev/null +++ b/testing/web-platform/tests/css/css-lists/counter-set-001.html @@ -0,0 +1,40 @@ + + + + + CSS Lists: basic tests for 'counter-set' + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testing/web-platform/tests/css/css-lists/li-list-item-counter-ref.html b/testing/web-platform/tests/css/css-lists/li-list-item-counter-ref.html new file mode 100644 index 000000000000..8340d6d7f65a --- /dev/null +++ b/testing/web-platform/tests/css/css-lists/li-list-item-counter-ref.html @@ -0,0 +1,26 @@ + + + + + Reference:_CSS Lists: 'counter-increment:list-item' on LI + + + + + +
                      1. a
                      2. b
                      3. c
                      +
                      1. a
                      2. b
                      3. c
                      +
                      1. a
                      2. b
                      3. c
                      +
                      1. a
                      2. b
                      3. c
                      +
                      1. a
                      2. b
                      3. c
                      + + + diff --git a/testing/web-platform/tests/css/css-lists/li-list-item-counter.html b/testing/web-platform/tests/css/css-lists/li-list-item-counter.html new file mode 100644 index 000000000000..b9a1196cabce --- /dev/null +++ b/testing/web-platform/tests/css/css-lists/li-list-item-counter.html @@ -0,0 +1,32 @@ + + + + + CSS Lists: 'counter-increment:list-item' on LI + + + + + + + +
                      1. a
                      2. b
                      3. c
                      +
                      1. a
                      2. b
                      3. c
                      +
                      1. a
                      2. b
                      3. c
                      +
                      1. a
                      2. b
                      3. c
                      +
                      1. a
                      2. b
                      3. c
                      + + + diff --git a/testing/web-platform/tests/css/css-lists/li-value-counter-reset-001-ref.html b/testing/web-platform/tests/css/css-lists/li-value-counter-reset-001-ref.html new file mode 100644 index 000000000000..9afb1ecfa059 --- /dev/null +++ b/testing/web-platform/tests/css/css-lists/li-value-counter-reset-001-ref.html @@ -0,0 +1,27 @@ + + + + + Reference:_CSS Lists: 'counter-set:list-item' trumps LI @value + + + + + +
                      1. a
                      2. b
                      +
                      1. a
                      2. b
                      +
                      1. a
                      2. b
                      +
                      1. a
                      2. b
                      +
                      1. a
                      2. b
                      +
                      1. a
                      2. b
                      + + + diff --git a/testing/web-platform/tests/css/css-lists/li-value-counter-reset-001.html b/testing/web-platform/tests/css/css-lists/li-value-counter-reset-001.html new file mode 100644 index 000000000000..0e91c3a03d61 --- /dev/null +++ b/testing/web-platform/tests/css/css-lists/li-value-counter-reset-001.html @@ -0,0 +1,30 @@ + + + + + CSS Lists: 'counter-set:list-item' trumps LI @value + + + + + + + +
                      1. a
                      2. b
                      +
                      1. a
                      2. b
                      +
                      1. a
                      2. b
                      +
                      1. a
                      2. b
                      +
                      1. a
                      2. b
                      +
                      1. a
                      2. b
                      + + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-content-001-ref.html b/testing/web-platform/tests/css/css-pseudo/marker-content-001-ref.html new file mode 100644 index 000000000000..e2c2daa17615 --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-content-001-ref.html @@ -0,0 +1,14 @@ + + + + +CSS Reference: ::marker pseudo elements styled with 'content' property + + + + +
                      1. B
                      2. C
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-content-001.html b/testing/web-platform/tests/css/css-pseudo/marker-content-001.html new file mode 100644 index 000000000000..5e5bfe1c23ab --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-content-001.html @@ -0,0 +1,25 @@ + + + + +CSS Test: ::marker pseudo elements styled with 'content' property + + + + + + +
                      1. B
                      2. C
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-content-001b.html b/testing/web-platform/tests/css/css-pseudo/marker-content-001b.html new file mode 100644 index 000000000000..6ab87a31d802 --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-content-001b.html @@ -0,0 +1,26 @@ + + + + +CSS Test: ::marker pseudo elements styled with 'content' property + + + + + + +
                      1. B
                      2. C
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-content-001c.html b/testing/web-platform/tests/css/css-pseudo/marker-content-001c.html new file mode 100644 index 000000000000..0a32b2ada035 --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-content-001c.html @@ -0,0 +1,27 @@ + + + + +CSS Test: ::marker pseudo elements styled with 'content' property + + + + + + +
                      1. B
                      2. C
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-content-002-ref.html b/testing/web-platform/tests/css/css-pseudo/marker-content-002-ref.html new file mode 100644 index 000000000000..5886f4216b6b --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-content-002-ref.html @@ -0,0 +1,14 @@ + + + + +CSS Reference: ::marker pseudo elements styled with 'content' property + + + + +
                      1. B
                      2. C
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-content-002.html b/testing/web-platform/tests/css/css-pseudo/marker-content-002.html new file mode 100644 index 000000000000..4c46c4b0b01b --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-content-002.html @@ -0,0 +1,19 @@ + + + + +CSS Test: ::marker pseudo elements styled with 'content' property + + + + + + +
                      1. B
                      2. C
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-content-003-ref.html b/testing/web-platform/tests/css/css-pseudo/marker-content-003-ref.html new file mode 100644 index 000000000000..5214d853c168 --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-content-003-ref.html @@ -0,0 +1,21 @@ + + + + +CSS Reference: ::marker pseudo elements styled with 'content' property and display:grid + + + + +
                      1. B
                      2. C
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-content-003.html b/testing/web-platform/tests/css/css-pseudo/marker-content-003.html new file mode 100644 index 000000000000..b4a41ce6d87e --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-content-003.html @@ -0,0 +1,22 @@ + + + + +CSS Test: ::marker pseudo elements styled with 'content' property and display:grid + + + + + + +
                      1. B
                      2. C
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-content-003b.html b/testing/web-platform/tests/css/css-pseudo/marker-content-003b.html new file mode 100644 index 000000000000..da7a2723ce32 --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-content-003b.html @@ -0,0 +1,22 @@ + + + + +CSS Test: ::marker pseudo elements styled with 'content' property and display:inline-grid + + + + + + +
                      1. B
                      2. C
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-content-004-ref.html b/testing/web-platform/tests/css/css-pseudo/marker-content-004-ref.html new file mode 100644 index 000000000000..3d706d9d622d --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-content-004-ref.html @@ -0,0 +1,26 @@ + + + + +CSS Reference: ::marker pseudo elements styled with 'content' property and display:flex + + + + +
                      1. B
                      2. C
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-content-004.html b/testing/web-platform/tests/css/css-pseudo/marker-content-004.html new file mode 100644 index 000000000000..24dbaae123cc --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-content-004.html @@ -0,0 +1,25 @@ + + + + +CSS Test: ::marker pseudo elements styled with 'content' property and display:flex + + + + + + +
                      1. B
                      2. C
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-content-005-ref.html b/testing/web-platform/tests/css/css-pseudo/marker-content-005-ref.html new file mode 100644 index 000000000000..46e77ddc2778 --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-content-005-ref.html @@ -0,0 +1,14 @@ + + + + +CSS Reference: ::marker pseudo elements styled with 'content' property + + + + +
                      1. B
                      2. C
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-content-005.html b/testing/web-platform/tests/css/css-pseudo/marker-content-005.html new file mode 100644 index 000000000000..ad37a65738f9 --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-content-005.html @@ -0,0 +1,22 @@ + + + + +CSS Test: ::marker pseudo elements styled with 'content' property + + + + + + +
                      1. B
                      2. C
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-content-006-ref.html b/testing/web-platform/tests/css/css-pseudo/marker-content-006-ref.html new file mode 100644 index 000000000000..f258c88731e5 --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-content-006-ref.html @@ -0,0 +1,24 @@ + + + + +CSS Reference: ::marker pseudo elements styled with 'content' property + + + + +
                      1. c
                      2. cB
                      3. cC
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-content-006.html b/testing/web-platform/tests/css/css-pseudo/marker-content-006.html new file mode 100644 index 000000000000..bf941ef3b1e8 --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-content-006.html @@ -0,0 +1,28 @@ + + + + +CSS Test: ::marker pseudo elements styled with 'content' property + + + + + + +
                      1. B
                      2. C
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-content-007-ref.html b/testing/web-platform/tests/css/css-pseudo/marker-content-007-ref.html new file mode 100644 index 000000000000..8cec2799c2e0 --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-content-007-ref.html @@ -0,0 +1,28 @@ + + + + +CSS Reference: ::marker pseudo elements styled with 'content' property and display:inline-grid + + + + +
                      1. c
                      2. cB
                      3. cC
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-content-007.html b/testing/web-platform/tests/css/css-pseudo/marker-content-007.html new file mode 100644 index 000000000000..fb452666e3c1 --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-content-007.html @@ -0,0 +1,30 @@ + + + + +CSS Test: ::marker pseudo elements styled with 'content' property and display:inline-grid + + + + + + +
                      1. B
                      2. C
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-content-008-ref.html b/testing/web-platform/tests/css/css-pseudo/marker-content-008-ref.html new file mode 100644 index 000000000000..6d5052b378b7 --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-content-008-ref.html @@ -0,0 +1,21 @@ + + + + +CSS Reference: ::marker pseudo elements styled with 'content' property + + + + +
                      1. c
                      2. cB
                      3. cC
                      +
                      1. c
                      2. cB
                      3. cC
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-content-008.html b/testing/web-platform/tests/css/css-pseudo/marker-content-008.html new file mode 100644 index 000000000000..88aee13dc8c9 --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-content-008.html @@ -0,0 +1,28 @@ + + + + +CSS Test: ::marker pseudo elements styled with 'content' property + + + + + + +
                      1. B
                      2. C
                      +
                      1. B
                      2. C
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-list-style-position-ref.html b/testing/web-platform/tests/css/css-pseudo/marker-list-style-position-ref.html new file mode 100644 index 000000000000..2593194d298f --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-list-style-position-ref.html @@ -0,0 +1,26 @@ + + + + +CSS Reference: ::marker pseudo elements styled with 'list-style-position' property + + + + +
                      1. B
                      2. C
                      +
                      1. B
                      2. C
                      +
                      1. B
                      2. C
                      +
                      1. B
                      2. C
                      + + diff --git a/testing/web-platform/tests/css/css-pseudo/marker-list-style-position.html b/testing/web-platform/tests/css/css-pseudo/marker-list-style-position.html new file mode 100644 index 000000000000..5b4391d4e7e4 --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/marker-list-style-position.html @@ -0,0 +1,35 @@ + + + + +CSS Test: ::marker pseudo elements styled with 'list-style-position' property + + + + + + + +
                      1. B
                      2. C
                      +
                      1. B
                      2. C
                      +
                      1. B
                      2. C
                      +
                      1. B
                      2. C
                      + + diff --git a/toolkit/components/remote/nsXRemoteServer.cpp b/toolkit/components/remote/nsXRemoteServer.cpp index c8d6eedc0180..8753dcf43b4c 100644 --- a/toolkit/components/remote/nsXRemoteServer.cpp +++ b/toolkit/components/remote/nsXRemoteServer.cpp @@ -111,7 +111,7 @@ bool nsXRemoteServer::HandleNewProperty(XID aWindowId, Display *aDisplay, result = XGetWindowProperty( aDisplay, aWindowId, aChangedAtom, 0, /* long_offset */ (65536 / sizeof(long)), /* long_length */ - True, /* atomic delete after */ + X11True, /* atomic delete after */ XA_STRING, /* req_type */ &actual_type, /* actual_type return */ &actual_format, /* actual_format_return */ @@ -156,7 +156,7 @@ void nsXRemoteServer::EnsureAtoms(void) { if (sMozVersionAtom) return; XInternAtoms(mozilla::DefaultXDisplay(), const_cast(XAtomNames), - ArrayLength(XAtomNames), False, XAtoms); + ArrayLength(XAtomNames), X11False, XAtoms); int i = 0; sMozVersionAtom = XAtoms[i++]; diff --git a/toolkit/xre/nsGDKErrorHandler.cpp b/toolkit/xre/nsGDKErrorHandler.cpp index d67712c1515b..da94dc47763d 100644 --- a/toolkit/xre/nsGDKErrorHandler.cpp +++ b/toolkit/xre/nsGDKErrorHandler.cpp @@ -104,6 +104,6 @@ void InstallGdkErrorHandler() { G_LOG_FLAG_RECURSION), GdkErrorHandler, nullptr); if (PR_GetEnv("MOZ_X_SYNC")) { - XSynchronize(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), True); + XSynchronize(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), X11True); } } diff --git a/toolkit/xre/nsX11ErrorHandler.cpp b/toolkit/xre/nsX11ErrorHandler.cpp index 514a2d3174b7..22052640a218 100644 --- a/toolkit/xre/nsX11ErrorHandler.cpp +++ b/toolkit/xre/nsX11ErrorHandler.cpp @@ -96,7 +96,7 @@ int X11Error(Display *display, XErrorEvent *event) { // XSynchronize returns the previous "after function". If a second // XSynchronize call returns the same function after an enable call then // synchronization must have already been enabled. - if (XSynchronize(display, True) == XSynchronize(display, False)) { + if (XSynchronize(display, X11True) == XSynchronize(display, X11False)) { notes.AppendLiteral("; sync"); } else { notes.AppendLiteral("; "); @@ -141,6 +141,6 @@ void InstallX11ErrorHandler() { Display *display = mozilla::DefaultXDisplay(); NS_ASSERTION(display, "No X display"); if (PR_GetEnv("MOZ_X_SYNC")) { - XSynchronize(display, True); + XSynchronize(display, X11True); } } diff --git a/widget/gtk/ScreenHelperGTK.cpp b/widget/gtk/ScreenHelperGTK.cpp index 65c3768fdbc8..db1a6497cac8 100644 --- a/widget/gtk/ScreenHelperGTK.cpp +++ b/widget/gtk/ScreenHelperGTK.cpp @@ -85,7 +85,7 @@ ScreenHelperGTK::ScreenHelperGTK() gdk_window_add_filter(mRootWindow, root_window_event_filter, this); if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) { mNetWorkareaAtom = - XInternAtom(GDK_WINDOW_XDISPLAY(mRootWindow), "_NET_WORKAREA", False); + XInternAtom(GDK_WINDOW_XDISPLAY(mRootWindow), "_NET_WORKAREA", X11False); } #endif RefreshScreens(); diff --git a/widget/gtk/nsClipboardX11.cpp b/widget/gtk/nsClipboardX11.cpp index b1debc84ecb7..369d78cccb3d 100644 --- a/widget/gtk/nsClipboardX11.cpp +++ b/widget/gtk/nsClipboardX11.cpp @@ -125,12 +125,12 @@ static Bool checkEventProc(Display *display, XEvent *event, XPointer arg) { gdk_window_get_user_data(cbWindow, (gpointer *)&cbWidget); if (cbWidget && GTK_IS_WIDGET(cbWidget)) { context->cbWidget = cbWidget; - return True; + return X11True; } } } - return False; + return X11False; } bool nsRetrievalContextX11::WaitForX11Content() { diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index fdc38ccd738c..46e46a8d0454 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -4831,7 +4831,7 @@ void nsWindow::SetWindowDecoration(nsBorderStyle aStyle) { // and GetWindowPos is called) #ifdef MOZ_X11 if (mIsX11Display) { - XSync(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), False); + XSync(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), X11False); } else #endif /* MOZ_X11 */ { diff --git a/xpcom/ds/StaticAtoms.py b/xpcom/ds/StaticAtoms.py index 699a314bf8f9..d2ae5b098d6d 100644 --- a/xpcom/ds/StaticAtoms.py +++ b/xpcom/ds/StaticAtoms.py @@ -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"), @@ -1411,6 +1412,7 @@ STATIC_ATOMS = [ Atom("limitingConeAngle", "limitingConeAngle"), Atom("linear", "linear"), Atom("linearGradient", "linearGradient"), + Atom("list_item", "list-item"), Atom("list_style_type", "list-style-type"), Atom("luminanceToAlpha", "luminanceToAlpha"), Atom("luminosity", "luminosity"), @@ -2065,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"), @@ -2380,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"), @@ -2387,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"),