mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Merge mozilla-central to autoland
This commit is contained in:
commit
35c8a01713
@ -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;
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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},
|
||||
];
|
||||
|
||||
|
@ -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));
|
||||
});
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -236,6 +236,7 @@ class AllChildrenIterator : private FlattenedChildIterator {
|
||||
|
||||
enum IteratorPhase {
|
||||
eAtBegin,
|
||||
eAtMarkerKid,
|
||||
eAtBeforeKid,
|
||||
eAtExplicitKids,
|
||||
eAtAnonKids,
|
||||
|
@ -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,
|
||||
|
@ -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},
|
||||
};
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
||||
|
10
js/src/jit-test/tests/gc/bug-1532376.js
Normal file
10
js/src/jit-test/tests/gc/bug-1532376.js
Normal 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()}
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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_;
|
||||
};
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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(); }
|
||||
};
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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.
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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());
|
||||
|
||||
|
@ -170,6 +170,10 @@ class Assembler : public AssemblerShared {
|
||||
const Disassembler::HeapAccess& heapAccess) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
void setUnlimitedBuffer() {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
};
|
||||
|
||||
class Operand {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -826,7 +826,7 @@ struct AssemblerBufferWithConstantPools
|
||||
// check.
|
||||
MOZ_ASSERT_IF(numPoolEntries, !canNotPlacePool_);
|
||||
|
||||
if (this->oom() && !this->bail()) {
|
||||
if (this->oom()) {
|
||||
return BufferOffset();
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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};
|
||||
|
@ -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.
|
||||
|
@ -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_));
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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());
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 =
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
//
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
li::-moz-list-bullet {
|
||||
li::marker {
|
||||
direction: rtl;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
*::-moz-list-bullet, * {
|
||||
*::marker, * {
|
||||
transform-style:preserve-3d;
|
||||
}
|
||||
</style>
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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(' ');
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -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>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
.foo::-moz-list-bullet { color: red }
|
||||
.foo::marker { color: red }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -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
|
||||
|
@ -5,5 +5,5 @@
|
||||
2147483647
|
||||
2147483647
|
||||
-2147483647
|
||||
-2147483647
|
||||
-2147483647
|
||||
0
|
||||
0
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user