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:
\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 |
| 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 |
|.
- */
- 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>
<%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
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 @@