Merge mozilla-central to autoland

This commit is contained in:
arthur.iakab 2019-03-25 17:54:29 +02:00
commit 35c8a01713
199 changed files with 1990 additions and 1088 deletions

View File

@ -39,7 +39,7 @@ HTMLLIAccessible::HTMLLIAccessible(nsIContent* aContent, DocAccessible* aDoc)
mType = eHTMLLiType;
nsBlockFrame* blockFrame = do_QueryFrame(GetFrame());
if (blockFrame && blockFrame->HasBullet()) {
if (blockFrame && blockFrame->HasMarker()) {
mBullet = new HTMLListBulletAccessible(mContent, mDoc);
Document()->BindToDocument(mBullet, nullptr);
AppendChild(mBullet);
@ -120,7 +120,7 @@ HTMLListBulletAccessible::HTMLListBulletAccessible(nsIContent* aContent,
nsIFrame* HTMLListBulletAccessible::GetFrame() const {
nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame());
return blockFrame ? blockFrame->GetBullet() : nullptr;
return blockFrame ? blockFrame->GetMarker() : nullptr;
}
ENameValueFlag HTMLListBulletAccessible::Name(nsString& aName) const {
@ -129,7 +129,7 @@ ENameValueFlag HTMLListBulletAccessible::Name(nsString& aName) const {
// Native anonymous content, ARIA can't be used. Get list bullet text.
nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame());
if (blockFrame) {
blockFrame->GetSpokenBulletText(aName);
blockFrame->GetSpokenMarkerText(aName);
}
return eNameOK;
@ -146,7 +146,7 @@ void HTMLListBulletAccessible::AppendTextTo(nsAString& aText,
uint32_t aLength) {
nsAutoString bulletText;
nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame());
if (blockFrame) blockFrame->GetSpokenBulletText(bulletText);
if (blockFrame) blockFrame->GetSpokenMarkerText(bulletText);
aText.Append(Substring(bulletText, aStartOffset, aLength));
}
@ -156,5 +156,5 @@ void HTMLListBulletAccessible::AppendTextTo(nsAString& aText,
bool HTMLListBulletAccessible::IsInside() const {
nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame());
return blockFrame ? blockFrame->HasInsideBullet() : false;
return blockFrame ? blockFrame->HasInsideMarker() : false;
}

View File

@ -48,6 +48,7 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
"content",
"counter-increment",
"counter-reset",
"counter-set",
"cursor",
"direction",
"dominant-baseline",
@ -92,6 +93,7 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
"list-style-image",
"list-style-position",
"list-style-type",
"-moz-list-reversed",
"marker-end",
"marker-mid",
"marker-start",

View File

@ -32,7 +32,7 @@ Test that css-logic calculates CSS specificity properly
{text: "* body#home div#warning p.message", expected: 2098179},
{text: "#footer :not(nav) li", expected: 1048578},
{text: "bar:nth-child(n)", expected: 1025},
{text: "li::-moz-list-number", expected: 2},
{text: "li::marker", expected: 2},
{text: "a:hover", expected: 1025},
];

View File

@ -82,7 +82,7 @@ addTest(function inheritedSystemStyles() {
ok(!applied[1].rule.parentStyleSheet.system, "Entry 1 should be a system style");
is(applied[1].rule.type, 1, "Entry 1 should be a rule style");
is(applied.length, 13, "Should have 13 rules.");
is(applied.length, 12, "Should have 12 rules.");
}).then(runNextTest));
});

View File

@ -3116,6 +3116,7 @@ exports.CSS_PROPERTIES = {
"content",
"counter-increment",
"counter-reset",
"counter-set",
"opacity",
"box-shadow",
"clip",
@ -5749,6 +5750,20 @@ exports.CSS_PROPERTIES = {
"unset"
]
},
"counter-set": {
"isInherited": false,
"subproperties": [
"counter-set"
],
"supports": [],
"values": [
"inherit",
"initial",
"none",
"revert",
"unset"
]
},
"cursor": {
"isInherited": true,
"subproperties": [
@ -10209,6 +10224,7 @@ exports.CSS_PROPERTIES = {
exports.PSEUDO_ELEMENTS = [
":after",
":before",
":marker",
":backdrop",
":cue",
":first-letter",
@ -10216,8 +10232,6 @@ exports.PSEUDO_ELEMENTS = [
":selection",
":-moz-focus-inner",
":-moz-focus-outer",
":-moz-list-bullet",
":-moz-list-number",
":-moz-progress-bar",
":-moz-range-track",
":-moz-range-progress",

View File

@ -295,6 +295,12 @@ nsIContent* ExplicitChildIterator::GetPreviousChild() {
nsIContent* AllChildrenIterator::Get() const {
switch (mPhase) {
case eAtMarkerKid: {
Element* marker = nsLayoutUtils::GetMarkerPseudo(mOriginalContent);
MOZ_ASSERT(marker, "No content marker frame at eAtMarkerKid phase");
return marker;
}
case eAtBeforeKid: {
Element* before = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
MOZ_ASSERT(before, "No content before frame at eAtBeforeKid phase");
@ -319,7 +325,15 @@ nsIContent* AllChildrenIterator::Get() const {
}
bool AllChildrenIterator::Seek(const nsIContent* aChildToFind) {
if (mPhase == eAtBegin || mPhase == eAtBeforeKid) {
if (mPhase == eAtBegin || mPhase == eAtMarkerKid) {
mPhase = eAtBeforeKid;
Element* markerPseudo = nsLayoutUtils::GetMarkerPseudo(mOriginalContent);
if (markerPseudo && markerPseudo == aChildToFind) {
mPhase = eAtMarkerKid;
return true;
}
}
if (mPhase == eAtBeforeKid) {
mPhase = eAtExplicitKids;
Element* beforePseudo = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
if (beforePseudo && beforePseudo == aChildToFind) {
@ -350,6 +364,14 @@ void AllChildrenIterator::AppendNativeAnonymousChildren() {
nsIContent* AllChildrenIterator::GetNextChild() {
if (mPhase == eAtBegin) {
Element* markerContent = nsLayoutUtils::GetMarkerPseudo(mOriginalContent);
if (markerContent) {
mPhase = eAtMarkerKid;
return markerContent;
}
}
if (mPhase == eAtBegin || mPhase == eAtMarkerKid) {
mPhase = eAtExplicitKids;
Element* beforeContent = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
if (beforeContent) {
@ -442,6 +464,14 @@ nsIContent* AllChildrenIterator::GetPreviousChild() {
}
}
if (mPhase == eAtExplicitKids || mPhase == eAtBeforeKid) {
Element* markerContent = nsLayoutUtils::GetMarkerPseudo(mOriginalContent);
if (markerContent) {
mPhase = eAtMarkerKid;
return markerContent;
}
}
mPhase = eAtBegin;
return nullptr;
}

View File

@ -236,6 +236,7 @@ class AllChildrenIterator : private FlattenedChildIterator {
enum IteratorPhase {
eAtBegin,
eAtMarkerKid,
eAtBeforeKid,
eAtExplicitKids,
eAtAnonKids,

View File

@ -303,6 +303,11 @@ class nsIContent : public nsINode {
mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentafter;
}
bool IsGeneratedContentContainerForMarker() const {
return IsRootOfNativeAnonymousSubtree() &&
mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentmarker;
}
/**
* Get direct access (but read only) to the text in the text content.
* NOTE: For elements this is *not* the concatenation of all text children,

View File

@ -67,6 +67,18 @@ void HTMLLIElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
value->GetEnumValue());
}
// Map <li value=INTEGER> 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},
};

View File

@ -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<int32_t>::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();
}

View File

@ -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

View File

@ -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;

View File

@ -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<void*>(&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

View File

@ -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

View File

@ -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();

View File

@ -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);
}

View File

@ -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 */

View File

@ -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> 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) {

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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<ArrayObject>().lastProperty());
gc::InitialHeap heap = GetInitialHeap(GenericObject, &ArrayObject::class_);
gc::InitialHeap heap = GetInitialHeap(GenericObject, group);
Rooted<ArrayObject*> 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) {

View File

@ -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,

View File

@ -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);

View File

@ -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<ClosureInfo*>(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) {

View File

@ -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<JSObject*> mType; // CType of the field
HeapPtr<JSObject*> 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<JSObject*> mABI;
HeapPtr<JSObject*> mABI;
// The CType of the value returned by the function.
JS::Heap<JSObject*> mReturnType;
HeapPtr<JSObject*> mReturnType;
// A fixed array of known parameter types, excluding any variadic
// parameters (if mIsVariadic).
Vector<JS::Heap<JSObject*>, 0, SystemAllocPolicy> mArgTypes;
GCVector<HeapPtr<JSObject*>, 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<JSObject*> closureObj; // CClosure object
JS::Heap<JSObject*> typeObj; // FunctionType describing the C function
JS::Heap<JSObject*> thisObj; // 'this' object to use for the JS function call
JS::Heap<JSObject*> jsfnObj; // JS function
HeapPtr<JSObject*> closureObj; // CClosure object
HeapPtr<JSObject*> typeObj; // FunctionType describing the C function
HeapPtr<JSObject*> thisObj; // 'this' object to use for the JS function call
HeapPtr<JSObject*> jsfnObj; // JS function
void* errResult; // Result that will be returned if the closure throws
ffi_closure* closure; // The C closure itself

View File

@ -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()}

View File

@ -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<Fn, js::NewDenseCopyOnWriteArray>()) {
return false;
}

View File

@ -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<Fn, js::NewDenseCopyOnWriteArray>(
lir, ArgList(ImmGCPtr(templateObject), Imm32(initialHeap)),
StoreRegisterTo(objReg));
lir, ArgList(ImmGCPtr(templateObject)), StoreRegisterTo(objReg));
TemplateObject templateObj(templateObject);
templateObj.setDenseElementsAreCopyOnWrite();

View File

@ -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);

View File

@ -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_;
};

View File

@ -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
}

View File

@ -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(); }
};

View File

@ -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.

View File

@ -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<ArrayObject>());
RootedValue result(cx);
ArrayObject* resultObject =
NewDenseCopyOnWriteArray(cx, templateObject, initialHeap_);
ArrayObject* resultObject = NewDenseCopyOnWriteArray(cx, templateObject);
if (!resultObject) {
return false;
}

View File

@ -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)

View File

@ -1619,10 +1619,8 @@ BufferOffset Assembler::as_BranchPool(uint32_t value, RepatchLabel* label,
if (label->bound()) {
BufferOffset dest(label);
BOffImm offset = dest.diffB<BOffImm>(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<BOffImm>(ret), c, ret);
BOffImm offset = BufferOffset(l).diffB<BOffImm>(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<BOffImm>(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<BOffImm>(b);
if (offset.isInvalid()) {
m_buffer.fail_bail();
return;
}
MOZ_RELEASE_ASSERT(!offset.isInvalid(),
"Buffer size limit should prevent this");
if (branch.is<InstBImm>()) {
as_b(offset, c, b);
} else if (branch.is<InstBLImm>()) {
@ -2268,10 +2257,8 @@ void Assembler::bind(RepatchLabel* label) {
}
BOffImm offset = dest.diffB<BOffImm>(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());

View File

@ -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.

View File

@ -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());

View File

@ -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<BOffImm>(inst), Always, inst);
BOffImm off = BufferOffset(calleeOffset).diffB<BOffImm>(inst);
MOZ_RELEASE_ASSERT(!off.isInvalid(),
"Failed to insert necessary far jump islands");
as_bl(off, Always, inst);
}
CodeOffset MacroAssembler::farJumpWithPatch() {

View File

@ -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();

View File

@ -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.

View File

@ -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());

View File

@ -170,6 +170,10 @@ class Assembler : public AssemblerShared {
const Disassembler::HeapAccess& heapAccess) {
MOZ_CRASH();
}
void setUnlimitedBuffer() {
MOZ_CRASH();
}
};
class Operand {

View File

@ -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;
}

View File

@ -826,7 +826,7 @@ struct AssemblerBufferWithConstantPools
// check.
MOZ_ASSERT_IF(numPoolEntries, !canNotPlacePool_);
if (this->oom() && !this->bail()) {
if (this->oom()) {
return BufferOffset();
}

View File

@ -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();

View File

@ -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};

View File

@ -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.

View File

@ -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<CallObject>();
}
@ -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_));

View File

@ -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,

View File

@ -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<PropertyIteratorObject>();
@ -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);

View File

@ -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.

View File

@ -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

View File

@ -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<TaggedProto> proto,
NewObjectKind newKind,

View File

@ -522,9 +522,11 @@ inline bool NativeObject::isInWholeCellBuffer() const {
}
/* static */ inline JS::Result<NativeObject*, JS::OOM&>
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<NativeObject>().lastProperty());
gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());

View File

@ -559,7 +559,7 @@ class NativeObject : public ShapedObject {
js::HandleShape shape, js::HandleObjectGroup group);
static inline JS::Result<NativeObject*, JS::OOM&> createWithTemplate(
JSContext* cx, js::gc::InitialHeap heap, HandleObject templateObject);
JSContext* cx, HandleObject templateObject);
#ifdef DEBUG
static void enableShapeConsistencyChecks();

View File

@ -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) {

View File

@ -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);

View File

@ -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 =

View File

@ -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() {

View File

@ -2050,10 +2050,6 @@ static const nsIFrame* ExpectedOwnerForChild(const nsIFrame* aFrame) {
: FirstContinuationOrPartOfIBSplit(parent);
}
if (aFrame->IsBulletFrame()) {
return FirstContinuationOrPartOfIBSplit(parent);
}
if (aFrame->IsLineFrame()) {
// A ::first-line always ends up here via its block, which is therefore the
// right expected owner. That block can be an
@ -2744,6 +2740,20 @@ bool RestyleManager::ProcessPostTraversal(Element* aElement,
aRestyleState.AddPendingWrapperRestyle(
ServoRestyleState::TableAwareParentFor(maybeAnonBoxChild));
}
// If we don't have a ::marker pseudo-element, but need it, then
// reconstruct the frame. (The opposite situation implies 'display'
// changes so doesn't need to be handled explicitly here.)
if (styleFrame->StyleDisplay()->mDisplay == StyleDisplay::ListItem &&
styleFrame->IsBlockFrameOrSubclass() &&
!nsLayoutUtils::GetMarkerPseudo(aElement)) {
RefPtr<ComputedStyle> pseudoStyle =
aRestyleState.StyleSet().ProbePseudoElementStyle(
*aElement, PseudoStyleType::marker, styleFrame->Style());
if (pseudoStyle) {
changeHint |= nsChangeHint_ReconstructFrame;
}
}
}
// Although we shouldn't generate non-ReconstructFrame hints for elements with

View File

@ -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<nsIContent> nsCSSFrameConstructor::CreateGeneratedContent(
*
* Any items created are added to aItems.
*
* We create an XML element (tag _moz_generated_content_before or
* _moz_generated_content_after) representing the pseudoelement. We
* create a DOM node for each 'content' item and make those nodes the
* children of the XML element. Then we create a frame subtree for
* the XML element as if it were a regular child of
* aParentFrame/aParentContent, giving the XML element the ::before or
* ::after style.
* We create an XML element (tag _moz_generated_content_before/after/marker)
* representing the pseudoelement. We create a DOM node for each 'content'
* item and make those nodes the children of the XML element. Then we create
* a frame subtree for the XML element as if it were a regular child of
* aParentFrame/aParentContent, giving the XML element the ::before, ::after
* or ::marker style.
*/
void nsCSSFrameConstructor::CreateGeneratedContentItem(
nsFrameConstructorState& aState, nsContainerFrame* aParentFrame,
Element& aOriginatingElement, ComputedStyle& aStyle,
PseudoStyleType aPseudoElement, FrameConstructionItemList& aItems) {
MOZ_ASSERT(aPseudoElement == PseudoStyleType::before ||
aPseudoElement == PseudoStyleType::after,
aPseudoElement == PseudoStyleType::after ||
aPseudoElement == PseudoStyleType::marker,
"unexpected aPseudoElement");
if (aParentFrame && (aParentFrame->IsHTMLVideoFrame() ||
@ -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> nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo(
elemName, nullptr, kNameSpaceID_None, nsINode::ELEMENT_NODE);
RefPtr<Element> 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 <ol reversed> 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<nsBlockFrame*>(*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,

View File

@ -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.
//

View File

@ -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 <ol reversed>.
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",

View File

@ -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 <ol reversed> 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<nsCounterChangeNode*>(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<int32_t>::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<nsStringHashKey, nsCounterList> mNames;
};

View File

@ -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;
}
}

View File

@ -71,8 +71,10 @@ struct nsGenConNode : public mozilla::LinkedListElement<nsGenConNode> {
mPseudoFrame->Style()->GetPseudoType() ==
mozilla::PseudoStyleType::before ||
mPseudoFrame->Style()->GetPseudoType() ==
mozilla::PseudoStyleType::after,
"not :before/:after generated content and not counter change");
mozilla::PseudoStyleType::after ||
mPseudoFrame->Style()->GetPseudoType() ==
mozilla::PseudoStyleType::marker,
"not CSS generated content and not counter change");
NS_ASSERTION(mContentIndex < 0 ||
mPseudoFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT,
"not generated content and not counter change");

View File

@ -1381,7 +1381,8 @@ FrameChildListID nsLayoutUtils::GetChildListNameFor(nsIFrame* aChildFrame) {
static Element* GetPseudo(const nsIContent* aContent, nsAtom* aPseudoProperty) {
MOZ_ASSERT(aPseudoProperty == nsGkAtoms::beforePseudoProperty ||
aPseudoProperty == nsGkAtoms::afterPseudoProperty);
aPseudoProperty == nsGkAtoms::afterPseudoProperty ||
aPseudoProperty == nsGkAtoms::markerPseudoProperty);
if (!aContent->MayHaveAnonymousChildren()) {
return nullptr;
}
@ -1410,6 +1411,17 @@ nsIFrame* nsLayoutUtils::GetAfterFrame(const nsIContent* aContent) {
return pseudo ? pseudo->GetPrimaryFrame() : nullptr;
}
/*static*/
Element* nsLayoutUtils::GetMarkerPseudo(const nsIContent* aContent) {
return GetPseudo(aContent, nsGkAtoms::markerPseudoProperty);
}
/*static*/
nsIFrame* nsLayoutUtils::GetMarkerFrame(const nsIContent* aContent) {
Element* pseudo = GetMarkerPseudo(aContent);
return pseudo ? pseudo->GetPrimaryFrame() : nullptr;
}
// static
nsIFrame* nsLayoutUtils::GetClosestFrameOfType(nsIFrame* aFrame,
LayoutFrameType aFrameType,
@ -1555,6 +1567,8 @@ bool nsLayoutUtils::IsProperAncestorFrame(const nsIFrame* aAncestorFrame,
int32_t nsLayoutUtils::DoCompareTreePosition(
nsIContent* aContent1, nsIContent* aContent2, int32_t aIf1Ancestor,
int32_t aIf2Ancestor, const nsIContent* aCommonAncestor) {
MOZ_ASSERT(aIf1Ancestor == -1 || aIf1Ancestor == 0 || aIf1Ancestor == 1);
MOZ_ASSERT(aIf2Ancestor == -1 || aIf2Ancestor == 0 || aIf2Ancestor == 1);
MOZ_ASSERT(aContent1, "aContent1 must not be null");
MOZ_ASSERT(aContent2, "aContent2 must not be null");
@ -1688,6 +1702,8 @@ int32_t nsLayoutUtils::DoCompareTreePosition(nsIFrame* aFrame1,
int32_t aIf1Ancestor,
int32_t aIf2Ancestor,
nsIFrame* aCommonAncestor) {
MOZ_ASSERT(aIf1Ancestor == -1 || aIf1Ancestor == 0 || aIf1Ancestor == 1);
MOZ_ASSERT(aIf2Ancestor == -1 || aIf2Ancestor == 0 || aIf2Ancestor == 1);
MOZ_ASSERT(aFrame1, "aFrame1 must not be null");
MOZ_ASSERT(aFrame2, "aFrame2 must not be null");
@ -1704,6 +1720,8 @@ int32_t nsLayoutUtils::DoCompareTreePosition(nsIFrame* aFrame1,
int32_t nsLayoutUtils::DoCompareTreePosition(
nsIFrame* aFrame1, nsIFrame* aFrame2, nsTArray<nsIFrame*>& aFrame2Ancestors,
int32_t aIf1Ancestor, int32_t aIf2Ancestor, nsIFrame* aCommonAncestor) {
MOZ_ASSERT(aIf1Ancestor == -1 || aIf1Ancestor == 0 || aIf1Ancestor == 1);
MOZ_ASSERT(aIf2Ancestor == -1 || aIf2Ancestor == 0 || aIf2Ancestor == 1);
MOZ_ASSERT(aFrame1, "aFrame1 must not be null");
MOZ_ASSERT(aFrame2, "aFrame2 must not be null");

View File

@ -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.

View File

@ -49,9 +49,11 @@ void DetailsFrame::SetInitialChildList(ChildListID aListID,
#ifdef DEBUG
bool DetailsFrame::CheckValidMainSummary(const nsFrameList& aFrameList) const {
for (nsIFrame* child : aFrameList) {
if (child->IsGeneratedContentFrame()) {
continue;
}
HTMLSummaryElement* summary =
HTMLSummaryElement::FromNode(child->GetContent());
if (child == aFrameList.FirstChild()) {
if (summary && summary->IsMainSummary()) {
return true;
@ -125,7 +127,7 @@ bool DetailsFrame::HasMainSummaryFrame(nsIFrame* aSummaryFrame) {
child = nsPlaceholderFrame::GetRealFrameFor(child);
// We skip any non-primary frames such as a list-style-position:inside
// bullet frame for the <details> itself.
if (child->IsPrimaryFrame()) {
if (!child->IsGeneratedContentFrame()) {
return aSummaryFrame == child;
}
}

View File

@ -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<const nsBlockFrame*>(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);
}
}

View File

@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<style>
li::-moz-list-bullet {
li::marker {
direction: rtl;
margin-right: 1em;
}

View File

@ -1,7 +1,7 @@
<html>
<head>
<style>
*::-moz-list-bullet, * {
*::marker, * {
transform-style:preserve-3d;
}
</style>

View File

@ -1,5 +1,5 @@
<style>
.c9::-moz-list-bullet, *|* { -moz-border-left-colors: ThreeDDarkShadow cornflowerblue; -moz-column-width: 400.816438698px;</style><source style="direction: ltr; font: 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999pt/375780pt Helvetica; margin: 14350em 65535em -65535; ">><style>body::first-letter {
.c9::marker, *|* { -moz-border-left-colors: ThreeDDarkShadow cornflowerblue; -moz-column-width: 400.816438698px;</style><source style="direction: ltr; font: 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999pt/375780pt Helvetica; margin: 14350em 65535em -65535; ">><style>body::first-letter {
float: left;
</style>
>><i style='-moz-transform: translate(140px) rotate(4228281368deg); display: -moz-inline-grid; '><body dir=rtl>

View File

@ -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<ChildList>* 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<nsBlockFrame*>(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: <LI>\n<P>... ). 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<nsBulletFrame*>(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<ComputedStyle> kidSC =
ResolveBulletStyle(pseudoType, shell->StyleSet());
// Create bullet frame
nsBulletFrame* bullet = new (shell) nsBulletFrame(kidSC, pc);
bullet->Init(mContent, this, nullptr);
// If the list bullet frame should be positioned inside then add
// it to the flow now.
if (styleList->mListStylePosition == NS_STYLE_LIST_STYLE_POSITION_INSIDE) {
nsFrameList bulletList(bullet, bullet);
AddFrames(bulletList, nullptr);
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<ComputedStyle> 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<ComputedStyle> nsBlockFrame::ResolveBulletStyle(
PseudoStyleType aType, ServoStyleSet* aStyleSet) {
ComputedStyle* parentStyle = CorrectStyleParentFrame(this, aType)->Style();
return aStyleSet->ResolvePseudoElementStyle(mContent->AsElement(), aType,
parentStyle, nullptr);
}
nsIFrame* nsBlockFrame::GetFirstLetter() const {
if (!(GetStateBits() & NS_BLOCK_HAS_FIRST_LETTER_STYLE)) {
// Certainly no first-letter frame.
@ -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;
}

View File

@ -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<ComputedStyle> ResolveBulletStyle(
mozilla::PseudoStyleType aType, mozilla::ServoStyleSet* aStyleSet);
#ifdef DEBUG
void VerifyLines(bool aFinalCheckOK);
void VerifyOverflowSituation();

View File

@ -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<nsBulletFrame*>(aItem->Frame());
mOrdinal = f->GetOrdinal();
mOrdinal = f->Ordinal();
}
virtual bool InvalidateForSyncDecodeImages() const override {
@ -581,7 +586,7 @@ class nsDisplayBullet final : public nsDisplayItem {
static_cast<const nsDisplayBulletGeometry*>(aGeometry);
nsBulletFrame* f = static_cast<nsBulletFrame*>(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<BulletRenderer> nsBulletFrame::CreateBulletRenderer(
RefPtr<nsFontMetrics> 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(' ');

View File

@ -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<imgIContainer> GetImage() const;
@ -137,7 +134,6 @@ class nsBulletFrame final : public nsFrame {
RefPtr<nsBulletListener> mListener;
mozilla::LogicalSize mIntrinsicSize;
int32_t mOrdinal;
private:
mozilla::CounterStyle* ResolveCounterStyle();

View File

@ -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<nsContainerFrame*>(FirstInFlow());
if (attr && attr->Type() == nsAttrValue::eInteger) {
ordinal = attr->GetIntegerValue();
} else if (increment < 0) {
// <ol reversed> 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)

View File

@ -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 |<li value="..">| changes, effectively counting them
* and storing the result in |aOrdinal|. This is useful for
* |<ol reversed>|, 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 |<li value="..">|.
*/
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

View File

@ -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());

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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(

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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",

View File

@ -2,7 +2,7 @@
<html>
<head>
<style type="text/css">
.foo::-moz-list-bullet { color: red }
.foo::marker { color: red }
.foo { color: black; }
</style>
</head>

View File

@ -2,7 +2,7 @@
<html>
<head>
<style type="text/css">
.foo::-moz-list-bullet { color: red }
.foo::marker { color: red }
</style>
</head>
<body>

View File

@ -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

View File

@ -5,5 +5,5 @@
2147483647
2147483647
-2147483647
-2147483647
-2147483647
0
0

View File

@ -10,5 +10,6 @@ span::after { content: counter(c); }
<span style="counter-reset: c 2147483648"></span>
<span style="counter-reset: c 2147483649"></span>
<span style="counter-reset: c -2147483647"></span>
<!-- The next two computes to std::numeric_limits<int32_t>::min() which we use as the "magic" number for the content based <ol reversed> start value. See https://drafts.csswg.org/css-lists-3/#ua-stylesheet -->
<span style="counter-reset: c -2147483648"></span>
<span style="counter-reset: c -2147483649"></span>

View File

@ -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;
}

View File

@ -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;
}

View File

@ -4,7 +4,7 @@
<html>
<style>
summary::-moz-list-bullet {
summary::marker {
/* Hide the triangle for comparing with div in reftest. */
list-style-type: none;
}

View File

@ -4,7 +4,7 @@
<html class="reftest-paged">
<style>
summary::-moz-list-bullet {
summary::marker {
/* Hide the triangle for comparing with div in reftest. */
list-style-type: none;
}

Some files were not shown because too many files have changed in this diff Show More