mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-13 21:35:39 +00:00
Merge inbound to central, a=merge
MozReview-Commit-ID: 4igUgM6r0wO
This commit is contained in:
commit
d509baac11
@ -1495,6 +1495,10 @@ a11y::ProxyEvent(ProxyAccessible* aTarget, uint32_t aEventType)
|
||||
case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
|
||||
g_object_notify((GObject*)wrapper, "accessible-value");
|
||||
break;
|
||||
case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED:
|
||||
case nsIAccessibleEvent::EVENT_SELECTION_WITHIN:
|
||||
g_signal_emit_by_name(wrapper, "selection_changed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1610,6 +1614,13 @@ MaiAtkObject::FireAtkShowHideEvent(AtkObject* aParent, bool aIsAdded,
|
||||
g_signal_emit_by_name(aParent, signal_name, indexInParent, this, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
a11y::ProxySelectionEvent(ProxyAccessible*, ProxyAccessible* aWidget, uint32_t)
|
||||
{
|
||||
MaiAtkObject* obj = MAI_ATK_OBJECT(GetWrapperFor(aWidget));
|
||||
g_signal_emit_by_name(obj, "selection_changed");
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
AccessibleWrap::GetKeyBinding(Accessible* aAccessible, nsAString& aResult)
|
||||
|
@ -77,6 +77,8 @@ void ProxyTextChangeEvent(ProxyAccessible* aTarget, const nsString& aStr,
|
||||
bool aFromUser);
|
||||
void ProxyShowHideEvent(ProxyAccessible* aTarget, ProxyAccessible* aParent,
|
||||
bool aInsert, bool aFromUser);
|
||||
void ProxySelectionEvent(ProxyAccessible* aTarget, ProxyAccessible* aWidget,
|
||||
uint32_t aType);
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -884,6 +884,15 @@ Accessible::HandleAccEvent(AccEvent* aEvent)
|
||||
event->IsFromUserInput());
|
||||
break;
|
||||
}
|
||||
case nsIAccessibleEvent::EVENT_SELECTION:
|
||||
case nsIAccessibleEvent::EVENT_SELECTION_ADD:
|
||||
case nsIAccessibleEvent::EVENT_SELECTION_REMOVE: {
|
||||
AccSelChangeEvent* selEvent = downcast_accEvent(aEvent);
|
||||
uint64_t widgetID = selEvent->Widget()->IsDoc() ? 0 :
|
||||
reinterpret_cast<uintptr_t>(selEvent->Widget());
|
||||
ipcDoc->SendSelectionEvent(id, widgetID, aEvent->GetEventType());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ipcDoc->SendEvent(id, aEvent->GetEventType());
|
||||
}
|
||||
|
@ -160,6 +160,25 @@ DocAccessible::GetAccessibleEvenIfNotInMapOrContainer(nsINode* aNode) const
|
||||
return acc ? acc : GetContainerAccessible(aNode);
|
||||
}
|
||||
|
||||
inline void
|
||||
DocAccessible::CreateSubtree(Accessible* aChild)
|
||||
{
|
||||
// If a focused node has been shown then it could mean its frame was recreated
|
||||
// while the node stays focused and we need to fire focus event on
|
||||
// the accessible we just created. If the queue contains a focus event for
|
||||
// this node already then it will be suppressed by this one.
|
||||
Accessible* focusedAcc = nullptr;
|
||||
CacheChildrenInSubtree(aChild, &focusedAcc);
|
||||
|
||||
// XXX: do we really want to send focus to focused DOM node not taking into
|
||||
// account active item?
|
||||
if (focusedAcc) {
|
||||
FocusMgr()->DispatchFocusEvent(this, focusedAcc);
|
||||
SelectionMgr()->
|
||||
SetControlSelectionListener(focusedAcc->GetNode()->AsElement());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -1762,7 +1762,6 @@ DocAccessible::ProcessContentInserted(Accessible* aContainer,
|
||||
aContainer);
|
||||
#endif
|
||||
|
||||
uint32_t updateFlags = 0;
|
||||
TreeMutation mt(aContainer);
|
||||
do {
|
||||
Accessible* parent = iter.Child()->Parent();
|
||||
@ -1791,7 +1790,7 @@ DocAccessible::ProcessContentInserted(Accessible* aContainer,
|
||||
#endif
|
||||
|
||||
mt.AfterInsertion(iter.Child());
|
||||
updateFlags |= UpdateTreeInternal(iter.Child(), true);
|
||||
CreateSubtree(iter.Child());
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1805,7 +1804,7 @@ DocAccessible::ProcessContentInserted(Accessible* aContainer,
|
||||
aContainer);
|
||||
#endif
|
||||
|
||||
FireEventsOnInsertion(aContainer, updateFlags);
|
||||
FireEventsOnInsertion(aContainer);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1828,25 +1827,18 @@ DocAccessible::ProcessContentInserted(Accessible* aContainer, nsIContent* aNode)
|
||||
mt.AfterInsertion(child);
|
||||
mt.Done();
|
||||
|
||||
uint32_t flags = UpdateTreeInternal(child, true);
|
||||
FireEventsOnInsertion(aContainer, flags);
|
||||
CreateSubtree(child);
|
||||
FireEventsOnInsertion(aContainer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DocAccessible::FireEventsOnInsertion(Accessible* aContainer,
|
||||
uint32_t aUpdateFlags)
|
||||
DocAccessible::FireEventsOnInsertion(Accessible* aContainer)
|
||||
{
|
||||
// Content insertion did not cause an accessible tree change.
|
||||
if (aUpdateFlags == eNoAccessible) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check to see if change occurred inside an alert, and fire an EVENT_ALERT
|
||||
// if it did.
|
||||
if (!(aUpdateFlags & eAlertAccessible) &&
|
||||
(aContainer->IsAlert() || aContainer->IsInsideAlert())) {
|
||||
if (aContainer->IsAlert() || aContainer->IsInsideAlert()) {
|
||||
Accessible* ancestor = aContainer;
|
||||
do {
|
||||
if (ancestor->IsAlert()) {
|
||||
@ -1880,72 +1872,23 @@ DocAccessible::UpdateTreeOnRemoval(Accessible* aContainer, nsIContent* aChildNod
|
||||
TreeMutation mt(aContainer);
|
||||
if (child) {
|
||||
mt.BeforeRemoval(child);
|
||||
UpdateTreeInternal(child, false);
|
||||
MOZ_ASSERT(aContainer == child->Parent(), "Wrong parent");
|
||||
aContainer->RemoveChild(child);
|
||||
UncacheChildrenInSubtree(child);
|
||||
mt.Done();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
TreeWalker walker(aContainer, aChildNode, TreeWalker::eWalkCache);
|
||||
Accessible* child = walker.Next();
|
||||
if (child) {
|
||||
do {
|
||||
mt.BeforeRemoval(child);
|
||||
UpdateTreeInternal(child, false);
|
||||
}
|
||||
while ((child = walker.Next()));
|
||||
}
|
||||
|
||||
TreeWalker walker(aContainer, aChildNode, TreeWalker::eWalkCache);
|
||||
while (Accessible* child = walker.Next()) {
|
||||
mt.BeforeRemoval(child);
|
||||
MOZ_ASSERT(aContainer == child->Parent(), "Wrong parent");
|
||||
aContainer->RemoveChild(child);
|
||||
UncacheChildrenInSubtree(child);
|
||||
}
|
||||
mt.Done();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
DocAccessible::UpdateTreeInternal(Accessible* aChild, bool aIsInsert)
|
||||
{
|
||||
uint32_t updateFlags = eAccessible;
|
||||
|
||||
// If a focused node has been shown then it could mean its frame was recreated
|
||||
// while the node stays focused and we need to fire focus event on
|
||||
// the accessible we just created. If the queue contains a focus event for
|
||||
// this node already then it will be suppressed by this one.
|
||||
Accessible* focusedAcc = nullptr;
|
||||
|
||||
if (aIsInsert) {
|
||||
// Create accessible tree for shown accessible.
|
||||
CacheChildrenInSubtree(aChild, &focusedAcc);
|
||||
}
|
||||
|
||||
if (aIsInsert) {
|
||||
roles::Role ariaRole = aChild->ARIARole();
|
||||
if (ariaRole == roles::MENUPOPUP) {
|
||||
// Fire EVENT_MENUPOPUP_START if ARIA menu appears.
|
||||
FireDelayedEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START, aChild);
|
||||
|
||||
} else if (ariaRole == roles::ALERT) {
|
||||
// Fire EVENT_ALERT if ARIA alert appears.
|
||||
updateFlags = eAlertAccessible;
|
||||
FireDelayedEvent(nsIAccessibleEvent::EVENT_ALERT, aChild);
|
||||
}
|
||||
} else {
|
||||
// Update the tree for content removal.
|
||||
// The accessible parent may differ from container accessible if
|
||||
// the parent doesn't have own DOM node like list accessible for HTML
|
||||
// selects.
|
||||
Accessible* parent = aChild->Parent();
|
||||
NS_ASSERTION(parent, "No accessible parent?!");
|
||||
if (parent)
|
||||
parent->RemoveChild(aChild);
|
||||
|
||||
UncacheChildrenInSubtree(aChild);
|
||||
}
|
||||
|
||||
// XXX: do we really want to send focus to focused DOM node not taking into
|
||||
// account active item?
|
||||
if (focusedAcc) {
|
||||
FocusMgr()->DispatchFocusEvent(this, focusedAcc);
|
||||
SelectionMgr()->SetControlSelectionListener(focusedAcc->GetNode()->AsElement());
|
||||
}
|
||||
|
||||
return updateFlags;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessible::RelocateARIAOwnedIfNeeded(nsIContent* aElement)
|
||||
{
|
||||
@ -2045,8 +1988,8 @@ DocAccessible::DoARIAOwnsRelocation(Accessible* aOwner)
|
||||
insertIdx = child->IndexInParent() + 1;
|
||||
arrayIdx++;
|
||||
|
||||
uint32_t flags = UpdateTreeInternal(child, true);
|
||||
FireEventsOnInsertion(aOwner, flags);
|
||||
CreateSubtree(child);
|
||||
FireEventsOnInsertion(aOwner);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
@ -2233,12 +2176,26 @@ DocAccessible::CacheChildrenInSubtree(Accessible* aRoot,
|
||||
mt.Done();
|
||||
}
|
||||
|
||||
// Fire document load complete on ARIA documents.
|
||||
// XXX: we should delay an event if the ARIA document has aria-busy.
|
||||
if (aRoot->HasARIARole() && !aRoot->IsDoc()) {
|
||||
a11y::role role = aRoot->ARIARole();
|
||||
if (role == roles::DIALOG || role == roles::DOCUMENT)
|
||||
FireDelayedEvent(nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE, aRoot);
|
||||
// Fire events for ARIA elements.
|
||||
if (!aRoot->HasARIARole()) {
|
||||
return;
|
||||
}
|
||||
|
||||
roles::Role role = aRoot->ARIARole();
|
||||
if (role == roles::MENUPOPUP) {
|
||||
FireDelayedEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START, aRoot);
|
||||
return;
|
||||
}
|
||||
|
||||
if (role == roles::ALERT) {
|
||||
FireDelayedEvent(nsIAccessibleEvent::EVENT_ALERT, aRoot);
|
||||
return;
|
||||
}
|
||||
|
||||
// XXX: we should delay document load complete event if the ARIA document
|
||||
// has aria-busy.
|
||||
if (!aRoot->IsDoc() && (role == roles::DIALOG || role == roles::DOCUMENT)) {
|
||||
FireDelayedEvent(nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE, aRoot);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,7 +187,7 @@ public:
|
||||
*/
|
||||
void FireDelayedEvent(AccEvent* aEvent);
|
||||
void FireDelayedEvent(uint32_t aEventType, Accessible* aTarget);
|
||||
void FireEventsOnInsertion(Accessible* aContainer, uint32_t aUpdateFlags);
|
||||
void FireEventsOnInsertion(Accessible* aContainer);
|
||||
|
||||
/**
|
||||
* Fire value change event on the given accessible if applicable.
|
||||
@ -516,17 +516,6 @@ protected:
|
||||
*/
|
||||
void UpdateTreeOnRemoval(Accessible* aContainer, nsIContent* aChildNode);
|
||||
|
||||
/**
|
||||
* Helper for UpdateTreeOn methods. Go down to DOM subtree and updates
|
||||
* accessible tree. Return one of these flags.
|
||||
*/
|
||||
enum EUpdateTreeFlags {
|
||||
eNoAccessible = 0,
|
||||
eAccessible = 1,
|
||||
eAlertAccessible = 2
|
||||
};
|
||||
uint32_t UpdateTreeInternal(Accessible* aChild, bool aIsInsert);
|
||||
|
||||
/**
|
||||
* Validates all aria-owns connections and updates the tree accordingly.
|
||||
*/
|
||||
@ -555,6 +544,7 @@ protected:
|
||||
*/
|
||||
void CacheChildrenInSubtree(Accessible* aRoot,
|
||||
Accessible** aFocusedAcc = nullptr);
|
||||
void CreateSubtree(Accessible* aRoot);
|
||||
|
||||
/**
|
||||
* Remove accessibles in subtree from node to accessible map.
|
||||
|
@ -259,6 +259,31 @@ DocAccessibleParent::RecvTextChangeEvent(const uint64_t& aID,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleParent::RecvSelectionEvent(const uint64_t& aID,
|
||||
const uint64_t& aWidgetID,
|
||||
const uint32_t& aType)
|
||||
{
|
||||
ProxyAccessible* target = GetAccessible(aID);
|
||||
ProxyAccessible* widget = GetAccessible(aWidgetID);
|
||||
if (!target || !widget) {
|
||||
NS_ERROR("invalid id in selection event");
|
||||
return true;
|
||||
}
|
||||
|
||||
ProxySelectionEvent(target, widget, aType);
|
||||
if (!nsCoreUtils::AccEventObserversExist()) {
|
||||
return true;
|
||||
}
|
||||
xpcAccessibleGeneric* xpcTarget = GetXPCAccessible(target);
|
||||
xpcAccessibleDocument* xpcDoc = GetAccService()->GetXPCDocument(this);
|
||||
RefPtr<xpcAccEvent> event = new xpcAccEvent(aType, xpcTarget, xpcDoc,
|
||||
nullptr, false);
|
||||
nsCoreUtils::DispatchAccEvent(Move(event));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleParent::RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID)
|
||||
{
|
||||
|
@ -64,6 +64,10 @@ public:
|
||||
const bool& aIsInsert,
|
||||
const bool& aFromUser) override;
|
||||
|
||||
virtual bool RecvSelectionEvent(const uint64_t& aID,
|
||||
const uint64_t& aWidgetID,
|
||||
const uint32_t& aType) override;
|
||||
|
||||
virtual bool RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID) override;
|
||||
void Unbind()
|
||||
{
|
||||
|
@ -61,6 +61,7 @@ parent:
|
||||
async CaretMoveEvent(uint64_t aID, int32_t aOffset);
|
||||
async TextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen,
|
||||
bool aIsInsert, bool aFromUser);
|
||||
async SelectionEvent(uint64_t aID, uint64_t aWidgetID, uint32_t aType);
|
||||
|
||||
/*
|
||||
* Tell the parent document to bind the existing document as a new child
|
||||
|
@ -106,6 +106,11 @@ void
|
||||
ProxyShowHideEvent(ProxyAccessible*, ProxyAccessible*, bool, bool)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ProxySelectionEvent(ProxyAccessible*, ProxyAccessible*, uint32_t)
|
||||
{
|
||||
}
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -54,3 +54,8 @@ void
|
||||
a11y::ProxyShowHideEvent(ProxyAccessible*, ProxyAccessible*, bool, bool)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
a11y::ProxySelectionEvent(ProxyAccessible*, ProxyAccessible*, uint32_t)
|
||||
{
|
||||
}
|
||||
|
@ -127,3 +127,10 @@ a11y::ProxyShowHideEvent(ProxyAccessible* aTarget, ProxyAccessible*, bool aInser
|
||||
AccessibleWrap* wrapper = WrapperFor(aTarget);
|
||||
AccessibleWrap::FireWinEvent(wrapper, event);
|
||||
}
|
||||
|
||||
void
|
||||
a11y::ProxySelectionEvent(ProxyAccessible* aTarget, ProxyAccessible*, uint32_t aType)
|
||||
{
|
||||
AccessibleWrap* wrapper = WrapperFor(aTarget);
|
||||
AccessibleWrap::FireWinEvent(wrapper, aType);
|
||||
}
|
||||
|
@ -138,58 +138,11 @@ button.default.focused {
|
||||
/* Radio Buttons */
|
||||
.radioItem {
|
||||
margin-bottom: 6px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
input[type="radio"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
input[type="radio"] + label {
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
input[type="radio"] + label::before {
|
||||
background-color: #fff;
|
||||
background-position: center;
|
||||
border: 1px solid #b1b1b1;
|
||||
border-radius: 50%;
|
||||
content: "";
|
||||
display: inline-block;
|
||||
height: 16px;
|
||||
margin-right: 6px;
|
||||
vertical-align: text-top;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
input[type="radio"]:hover + label::before,
|
||||
.radioItem.hover input[type="radio"]:not(active) + label::before {
|
||||
background-color: #fbfbfb;
|
||||
border-color: #b1b1b1;
|
||||
}
|
||||
|
||||
input[type="radio"]:hover:active + label::before,
|
||||
.radioItem.pressed input[type="radio"]:not(active) + label::before {
|
||||
background-color: #ebebeb;
|
||||
border-color: #858585;
|
||||
}
|
||||
|
||||
input[type="radio"]:checked + label::before {
|
||||
background-color: #0996f8;
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8Y2lyY2xlIGN4PSI4IiBjeT0iOCIgcj0iNCIgZmlsbD0iI2ZmZiIgLz4KPC9zdmc+Cg==);
|
||||
border-color: #0670cc;
|
||||
}
|
||||
|
||||
input[type="radio"]:checked:hover + label::before,
|
||||
.radioItem.hover input[type="radio"]:checked:not(active) + label::before {
|
||||
background-color: #0670cc;
|
||||
border-color: #005bab;
|
||||
}
|
||||
|
||||
input[type="radio"]:checked:hover:active + label::before,
|
||||
.radioItem.pressed input[type="radio"]:checked:not(active) + label::before {
|
||||
background-color: #005bab;
|
||||
border-color: #004480;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.radioItem.disabled input[type="radio"] + label,
|
||||
@ -199,69 +152,14 @@ input[type="radio"]:checked:hover:active + label::before,
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.radioItem.focused input[type="radio"] + label::before {
|
||||
border-color: #0996f8;
|
||||
box-shadow: 0 0 0 2px rgba(97, 181, 255, 0.75);
|
||||
}
|
||||
|
||||
.radioItem.focused input[type="radio"]:checked + label::before {
|
||||
border-color: #fff;
|
||||
}
|
||||
|
||||
/* Checkboxes */
|
||||
.checkboxItem {
|
||||
margin-bottom: 6px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
input[type="checkbox"] + label {
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
input[type="checkbox"] + label::before {
|
||||
background-color: #fff;
|
||||
background-position: center;
|
||||
border: 1px solid #b1b1b1;
|
||||
content: "";
|
||||
display: inline-block;
|
||||
height: 16px;
|
||||
margin-right: 6px;
|
||||
vertical-align: text-top;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:hover + label::before,
|
||||
.checkboxItem.hover input[type="checkbox"]:not(active) + label::before {
|
||||
background-color: #fbfbfb;
|
||||
border-color: #b1b1b1;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:hover:active + label::before,
|
||||
.checkboxItem.pressed input[type="checkbox"]:not(active) + label::before {
|
||||
background-color: #ebebeb;
|
||||
border-color: #858585;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked + label::before {
|
||||
background-color: #0996f8;
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8cGF0aCBkPSJNNy43LDEyLjkgQzcuNCwxMy4zIDYuOCwxMy40IDYuNCwxMyBMMy4yLDkuOCBDMi44LDkuNCAyLjgsOC42IDMuMiw4LjIgQzMuNiw3LjggNC40LDcuOCA0LjgsOC4yIEw2LjksMTAuMyBMMTEuMSw0LjQgQzExLjUsMy45IDEyLjIsMy44IDEyLjcsNC4xIEMxMy4yLDQuNSAxMy4zLDUuMiAxMyw1LjcgTDcuNywxMi45IEw3LjcsMTIuOSBaIiBmaWxsPSIjZmZmIiAvPgo8L3N2Zz4K);
|
||||
border-color: #0670cc;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked:hover + label::before,
|
||||
.checkboxItem.hover input[type="checkbox"]:checked:not(active) + label::before {
|
||||
background-color: #0670cc;
|
||||
border-color: #005bab;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked:hover:active + label::before,
|
||||
.checkboxItem.pressed input[type="checkbox"]:checked:not(active) + label::before {
|
||||
background-color: #005bab;
|
||||
border-color: #004480;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.checkboxItem.disabled input[type="checkbox"] + label,
|
||||
@ -271,15 +169,6 @@ input[type="checkbox"]:checked:hover:active + label::before,
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.checkboxItem.focused input[type="checkbox"] + label::before {
|
||||
border-color: #0996f8;
|
||||
box-shadow: 0 0 0 2px rgba(97, 181, 255, 0.75);
|
||||
}
|
||||
|
||||
.checkboxItem.focused input[type="checkbox"]:checked + label::before {
|
||||
border-color: #fff;
|
||||
}
|
||||
|
||||
/* Expander Button */
|
||||
button.expander {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8cGF0aCBkPSJNOCwxMkwzLDcsNCw2bDQsNCw0LTQsMSwxWiIgZmlsbD0iIzZBNkE2QSIgLz4KPC9zdmc+Cg==);
|
||||
@ -465,7 +354,7 @@ textarea:focus:hover {
|
||||
|
||||
.panel-formElements-item label {
|
||||
flex-shrink: 0;
|
||||
margin-right: 6px;
|
||||
margin: 0 6px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ if test -z "$SCCACHE_DISABLE" -a -z "$no_sccache" -a -z "$MOZ_PGO_IS_SET" -a -z
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
b2g-inbound|mozilla-inbound|fx-team)
|
||||
mozilla-inbound|fx-team)
|
||||
case "${master}" in
|
||||
*use1.mozilla.com*)
|
||||
bucket=mozilla-releng-s3-cache-us-east-1-prod
|
||||
|
@ -96,6 +96,7 @@ public:
|
||||
, mIDType(eUnknown)
|
||||
, mOuterIDNumber(0)
|
||||
, mInnerIDNumber(0)
|
||||
, mStatus(eUnused)
|
||||
#ifdef DEBUG
|
||||
, mOwningThread(PR_GetCurrentThread())
|
||||
#endif
|
||||
|
@ -1567,7 +1567,7 @@ nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
|
||||
|
||||
if (!aString.empty()) {
|
||||
aRequest->mScriptTextLength = aString.length();
|
||||
aRequest->mScriptTextBuf = aString.extractRawBuffer();
|
||||
aRequest->mScriptTextBuf = aString.extractOrCopyRawBuffer();
|
||||
}
|
||||
|
||||
// This assertion could fire errorously if we ran out of memory when
|
||||
|
@ -119,18 +119,7 @@ WebGLContext::GetChannelBits(const char* funcName, GLenum pname, GLint* const ou
|
||||
|
||||
case LOCAL_GL_DEPTH_BITS:
|
||||
if (mOptions.depth) {
|
||||
const auto& glFormats = gl->GetGLFormats();
|
||||
|
||||
GLenum depthFormat = glFormats.depth;
|
||||
if (mOptions.stencil && glFormats.depthStencil) {
|
||||
depthFormat = glFormats.depthStencil;
|
||||
}
|
||||
|
||||
if (depthFormat == LOCAL_GL_DEPTH_COMPONENT16) {
|
||||
*out_val = 16;
|
||||
} else {
|
||||
*out_val = 24;
|
||||
}
|
||||
*out_val = gl->Screen()->DepthBits();
|
||||
} else {
|
||||
*out_val = 0;
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ NS_IMPL_RELEASE_INHERITED(CommandEvent, Event)
|
||||
NS_IMETHODIMP
|
||||
CommandEvent::GetCommand(nsAString& aCommand)
|
||||
{
|
||||
nsIAtom* command = mEvent->AsCommandEvent()->command;
|
||||
nsIAtom* command = mEvent->AsCommandEvent()->mCommand;
|
||||
if (command) {
|
||||
command->ToString(aCommand);
|
||||
} else {
|
||||
@ -53,7 +53,7 @@ CommandEvent::InitCommandEvent(const nsAString& aTypeArg,
|
||||
{
|
||||
Event::InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg);
|
||||
|
||||
mEvent->AsCommandEvent()->command = NS_Atomize(aCommand);
|
||||
mEvent->AsCommandEvent()->mCommand = NS_Atomize(aCommand);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -3831,6 +3831,8 @@ void HTMLMediaElement::CheckProgress(bool aHaveNewProgress)
|
||||
ChangeDelayLoadStatus(true);
|
||||
}
|
||||
}
|
||||
// Download statistics may have been updated, force a recheck of the readyState.
|
||||
UpdateReadyStateInternal();
|
||||
}
|
||||
|
||||
if (now - mDataTime >= TimeDuration::FromMilliseconds(STALL_MS)) {
|
||||
|
@ -9,11 +9,14 @@
|
||||
#include "MediaData.h"
|
||||
#include "PDMFactory.h"
|
||||
#include "WebMDemuxer.h"
|
||||
#include "WebMSample.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
|
||||
#ifndef MOZ_WIDGET_ANDROID
|
||||
#include "WebMSample.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Update this version number to force re-running the benchmark. Such as when
|
||||
@ -30,6 +33,9 @@ VP9Benchmark::IsVP9DecodeFast()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
return true;
|
||||
#else
|
||||
bool hasPref = Preferences::HasUserValue(sBenchmarkFpsPref);
|
||||
uint32_t hadRecentUpdate = Preferences::GetUint(sBenchmarkFpsVersionCheck, 0U);
|
||||
|
||||
@ -77,6 +83,7 @@ VP9Benchmark::IsVP9DecodeFast()
|
||||
Preferences::GetUint("media.benchmark.vp9.threshold", 150);
|
||||
|
||||
return decodeFps >= threshold;
|
||||
#endif
|
||||
}
|
||||
|
||||
Benchmark::Benchmark(MediaDataDemuxer* aDemuxer, const Parameters& aParameters)
|
||||
|
@ -429,7 +429,7 @@ void MediaDecoderStateMachine::DiscardStreamData()
|
||||
|
||||
const auto clockTime = GetClock();
|
||||
while (true) {
|
||||
const MediaData* a = AudioQueue().PeekFront();
|
||||
RefPtr<MediaData> a = AudioQueue().PeekFront();
|
||||
|
||||
// If we discard audio samples fed to the stream immediately, we will
|
||||
// keep decoding audio samples till the end and consume a lot of memory.
|
||||
@ -1977,7 +1977,7 @@ MediaDecoderStateMachine::SeekCompleted()
|
||||
if (seekTime == Duration().ToMicroseconds()) {
|
||||
newCurrentTime = seekTime;
|
||||
} else if (HasAudio()) {
|
||||
MediaData* audio = AudioQueue().PeekFront();
|
||||
RefPtr<MediaData> audio = AudioQueue().PeekFront();
|
||||
// Though we adjust the newCurrentTime in audio-based, and supplemented
|
||||
// by video. For better UX, should NOT bind the slide position to
|
||||
// the first audio data timestamp directly.
|
||||
|
@ -65,12 +65,12 @@ public:
|
||||
return rv.forget();
|
||||
}
|
||||
|
||||
inline T* Peek() {
|
||||
inline RefPtr<T> Peek() {
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
return static_cast<T*>(nsDeque::Peek());
|
||||
}
|
||||
|
||||
inline T* PeekFront() {
|
||||
inline RefPtr<T> PeekFront() {
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
return static_cast<T*>(nsDeque::PeekFront());
|
||||
}
|
||||
@ -109,8 +109,8 @@ public:
|
||||
if (GetSize() == 0) {
|
||||
return 0;
|
||||
}
|
||||
T* last = Peek();
|
||||
T* first = PeekFront();
|
||||
T* last = static_cast<T*>(nsDeque::Peek());
|
||||
T* first = static_cast<T*>(nsDeque::PeekFront());
|
||||
return last->GetEndTime() - first->mTime;
|
||||
}
|
||||
|
||||
|
@ -223,7 +223,7 @@ DecodedAudioDataSink::PopFrames(uint32_t aFrames)
|
||||
return MakeUnique<Chunk>();
|
||||
}
|
||||
|
||||
AudioData* a = AudioQueue().PeekFront()->As<AudioData>();
|
||||
RefPtr<AudioData> a = AudioQueue().PeekFront()->As<AudioData>();
|
||||
|
||||
// Ignore the element with 0 frames and try next.
|
||||
if (a->mFrames == 0) {
|
||||
|
@ -383,7 +383,7 @@ VideoSink::UpdateRenderedVideoFrames()
|
||||
RefPtr<MediaData> currentFrame = VideoQueue().PopFront();
|
||||
int32_t framesRemoved = 0;
|
||||
while (VideoQueue().GetSize() > 0) {
|
||||
MediaData* nextFrame = VideoQueue().PeekFront();
|
||||
RefPtr<MediaData> nextFrame = VideoQueue().PeekFront();
|
||||
if (nextFrame->mTime > clockTime) {
|
||||
remainingTime = nextFrame->mTime - clockTime;
|
||||
break;
|
||||
|
@ -1358,7 +1358,7 @@ nsresult OggReader::SeekInBufferedRange(int64_t aTarget,
|
||||
} while (!eof &&
|
||||
mVideoQueue.GetSize() == 0);
|
||||
|
||||
VideoData* video = mVideoQueue.PeekFront();
|
||||
RefPtr<VideoData> video = mVideoQueue.PeekFront();
|
||||
if (video && !video->mKeyframe) {
|
||||
// First decoded frame isn't a keyframe, seek back to previous keyframe,
|
||||
// otherwise we'll get visual artifacts.
|
||||
@ -1490,7 +1490,7 @@ nsresult OggReader::SeekInternal(int64_t aTarget, int64_t aEndTime)
|
||||
// First, we must check to see if there's already a keyframe in the frames
|
||||
// that we may have already decoded, and discard frames up to the
|
||||
// keyframe.
|
||||
VideoData* v;
|
||||
RefPtr<VideoData> v;
|
||||
while ((v = mVideoQueue.PeekFront()) && !v->mKeyframe) {
|
||||
RefPtr<VideoData> releaseMe = mVideoQueue.PopFront();
|
||||
}
|
||||
@ -1959,7 +1959,7 @@ media::TimeIntervals OggReader::GetBuffered()
|
||||
#endif
|
||||
}
|
||||
|
||||
VideoData* OggReader::FindStartTime(int64_t& aOutStartTime)
|
||||
void OggReader::FindStartTime(int64_t& aOutStartTime)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
@ -1967,17 +1967,16 @@ VideoData* OggReader::FindStartTime(int64_t& aOutStartTime)
|
||||
// the duration.
|
||||
int64_t videoStartTime = INT64_MAX;
|
||||
int64_t audioStartTime = INT64_MAX;
|
||||
VideoData* videoData = nullptr;
|
||||
|
||||
if (HasVideo()) {
|
||||
videoData = SyncDecodeToFirstVideoData();
|
||||
RefPtr<VideoData> videoData = SyncDecodeToFirstVideoData();
|
||||
if (videoData) {
|
||||
videoStartTime = videoData->mTime;
|
||||
LOG(LogLevel::Debug, ("OggReader::FindStartTime() video=%lld", videoStartTime));
|
||||
}
|
||||
}
|
||||
if (HasAudio()) {
|
||||
AudioData* audioData = SyncDecodeToFirstAudioData();
|
||||
RefPtr<AudioData> audioData = SyncDecodeToFirstAudioData();
|
||||
if (audioData) {
|
||||
audioStartTime = audioData->mTime;
|
||||
LOG(LogLevel::Debug, ("OggReader::FindStartTime() audio=%lld", audioStartTime));
|
||||
@ -1988,11 +1987,9 @@ VideoData* OggReader::FindStartTime(int64_t& aOutStartTime)
|
||||
if (startTime != INT64_MAX) {
|
||||
aOutStartTime = startTime;
|
||||
}
|
||||
|
||||
return videoData;
|
||||
}
|
||||
|
||||
AudioData* OggReader::SyncDecodeToFirstAudioData()
|
||||
RefPtr<AudioData> OggReader::SyncDecodeToFirstAudioData()
|
||||
{
|
||||
bool eof = false;
|
||||
while (!eof && AudioQueue().GetSize() == 0) {
|
||||
@ -2004,11 +2001,10 @@ AudioData* OggReader::SyncDecodeToFirstAudioData()
|
||||
if (eof) {
|
||||
AudioQueue().Finish();
|
||||
}
|
||||
AudioData* d = nullptr;
|
||||
return (d = AudioQueue().PeekFront()) ? d : nullptr;
|
||||
return AudioQueue().PeekFront();
|
||||
}
|
||||
|
||||
VideoData* OggReader::SyncDecodeToFirstVideoData()
|
||||
RefPtr<VideoData> OggReader::SyncDecodeToFirstVideoData()
|
||||
{
|
||||
bool eof = false;
|
||||
while (!eof && VideoQueue().GetSize() == 0) {
|
||||
@ -2021,8 +2017,7 @@ VideoData* OggReader::SyncDecodeToFirstVideoData()
|
||||
if (eof) {
|
||||
VideoQueue().Finish();
|
||||
}
|
||||
VideoData* d = nullptr;
|
||||
return (d = VideoQueue().PeekFront()) ? d : nullptr;
|
||||
return VideoQueue().PeekFront();
|
||||
}
|
||||
|
||||
OggCodecStore::OggCodecStore()
|
||||
|
@ -77,9 +77,9 @@ private:
|
||||
// Stores the presentation time of the first frame we'd be able to play if
|
||||
// we started playback at the current position. Returns the first video
|
||||
// frame, if we have video.
|
||||
VideoData* FindStartTime(int64_t& aOutStartTime);
|
||||
AudioData* SyncDecodeToFirstAudioData();
|
||||
VideoData* SyncDecodeToFirstVideoData();
|
||||
void FindStartTime(int64_t& aOutStartTime);
|
||||
RefPtr<AudioData> SyncDecodeToFirstAudioData();
|
||||
RefPtr<VideoData> SyncDecodeToFirstVideoData();
|
||||
|
||||
// This monitor should be taken when reading or writing to mIsChained.
|
||||
ReentrantMonitor mMonitor;
|
||||
|
@ -1036,6 +1036,9 @@ AudioContext::StartRendering(ErrorResult& aRv)
|
||||
|
||||
mIsStarted = true;
|
||||
RefPtr<Promise> promise = Promise::Create(parentObject, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
mDestination->StartRendering(promise);
|
||||
|
||||
OnStateChanged(nullptr, AudioContextState::Running);
|
||||
@ -1043,6 +1046,13 @@ AudioContext::StartRendering(ErrorResult& aRv)
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
unsigned long
|
||||
AudioContext::Length()
|
||||
{
|
||||
MOZ_ASSERT(mIsOffline);
|
||||
return mDestination->Length();
|
||||
}
|
||||
|
||||
void
|
||||
AudioContext::Mute() const
|
||||
{
|
||||
|
@ -266,6 +266,7 @@ public:
|
||||
// OfflineAudioContext methods
|
||||
already_AddRefed<Promise> StartRendering(ErrorResult& aRv);
|
||||
IMPL_EVENT_HANDLER(complete)
|
||||
unsigned long Length();
|
||||
|
||||
bool IsOffline() const { return mIsOffline; }
|
||||
|
||||
|
@ -86,6 +86,12 @@ public:
|
||||
void InputMuted(bool aInputMuted);
|
||||
void ResolvePromise(AudioBuffer* aRenderedBuffer);
|
||||
|
||||
unsigned long Length()
|
||||
{
|
||||
MOZ_ASSERT(mIsOffline);
|
||||
return mFramesToProduce;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~AudioDestinationNode();
|
||||
|
||||
|
@ -33,6 +33,7 @@ SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function() {
|
||||
var ctx = new OfflineAudioContext(2, 100, 22050);
|
||||
ok(ctx instanceof EventTarget, "OfflineAudioContexts must be EventTargets");
|
||||
is(ctx.length, 100, "OfflineAudioContext.length is equal to the value passed to the ctor.");
|
||||
|
||||
var buf = ctx.createBuffer(2, 100, ctx.sampleRate);
|
||||
for (var i = 0; i < 2; ++i) {
|
||||
|
@ -525,6 +525,10 @@ Promise::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
|
||||
already_AddRefed<Promise>
|
||||
Promise::Create(nsIGlobalObject* aGlobal, ErrorResult& aRv)
|
||||
{
|
||||
if (!aGlobal) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
RefPtr<Promise> p = new Promise(aGlobal);
|
||||
p->CreateWrapper(nullptr, aRv);
|
||||
if (aRv.Failed()) {
|
||||
@ -859,6 +863,10 @@ already_AddRefed<Promise>
|
||||
Promise::Create(nsIGlobalObject* aGlobal, ErrorResult& aRv,
|
||||
JS::Handle<JSObject*> aDesiredProto)
|
||||
{
|
||||
if (!aGlobal) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
RefPtr<Promise> p = new Promise(aGlobal);
|
||||
p->CreateWrapper(aDesiredProto, aRv);
|
||||
if (aRv.Failed()) {
|
||||
|
@ -19,5 +19,6 @@ interface OfflineAudioContext : AudioContext {
|
||||
Promise<AudioBuffer> startRendering();
|
||||
|
||||
attribute EventHandler oncomplete;
|
||||
readonly attribute unsigned long length;
|
||||
|
||||
};
|
||||
|
@ -416,7 +416,8 @@ DrawTargetSkia::DrawSurfaceWithShadow(SourceSurface *aSurface,
|
||||
Float aSigma,
|
||||
CompositionOp aOperator)
|
||||
{
|
||||
if (!(aSurface->GetType() == SurfaceType::SKIA || aSurface->GetType() == SurfaceType::DATA)) {
|
||||
if (!(aSurface->GetType() == SurfaceType::SKIA || aSurface->GetType() == SurfaceType::DATA) ||
|
||||
aSurface->GetSize().IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -138,6 +138,7 @@ enum class LogReason : int {
|
||||
TextureAliveAfterShutdown,
|
||||
InvalidContext,
|
||||
InvalidCommandList,
|
||||
AsyncTransactionTimeout,
|
||||
// End
|
||||
MustBeLessThanThis = 101,
|
||||
};
|
||||
|
@ -1045,8 +1045,6 @@ GLContext::InitWithPrefixImpl(const char* prefix, bool trygl)
|
||||
mCaps.alpha = false;
|
||||
}
|
||||
|
||||
UpdateGLFormats(mCaps);
|
||||
|
||||
mTexGarbageBin = new TextureGarbageBin(this);
|
||||
|
||||
MOZ_ASSERT(IsCurrent());
|
||||
@ -2868,8 +2866,6 @@ GLContext::InitOffscreen(const gfx::IntSize& size, const SurfaceCaps& caps)
|
||||
mCaps = mScreen->mCaps;
|
||||
MOZ_ASSERT(!mCaps.any);
|
||||
|
||||
UpdateGLFormats(mCaps);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3412,7 +3412,6 @@ public:
|
||||
|
||||
protected:
|
||||
SurfaceCaps mCaps;
|
||||
nsAutoPtr<GLFormats> mGLFormats;
|
||||
|
||||
public:
|
||||
const SurfaceCaps& Caps() const {
|
||||
@ -3421,14 +3420,6 @@ public:
|
||||
|
||||
// Only varies based on bpp16 and alpha.
|
||||
GLFormats ChooseGLFormats(const SurfaceCaps& caps) const;
|
||||
void UpdateGLFormats(const SurfaceCaps& caps) {
|
||||
mGLFormats = new GLFormats(ChooseGLFormats(caps));
|
||||
}
|
||||
|
||||
const GLFormats& GetGLFormats() const {
|
||||
MOZ_ASSERT(mGLFormats);
|
||||
return *mGLFormats;
|
||||
}
|
||||
|
||||
bool IsFramebufferComplete(GLuint fb, GLenum* status = nullptr);
|
||||
|
||||
|
@ -694,6 +694,17 @@ GLScreenBuffer::IsReadFramebufferDefault() const
|
||||
return SharedSurf()->mAttachType == AttachmentType::Screen;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GLScreenBuffer::DepthBits() const
|
||||
{
|
||||
const GLFormats& formats = mFactory->mFormats;
|
||||
|
||||
if (formats.depth == LOCAL_GL_DEPTH_COMPONENT16)
|
||||
return 16;
|
||||
|
||||
return 24;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Utils
|
||||
|
||||
|
@ -211,6 +211,8 @@ public:
|
||||
return mDraw->mSamples;
|
||||
}
|
||||
|
||||
uint32_t DepthBits() const;
|
||||
|
||||
void DeletingFB(GLuint fb);
|
||||
|
||||
const gfx::IntSize& Size() const {
|
||||
|
@ -898,7 +898,7 @@ struct ParamTraits<mozilla::StereoMode>
|
||||
: public ContiguousEnumSerializer<
|
||||
mozilla::StereoMode,
|
||||
mozilla::StereoMode::MONO,
|
||||
mozilla::StereoMode::TOP_BOTTOM>
|
||||
mozilla::StereoMode::MAX>
|
||||
{};
|
||||
|
||||
template <>
|
||||
|
@ -99,7 +99,8 @@ enum class StereoMode {
|
||||
LEFT_RIGHT,
|
||||
RIGHT_LEFT,
|
||||
BOTTOM_TOP,
|
||||
TOP_BOTTOM
|
||||
TOP_BOTTOM,
|
||||
MAX,
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -34,6 +34,10 @@ AsyncTransactionWaiter::WaitComplete()
|
||||
if (mWaitCount > 0) {
|
||||
printf_stderr("Timeout of waiting transaction complete.");
|
||||
}
|
||||
|
||||
if (count == maxCount) {
|
||||
gfxDevCrash(LogReason::AsyncTransactionTimeout) << "Bug 1244883: AsyncTransactionWaiter timed out.";
|
||||
}
|
||||
}
|
||||
|
||||
Atomic<uint64_t> AsyncTransactionTracker::sSerialCounter(0);
|
||||
|
@ -1799,7 +1799,7 @@ bool DoesD3D11TextureSharingWorkInternal(ID3D11Device *device, DXGI_FORMAT forma
|
||||
// get a crash on Intel 8.5.10.[18xx-1994] drivers.
|
||||
// We can work around this issue by doing UpdateSubresource.
|
||||
if (!TryCreateTexture2D(device, &desc, nullptr, texture)) {
|
||||
gfxCriticalError() << "DoesD3D11TextureSharingWork_TryCreateTextureFailure";
|
||||
gfxCriticalNote << "DoesD3D11TextureSharingWork_TryCreateTextureFailure";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1236,7 +1236,7 @@ DecodeExportName(JSContext* cx, Decoder& d, CStringSet* dupSet)
|
||||
if (!fieldBytes.append(0))
|
||||
return nullptr;
|
||||
|
||||
UniqueChars fieldName((char*)fieldBytes.extractRawBuffer());
|
||||
UniqueChars fieldName((char*)fieldBytes.extractOrCopyRawBuffer());
|
||||
if (!fieldName)
|
||||
return nullptr;
|
||||
|
||||
|
@ -1446,6 +1446,58 @@ js::RegExpGetSubstitution(JSContext* cx, HandleLinearString matched, HandleLinea
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::GetFirstDollarIndex(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 1);
|
||||
RootedString str(cx, args[0].toString());
|
||||
|
||||
int32_t index = -1;
|
||||
if (!GetFirstDollarIndexRaw(cx, str, &index))
|
||||
return false;
|
||||
|
||||
args.rval().setInt32(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TextChar>
|
||||
static MOZ_ALWAYS_INLINE int
|
||||
GetFirstDollarIndexImpl(const TextChar* text, uint32_t textLen)
|
||||
{
|
||||
const TextChar* end = text + textLen;
|
||||
for (const TextChar* c = text; c != end; ++c) {
|
||||
if (*c == '$')
|
||||
return c - text;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t
|
||||
js::GetFirstDollarIndexRawFlat(JSLinearString* text)
|
||||
{
|
||||
uint32_t len = text->length();
|
||||
// Should be handled in different path.
|
||||
MOZ_ASSERT(len != 0);
|
||||
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
if (text->hasLatin1Chars())
|
||||
return GetFirstDollarIndexImpl(text->latin1Chars(nogc), len);
|
||||
|
||||
return GetFirstDollarIndexImpl(text->twoByteChars(nogc), len);
|
||||
}
|
||||
|
||||
bool
|
||||
js::GetFirstDollarIndexRaw(JSContext* cx, HandleString str, int32_t* index)
|
||||
{
|
||||
JSLinearString* text = str->ensureLinear(cx);
|
||||
if (!text)
|
||||
return false;
|
||||
|
||||
*index = GetFirstDollarIndexRawFlat(text);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::RegExpPrototypeOptimizable(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
|
@ -130,6 +130,15 @@ RegExpGetSubstitution(JSContext* cx, HandleLinearString matched, HandleLinearStr
|
||||
size_t position, HandleObject capturesObj, HandleLinearString replacement,
|
||||
size_t firstDollarIndex, MutableHandleValue rval);
|
||||
|
||||
extern bool
|
||||
GetFirstDollarIndex(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
extern bool
|
||||
GetFirstDollarIndexRaw(JSContext* cx, HandleString str, int32_t* index);
|
||||
|
||||
extern int32_t
|
||||
GetFirstDollarIndexRawFlat(JSLinearString* text);
|
||||
|
||||
// RegExp ClassSpec members used in RegExpObject.cpp.
|
||||
extern bool
|
||||
regexp_construct(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
@ -190,7 +190,7 @@ function RegExpReplace(string, replaceValue) {
|
||||
// A single character string may contain "$", but that cannot be a
|
||||
// substitution.
|
||||
if (replaceValue.length > 1)
|
||||
firstDollarIndex = callFunction(std_String_indexOf, replaceValue, "$");
|
||||
firstDollarIndex = GetFirstDollarIndex(replaceValue);
|
||||
}
|
||||
|
||||
// Step 7.
|
||||
|
@ -644,8 +644,10 @@ ArrayMetaTypeDescr::create(JSContext* cx,
|
||||
if (!CreateTraceList(cx, obj))
|
||||
return nullptr;
|
||||
|
||||
if (!cx->zone()->typeDescrObjects.put(obj))
|
||||
if (!cx->zone()->typeDescrObjects.put(obj)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
@ -691,12 +693,16 @@ ArrayMetaTypeDescr::construct(JSContext* cx, unsigned argc, Value* vp)
|
||||
|
||||
// Construct a canonical string `new ArrayType(<elementType>, N)`:
|
||||
StringBuffer contents(cx);
|
||||
contents.append("new ArrayType(");
|
||||
contents.append(&elementType->stringRepr());
|
||||
contents.append(", ");
|
||||
if (!contents.append("new ArrayType("))
|
||||
return false;
|
||||
if (!contents.append(&elementType->stringRepr()))
|
||||
return false;
|
||||
if (!contents.append(", "))
|
||||
return false;
|
||||
if (!NumberValueToStringBuffer(cx, NumberValue(length), contents))
|
||||
return false;
|
||||
contents.append(")");
|
||||
if (!contents.append(")"))
|
||||
return false;
|
||||
RootedAtom stringRepr(cx, contents.finishAtom());
|
||||
if (!stringRepr)
|
||||
return false;
|
||||
@ -799,10 +805,8 @@ StructMetaTypeDescr::create(JSContext* cx,
|
||||
if (!userFieldTypes)
|
||||
return nullptr;
|
||||
|
||||
if (!stringBuffer.append("new StructType({")) {
|
||||
ReportOutOfMemory(cx);
|
||||
if (!stringBuffer.append("new StructType({"))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RootedValue fieldTypeVal(cx);
|
||||
RootedId id(cx);
|
||||
@ -830,14 +834,10 @@ StructMetaTypeDescr::create(JSContext* cx,
|
||||
|
||||
// Collect field name and type object
|
||||
RootedValue fieldName(cx, IdToValue(id));
|
||||
if (!fieldNames.append(fieldName)) {
|
||||
ReportOutOfMemory(cx);
|
||||
if (!fieldNames.append(fieldName))
|
||||
return nullptr;
|
||||
}
|
||||
if (!fieldTypeObjs.append(ObjectValue(*fieldType))) {
|
||||
ReportOutOfMemory(cx);
|
||||
if (!fieldTypeObjs.append(ObjectValue(*fieldType)))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// userFieldTypes[id] = typeObj
|
||||
if (!DefineProperty(cx, userFieldTypes, id, fieldTypeObjs[i], nullptr, nullptr,
|
||||
@ -847,22 +847,14 @@ StructMetaTypeDescr::create(JSContext* cx,
|
||||
}
|
||||
|
||||
// Append "f:Type" to the string repr
|
||||
if (i > 0 && !stringBuffer.append(", ")) {
|
||||
ReportOutOfMemory(cx);
|
||||
if (i > 0 && !stringBuffer.append(", "))
|
||||
return nullptr;
|
||||
}
|
||||
if (!stringBuffer.append(JSID_TO_ATOM(id))) {
|
||||
ReportOutOfMemory(cx);
|
||||
if (!stringBuffer.append(JSID_TO_ATOM(id)))
|
||||
return nullptr;
|
||||
}
|
||||
if (!stringBuffer.append(": ")) {
|
||||
ReportOutOfMemory(cx);
|
||||
if (!stringBuffer.append(": "))
|
||||
return nullptr;
|
||||
}
|
||||
if (!stringBuffer.append(&fieldType->stringRepr())) {
|
||||
ReportOutOfMemory(cx);
|
||||
if (!stringBuffer.append(&fieldType->stringRepr()))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Offset of this field is the current total size adjusted for
|
||||
// the field's alignment.
|
||||
@ -873,10 +865,8 @@ StructMetaTypeDescr::create(JSContext* cx,
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(offset.value() >= 0);
|
||||
if (!fieldOffsets.append(Int32Value(offset.value()))) {
|
||||
ReportOutOfMemory(cx);
|
||||
if (!fieldOffsets.append(Int32Value(offset.value())))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// userFieldOffsets[id] = offset
|
||||
RootedValue offsetValue(cx, Int32Value(offset.value()));
|
||||
@ -903,10 +893,9 @@ StructMetaTypeDescr::create(JSContext* cx,
|
||||
}
|
||||
|
||||
// Complete string representation.
|
||||
if (!stringBuffer.append("})")) {
|
||||
ReportOutOfMemory(cx);
|
||||
if (!stringBuffer.append("})"))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RootedAtom stringRepr(cx, stringBuffer.finishAtom());
|
||||
if (!stringRepr)
|
||||
return nullptr;
|
||||
@ -1003,6 +992,7 @@ StructMetaTypeDescr::create(JSContext* cx,
|
||||
if (!cx->zone()->typeDescrObjects.put(descr) ||
|
||||
!cx->zone()->typeDescrObjects.put(fieldTypeVec))
|
||||
{
|
||||
ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -1172,8 +1162,10 @@ DefineSimpleTypeDescr(JSContext* cx,
|
||||
if (!CreateTraceList(cx, descr))
|
||||
return false;
|
||||
|
||||
if (!cx->zone()->typeDescrObjects.put(descr))
|
||||
if (!cx->zone()->typeDescrObjects.put(descr)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
14
js/src/jit-test/tests/TypedObject/bug1265690.js
Normal file
14
js/src/jit-test/tests/TypedObject/bug1265690.js
Normal file
@ -0,0 +1,14 @@
|
||||
if (!('oomTest' in this) || !this.hasOwnProperty("TypedObject"))
|
||||
quit();
|
||||
lfCodeBuffer = `
|
||||
ArrayType = TypedObject.ArrayType;
|
||||
var StructType = TypedObject.StructType;
|
||||
float32 = TypedObject.float32;
|
||||
Point = new ArrayType(float32, 3);
|
||||
var Line = new StructType({ Point });
|
||||
new ArrayType(Line, 3);
|
||||
`;
|
||||
loadFile(lfCodeBuffer);
|
||||
function loadFile(lfVarx) {
|
||||
oomTest(function() { eval(lfVarx) });
|
||||
}
|
@ -12,5 +12,6 @@ evalcx(`
|
||||
}\
|
||||
');
|
||||
oomTest(() => eval('Array(..."")'));
|
||||
Intl.NumberFormat.prototype.format(0);
|
||||
if ('Intl' in this)
|
||||
Intl.NumberFormat.prototype.format(0);
|
||||
`, newGlobal());
|
||||
|
28
js/src/jit-test/tests/auto-regress/bug1266579.js
Normal file
28
js/src/jit-test/tests/auto-regress/bug1266579.js
Normal file
@ -0,0 +1,28 @@
|
||||
function test1() {
|
||||
do {
|
||||
"8pan08pa8pan08pa".split("");
|
||||
} while (!inIon());
|
||||
}
|
||||
|
||||
function test2() {
|
||||
do {
|
||||
"abababababababababababababababab".split("a");
|
||||
} while (!inIon());
|
||||
}
|
||||
|
||||
function test3() {
|
||||
do {
|
||||
"abcabcabcabcabcabcabcabcabcabcabcabcabcabcabc".split("ab");
|
||||
} while (!inIon());
|
||||
}
|
||||
|
||||
function test4() {
|
||||
do {
|
||||
"".split("");
|
||||
} while (!inIon());
|
||||
}
|
||||
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
test4();
|
@ -1402,7 +1402,9 @@ TryAttachGetElemStub(JSContext* cx, JSScript* script, jsbytecode* pc, ICGetElem_
|
||||
RootedObject obj(cx, &lhs.toObject());
|
||||
|
||||
// Check for ArgumentsObj[int] accesses
|
||||
if (obj->is<ArgumentsObject>() && rhs.isInt32()) {
|
||||
if (obj->is<ArgumentsObject>() && rhs.isInt32() &&
|
||||
!obj->as<ArgumentsObject>().hasOverriddenElement())
|
||||
{
|
||||
ICGetElem_Arguments::Which which = ICGetElem_Arguments::Mapped;
|
||||
if (obj->is<UnmappedArgumentsObject>())
|
||||
which = ICGetElem_Arguments::Unmapped;
|
||||
@ -2272,10 +2274,11 @@ ICGetElem_Arguments::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
// Get initial ArgsObj length value.
|
||||
masm.unboxInt32(Address(objReg, ArgumentsObject::getInitialLengthSlotOffset()), scratchReg);
|
||||
|
||||
// Test if length has been overridden.
|
||||
// Test if length or any element have been overridden.
|
||||
masm.branchTest32(Assembler::NonZero,
|
||||
scratchReg,
|
||||
Imm32(ArgumentsObject::LENGTH_OVERRIDDEN_BIT),
|
||||
Imm32(ArgumentsObject::LENGTH_OVERRIDDEN_BIT |
|
||||
ArgumentsObject::ELEMENT_OVERRIDDEN_BIT),
|
||||
&failure);
|
||||
|
||||
// Length has not been overridden, ensure that R1 is an integer and is <= length.
|
||||
|
@ -2213,6 +2213,63 @@ CodeGenerator::visitOutOfLineRegExpInstanceOptimizable(OutOfLineRegExpInstanceOp
|
||||
masm.jump(ool->rejoin());
|
||||
}
|
||||
|
||||
static void
|
||||
FindFirstDollarIndex(MacroAssembler& masm, Register str, Register len, Register chars,
|
||||
Register temp, Register output, bool isLatin1)
|
||||
{
|
||||
masm.loadStringChars(str, chars);
|
||||
|
||||
masm.move32(Imm32(0), output);
|
||||
|
||||
Label start, done;
|
||||
masm.bind(&start);
|
||||
if (isLatin1)
|
||||
masm.load8ZeroExtend(BaseIndex(chars, output, TimesOne), temp);
|
||||
else
|
||||
masm.load16ZeroExtend(BaseIndex(chars, output, TimesTwo), temp);
|
||||
|
||||
masm.branch32(Assembler::Equal, temp, Imm32('$'), &done);
|
||||
|
||||
masm.add32(Imm32(1), output);
|
||||
masm.branch32(Assembler::NotEqual, output, len, &start);
|
||||
|
||||
masm.move32(Imm32(-1), output);
|
||||
|
||||
masm.bind(&done);
|
||||
}
|
||||
|
||||
typedef bool (*GetFirstDollarIndexRawFn)(JSContext*, HandleString, int32_t*);
|
||||
static const VMFunction GetFirstDollarIndexRawInfo = FunctionInfo<GetFirstDollarIndexRawFn>(GetFirstDollarIndexRaw);
|
||||
|
||||
void
|
||||
CodeGenerator::visitGetFirstDollarIndex(LGetFirstDollarIndex* ins)
|
||||
{
|
||||
Register str = ToRegister(ins->str());
|
||||
Register output = ToRegister(ins->output());
|
||||
Register temp0 = ToRegister(ins->temp0());
|
||||
Register temp1 = ToRegister(ins->temp1());
|
||||
Register len = ToRegister(ins->temp2());
|
||||
|
||||
OutOfLineCode* ool = oolCallVM(GetFirstDollarIndexRawInfo, ins, ArgList(str),
|
||||
StoreRegisterTo(output));
|
||||
|
||||
masm.branchIfRope(str, ool->entry());
|
||||
masm.loadStringLength(str, len);
|
||||
|
||||
Label isLatin1, done;
|
||||
masm.branchLatin1String(str, &isLatin1);
|
||||
{
|
||||
FindFirstDollarIndex(masm, str, len, temp0, temp1, output, /* isLatin1 = */ false);
|
||||
}
|
||||
masm.jump(&done);
|
||||
{
|
||||
masm.bind(&isLatin1);
|
||||
FindFirstDollarIndex(masm, str, len, temp0, temp1, output, /* isLatin1 = */ true);
|
||||
}
|
||||
masm.bind(&done);
|
||||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
||||
typedef JSString* (*StringReplaceFn)(JSContext*, HandleString, HandleString, HandleString);
|
||||
static const VMFunction StringFlatReplaceInfo = FunctionInfo<StringReplaceFn>(js::str_flat_replace_string);
|
||||
static const VMFunction StringReplaceInfo = FunctionInfo<StringReplaceFn>(StringReplace);
|
||||
|
@ -122,6 +122,7 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
void visitOutOfLineRegExpPrototypeOptimizable(OutOfLineRegExpPrototypeOptimizable* ool);
|
||||
void visitRegExpInstanceOptimizable(LRegExpInstanceOptimizable* lir);
|
||||
void visitOutOfLineRegExpInstanceOptimizable(OutOfLineRegExpInstanceOptimizable* ool);
|
||||
void visitGetFirstDollarIndex(LGetFirstDollarIndex* lir);
|
||||
void visitStringReplace(LStringReplace* lir);
|
||||
void emitSharedStub(ICStub::Kind kind, LInstruction* lir);
|
||||
void visitBinarySharedStub(LBinarySharedStub* lir);
|
||||
|
@ -70,6 +70,7 @@
|
||||
_(IsRegExpObject) \
|
||||
_(RegExpPrototypeOptimizable) \
|
||||
_(RegExpInstanceOptimizable) \
|
||||
_(GetFirstDollarIndex) \
|
||||
\
|
||||
_(String) \
|
||||
_(StringCharCodeAt) \
|
||||
|
@ -842,6 +842,7 @@ class IonBuilder
|
||||
InliningStatus inlineIsRegExpObject(CallInfo& callInfo);
|
||||
InliningStatus inlineRegExpPrototypeOptimizable(CallInfo& callInfo);
|
||||
InliningStatus inlineRegExpInstanceOptimizable(CallInfo& callInfo);
|
||||
InliningStatus inlineGetFirstDollarIndex(CallInfo& callInfo);
|
||||
|
||||
// Object natives and intrinsics.
|
||||
InliningStatus inlineObjectCreate(CallInfo& callInfo);
|
||||
|
@ -542,6 +542,9 @@ IsOptimizableArgumentsObjectForGetElem(JSObject* obj, Value idval)
|
||||
if (argsObj.isAnyElementDeleted())
|
||||
return false;
|
||||
|
||||
if (argsObj.hasOverriddenElement())
|
||||
return false;
|
||||
|
||||
if (!idval.isInt32())
|
||||
return false;
|
||||
|
||||
@ -4211,9 +4214,12 @@ GetPropertyIC::tryAttachArgumentsElement(JSContext* cx, HandleScript outerScript
|
||||
|
||||
masm.branchTestObjClass(Assembler::NotEqual, object(), tmpReg, obj->getClass(), &failures);
|
||||
|
||||
// Get initial ArgsObj length value, test if length has been overridden.
|
||||
// Get initial ArgsObj length value, test if length or any element have
|
||||
// been overridden.
|
||||
masm.unboxInt32(Address(object(), ArgumentsObject::getInitialLengthSlotOffset()), tmpReg);
|
||||
masm.branchTest32(Assembler::NonZero, tmpReg, Imm32(ArgumentsObject::LENGTH_OVERRIDDEN_BIT),
|
||||
masm.branchTest32(Assembler::NonZero, tmpReg,
|
||||
Imm32(ArgumentsObject::LENGTH_OVERRIDDEN_BIT |
|
||||
ArgumentsObject::ELEMENT_OVERRIDDEN_BIT),
|
||||
&failures);
|
||||
masm.rshiftPtr(Imm32(ArgumentsObject::PACKED_BITS_COUNT), tmpReg);
|
||||
|
||||
|
@ -2315,6 +2315,17 @@ LIRGenerator::visitRegExpInstanceOptimizable(MRegExpInstanceOptimizable* ins)
|
||||
define(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitGetFirstDollarIndex(MGetFirstDollarIndex* ins)
|
||||
{
|
||||
MOZ_ASSERT(ins->str()->type() == MIRType_String);
|
||||
MOZ_ASSERT(ins->type() == MIRType_Int32);
|
||||
LGetFirstDollarIndex* lir = new(alloc()) LGetFirstDollarIndex(useRegister(ins->str()),
|
||||
temp(), temp(), temp());
|
||||
define(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitStringReplace(MStringReplace* ins)
|
||||
{
|
||||
|
@ -168,6 +168,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||
void visitRegExpTester(MRegExpTester* ins);
|
||||
void visitRegExpPrototypeOptimizable(MRegExpPrototypeOptimizable* ins);
|
||||
void visitRegExpInstanceOptimizable(MRegExpInstanceOptimizable* ins);
|
||||
void visitGetFirstDollarIndex(MGetFirstDollarIndex* ins);
|
||||
void visitStringReplace(MStringReplace* ins);
|
||||
void visitBinarySharedStub(MBinarySharedStub* ins);
|
||||
void visitUnarySharedStub(MUnarySharedStub* ins);
|
||||
|
@ -188,6 +188,8 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
|
||||
return inlineRegExpPrototypeOptimizable(callInfo);
|
||||
case InlinableNative::RegExpInstanceOptimizable:
|
||||
return inlineRegExpInstanceOptimizable(callInfo);
|
||||
case InlinableNative::GetFirstDollarIndex:
|
||||
return inlineGetFirstDollarIndex(callInfo);
|
||||
|
||||
// String natives.
|
||||
case InlinableNative::String:
|
||||
@ -1447,18 +1449,16 @@ IonBuilder::inlineConstantStringSplitString(CallInfo& callInfo)
|
||||
if (conversion == TemporaryTypeSet::AlwaysConvertToDoubles)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
|
||||
current->add(templateConst);
|
||||
if (!jsop_newarray(templateObject, initLength))
|
||||
return InliningStatus_Error;
|
||||
|
||||
MNewArray* ins = MNewArray::New(alloc(), constraints(), initLength, templateConst,
|
||||
templateObject->group()->initialHeap(constraints()), pc);
|
||||
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
MDefinition* array = current->peek(-1);
|
||||
|
||||
if (!initLength) {
|
||||
if (!resumeAfter(ins))
|
||||
return InliningStatus_Error;
|
||||
if (!array->isResumePoint()) {
|
||||
if (!resumeAfter(array->toNewArray()))
|
||||
return InliningStatus_Error;
|
||||
}
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
@ -1471,11 +1471,11 @@ IonBuilder::inlineConstantStringSplitString(CallInfo& callInfo)
|
||||
MConstant* value = arrayValues[i];
|
||||
current->add(value);
|
||||
|
||||
if (!initializeArrayElement(ins, i, value, unboxedType, /* addResumePoint = */ false))
|
||||
if (!initializeArrayElement(array, i, value, unboxedType, /* addResumePoint = */ false))
|
||||
return InliningStatus_Error;
|
||||
}
|
||||
|
||||
MInstruction* setLength = setInitializedLength(ins, unboxedType, initLength);
|
||||
MInstruction* setLength = setInitializedLength(array, unboxedType, initLength);
|
||||
if (!resumeAfter(setLength))
|
||||
return InliningStatus_Error;
|
||||
|
||||
@ -1954,6 +1954,31 @@ IonBuilder::inlineRegExpInstanceOptimizable(CallInfo& callInfo)
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineGetFirstDollarIndex(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 1 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
MDefinition* strArg = callInfo.getArg(0);
|
||||
|
||||
if (strArg->type() != MIRType_String)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
if (getInlineReturnType() != MIRType_Int32)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
||||
MInstruction* ins = MGetFirstDollarIndex::New(alloc(), strArg);
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineStringReplaceString(CallInfo& callInfo)
|
||||
{
|
||||
|
@ -5290,6 +5290,18 @@ MArrayJoin::foldsTo(TempAllocator& alloc)
|
||||
return substr;
|
||||
}
|
||||
|
||||
MDefinition*
|
||||
MGetFirstDollarIndex::foldsTo(TempAllocator& alloc)
|
||||
{
|
||||
MDefinition* strArg = str();
|
||||
if (!strArg->isConstant())
|
||||
return this;
|
||||
|
||||
JSAtom* atom = &strArg->toConstant()->toString()->asAtom();
|
||||
int32_t index = GetFirstDollarIndexRawFlat(atom);
|
||||
return MConstant::New(alloc, Int32Value(index));
|
||||
}
|
||||
|
||||
MConvertUnboxedObjectToNative*
|
||||
MConvertUnboxedObjectToNative::New(TempAllocator& alloc, MDefinition* obj, ObjectGroup* group)
|
||||
{
|
||||
|
@ -8099,6 +8099,33 @@ class MRegExpInstanceOptimizable
|
||||
}
|
||||
};
|
||||
|
||||
class MGetFirstDollarIndex
|
||||
: public MUnaryInstruction,
|
||||
public StringPolicy<0>::Data
|
||||
{
|
||||
explicit MGetFirstDollarIndex(MDefinition* str)
|
||||
: MUnaryInstruction(str)
|
||||
{
|
||||
setResultType(MIRType_Int32);
|
||||
setMovable();
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(GetFirstDollarIndex)
|
||||
|
||||
static MGetFirstDollarIndex* New(TempAllocator& alloc, MDefinition* str) {
|
||||
return new(alloc) MGetFirstDollarIndex(str);
|
||||
}
|
||||
MDefinition* str() const {
|
||||
return getOperand(0);
|
||||
}
|
||||
AliasSet getAliasSet() const override {
|
||||
return AliasSet::None();
|
||||
}
|
||||
|
||||
MDefinition* foldsTo(TempAllocator& alloc) override;
|
||||
};
|
||||
|
||||
class MStringReplace
|
||||
: public MTernaryInstruction,
|
||||
public Mix3Policy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2> >::Data
|
||||
|
@ -151,6 +151,7 @@ namespace jit {
|
||||
_(RegExpTester) \
|
||||
_(RegExpPrototypeOptimizable) \
|
||||
_(RegExpInstanceOptimizable) \
|
||||
_(GetFirstDollarIndex) \
|
||||
_(StringReplace) \
|
||||
_(Lambda) \
|
||||
_(LambdaArrow) \
|
||||
|
@ -4439,6 +4439,32 @@ class LRegExpInstanceOptimizable : public LInstructionHelper<1, 2, 1>
|
||||
}
|
||||
};
|
||||
|
||||
class LGetFirstDollarIndex : public LInstructionHelper<1, 1, 3>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(GetFirstDollarIndex);
|
||||
explicit LGetFirstDollarIndex(const LAllocation& str, const LDefinition& temp0,
|
||||
const LDefinition& temp1, const LDefinition& temp2) {
|
||||
setOperand(0, str);
|
||||
setTemp(0, temp0);
|
||||
setTemp(1, temp1);
|
||||
setTemp(2, temp2);
|
||||
}
|
||||
|
||||
const LAllocation* str() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LDefinition* temp0() {
|
||||
return getTemp(0);
|
||||
}
|
||||
const LDefinition* temp1() {
|
||||
return getTemp(1);
|
||||
}
|
||||
const LDefinition* temp2() {
|
||||
return getTemp(2);
|
||||
}
|
||||
};
|
||||
|
||||
class LStringReplace: public LCallInstructionHelper<1, 3, 0>
|
||||
{
|
||||
public:
|
||||
|
@ -211,6 +211,7 @@
|
||||
_(RegExpTester) \
|
||||
_(RegExpPrototypeOptimizable) \
|
||||
_(RegExpInstanceOptimizable) \
|
||||
_(GetFirstDollarIndex) \
|
||||
_(StringReplace) \
|
||||
_(Substr) \
|
||||
_(BinarySharedStub) \
|
||||
|
@ -1028,49 +1028,49 @@ JS::CreateError(JSContext* cx, JSExnType type, HandleObject stack, HandleString
|
||||
const char*
|
||||
js::ValueToSourceForError(JSContext* cx, HandleValue val, JSAutoByteString& bytes)
|
||||
{
|
||||
if (val.isUndefined()) {
|
||||
if (val.isUndefined())
|
||||
return "undefined";
|
||||
}
|
||||
if (val.isNull()) {
|
||||
|
||||
if (val.isNull())
|
||||
return "null";
|
||||
}
|
||||
|
||||
AutoClearPendingException acpe(cx);
|
||||
|
||||
RootedString str(cx, JS_ValueToSource(cx, val));
|
||||
if (!str) {
|
||||
JS_ClearPendingException(cx);
|
||||
if (!str)
|
||||
return "<<error converting value to string>>";
|
||||
}
|
||||
|
||||
StringBuffer sb(cx);
|
||||
if (val.isObject()) {
|
||||
RootedObject valObj(cx, val.toObjectOrNull());
|
||||
ESClassValue cls;
|
||||
if (!GetBuiltinClass(cx, valObj, &cls)) {
|
||||
JS_ClearPendingException(cx);
|
||||
if (!GetBuiltinClass(cx, valObj, &cls))
|
||||
return "<<error determining class of value>>";
|
||||
}
|
||||
if (cls == ESClass_Array) {
|
||||
sb.append("the array ");
|
||||
} else if (cls == ESClass_ArrayBuffer) {
|
||||
sb.append("the array buffer ");
|
||||
} else if (JS_IsArrayBufferViewObject(valObj)) {
|
||||
sb.append("the typed array ");
|
||||
} else {
|
||||
sb.append("the object ");
|
||||
}
|
||||
const char* s;
|
||||
if (cls == ESClass_Array)
|
||||
s = "the array ";
|
||||
else if (cls == ESClass_ArrayBuffer)
|
||||
s = "the array buffer ";
|
||||
else if (JS_IsArrayBufferViewObject(valObj))
|
||||
s = "the typed array ";
|
||||
else
|
||||
s = "the object ";
|
||||
if (!sb.append(s, strlen(s)))
|
||||
return "<<error converting value to string>>";
|
||||
} else if (val.isNumber()) {
|
||||
sb.append("the number ");
|
||||
if (!sb.append("the number "))
|
||||
return "<<error converting value to string>>";
|
||||
} else if (val.isString()) {
|
||||
sb.append("the string ");
|
||||
if (!sb.append("the string "))
|
||||
return "<<error converting value to string>>";
|
||||
} else {
|
||||
MOZ_ASSERT(val.isBoolean() || val.isSymbol());
|
||||
return bytes.encodeLatin1(cx, str);
|
||||
}
|
||||
sb.append(str);
|
||||
str = sb.finishString();
|
||||
if (!str) {
|
||||
JS_ClearPendingException(cx);
|
||||
if (!sb.append(str))
|
||||
return "<<error converting value to string>>";
|
||||
str = sb.finishString();
|
||||
if (!str)
|
||||
return "<<error converting value to string>>";
|
||||
}
|
||||
return bytes.encodeLatin1(cx, str);
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Casting.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
@ -1295,21 +1296,27 @@ GetErrorMessage(void* userRef, const unsigned errorNumber);
|
||||
*/
|
||||
class MOZ_STACK_CLASS AutoStableStringChars
|
||||
{
|
||||
/*
|
||||
* When copying string char, use this many bytes of inline storage. This is
|
||||
* chosen to allow the inline string types to be copied without allocating.
|
||||
* This is asserted in AutoStableStringChars::allocOwnChars.
|
||||
*/
|
||||
static const size_t InlineCapacity = 24;
|
||||
|
||||
/* Ensure the string is kept alive while we're using its chars. */
|
||||
JS::RootedString s_;
|
||||
union {
|
||||
const char16_t* twoByteChars_;
|
||||
const JS::Latin1Char* latin1Chars_;
|
||||
};
|
||||
mozilla::Maybe<Vector<uint8_t, InlineCapacity>> ownChars_;
|
||||
enum State { Uninitialized, Latin1, TwoByte };
|
||||
State state_;
|
||||
bool ownsChars_;
|
||||
|
||||
public:
|
||||
explicit AutoStableStringChars(JSContext* cx)
|
||||
: s_(cx), state_(Uninitialized), ownsChars_(false)
|
||||
: s_(cx), state_(Uninitialized)
|
||||
{}
|
||||
~AutoStableStringChars();
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
bool init(JSContext* cx, JSString* s);
|
||||
@ -1335,16 +1342,16 @@ class MOZ_STACK_CLASS AutoStableStringChars
|
||||
mozilla::Range<const char16_t> twoByteRange() const {
|
||||
MOZ_ASSERT(state_ == TwoByte);
|
||||
return mozilla::Range<const char16_t>(twoByteChars_,
|
||||
GetStringLength(s_));
|
||||
GetStringLength(s_));
|
||||
}
|
||||
|
||||
/* If we own the chars, transfer ownership to the caller. */
|
||||
bool maybeGiveOwnershipToCaller() {
|
||||
MOZ_ASSERT(state_ != Uninitialized);
|
||||
if (!ownsChars_)
|
||||
if (!ownChars_.isSome() || !ownChars_->extractRawBuffer())
|
||||
return false;
|
||||
state_ = Uninitialized;
|
||||
ownsChars_ = false;
|
||||
ownChars_.reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1353,8 +1360,9 @@ class MOZ_STACK_CLASS AutoStableStringChars
|
||||
void operator=(const AutoStableStringChars& other) = delete;
|
||||
|
||||
bool baseIsInline(JS::Handle<JSLinearString*> linearString);
|
||||
bool copyLatin1Chars(JSContext*, JS::Handle<JSLinearString*> linearString);
|
||||
bool copyTwoByteChars(JSContext*, JS::Handle<JSLinearString*> linearString);
|
||||
template <typename T> T* allocOwnChars(JSContext* cx, size_t count);
|
||||
bool copyLatin1Chars(JSContext* cx, JS::Handle<JSLinearString*> linearString);
|
||||
bool copyTwoByteChars(JSContext* cx, JS::Handle<JSLinearString*> linearString);
|
||||
bool copyAndInflateLatin1Chars(JSContext*, JS::Handle<JSLinearString*> linearString);
|
||||
};
|
||||
|
||||
|
@ -193,8 +193,16 @@ class ZoneCellIterImpl
|
||||
|
||||
public:
|
||||
ZoneCellIterImpl(JS::Zone* zone, AllocKind kind) {
|
||||
JSRuntime* rt = zone->runtimeFromAnyThread();
|
||||
MOZ_ASSERT(zone);
|
||||
MOZ_ASSERT(zone->runtimeFromAnyThread()->gc.nursery.isEmpty());
|
||||
MOZ_ASSERT(rt->gc.nursery.isEmpty());
|
||||
|
||||
// We have a single-threaded runtime, so there's no need to protect
|
||||
// against other threads iterating or allocating. However, we do have
|
||||
// background finalization; we may have to wait for this to finish if
|
||||
// it's currently active.
|
||||
if (IsBackgroundFinalized(kind) && zone->arenas.needBackgroundFinalizeWait(kind))
|
||||
rt->gc.waitBackgroundSweepEnd();
|
||||
|
||||
arenaIter.init(zone, kind);
|
||||
if (!arenaIter.done())
|
||||
@ -248,13 +256,6 @@ class ZoneCellIter
|
||||
// that allows us to iterate.
|
||||
JSRuntime* rt = zone->runtimeFromMainThread();
|
||||
if (!rt->isHeapBusy()) {
|
||||
// We have a single-threaded runtime, so there's no need to protect
|
||||
// against other threads iterating or allocating. However, we do
|
||||
// have background finalization; we have to wait for this to finish
|
||||
// if it's currently active.
|
||||
if (IsBackgroundFinalized(kind) && zone->arenas.needBackgroundFinalizeWait(kind))
|
||||
rt->gc.waitBackgroundSweepEnd();
|
||||
|
||||
// Evict the nursery before iterating so we can see all things.
|
||||
rt->gc.evictNursery();
|
||||
|
||||
|
@ -1672,15 +1672,15 @@ js::GetPCCountScriptCount(JSContext* cx)
|
||||
|
||||
enum MaybeComma {NO_COMMA, COMMA};
|
||||
|
||||
static void
|
||||
static MOZ_WARN_UNUSED_RESULT bool
|
||||
AppendJSONProperty(StringBuffer& buf, const char* name, MaybeComma comma = COMMA)
|
||||
{
|
||||
if (comma)
|
||||
buf.append(',');
|
||||
if (comma && !buf.append(','))
|
||||
return false;
|
||||
|
||||
buf.append('\"');
|
||||
buf.append(name, strlen(name));
|
||||
buf.append("\":", 2);
|
||||
return buf.append('\"') &&
|
||||
buf.append(name, strlen(name)) &&
|
||||
buf.append("\":", 2);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSString*)
|
||||
@ -1703,24 +1703,30 @@ js::GetPCCountScriptSummary(JSContext* cx, size_t index)
|
||||
*/
|
||||
StringBuffer buf(cx);
|
||||
|
||||
buf.append('{');
|
||||
if (!buf.append('{'))
|
||||
return nullptr;
|
||||
|
||||
AppendJSONProperty(buf, "file", NO_COMMA);
|
||||
if (!AppendJSONProperty(buf, "file", NO_COMMA))
|
||||
return nullptr;
|
||||
JSString* str = JS_NewStringCopyZ(cx, script->filename());
|
||||
if (!str || !(str = StringToSource(cx, str)))
|
||||
return nullptr;
|
||||
buf.append(str);
|
||||
if (!buf.append(str))
|
||||
return nullptr;
|
||||
|
||||
AppendJSONProperty(buf, "line");
|
||||
if (!AppendJSONProperty(buf, "line"))
|
||||
return nullptr;
|
||||
NumberValueToStringBuffer(cx, Int32Value(script->lineno()), buf);
|
||||
|
||||
if (script->functionNonDelazifying()) {
|
||||
JSAtom* atom = script->functionNonDelazifying()->displayAtom();
|
||||
if (atom) {
|
||||
AppendJSONProperty(buf, "name");
|
||||
if (!AppendJSONProperty(buf, "name"))
|
||||
return nullptr;
|
||||
if (!(str = StringToSource(cx, atom)))
|
||||
return nullptr;
|
||||
buf.append(str);
|
||||
if (!buf.append(str))
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1734,11 +1740,15 @@ js::GetPCCountScriptSummary(JSContext* cx, size_t index)
|
||||
total += counts->numExec();
|
||||
}
|
||||
|
||||
AppendJSONProperty(buf, "totals");
|
||||
buf.append('{');
|
||||
if (!AppendJSONProperty(buf, "totals"))
|
||||
return nullptr;
|
||||
if (!buf.append('{'))
|
||||
return nullptr;
|
||||
|
||||
AppendJSONProperty(buf, PCCounts::numExecName, NO_COMMA);
|
||||
NumberValueToStringBuffer(cx, DoubleValue(total), buf);
|
||||
if (!AppendJSONProperty(buf, PCCounts::numExecName, NO_COMMA))
|
||||
return nullptr;
|
||||
if (!NumberValueToStringBuffer(cx, DoubleValue(total), buf))
|
||||
return nullptr;
|
||||
|
||||
uint64_t ionActivity = 0;
|
||||
jit::IonScriptCounts* ionCounts = sac.getIonCounts();
|
||||
@ -1748,15 +1758,18 @@ js::GetPCCountScriptSummary(JSContext* cx, size_t index)
|
||||
ionCounts = ionCounts->previous();
|
||||
}
|
||||
if (ionActivity) {
|
||||
AppendJSONProperty(buf, "ion", COMMA);
|
||||
NumberValueToStringBuffer(cx, DoubleValue(ionActivity), buf);
|
||||
if (!AppendJSONProperty(buf, "ion", COMMA))
|
||||
return nullptr;
|
||||
if (!NumberValueToStringBuffer(cx, DoubleValue(ionActivity), buf))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
buf.append('}');
|
||||
buf.append('}');
|
||||
|
||||
if (cx->isExceptionPending())
|
||||
if (!buf.append('}'))
|
||||
return nullptr;
|
||||
if (!buf.append('}'))
|
||||
return nullptr;
|
||||
|
||||
MOZ_ASSERT(!cx->isExceptionPending());
|
||||
|
||||
return buf.finishString();
|
||||
}
|
||||
@ -1766,20 +1779,27 @@ GetPCCountJSON(JSContext* cx, const ScriptAndCounts& sac, StringBuffer& buf)
|
||||
{
|
||||
RootedScript script(cx, sac.script);
|
||||
|
||||
buf.append('{');
|
||||
AppendJSONProperty(buf, "text", NO_COMMA);
|
||||
if (!buf.append('{'))
|
||||
return false;
|
||||
if (!AppendJSONProperty(buf, "text", NO_COMMA))
|
||||
return false;
|
||||
|
||||
JSString* str = JS_DecompileScript(cx, script, nullptr, 0);
|
||||
if (!str || !(str = StringToSource(cx, str)))
|
||||
return false;
|
||||
|
||||
buf.append(str);
|
||||
if (!buf.append(str))
|
||||
return false;
|
||||
|
||||
AppendJSONProperty(buf, "line");
|
||||
NumberValueToStringBuffer(cx, Int32Value(script->lineno()), buf);
|
||||
if (!AppendJSONProperty(buf, "line"))
|
||||
return false;
|
||||
if (!NumberValueToStringBuffer(cx, Int32Value(script->lineno()), buf))
|
||||
return false;
|
||||
|
||||
AppendJSONProperty(buf, "opcodes");
|
||||
buf.append('[');
|
||||
if (!AppendJSONProperty(buf, "opcodes"))
|
||||
return false;
|
||||
if (!buf.append('['))
|
||||
return false;
|
||||
bool comma = false;
|
||||
|
||||
SrcNoteLineScanner scanner(script->notes(), script->lineno());
|
||||
@ -1796,26 +1816,35 @@ GetPCCountJSON(JSContext* cx, const ScriptAndCounts& sac, StringBuffer& buf)
|
||||
if (counts)
|
||||
hits = counts->numExec();
|
||||
|
||||
if (comma)
|
||||
buf.append(',');
|
||||
if (comma && !buf.append(','))
|
||||
return false;
|
||||
comma = true;
|
||||
|
||||
buf.append('{');
|
||||
if (!buf.append('{'))
|
||||
return false;
|
||||
|
||||
AppendJSONProperty(buf, "id", NO_COMMA);
|
||||
NumberValueToStringBuffer(cx, Int32Value(offset), buf);
|
||||
if (!AppendJSONProperty(buf, "id", NO_COMMA))
|
||||
return false;
|
||||
if (!NumberValueToStringBuffer(cx, Int32Value(offset), buf))
|
||||
return false;
|
||||
|
||||
scanner.advanceTo(offset);
|
||||
|
||||
AppendJSONProperty(buf, "line");
|
||||
NumberValueToStringBuffer(cx, Int32Value(scanner.getLine()), buf);
|
||||
if (!AppendJSONProperty(buf, "line"))
|
||||
return false;
|
||||
if (!NumberValueToStringBuffer(cx, Int32Value(scanner.getLine()), buf))
|
||||
return false;
|
||||
|
||||
{
|
||||
const char* name = CodeName[op];
|
||||
AppendJSONProperty(buf, "name");
|
||||
buf.append('\"');
|
||||
buf.append(name, strlen(name));
|
||||
buf.append('\"');
|
||||
if (!AppendJSONProperty(buf, "name"))
|
||||
return false;
|
||||
if (!buf.append('\"'))
|
||||
return false;
|
||||
if (!buf.append(name, strlen(name)))
|
||||
return false;
|
||||
if (!buf.append('\"'))
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
@ -1827,24 +1856,32 @@ GetPCCountJSON(JSContext* cx, const ScriptAndCounts& sac, StringBuffer& buf)
|
||||
char* text;
|
||||
if (!ed.getOutput(&text))
|
||||
return false;
|
||||
AppendJSONProperty(buf, "text");
|
||||
JSString* str = JS_NewStringCopyZ(cx, text);
|
||||
js_free(text);
|
||||
if (!AppendJSONProperty(buf, "text"))
|
||||
return false;
|
||||
if (!str || !(str = StringToSource(cx, str)))
|
||||
return false;
|
||||
buf.append(str);
|
||||
if (!buf.append(str))
|
||||
return false;
|
||||
}
|
||||
|
||||
AppendJSONProperty(buf, "counts");
|
||||
buf.append('{');
|
||||
if (!AppendJSONProperty(buf, "counts"))
|
||||
return false;
|
||||
if (!buf.append('{'))
|
||||
return false;
|
||||
|
||||
if (hits > 0) {
|
||||
AppendJSONProperty(buf, PCCounts::numExecName, NO_COMMA);
|
||||
NumberValueToStringBuffer(cx, DoubleValue(hits), buf);
|
||||
if (!AppendJSONProperty(buf, PCCounts::numExecName, NO_COMMA))
|
||||
return false;
|
||||
if (!NumberValueToStringBuffer(cx, DoubleValue(hits), buf))
|
||||
return false;
|
||||
}
|
||||
|
||||
buf.append('}');
|
||||
buf.append('}');
|
||||
if (!buf.append('}'))
|
||||
return false;
|
||||
if (!buf.append('}'))
|
||||
return false;
|
||||
|
||||
// If the current instruction has thrown,
|
||||
// then decrement the hit counts with the number of throws.
|
||||
@ -1853,57 +1890,79 @@ GetPCCountJSON(JSContext* cx, const ScriptAndCounts& sac, StringBuffer& buf)
|
||||
hits -= counts->numExec();
|
||||
}
|
||||
|
||||
buf.append(']');
|
||||
if (!buf.append(']'))
|
||||
return false;
|
||||
|
||||
jit::IonScriptCounts* ionCounts = sac.getIonCounts();
|
||||
if (ionCounts) {
|
||||
AppendJSONProperty(buf, "ion");
|
||||
buf.append('[');
|
||||
if (!AppendJSONProperty(buf, "ion"))
|
||||
return false;
|
||||
if (!buf.append('['))
|
||||
return false;
|
||||
bool comma = false;
|
||||
while (ionCounts) {
|
||||
if (comma)
|
||||
buf.append(',');
|
||||
if (comma && !buf.append(','))
|
||||
return false;
|
||||
comma = true;
|
||||
|
||||
buf.append('[');
|
||||
if (!buf.append('['))
|
||||
return false;
|
||||
for (size_t i = 0; i < ionCounts->numBlocks(); i++) {
|
||||
if (i)
|
||||
buf.append(',');
|
||||
if (i && !buf.append(','))
|
||||
return false;
|
||||
const jit::IonBlockCounts& block = ionCounts->block(i);
|
||||
|
||||
buf.append('{');
|
||||
AppendJSONProperty(buf, "id", NO_COMMA);
|
||||
NumberValueToStringBuffer(cx, Int32Value(block.id()), buf);
|
||||
AppendJSONProperty(buf, "offset");
|
||||
NumberValueToStringBuffer(cx, Int32Value(block.offset()), buf);
|
||||
AppendJSONProperty(buf, "successors");
|
||||
buf.append('[');
|
||||
if (!buf.append('{'))
|
||||
return false;
|
||||
if (!AppendJSONProperty(buf, "id", NO_COMMA))
|
||||
return false;
|
||||
if (!NumberValueToStringBuffer(cx, Int32Value(block.id()), buf))
|
||||
return false;
|
||||
if (!AppendJSONProperty(buf, "offset"))
|
||||
return false;
|
||||
if (!NumberValueToStringBuffer(cx, Int32Value(block.offset()), buf))
|
||||
return false;
|
||||
if (!AppendJSONProperty(buf, "successors"))
|
||||
return false;
|
||||
if (!buf.append('['))
|
||||
return false;
|
||||
for (size_t j = 0; j < block.numSuccessors(); j++) {
|
||||
if (j)
|
||||
buf.append(',');
|
||||
NumberValueToStringBuffer(cx, Int32Value(block.successor(j)), buf);
|
||||
if (j && !buf.append(','))
|
||||
return false;
|
||||
if (!NumberValueToStringBuffer(cx, Int32Value(block.successor(j)), buf))
|
||||
return false;
|
||||
}
|
||||
buf.append(']');
|
||||
AppendJSONProperty(buf, "hits");
|
||||
NumberValueToStringBuffer(cx, DoubleValue(block.hitCount()), buf);
|
||||
if (!buf.append(']'))
|
||||
return false;
|
||||
if (!AppendJSONProperty(buf, "hits"))
|
||||
return false;
|
||||
if (!NumberValueToStringBuffer(cx, DoubleValue(block.hitCount()), buf))
|
||||
return false;
|
||||
|
||||
AppendJSONProperty(buf, "code");
|
||||
if (!AppendJSONProperty(buf, "code"))
|
||||
return false;
|
||||
JSString* str = JS_NewStringCopyZ(cx, block.code());
|
||||
if (!str || !(str = StringToSource(cx, str)))
|
||||
return false;
|
||||
buf.append(str);
|
||||
buf.append('}');
|
||||
if (!buf.append(str))
|
||||
return false;
|
||||
if (!buf.append('}'))
|
||||
return false;
|
||||
}
|
||||
buf.append(']');
|
||||
if (!buf.append(']'))
|
||||
return false;
|
||||
|
||||
ionCounts = ionCounts->previous();
|
||||
}
|
||||
buf.append(']');
|
||||
if (!buf.append(']'))
|
||||
return false;
|
||||
}
|
||||
|
||||
buf.append('}');
|
||||
if (!buf.append('}'))
|
||||
return false;
|
||||
|
||||
return !cx->isExceptionPending();
|
||||
MOZ_ASSERT(!cx->isExceptionPending());
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSString*)
|
||||
|
33
js/src/tests/ecma_6/Function/arguments-extra-property.js
Normal file
33
js/src/tests/ecma_6/Function/arguments-extra-property.js
Normal file
@ -0,0 +1,33 @@
|
||||
var BUGNUMBER = 1263811;
|
||||
var summary = "GetElem for modified arguments shouldn't be optimized to get original argument.";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
function testModifyFirst() {
|
||||
function f() {
|
||||
Object.defineProperty(arguments, 1, { value: 30 });
|
||||
assertEq(arguments[1], 30);
|
||||
}
|
||||
for (let i = 0; i < 10; i++)
|
||||
f(10, 20);
|
||||
}
|
||||
testModifyFirst();
|
||||
|
||||
function testModifyLater() {
|
||||
function f() {
|
||||
var ans = 20;
|
||||
for (let i = 0; i < 10; i++) {
|
||||
if (i == 5) {
|
||||
Object.defineProperty(arguments, 1, { value: 30 });
|
||||
ans = 30;
|
||||
}
|
||||
assertEq(arguments[1], ans);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < 10; i++)
|
||||
f(10, 20);
|
||||
}
|
||||
testModifyLater();
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
@ -127,7 +127,11 @@ class ArgumentsObject : public NativeObject
|
||||
public:
|
||||
static const uint32_t LENGTH_OVERRIDDEN_BIT = 0x1;
|
||||
static const uint32_t ITERATOR_OVERRIDDEN_BIT = 0x2;
|
||||
static const uint32_t PACKED_BITS_COUNT = 2;
|
||||
static const uint32_t ELEMENT_OVERRIDDEN_BIT = 0x4;
|
||||
static const uint32_t PACKED_BITS_COUNT = 3;
|
||||
|
||||
static_assert(ARGS_LENGTH_MAX <= (UINT32_MAX >> PACKED_BITS_COUNT),
|
||||
"Max arguments length must fit in available bits");
|
||||
|
||||
protected:
|
||||
template <typename CopyArgs>
|
||||
@ -199,6 +203,18 @@ class ArgumentsObject : public NativeObject
|
||||
setFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(v));
|
||||
}
|
||||
|
||||
/* True iff any element has been assigned or its attributes
|
||||
* changed. */
|
||||
bool hasOverriddenElement() const {
|
||||
const Value& v = getFixedSlot(INITIAL_LENGTH_SLOT);
|
||||
return v.toInt32() & ELEMENT_OVERRIDDEN_BIT;
|
||||
}
|
||||
|
||||
void markElementOverridden() {
|
||||
uint32_t v = getFixedSlot(INITIAL_LENGTH_SLOT).toInt32() | ELEMENT_OVERRIDDEN_BIT;
|
||||
setFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(v));
|
||||
}
|
||||
|
||||
/*
|
||||
* Because the arguments object is a real object, its elements may be
|
||||
* deleted. This is implemented by setting a 'deleted' flag for the arg
|
||||
|
@ -1344,11 +1344,13 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId
|
||||
// redefined, it will.
|
||||
if ((desc_.attributes() & JSPROP_RESOLVING) == 0)
|
||||
obj->as<ArgumentsObject>().markLengthOverridden();
|
||||
}
|
||||
if (JSID_IS_SYMBOL(id) && JSID_TO_SYMBOL(id) == cx->wellKnownSymbols().iterator) {
|
||||
} else if (JSID_IS_SYMBOL(id) && JSID_TO_SYMBOL(id) == cx->wellKnownSymbols().iterator) {
|
||||
// Do same thing as .length for [@@iterator].
|
||||
if ((desc_.attributes() & JSPROP_RESOLVING) == 0)
|
||||
obj->as<ArgumentsObject>().markIteratorOverridden();
|
||||
} else if (JSID_IS_INT(id)) {
|
||||
if ((desc_.attributes() & JSPROP_RESOLVING) == 0)
|
||||
obj->as<ArgumentsObject>().markElementOverridden();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2568,6 +2568,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||
JS_FN("RegExpEscapeMetaChars", intrinsic_RegExpEscapeMetaChars, 1,0),
|
||||
JS_FN("GetElemBaseForLambda", intrinsic_GetElemBaseForLambda, 1,0),
|
||||
JS_FN("GetStringDataProperty", intrinsic_GetStringDataProperty, 2,0),
|
||||
JS_INLINABLE_FN("GetFirstDollarIndex", GetFirstDollarIndex, 1,0,
|
||||
GetFirstDollarIndex),
|
||||
|
||||
JS_FN("FlatStringMatch", FlatStringMatch, 2,0),
|
||||
JS_FN("FlatStringSearch", FlatStringSearch, 2,0),
|
||||
|
@ -874,17 +874,6 @@ StaticStrings::isStatic(JSAtom* atom)
|
||||
: isStatic(atom->twoByteChars(nogc), atom->length());
|
||||
}
|
||||
|
||||
AutoStableStringChars::~AutoStableStringChars()
|
||||
{
|
||||
if (ownsChars_) {
|
||||
MOZ_ASSERT(state_ == Latin1 || state_ == TwoByte);
|
||||
if (state_ == Latin1)
|
||||
js_free(const_cast<Latin1Char*>(latin1Chars_));
|
||||
else
|
||||
js_free(const_cast<char16_t*>(twoByteChars_));
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AutoStableStringChars::init(JSContext* cx, JSString* s)
|
||||
{
|
||||
@ -944,10 +933,33 @@ bool AutoStableStringChars::baseIsInline(HandleLinearString linearString)
|
||||
return base->isInline();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T*
|
||||
AutoStableStringChars::allocOwnChars(JSContext* cx, size_t count)
|
||||
{
|
||||
static_assert(
|
||||
InlineCapacity >= sizeof(JS::Latin1Char) * (JSFatInlineString::MAX_LENGTH_LATIN1 + 1) &&
|
||||
InlineCapacity >= sizeof(char16_t) * (JSFatInlineString::MAX_LENGTH_TWO_BYTE + 1),
|
||||
"InlineCapacity too small to hold fat inline strings");
|
||||
|
||||
static_assert((JSString::MAX_LENGTH & mozilla::tl::MulOverflowMask<sizeof(T)>::value) == 0,
|
||||
"Size calculation can overflow");
|
||||
MOZ_ASSERT(count <= JSString::MAX_LENGTH);
|
||||
size_t size = sizeof(T) * count;
|
||||
|
||||
ownChars_.emplace(cx);
|
||||
if (!ownChars_->resize(size)) {
|
||||
ownChars_.reset();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reinterpret_cast<T*>(ownChars_->begin());
|
||||
}
|
||||
|
||||
bool
|
||||
AutoStableStringChars::copyAndInflateLatin1Chars(JSContext* cx, HandleLinearString linearString)
|
||||
{
|
||||
char16_t* chars = cx->pod_malloc<char16_t>(linearString->length() + 1);
|
||||
char16_t* chars = allocOwnChars<char16_t>(cx, linearString->length() + 1);
|
||||
if (!chars)
|
||||
return false;
|
||||
|
||||
@ -956,7 +968,6 @@ AutoStableStringChars::copyAndInflateLatin1Chars(JSContext* cx, HandleLinearStri
|
||||
chars[linearString->length()] = 0;
|
||||
|
||||
state_ = TwoByte;
|
||||
ownsChars_ = true;
|
||||
twoByteChars_ = chars;
|
||||
s_ = linearString;
|
||||
return true;
|
||||
@ -966,7 +977,7 @@ bool
|
||||
AutoStableStringChars::copyLatin1Chars(JSContext* cx, HandleLinearString linearString)
|
||||
{
|
||||
size_t length = linearString->length();
|
||||
JS::Latin1Char* chars = cx->pod_malloc<JS::Latin1Char>(length + 1);
|
||||
JS::Latin1Char* chars = allocOwnChars<JS::Latin1Char>(cx, length + 1);
|
||||
if (!chars)
|
||||
return false;
|
||||
|
||||
@ -974,7 +985,6 @@ AutoStableStringChars::copyLatin1Chars(JSContext* cx, HandleLinearString linearS
|
||||
chars[length] = 0;
|
||||
|
||||
state_ = Latin1;
|
||||
ownsChars_ = true;
|
||||
latin1Chars_ = chars;
|
||||
s_ = linearString;
|
||||
return true;
|
||||
@ -984,7 +994,7 @@ bool
|
||||
AutoStableStringChars::copyTwoByteChars(JSContext* cx, HandleLinearString linearString)
|
||||
{
|
||||
size_t length = linearString->length();
|
||||
char16_t* chars = cx->pod_malloc<char16_t>(length + 1);
|
||||
char16_t* chars = allocOwnChars<char16_t>(cx, length + 1);
|
||||
if (!chars)
|
||||
return false;
|
||||
|
||||
@ -992,7 +1002,6 @@ AutoStableStringChars::copyTwoByteChars(JSContext* cx, HandleLinearString linear
|
||||
chars[length] = 0;
|
||||
|
||||
state_ = TwoByte;
|
||||
ownsChars_ = true;
|
||||
twoByteChars_ = chars;
|
||||
s_ = linearString;
|
||||
return true;
|
||||
|
@ -21,7 +21,7 @@ ExtractWellSized(ExclusiveContext* cx, Buffer& cb)
|
||||
size_t capacity = cb.capacity();
|
||||
size_t length = cb.length();
|
||||
|
||||
CharT* buf = cb.extractRawBuffer();
|
||||
CharT* buf = cb.extractOrCopyRawBuffer();
|
||||
if (!buf)
|
||||
return nullptr;
|
||||
|
||||
|
@ -72,7 +72,7 @@ class StringBuffer
|
||||
return cb.ref<TwoByteCharBuffer>();
|
||||
}
|
||||
|
||||
bool inflateChars();
|
||||
MOZ_WARN_UNUSED_RESULT bool inflateChars();
|
||||
|
||||
public:
|
||||
explicit StringBuffer(ExclusiveContext* cx)
|
||||
@ -85,25 +85,25 @@ class StringBuffer
|
||||
cb.construct<Latin1CharBuffer>(cx);
|
||||
}
|
||||
|
||||
inline bool reserve(size_t len) {
|
||||
MOZ_WARN_UNUSED_RESULT bool reserve(size_t len) {
|
||||
if (len > reserved_)
|
||||
reserved_ = len;
|
||||
return isLatin1() ? latin1Chars().reserve(len) : twoByteChars().reserve(len);
|
||||
}
|
||||
inline bool resize(size_t len) {
|
||||
MOZ_WARN_UNUSED_RESULT bool resize(size_t len) {
|
||||
return isLatin1() ? latin1Chars().resize(len) : twoByteChars().resize(len);
|
||||
}
|
||||
inline bool empty() const {
|
||||
bool empty() const {
|
||||
return isLatin1() ? latin1Chars().empty() : twoByteChars().empty();
|
||||
}
|
||||
inline size_t length() const {
|
||||
size_t length() const {
|
||||
return isLatin1() ? latin1Chars().length() : twoByteChars().length();
|
||||
}
|
||||
inline char16_t getChar(size_t idx) const {
|
||||
char16_t getChar(size_t idx) const {
|
||||
return isLatin1() ? latin1Chars()[idx] : twoByteChars()[idx];
|
||||
}
|
||||
|
||||
inline bool ensureTwoByteChars() {
|
||||
MOZ_WARN_UNUSED_RESULT bool ensureTwoByteChars() {
|
||||
if (isLatin1() && !inflateChars())
|
||||
return false;
|
||||
|
||||
@ -113,7 +113,7 @@ class StringBuffer
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool append(const char16_t c) {
|
||||
MOZ_WARN_UNUSED_RESULT bool append(const char16_t c) {
|
||||
if (isLatin1()) {
|
||||
if (c <= JSString::MAX_LATIN1_CHAR)
|
||||
return latin1Chars().append(Latin1Char(c));
|
||||
@ -122,43 +122,44 @@ class StringBuffer
|
||||
}
|
||||
return twoByteChars().append(c);
|
||||
}
|
||||
inline bool append(Latin1Char c) {
|
||||
MOZ_WARN_UNUSED_RESULT bool append(Latin1Char c) {
|
||||
return isLatin1() ? latin1Chars().append(c) : twoByteChars().append(c);
|
||||
}
|
||||
inline bool append(char c) {
|
||||
MOZ_WARN_UNUSED_RESULT bool append(char c) {
|
||||
return append(Latin1Char(c));
|
||||
}
|
||||
|
||||
inline bool append(const char16_t* begin, const char16_t* end);
|
||||
inline bool append(const char16_t* chars, size_t len) {
|
||||
inline MOZ_WARN_UNUSED_RESULT bool append(const char16_t* begin, const char16_t* end);
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT bool append(const char16_t* chars, size_t len) {
|
||||
return append(chars, chars + len);
|
||||
}
|
||||
|
||||
inline bool append(const Latin1Char* begin, const Latin1Char* end) {
|
||||
MOZ_WARN_UNUSED_RESULT bool append(const Latin1Char* begin, const Latin1Char* end) {
|
||||
return isLatin1() ? latin1Chars().append(begin, end) : twoByteChars().append(begin, end);
|
||||
}
|
||||
inline bool append(const Latin1Char* chars, size_t len) {
|
||||
MOZ_WARN_UNUSED_RESULT bool append(const Latin1Char* chars, size_t len) {
|
||||
return append(chars, chars + len);
|
||||
}
|
||||
|
||||
inline bool append(const JS::ConstCharPtr chars, size_t len) {
|
||||
MOZ_WARN_UNUSED_RESULT bool append(const JS::ConstCharPtr chars, size_t len) {
|
||||
return append(chars.get(), chars.get() + len);
|
||||
}
|
||||
inline bool appendN(Latin1Char c, size_t n) {
|
||||
MOZ_WARN_UNUSED_RESULT bool appendN(Latin1Char c, size_t n) {
|
||||
return isLatin1() ? latin1Chars().appendN(c, n) : twoByteChars().appendN(c, n);
|
||||
}
|
||||
|
||||
inline bool append(JSString* str);
|
||||
inline bool append(JSLinearString* str);
|
||||
inline bool appendSubstring(JSString* base, size_t off, size_t len);
|
||||
inline bool appendSubstring(JSLinearString* base, size_t off, size_t len);
|
||||
inline MOZ_WARN_UNUSED_RESULT bool append(JSString* str);
|
||||
inline MOZ_WARN_UNUSED_RESULT bool append(JSLinearString* str);
|
||||
inline MOZ_WARN_UNUSED_RESULT bool appendSubstring(JSString* base, size_t off, size_t len);
|
||||
inline MOZ_WARN_UNUSED_RESULT bool appendSubstring(JSLinearString* base, size_t off, size_t len);
|
||||
|
||||
inline bool append(const char* chars, size_t len) {
|
||||
MOZ_WARN_UNUSED_RESULT bool append(const char* chars, size_t len) {
|
||||
return append(reinterpret_cast<const Latin1Char*>(chars), len);
|
||||
}
|
||||
|
||||
template <size_t ArrayLength>
|
||||
bool append(const char (&array)[ArrayLength]) {
|
||||
MOZ_WARN_UNUSED_RESULT bool append(const char (&array)[ArrayLength]) {
|
||||
return append(array, ArrayLength - 1); /* No trailing '\0'. */
|
||||
}
|
||||
|
||||
|
@ -742,7 +742,7 @@ bool
|
||||
SCOutput::extractBuffer(uint64_t** datap, size_t* sizep)
|
||||
{
|
||||
*sizep = buf.length() * sizeof(uint64_t);
|
||||
return (*datap = buf.extractRawBuffer()) != nullptr;
|
||||
return (*datap = buf.extractOrCopyRawBuffer()) != nullptr;
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
@ -2158,14 +2158,6 @@ static bool IsContentLEQ(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
|
||||
return nsLayoutUtils::CompareTreePosition(content1, content2, commonAncestor) <= 0;
|
||||
}
|
||||
|
||||
static bool IsCSSOrderLEQ(nsDisplayItem* aItem1, nsDisplayItem* aItem2, void*) {
|
||||
nsIFrame* frame1 = aItem1->Frame();
|
||||
nsIFrame* frame2 = aItem2->Frame();
|
||||
int32_t order1 = frame1 ? frame1->StylePosition()->mOrder : 0;
|
||||
int32_t order2 = frame2 ? frame2->StylePosition()->mOrder : 0;
|
||||
return order1 <= order2;
|
||||
}
|
||||
|
||||
static bool IsZOrderLEQ(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
|
||||
void* aClosure) {
|
||||
{
|
||||
@ -2189,10 +2181,6 @@ void nsDisplayList::SortByContentOrder(nsIContent* aCommonAncestor) {
|
||||
Sort(IsContentLEQ, aCommonAncestor);
|
||||
}
|
||||
|
||||
void nsDisplayList::SortByCSSOrder() {
|
||||
Sort(IsCSSOrderLEQ, nullptr);
|
||||
}
|
||||
|
||||
void nsDisplayList::Sort(SortLEQ aCmp, void* aClosure) {
|
||||
::Sort(this, Count(), aCmp, aClosure);
|
||||
}
|
||||
|
@ -2017,13 +2017,6 @@ public:
|
||||
* ancestor of some elements, then we lose performance but not correctness
|
||||
*/
|
||||
void SortByContentOrder(nsIContent* aCommonAncestor);
|
||||
/**
|
||||
* Stable sort this list by CSS 'order' property order.
|
||||
* http://dev.w3.org/csswg/css-flexbox-1/#order-property
|
||||
* (also applies to CSS Grid although it's in the Flexbox spec ATM)
|
||||
* It is assumed that the list is already in document content order.
|
||||
*/
|
||||
void SortByCSSOrder();
|
||||
|
||||
/**
|
||||
* Generic stable sort. Take care, because some of the items might be nsDisplayLists
|
||||
|
@ -112,7 +112,7 @@ struct nsGridContainerFrame::TrackSize
|
||||
eMaxContentMinSizing = 0x4,
|
||||
eMinOrMaxContentMinSizing = eMinContentMinSizing | eMaxContentMinSizing,
|
||||
eIntrinsicMinSizing = eMinOrMaxContentMinSizing | eAutoMinSizing,
|
||||
eFlexMinSizing = 0x8,
|
||||
eFlexMinSizing = 0x8, // not really used ATM due to a spec change
|
||||
eAutoMaxSizing = 0x10,
|
||||
eMinContentMaxSizing = 0x20,
|
||||
eMaxContentMaxSizing = 0x40,
|
||||
@ -167,6 +167,7 @@ nsGridContainerFrame::TrackSize::Initialize(nscoord aPercentageBasis,
|
||||
}
|
||||
// http://dev.w3.org/csswg/css-grid/#algo-init
|
||||
switch (minSizeUnit) {
|
||||
case eStyleUnit_FlexFraction:
|
||||
case eStyleUnit_Auto:
|
||||
mState = eAutoMinSizing;
|
||||
break;
|
||||
@ -174,9 +175,6 @@ nsGridContainerFrame::TrackSize::Initialize(nscoord aPercentageBasis,
|
||||
mState = IsMinContent(aMinCoord) ? eMinContentMinSizing
|
||||
: eMaxContentMinSizing;
|
||||
break;
|
||||
case eStyleUnit_FlexFraction:
|
||||
mState = eFlexMinSizing;
|
||||
break;
|
||||
default:
|
||||
mBase = nsRuleNode::ComputeCoordPercentCalc(aMinCoord, aPercentageBasis);
|
||||
}
|
||||
@ -5215,15 +5213,6 @@ nsGridContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
// Our children are all grid-level boxes, which behave the same as
|
||||
// inline-blocks in painting, so their borders/backgrounds all go on
|
||||
// the BlockBorderBackgrounds list.
|
||||
// Also, we capture positioned descendants so we can sort them by
|
||||
// CSS 'order'.
|
||||
nsDisplayList positionedDescendants;
|
||||
nsDisplayListSet childLists(aLists.BlockBorderBackgrounds(),
|
||||
aLists.BlockBorderBackgrounds(),
|
||||
aLists.Floats(),
|
||||
aLists.Content(),
|
||||
&positionedDescendants,
|
||||
aLists.Outlines());
|
||||
typedef GridItemCSSOrderIterator::OrderState OrderState;
|
||||
OrderState order = HasAnyStateBits(NS_STATE_GRID_NORMAL_FLOW_CHILDREN_IN_CSS_ORDER)
|
||||
? OrderState::eKnownOrdered
|
||||
@ -5232,11 +5221,9 @@ nsGridContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
GridItemCSSOrderIterator::eIncludeAll, order);
|
||||
for (; !iter.AtEnd(); iter.Next()) {
|
||||
nsIFrame* child = *iter;
|
||||
BuildDisplayListForChild(aBuilder, child, aDirtyRect, childLists,
|
||||
BuildDisplayListForChild(aBuilder, child, aDirtyRect, aLists,
|
||||
::GetDisplayFlagsForGridItem(child));
|
||||
}
|
||||
positionedDescendants.SortByCSSOrder();
|
||||
aLists.PositionedDescendants()->AppendToTop(&positionedDescendants);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -5,7 +5,7 @@
|
||||
-->
|
||||
<html><head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Grid Test: flex min-sizing</title>
|
||||
<title>Reference: flex/auto min-sizing</title>
|
||||
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1151212">
|
||||
<style type="text/css">
|
||||
body,html { color:black; background:white; font-family:monospace; font-size:16px; padding:0; margin:0; }
|
||||
@ -42,9 +42,9 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
||||
}
|
||||
|
||||
.g4 {
|
||||
grid-template-columns: minmax(0,0)
|
||||
minmax(0,0)
|
||||
minmax(0,0)
|
||||
grid-template-columns: minmax(2px,0)
|
||||
minmax(1px,0)
|
||||
minmax(1px,0)
|
||||
1fr;
|
||||
}
|
||||
|
||||
@ -56,9 +56,9 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
||||
}
|
||||
|
||||
.g6 {
|
||||
grid-template-columns: minmax(0,0)
|
||||
minmax(0,0)
|
||||
minmax(0,0)
|
||||
grid-template-columns: minmax(2px,0)
|
||||
minmax(1px,0)
|
||||
minmax(1px,0)
|
||||
20px;
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
-->
|
||||
<html><head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Grid Test: flex min-sizing</title>
|
||||
<title>CSS Grid Test: flex/auto min-sizing</title>
|
||||
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1151212">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-minmax">
|
||||
<link rel="match" href="grid-flex-min-sizing-001-ref.html">
|
||||
@ -22,108 +22,113 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
||||
width:140px;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE Due to a spec change, 'fr' min-sizing inside minmax() is now
|
||||
* invalid, so they were replaced in this test with 'auto' instead (for now).
|
||||
*/
|
||||
|
||||
.g1 {
|
||||
grid-template-columns: minmax(1fr,min-content)
|
||||
minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
grid-template-columns: minmax(auto,min-content)
|
||||
minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
1fr;
|
||||
}
|
||||
|
||||
.g2 {
|
||||
grid-template-columns: minmax(1fr,max-content)
|
||||
minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
grid-template-columns: minmax(auto,max-content)
|
||||
minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
1fr;
|
||||
}
|
||||
|
||||
.g3 {
|
||||
grid-template-columns: minmax(1fr,auto)
|
||||
minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
grid-template-columns: minmax(auto,auto)
|
||||
minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
1fr;
|
||||
}
|
||||
|
||||
.g4 {
|
||||
grid-template-columns: minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
grid-template-columns: minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
1fr;
|
||||
}
|
||||
|
||||
.g5 {
|
||||
grid-template-columns: minmax(20px,0)
|
||||
minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
1fr;
|
||||
}
|
||||
|
||||
.g6 {
|
||||
grid-template-columns: minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
grid-template-columns: minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
20px;
|
||||
}
|
||||
|
||||
.g7 {
|
||||
grid-template-columns: minmax(20px,1fr)
|
||||
minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
20px;
|
||||
}
|
||||
|
||||
.g8 {
|
||||
grid-template-columns: minmax(1fr,1fr)
|
||||
minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
grid-template-columns: minmax(auto,1fr)
|
||||
minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
20px;
|
||||
}
|
||||
|
||||
.g9 {
|
||||
grid-template-columns: 20px
|
||||
30px
|
||||
minmax(1fr,0)
|
||||
minmax(auto,0)
|
||||
10px;
|
||||
}
|
||||
|
||||
.gA {
|
||||
grid-template-columns: minmax(1fr,0)
|
||||
grid-template-columns: minmax(auto,0)
|
||||
minmax(min-content,40px)
|
||||
minmax(1fr,0)
|
||||
minmax(auto,0)
|
||||
20px;
|
||||
}
|
||||
|
||||
.gB {
|
||||
grid-template-columns: minmax(1fr,0)
|
||||
grid-template-columns: minmax(auto,0)
|
||||
minmax(auto,40px)
|
||||
minmax(1fr,0)
|
||||
minmax(auto,0)
|
||||
20px;
|
||||
}
|
||||
|
||||
.gC {
|
||||
grid-template-columns: minmax(1fr,20px)
|
||||
grid-template-columns: minmax(auto,20px)
|
||||
minmax(auto,40px)
|
||||
minmax(1fr,0)
|
||||
minmax(auto,0)
|
||||
20px;
|
||||
}
|
||||
|
||||
.gD {
|
||||
grid-template-columns: minmax(auto,20px)
|
||||
minmax(auto,40px)
|
||||
minmax(1fr,0)
|
||||
minmax(auto,0)
|
||||
min-content;
|
||||
}
|
||||
|
||||
.gE {
|
||||
grid-template-columns: minmax(auto,20px)
|
||||
minmax(auto,40px)
|
||||
minmax(1fr,20px)
|
||||
minmax(auto,20px)
|
||||
auto;
|
||||
}
|
||||
|
||||
.gF {
|
||||
grid-template-columns: minmax(auto,20px)
|
||||
minmax(min-content,max-content)
|
||||
minmax(1fr,40px)
|
||||
minmax(auto,40px)
|
||||
auto;
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
-->
|
||||
<html><head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Grid Test: flex min-sizing</title>
|
||||
<title>Reference: flex/auto min-sizing</title>
|
||||
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1151212">
|
||||
<style type="text/css">
|
||||
body,html { color:black; background:white; font-family:monospace; font-size:16px; padding:0; margin:0; }
|
||||
@ -25,47 +25,45 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
||||
}
|
||||
|
||||
.g1 {
|
||||
grid-template-columns: minmax(min-content,min-content)
|
||||
minmax(min-content,0)
|
||||
minmax(min-content,0)
|
||||
grid-template-columns: minmax(4px,0)
|
||||
minmax(0,0)
|
||||
minmax(0,0)
|
||||
1fr;
|
||||
}
|
||||
|
||||
.g2 {
|
||||
grid-template-columns: minmax(min-content,max-content)
|
||||
minmax(min-content,0)
|
||||
minmax(min-content,0)
|
||||
grid-template-columns: minmax(4px,0)
|
||||
0
|
||||
0
|
||||
1fr;
|
||||
}
|
||||
|
||||
.g3 {
|
||||
grid-template-columns: minmax(min-content,auto)
|
||||
minmax(min-content,0)
|
||||
minmax(min-content,0)
|
||||
grid-template-columns: minmax(4px,0)
|
||||
0
|
||||
0
|
||||
1fr;
|
||||
}
|
||||
|
||||
.g4 {
|
||||
grid-template-columns: minmax(0,0)
|
||||
minmax(0,0)
|
||||
minmax(0,0)
|
||||
grid-template-columns: minmax(2px,0)
|
||||
1px
|
||||
1px
|
||||
1fr;
|
||||
min-width:24px;
|
||||
}
|
||||
|
||||
.g5 {
|
||||
grid-template-columns: minmax(20px,0)
|
||||
minmax(0,0)
|
||||
minmax(0,0)
|
||||
4px;
|
||||
0;
|
||||
}
|
||||
|
||||
.g6 {
|
||||
grid-template-columns: minmax(0,0)
|
||||
minmax(0,0)
|
||||
minmax(0,0)
|
||||
grid-template-columns: minmax(2px,0)
|
||||
minmax(1px,0)
|
||||
minmax(1px,0)
|
||||
20px;
|
||||
min-width:44px;
|
||||
}
|
||||
|
||||
.g7 {
|
||||
@ -97,37 +95,37 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
||||
}
|
||||
|
||||
.gB {
|
||||
grid-template-columns: minmax(min-content,0)
|
||||
minmax(auto,40px)
|
||||
minmax(0,0)
|
||||
grid-template-columns: minmax(4px,0)
|
||||
0
|
||||
0
|
||||
20px;
|
||||
}
|
||||
|
||||
.gC {
|
||||
grid-template-columns: minmax(min-content,20px)
|
||||
minmax(auto,40px)
|
||||
minmax(0,0)
|
||||
grid-template-columns: minmax(4px,0)
|
||||
0
|
||||
0
|
||||
20px;
|
||||
}
|
||||
|
||||
.gD {
|
||||
grid-template-columns: minmax(min-content,20px)
|
||||
minmax(auto,40px)
|
||||
minmax(0,0)
|
||||
min-content;
|
||||
grid-template-columns: minmax(4px,0)
|
||||
0
|
||||
0
|
||||
0;
|
||||
}
|
||||
|
||||
.gE {
|
||||
grid-template-columns: minmax(min-content,20px)
|
||||
minmax(min-content,40px)
|
||||
minmax(7px,20px)
|
||||
auto;
|
||||
grid-template-columns: minmax(2px,0)
|
||||
minmax(1px,0)
|
||||
minmax(1px,0)
|
||||
0px;
|
||||
}
|
||||
|
||||
.gF {
|
||||
grid-template-columns: minmax(min-content,20px)
|
||||
minmax(0,max-content)
|
||||
minmax(0,40px)
|
||||
grid-template-columns: 22px
|
||||
1px
|
||||
1px
|
||||
auto;
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
-->
|
||||
<html><head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Grid Test: flex min-sizing</title>
|
||||
<title>CSS Grid Test: flex/auto min-sizing</title>
|
||||
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1151212">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-minmax">
|
||||
<link rel="match" href="grid-flex-min-sizing-002-ref.html">
|
||||
@ -26,108 +26,113 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE Due to a spec change, 'fr' min-sizing inside minmax() is now
|
||||
* invalid, so they were replaced in this test with 'auto' instead (for now).
|
||||
*/
|
||||
|
||||
.g1 {
|
||||
grid-template-columns: minmax(1fr,min-content)
|
||||
minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
grid-template-columns: minmax(auto,min-content)
|
||||
minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
1fr;
|
||||
}
|
||||
|
||||
.g2 {
|
||||
grid-template-columns: minmax(1fr,max-content)
|
||||
minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
grid-template-columns: minmax(auto,max-content)
|
||||
minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
1fr;
|
||||
}
|
||||
|
||||
.g3 {
|
||||
grid-template-columns: minmax(1fr,auto)
|
||||
minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
grid-template-columns: minmax(auto,auto)
|
||||
minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
1fr;
|
||||
}
|
||||
|
||||
.g4 {
|
||||
grid-template-columns: minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
grid-template-columns: minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
1fr;
|
||||
}
|
||||
|
||||
.g5 {
|
||||
grid-template-columns: minmax(20px,0)
|
||||
minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
1fr;
|
||||
}
|
||||
|
||||
.g6 {
|
||||
grid-template-columns: minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
grid-template-columns: minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
20px;
|
||||
}
|
||||
|
||||
.g7 {
|
||||
grid-template-columns: minmax(20px,1fr)
|
||||
minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
20px;
|
||||
}
|
||||
|
||||
.g8 {
|
||||
grid-template-columns: minmax(1fr,1fr)
|
||||
minmax(1fr,0)
|
||||
minmax(1fr,0)
|
||||
grid-template-columns: minmax(auto,1fr)
|
||||
minmax(auto,0)
|
||||
minmax(auto,0)
|
||||
20px;
|
||||
}
|
||||
|
||||
.g9 {
|
||||
grid-template-columns: 20px
|
||||
30px
|
||||
minmax(1fr,0)
|
||||
minmax(auto,0)
|
||||
10px;
|
||||
}
|
||||
|
||||
.gA {
|
||||
grid-template-columns: minmax(1fr,0)
|
||||
grid-template-columns: minmax(auto,0)
|
||||
minmax(min-content,40px)
|
||||
minmax(1fr,0)
|
||||
minmax(auto,0)
|
||||
20px;
|
||||
}
|
||||
|
||||
.gB {
|
||||
grid-template-columns: minmax(1fr,0)
|
||||
grid-template-columns: minmax(auto,0)
|
||||
minmax(auto,40px)
|
||||
minmax(1fr,0)
|
||||
minmax(auto,0)
|
||||
20px;
|
||||
}
|
||||
|
||||
.gC {
|
||||
grid-template-columns: minmax(1fr,20px)
|
||||
grid-template-columns: minmax(auto,20px)
|
||||
minmax(auto,40px)
|
||||
minmax(1fr,0)
|
||||
minmax(auto,0)
|
||||
20px;
|
||||
}
|
||||
|
||||
.gD {
|
||||
grid-template-columns: minmax(auto,20px)
|
||||
minmax(auto,40px)
|
||||
minmax(1fr,0)
|
||||
minmax(auto,0)
|
||||
min-content;
|
||||
}
|
||||
|
||||
.gE {
|
||||
grid-template-columns: minmax(auto,20px)
|
||||
minmax(auto,40px)
|
||||
minmax(1fr,20px)
|
||||
minmax(auto,20px)
|
||||
auto;
|
||||
}
|
||||
|
||||
.gF {
|
||||
grid-template-columns: minmax(auto,20px)
|
||||
minmax(min-content,max-content)
|
||||
minmax(1fr,40px)
|
||||
minmax(auto,40px)
|
||||
auto;
|
||||
}
|
||||
|
||||
|
@ -22,9 +22,9 @@ body,html { color:black; background:white; font-size:16px; padding:0; margin:0;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.a { z-index:4; left:74px; right:5px; background:lime; }
|
||||
.b { z-index:3; left:54px; right:5px; background:pink; }
|
||||
.c { z-index:2; left:34px; right:5px; background:yellow; }
|
||||
.a { z-index:1; left:74px; right:5px; background:lime; }
|
||||
.b { z-index:1; left:54px; right:5px; background:pink; }
|
||||
.c { z-index:1; left:34px; right:5px; background:yellow; }
|
||||
.d { z-index:1; left:14px; right:5px; background:silver; }
|
||||
.e { display:none; }
|
||||
|
||||
@ -64,34 +64,34 @@ f { float:left; }
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
<div style="order:2">
|
||||
<span class="abs a">a</span>
|
||||
<span class="abs b">b</span>
|
||||
</div>
|
||||
<div style="order:1">
|
||||
<div>
|
||||
<span class="abs c">c</span>
|
||||
<span class="abs e">FAIL<x>x</x></span>
|
||||
<span class="abs d">d<x>x</x></span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="abs a">a</span>
|
||||
<span class="abs b">b</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
<div style="display:grid; order:2">
|
||||
<div style="order:2">
|
||||
<span class="abs a">a</span>
|
||||
</div>
|
||||
<div style="order:1">
|
||||
<span class="abs c">c</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:grid; order:1">
|
||||
<div style="order:2">
|
||||
<span class="abs b">b</span>
|
||||
</div>
|
||||
<div style="order:1">
|
||||
<div style="display:grid;">
|
||||
<div>
|
||||
<span class="abs e">FAIL<x>x</x></span>
|
||||
<span class="abs d">d<x>x</x></span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="abs b">b</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="abs c">c</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="abs a">a</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -104,15 +104,15 @@ f { float:left; }
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
<div style="order:2">
|
||||
<span class="abs a">a</span>
|
||||
<span class="abs z1 b">b</span>
|
||||
</div>
|
||||
<div style="order:1">
|
||||
<div>
|
||||
<span class="abs z1 c">c</span>
|
||||
<span class="abs e">FAIL<x>x</x></span>
|
||||
<span class="abs d">d<x>x</x></span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="abs a">a</span>
|
||||
<span class="abs z1 b">b</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
|
@ -33,7 +33,7 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
||||
width: 56px;
|
||||
}
|
||||
.g2f .d1 {
|
||||
width: 52px;
|
||||
width: 69px;
|
||||
}
|
||||
.g3 .d1 {
|
||||
width: 56px;
|
||||
@ -42,7 +42,7 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
||||
width: 96px;
|
||||
}
|
||||
.g4f .d1 {
|
||||
width: 92px;
|
||||
width: 69px;
|
||||
}
|
||||
.g5 .d1 {
|
||||
width: 96px;
|
||||
@ -51,7 +51,7 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
||||
width: 69px;
|
||||
}
|
||||
.g6f .d1 {
|
||||
width: 77px;
|
||||
width: 69px;
|
||||
}
|
||||
.g7 .d1 {
|
||||
width: 69px;
|
||||
|
@ -33,7 +33,7 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
||||
width: 56px;
|
||||
}
|
||||
.g2f .d1 {
|
||||
width: 56px;
|
||||
width: 69px;
|
||||
}
|
||||
.g3 .d1 {
|
||||
width: 56px;
|
||||
@ -90,7 +90,9 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
||||
width: 444px;
|
||||
}
|
||||
.g2f .d2 {
|
||||
width: 448px;
|
||||
right: auto;
|
||||
left: 69px;
|
||||
width: 35px;
|
||||
}
|
||||
.g3 .d2 {
|
||||
width: 444px;
|
||||
@ -99,7 +101,9 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
||||
width: 404px;
|
||||
}
|
||||
.g4f .d2 {
|
||||
width: 396px;
|
||||
right: auto;
|
||||
left: 69px;
|
||||
width: 35px;
|
||||
}
|
||||
.g5 .d2 {
|
||||
width: 404px;
|
||||
@ -108,7 +112,9 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
||||
width: 431px;
|
||||
}
|
||||
.g6f .d2 {
|
||||
width: 423px;
|
||||
right: auto;
|
||||
left: 69px;
|
||||
width: 35px;
|
||||
}
|
||||
.g7 .d2 {
|
||||
width: 431px;
|
||||
|
@ -33,7 +33,8 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
||||
width: 56px;
|
||||
}
|
||||
.g2f .d1 {
|
||||
width: 52px;
|
||||
left: 28px;
|
||||
width: 28px;
|
||||
}
|
||||
.g3 .d1 {
|
||||
left: 41px;
|
||||
@ -44,8 +45,8 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
||||
width: 2px;
|
||||
}
|
||||
.g4f .d1 {
|
||||
left: 83px;
|
||||
width: 0px;
|
||||
left: 28px;
|
||||
width: 28px;
|
||||
}
|
||||
.g5 .d1 {
|
||||
left: 81px;
|
||||
@ -56,7 +57,7 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
||||
width: 28px;
|
||||
}
|
||||
.g6f .d1 {
|
||||
left: 27px;
|
||||
left: 28px;
|
||||
width: 28px;
|
||||
}
|
||||
.g7 .d1 {
|
||||
@ -104,7 +105,8 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
||||
left: 2px;
|
||||
}
|
||||
.g2f .d2 {
|
||||
width: 104px;
|
||||
width: 48px;
|
||||
left: 56px;
|
||||
}
|
||||
.g3 .d2 {
|
||||
width: 61px;
|
||||
@ -115,8 +117,8 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
||||
left: 83px;
|
||||
}
|
||||
.g4f .d2 {
|
||||
width: 22px;
|
||||
left: 82px;
|
||||
width: 48px;
|
||||
left: 56px;
|
||||
}
|
||||
.g5 .d2 {
|
||||
width: 21px;
|
||||
@ -127,8 +129,8 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
||||
left: 56px;
|
||||
}
|
||||
.g6f .d2 {
|
||||
width: 49px;
|
||||
left: 55px;
|
||||
width: 48px;
|
||||
left: 56px;
|
||||
}
|
||||
.g7 .d2 {
|
||||
width: 48px;
|
||||
|
@ -8735,6 +8735,10 @@ CSSParserImpl::ParseGridTrackSize(nsCSSValue& aValue,
|
||||
!func->Item(2).IsLengthPercentCalcUnit()) {
|
||||
return CSSParseResult::Error;
|
||||
}
|
||||
// Reject 'fr' min-sizing.
|
||||
if (func->Item(1).GetUnit() == eCSSUnit_FlexFraction) {
|
||||
return CSSParseResult::Error;
|
||||
}
|
||||
return CSSParseResult::Ok;
|
||||
}
|
||||
SkipUntil(')');
|
||||
@ -10812,7 +10816,7 @@ CSSParserImpl::ParseWebkitTextStroke()
|
||||
eCSSProperty__webkit_text_stroke_color
|
||||
};
|
||||
|
||||
const size_t numProps = ArrayLength(kWebkitTextStrokeIDs);
|
||||
const size_t numProps = MOZ_ARRAY_LENGTH(kWebkitTextStrokeIDs);
|
||||
nsCSSValue values[numProps];
|
||||
|
||||
int32_t found = ParseChoice(values, kWebkitTextStrokeIDs, numProps);
|
||||
|
@ -5996,7 +5996,6 @@ if (IsCSSPropertyPrefEnabled("layout.css.grid.enabled")) {
|
||||
"[a] calc(1%) [b] repeat(auto-fit,[a b] minmax(1mm, 1%) [c]) [c]",
|
||||
"repeat(auto-fill,minmax(1%,auto))",
|
||||
"repeat(auto-fill,minmax(1em,min-content)) minmax(min-content,0)",
|
||||
"repeat(auto-fill,minmax(1fr,1em)) [a] minmax(0, max-content)",
|
||||
"repeat(auto-fill,minmax(max-content,1mm))",
|
||||
],
|
||||
invalid_values: [
|
||||
@ -6051,6 +6050,7 @@ if (IsCSSPropertyPrefEnabled("layout.css.grid.enabled")) {
|
||||
"repeat(auto-fit,minmax(auto,auto))",
|
||||
"repeat(auto-fit,minmax(min-content,1fr))",
|
||||
"repeat(auto-fit,minmax(1fr,auto))",
|
||||
"repeat(auto-fill,minmax(1fr,1em))",
|
||||
"repeat(auto-fill, 10px) auto",
|
||||
"auto repeat(auto-fit, 10px)",
|
||||
"minmax(min-content,max-content) repeat(auto-fit, 0)",
|
||||
|
@ -931,6 +931,11 @@ static int nr_ice_component_stun_server_cb(void *cb_arg,nr_stun_server_ctx *stun
|
||||
nr_transport_addr local_addr;
|
||||
int r,_status;
|
||||
|
||||
if(comp->state==NR_ICE_COMPONENT_FAILED) {
|
||||
*error=400;
|
||||
ABORT(R_REJECTED);
|
||||
}
|
||||
|
||||
/* Find the candidate pair that this maps to */
|
||||
if(r=nr_socket_getaddr(sock,&local_addr)) {
|
||||
*error=500;
|
||||
|
@ -640,17 +640,35 @@ public:
|
||||
T popCopy();
|
||||
|
||||
/**
|
||||
* Transfers ownership of the internal buffer used by this vector to the
|
||||
* caller. (It's the caller's responsibility to properly deallocate this
|
||||
* buffer, in accordance with this vector's AllocPolicy.) After this call,
|
||||
* the vector is empty. Since the returned buffer may need to be allocated
|
||||
* (if the elements are currently stored in-place), the call can fail,
|
||||
* returning nullptr.
|
||||
* If elements are stored in-place, return nullptr and leave this vector
|
||||
* unmodified.
|
||||
*
|
||||
* Otherwise return this vector's elements buffer, and clear this vector as if
|
||||
* by clearAndFree(). The caller now owns the buffer and is responsible for
|
||||
* deallocating it consistent with this vector's AllocPolicy.
|
||||
*
|
||||
* N.B. Although a T*, only the range [0, length()) is constructed.
|
||||
*/
|
||||
MOZ_WARN_UNUSED_RESULT T* extractRawBuffer();
|
||||
|
||||
/**
|
||||
* If elements are stored in-place, allocate a new buffer, move this vector's
|
||||
* elements into it, and return that buffer.
|
||||
*
|
||||
* Otherwise return this vector's elements buffer. The caller now owns the
|
||||
* buffer and is responsible for deallocating it consistent with this vector's
|
||||
* AllocPolicy.
|
||||
*
|
||||
* This vector is cleared, as if by clearAndFree(), when this method
|
||||
* succeeds. This method fails and returns nullptr only if new elements buffer
|
||||
* allocation fails.
|
||||
*
|
||||
* N.B. Only the range [0, length()) of the returned buffer is constructed.
|
||||
* If any of these elements are uninitialized (as growByUninitialized
|
||||
* enables), behavior is undefined.
|
||||
*/
|
||||
MOZ_WARN_UNUSED_RESULT T* extractOrCopyRawBuffer();
|
||||
|
||||
/**
|
||||
* Transfer ownership of an array of objects into the vector. The caller
|
||||
* must have allocated the array in accordance with this vector's
|
||||
@ -1303,28 +1321,48 @@ template<typename T, size_t N, class AP>
|
||||
inline T*
|
||||
Vector<T, N, AP>::extractRawBuffer()
|
||||
{
|
||||
T* ret;
|
||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||
|
||||
if (usingInlineStorage()) {
|
||||
ret = this->template pod_malloc<T>(mLength);
|
||||
if (!ret) {
|
||||
return nullptr;
|
||||
}
|
||||
Impl::copyConstruct(ret, beginNoCheck(), endNoCheck());
|
||||
Impl::destroy(beginNoCheck(), endNoCheck());
|
||||
/* mBegin, mCapacity are unchanged. */
|
||||
mLength = 0;
|
||||
} else {
|
||||
ret = mBegin;
|
||||
mBegin = static_cast<T*>(mStorage.addr());
|
||||
mLength = 0;
|
||||
mCapacity = kInlineCapacity;
|
||||
#ifdef DEBUG
|
||||
mReserved = 0;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
T* ret = mBegin;
|
||||
mBegin = static_cast<T*>(mStorage.addr());
|
||||
mLength = 0;
|
||||
mCapacity = kInlineCapacity;
|
||||
#ifdef DEBUG
|
||||
mReserved = 0;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T, size_t N, class AP>
|
||||
inline T*
|
||||
Vector<T, N, AP>::extractOrCopyRawBuffer()
|
||||
{
|
||||
if (T* ret = extractRawBuffer()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||
|
||||
T* copy = this->template pod_malloc<T>(mLength);
|
||||
if (!copy) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Impl::moveConstruct(copy, beginNoCheck(), endNoCheck());
|
||||
Impl::destroy(beginNoCheck(), endNoCheck());
|
||||
mBegin = static_cast<T*>(mStorage.addr());
|
||||
mLength = 0;
|
||||
mCapacity = kInlineCapacity;
|
||||
#ifdef DEBUG
|
||||
mReserved = 0;
|
||||
#endif
|
||||
return copy;
|
||||
}
|
||||
|
||||
template<typename T, size_t N, class AP>
|
||||
inline void
|
||||
Vector<T, N, AP>::replaceRawBuffer(T* aP, size_t aLength)
|
||||
|
@ -20,6 +20,8 @@ struct mozilla::detail::VectorTesting
|
||||
static void testConstRange();
|
||||
static void testEmplaceBack();
|
||||
static void testReverse();
|
||||
static void testExtractRawBuffer();
|
||||
static void testExtractOrCopyRawBuffer();
|
||||
};
|
||||
|
||||
void
|
||||
@ -111,6 +113,13 @@ struct S
|
||||
|
||||
static size_t constructCount;
|
||||
static size_t moveCount;
|
||||
static size_t destructCount;
|
||||
|
||||
static void resetCounts() {
|
||||
constructCount = 0;
|
||||
moveCount = 0;
|
||||
destructCount = 0;
|
||||
}
|
||||
|
||||
S(size_t j, size_t k)
|
||||
: j(j)
|
||||
@ -123,27 +132,35 @@ struct S
|
||||
: j(rhs.j)
|
||||
, k(Move(rhs.k))
|
||||
{
|
||||
rhs.~S();
|
||||
rhs.j = 0;
|
||||
rhs.k.reset(0);
|
||||
moveCount++;
|
||||
}
|
||||
|
||||
~S() {
|
||||
destructCount++;
|
||||
}
|
||||
|
||||
S(const S&) = delete;
|
||||
S& operator=(const S&) = delete;
|
||||
};
|
||||
|
||||
size_t S::constructCount = 0;
|
||||
size_t S::moveCount = 0;
|
||||
size_t S::destructCount = 0;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
mozilla::detail::VectorTesting::testEmplaceBack()
|
||||
{
|
||||
S::resetCounts();
|
||||
|
||||
Vector<S> vec;
|
||||
MOZ_RELEASE_ASSERT(vec.reserve(20));
|
||||
|
||||
for (size_t i = 0; i < 10; i++) {
|
||||
S s(i, i*i);
|
||||
S s(i, i * i);
|
||||
MOZ_RELEASE_ASSERT(vec.append(Move(s)));
|
||||
}
|
||||
|
||||
@ -152,7 +169,7 @@ mozilla::detail::VectorTesting::testEmplaceBack()
|
||||
MOZ_RELEASE_ASSERT(S::moveCount == 10);
|
||||
|
||||
for (size_t i = 10; i < 20; i++) {
|
||||
MOZ_RELEASE_ASSERT(vec.emplaceBack(i, i*i));
|
||||
MOZ_RELEASE_ASSERT(vec.emplaceBack(i, i * i));
|
||||
}
|
||||
|
||||
MOZ_RELEASE_ASSERT(vec.length() == 20);
|
||||
@ -161,7 +178,7 @@ mozilla::detail::VectorTesting::testEmplaceBack()
|
||||
|
||||
for (size_t i = 0; i < 20; i++) {
|
||||
MOZ_RELEASE_ASSERT(vec[i].j == i);
|
||||
MOZ_RELEASE_ASSERT(*vec[i].k == i*i);
|
||||
MOZ_RELEASE_ASSERT(*vec[i].k == i * i);
|
||||
}
|
||||
}
|
||||
|
||||
@ -222,6 +239,113 @@ mozilla::detail::VectorTesting::testReverse()
|
||||
MOZ_RELEASE_ASSERT(*vec2[4] == 0);
|
||||
}
|
||||
|
||||
void
|
||||
mozilla::detail::VectorTesting::testExtractRawBuffer()
|
||||
{
|
||||
S::resetCounts();
|
||||
|
||||
Vector<S, 5> vec;
|
||||
MOZ_RELEASE_ASSERT(vec.reserve(5));
|
||||
for (size_t i = 0; i < 5; i++) {
|
||||
vec.infallibleEmplaceBack(i, i * i);
|
||||
}
|
||||
MOZ_RELEASE_ASSERT(vec.length() == 5);
|
||||
MOZ_ASSERT(vec.reserved() == 5);
|
||||
MOZ_RELEASE_ASSERT(S::constructCount == 5);
|
||||
MOZ_RELEASE_ASSERT(S::moveCount == 0);
|
||||
MOZ_RELEASE_ASSERT(S::destructCount == 0);
|
||||
|
||||
S* buf = vec.extractRawBuffer();
|
||||
MOZ_RELEASE_ASSERT(!buf);
|
||||
MOZ_RELEASE_ASSERT(vec.length() == 5);
|
||||
MOZ_ASSERT(vec.reserved() == 5);
|
||||
MOZ_RELEASE_ASSERT(S::constructCount == 5);
|
||||
MOZ_RELEASE_ASSERT(S::moveCount == 0);
|
||||
MOZ_RELEASE_ASSERT(S::destructCount == 0);
|
||||
|
||||
MOZ_RELEASE_ASSERT(vec.reserve(10));
|
||||
for (size_t i = 5; i < 10; i++) {
|
||||
vec.infallibleEmplaceBack(i, i * i);
|
||||
}
|
||||
MOZ_RELEASE_ASSERT(vec.length() == 10);
|
||||
MOZ_ASSERT(vec.reserved() == 10);
|
||||
MOZ_RELEASE_ASSERT(S::constructCount == 10);
|
||||
MOZ_RELEASE_ASSERT(S::moveCount == 5);
|
||||
MOZ_RELEASE_ASSERT(S::destructCount == 5);
|
||||
|
||||
buf = vec.extractRawBuffer();
|
||||
MOZ_RELEASE_ASSERT(buf);
|
||||
MOZ_RELEASE_ASSERT(vec.length() == 0);
|
||||
MOZ_ASSERT(vec.reserved() == 0);
|
||||
MOZ_RELEASE_ASSERT(S::constructCount == 10);
|
||||
MOZ_RELEASE_ASSERT(S::moveCount == 5);
|
||||
MOZ_RELEASE_ASSERT(S::destructCount == 5);
|
||||
|
||||
for (size_t i = 0; i < 10; i++) {
|
||||
MOZ_RELEASE_ASSERT(buf[i].j == i);
|
||||
MOZ_RELEASE_ASSERT(*buf[i].k == i * i);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void
|
||||
mozilla::detail::VectorTesting::testExtractOrCopyRawBuffer()
|
||||
{
|
||||
S::resetCounts();
|
||||
|
||||
Vector<S, 5> vec;
|
||||
MOZ_RELEASE_ASSERT(vec.reserve(5));
|
||||
for (size_t i = 0; i < 5; i++) {
|
||||
vec.infallibleEmplaceBack(i, i * i);
|
||||
}
|
||||
MOZ_RELEASE_ASSERT(vec.length() == 5);
|
||||
MOZ_ASSERT(vec.reserved() == 5);
|
||||
MOZ_RELEASE_ASSERT(S::constructCount == 5);
|
||||
MOZ_RELEASE_ASSERT(S::moveCount == 0);
|
||||
MOZ_RELEASE_ASSERT(S::destructCount == 0);
|
||||
|
||||
S* buf = vec.extractOrCopyRawBuffer();
|
||||
MOZ_RELEASE_ASSERT(buf);
|
||||
MOZ_RELEASE_ASSERT(vec.length() == 0);
|
||||
MOZ_ASSERT(vec.reserved() == 0);
|
||||
MOZ_RELEASE_ASSERT(S::constructCount == 5);
|
||||
MOZ_RELEASE_ASSERT(S::moveCount == 5);
|
||||
MOZ_RELEASE_ASSERT(S::destructCount == 5);
|
||||
|
||||
for (size_t i = 0; i < 5; i++) {
|
||||
MOZ_RELEASE_ASSERT(buf[i].j == i);
|
||||
MOZ_RELEASE_ASSERT(*buf[i].k == i * i);
|
||||
}
|
||||
|
||||
S::resetCounts();
|
||||
|
||||
MOZ_RELEASE_ASSERT(vec.reserve(10));
|
||||
for (size_t i = 0; i < 10; i++) {
|
||||
vec.infallibleEmplaceBack(i, i * i);
|
||||
}
|
||||
MOZ_RELEASE_ASSERT(vec.length() == 10);
|
||||
MOZ_ASSERT(vec.reserved() == 10);
|
||||
MOZ_RELEASE_ASSERT(S::constructCount == 10);
|
||||
MOZ_RELEASE_ASSERT(S::moveCount == 0);
|
||||
MOZ_RELEASE_ASSERT(S::destructCount == 0);
|
||||
|
||||
buf = vec.extractOrCopyRawBuffer();
|
||||
MOZ_RELEASE_ASSERT(buf);
|
||||
MOZ_RELEASE_ASSERT(vec.length() == 0);
|
||||
MOZ_ASSERT(vec.reserved() == 0);
|
||||
MOZ_RELEASE_ASSERT(S::constructCount == 10);
|
||||
MOZ_RELEASE_ASSERT(S::moveCount == 0);
|
||||
MOZ_RELEASE_ASSERT(S::destructCount == 0);
|
||||
|
||||
for (size_t i = 0; i < 10; i++) {
|
||||
MOZ_RELEASE_ASSERT(buf[i].j == i);
|
||||
MOZ_RELEASE_ASSERT(*buf[i].k == i * i);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
@ -229,4 +353,6 @@ main()
|
||||
VectorTesting::testConstRange();
|
||||
VectorTesting::testEmplaceBack();
|
||||
VectorTesting::testReverse();
|
||||
VectorTesting::testExtractRawBuffer();
|
||||
VectorTesting::testExtractOrCopyRawBuffer();
|
||||
}
|
||||
|
@ -234,26 +234,21 @@ class GeckoInputConnection
|
||||
}
|
||||
|
||||
private void showSoftInput() {
|
||||
final View v = getView();
|
||||
final InputMethodManager imm = getInputMethodManager();
|
||||
if (imm != null) {
|
||||
final View v = getView();
|
||||
|
||||
if (v.hasFocus() && !imm.isActive(v)) {
|
||||
// Workaround: The view has focus but it is not the active view for the input method. (Bug 1211848)
|
||||
refocusAndShowSoftInput(imm, v);
|
||||
} else {
|
||||
imm.showSoftInput(v, 0);
|
||||
}
|
||||
if (v == null || imm == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static void refocusAndShowSoftInput(final InputMethodManager imm, final View v) {
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
v.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
v.clearFocus();
|
||||
v.requestFocus();
|
||||
|
||||
if (v.hasFocus() && !imm.isActive(v)) {
|
||||
// Marshmallow workaround: The view has focus but it is not the active
|
||||
// view for the input method. (Bug 1211848)
|
||||
v.clearFocus();
|
||||
v.requestFocus();
|
||||
}
|
||||
imm.showSoftInput(v, 0);
|
||||
}
|
||||
});
|
||||
@ -472,18 +467,18 @@ class GeckoInputConnection
|
||||
return mEditableClient.setInputConnectionHandler(getBackgroundHandler());
|
||||
}
|
||||
|
||||
private boolean mIsVisible = false;
|
||||
|
||||
@Override
|
||||
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
|
||||
if (mIMEState == IME_STATE_DISABLED) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Some keyboards require us to fill out outAttrs even if we return null.
|
||||
outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
|
||||
outAttrs.imeOptions = EditorInfo.IME_ACTION_NONE;
|
||||
outAttrs.actionLabel = null;
|
||||
|
||||
if (mIMEState == IME_STATE_DISABLED) {
|
||||
hideSoftInput();
|
||||
return null;
|
||||
}
|
||||
|
||||
if (mIMEState == IME_STATE_PASSWORD ||
|
||||
"password".equalsIgnoreCase(mIMETypeHint))
|
||||
outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_PASSWORD;
|
||||
@ -587,12 +582,7 @@ class GeckoInputConnection
|
||||
outAttrs.initialSelStart = Selection.getSelectionStart(editable);
|
||||
outAttrs.initialSelEnd = Selection.getSelectionEnd(editable);
|
||||
|
||||
if (mIsVisible) {
|
||||
// The app has been brought to the foreground and the Soft Keyboard
|
||||
// was previously visible, so request that it be shown again.
|
||||
showSoftInput();
|
||||
}
|
||||
|
||||
showSoftInput();
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -798,16 +788,6 @@ class GeckoInputConnection
|
||||
return processKey(KeyEvent.ACTION_UP, keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowVisibilityChanged (int visibility) {
|
||||
if (visibility == View.VISIBLE) {
|
||||
mIsVisible = true;
|
||||
} else {
|
||||
mIsVisible = false;
|
||||
hideSoftInput();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a key that represents a given character.
|
||||
*/
|
||||
@ -936,11 +916,6 @@ class GeckoInputConnection
|
||||
return;
|
||||
}
|
||||
restartInput();
|
||||
if (mIMEState == IME_STATE_DISABLED) {
|
||||
hideSoftInput();
|
||||
} else {
|
||||
showSoftInput();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -272,24 +272,8 @@ public class GeckoView extends LayerView
|
||||
}
|
||||
}
|
||||
|
||||
private int mLastVisibility = View.GONE;
|
||||
|
||||
/* package */ void setInputConnectionListener(final InputConnectionListener icl) {
|
||||
mInputConnectionListener = icl;
|
||||
if (mInputConnectionListener != null) {
|
||||
mInputConnectionListener.onWindowVisibilityChanged(mLastVisibility);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onWindowVisibilityChanged (int visibility) {
|
||||
mLastVisibility = visibility;
|
||||
|
||||
if (mInputConnectionListener != null) {
|
||||
mInputConnectionListener.onWindowVisibilityChanged(visibility);
|
||||
}
|
||||
|
||||
super.onWindowVisibilityChanged(visibility);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -21,6 +21,5 @@ interface InputConnectionListener
|
||||
boolean onKeyLongPress(int keyCode, KeyEvent event);
|
||||
boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event);
|
||||
boolean onKeyUp(int keyCode, KeyEvent event);
|
||||
void onWindowVisibilityChanged (int visibility);
|
||||
boolean isIMEEnabled();
|
||||
}
|
||||
|
@ -219,6 +219,14 @@ AssertNotAlreadyCached(const char* aPrefType,
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
ReportToConsole(const char* aMessage, int aLine, bool aError)
|
||||
{
|
||||
nsPrintfCString message("** Preference parsing %s (line %d) = %s **\n",
|
||||
(aError ? "error" : "warning"), aLine, aMessage);
|
||||
nsPrefBranch::ReportToConsole(NS_ConvertUTF8toUTF16(message.get()));
|
||||
}
|
||||
|
||||
// Although this is a member of Preferences, it measures sPreferences and
|
||||
// several other global structures.
|
||||
/* static */ int64_t
|
||||
@ -683,7 +691,7 @@ ReadExtensionPrefs(nsIFile *aFile)
|
||||
uint32_t read;
|
||||
|
||||
PrefParseState ps;
|
||||
PREF_InitParseState(&ps, PREF_ReaderCallback, nullptr);
|
||||
PREF_InitParseState(&ps, PREF_ReaderCallback, ReportToConsole, nullptr);
|
||||
while (NS_SUCCEEDED(rv = stream->Available(&avail)) && avail) {
|
||||
rv = stream->Read(buffer, 4096, &read);
|
||||
if (NS_FAILED(rv)) {
|
||||
@ -997,7 +1005,7 @@ static nsresult openPrefFile(nsIFile* aFile)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
PrefParseState ps;
|
||||
PREF_InitParseState(&ps, PREF_ReaderCallback, nullptr);
|
||||
PREF_InitParseState(&ps, PREF_ReaderCallback, ReportToConsole, nullptr);
|
||||
|
||||
// Read is not guaranteed to return a buf the size of fileSize,
|
||||
// but usually will.
|
||||
@ -1179,7 +1187,7 @@ static nsresult pref_ReadPrefFromJar(nsZipArchive* jarReader, const char *name)
|
||||
NS_ENSURE_TRUE(manifest.Buffer(), NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
PrefParseState ps;
|
||||
PREF_InitParseState(&ps, PREF_ReaderCallback, nullptr);
|
||||
PREF_InitParseState(&ps, PREF_ReaderCallback, ReportToConsole, nullptr);
|
||||
PREF_ParseBuf(&ps, manifest, manifest.Length());
|
||||
PREF_FinalizeParseState(&ps);
|
||||
|
||||
|
@ -390,6 +390,17 @@ nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, const ui
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
void nsPrefBranch::ReportToConsole(const nsAString& aMessage)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIConsoleService> console = do_GetService("@mozilla.org/consoleservice;1", &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
nsAutoString message(aMessage);
|
||||
console->LogStringMessage(message.get());
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPrefBranch::SetComplexValue(const char *aPrefName, const nsIID & aType, nsISupports *aValue)
|
||||
{
|
||||
|
@ -196,6 +196,8 @@ public:
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
|
||||
|
||||
static void ReportToConsole(const nsAString& aMessage);
|
||||
|
||||
protected:
|
||||
virtual ~nsPrefBranch();
|
||||
|
||||
|
@ -97,6 +97,20 @@ pref_GrowBuf(PrefParseState *ps)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an error or a warning. If not specified, just dump to stderr.
|
||||
*/
|
||||
static void
|
||||
pref_ReportParseProblem(PrefParseState& ps, const char* aMessage, int aLine, bool aError)
|
||||
{
|
||||
if (ps.reporter) {
|
||||
ps.reporter(aMessage, aLine, aError);
|
||||
} else {
|
||||
printf_stderr("**** Preference parsing %s (line %d) = %s **\n",
|
||||
(aError ? "error" : "warning"), aLine, aMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pref_DoCallback
|
||||
*
|
||||
@ -119,6 +133,7 @@ pref_DoCallback(PrefParseState *ps)
|
||||
break;
|
||||
case PrefType::Int:
|
||||
if ((ps->vb[0] == '-' || ps->vb[0] == '+') && ps->vb[1] == '\0') {
|
||||
pref_ReportParseProblem(*ps, "invalid integer value", 0, true);
|
||||
NS_WARNING("malformed integer value");
|
||||
return false;
|
||||
}
|
||||
@ -136,11 +151,13 @@ pref_DoCallback(PrefParseState *ps)
|
||||
}
|
||||
|
||||
void
|
||||
PREF_InitParseState(PrefParseState *ps, PrefReader reader, void *closure)
|
||||
PREF_InitParseState(PrefParseState *ps, PrefReader reader,
|
||||
PrefParseErrorReporter reporter, void *closure)
|
||||
{
|
||||
memset(ps, 0, sizeof(*ps));
|
||||
ps->reader = reader;
|
||||
ps->closure = closure;
|
||||
ps->reporter = reporter;
|
||||
}
|
||||
|
||||
void
|
||||
@ -179,9 +196,16 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen)
|
||||
char udigit;
|
||||
int state;
|
||||
|
||||
// The line number is currently only used for the error/warning reporting.
|
||||
int lineNum = 0;
|
||||
|
||||
state = ps->state;
|
||||
for (end = buf + bufLen; buf != end; ++buf) {
|
||||
c = *buf;
|
||||
if (c == '\r' || c == '\n' || c == 0x1A) {
|
||||
lineNum ++;
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
/* initial state */
|
||||
case PREF_PARSE_INIT:
|
||||
@ -228,6 +252,7 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen)
|
||||
/* else wait for next char */
|
||||
}
|
||||
else {
|
||||
pref_ReportParseProblem(*ps, "non-matching string", lineNum, true);
|
||||
NS_WARNING("malformed pref file");
|
||||
return false;
|
||||
}
|
||||
@ -263,6 +288,7 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen)
|
||||
state = PREF_PARSE_COMMENT_MAYBE_START;
|
||||
}
|
||||
else if (!isspace(c)) {
|
||||
pref_ReportParseProblem(*ps, "need space, comment or quote", lineNum, true);
|
||||
NS_WARNING("malformed pref file");
|
||||
return false;
|
||||
}
|
||||
@ -279,6 +305,7 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen)
|
||||
state = PREF_PARSE_COMMENT_MAYBE_START;
|
||||
}
|
||||
else if (!isspace(c)) {
|
||||
pref_ReportParseProblem(*ps, "need space, comment or comma", lineNum, true);
|
||||
NS_WARNING("malformed pref file");
|
||||
return false;
|
||||
}
|
||||
@ -315,6 +342,7 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen)
|
||||
state = PREF_PARSE_COMMENT_MAYBE_START;
|
||||
}
|
||||
else if (!isspace(c)) {
|
||||
pref_ReportParseProblem(*ps, "need value, comment or space", lineNum, true);
|
||||
NS_WARNING("malformed pref file");
|
||||
return false;
|
||||
}
|
||||
@ -336,6 +364,7 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen)
|
||||
else if (isspace(c))
|
||||
state = PREF_PARSE_UNTIL_CLOSE_PAREN;
|
||||
else {
|
||||
pref_ReportParseProblem(*ps, "while parsing integer", lineNum, true);
|
||||
NS_WARNING("malformed pref file");
|
||||
return false;
|
||||
}
|
||||
@ -353,12 +382,13 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen)
|
||||
break;
|
||||
default:
|
||||
/* pref file is malformed */
|
||||
pref_ReportParseProblem(*ps, "while parsing comment", lineNum, true);
|
||||
NS_WARNING("malformed pref file");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case PREF_PARSE_COMMENT_BLOCK:
|
||||
if (c == '*')
|
||||
if (c == '*')
|
||||
state = PREF_PARSE_COMMENT_BLOCK_MAYBE_END;
|
||||
break;
|
||||
case PREF_PARSE_COMMENT_BLOCK_MAYBE_END:
|
||||
@ -401,6 +431,8 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen)
|
||||
state = PREF_PARSE_HEX_ESCAPE;
|
||||
continue;
|
||||
default:
|
||||
pref_ReportParseProblem(*ps, "preserving unexpected JS escape sequence",
|
||||
lineNum, false);
|
||||
NS_WARNING("preserving unexpected JS escape sequence");
|
||||
/* Invalid escape sequence so we do have to write more than
|
||||
* one character. Grow line buffer if necessary... */
|
||||
@ -423,6 +455,8 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen)
|
||||
udigit = (c - 'a') + 10;
|
||||
else {
|
||||
/* bad escape sequence found, write out broken escape as-is */
|
||||
pref_ReportParseProblem(*ps, "preserving invalid or incomplete hex escape",
|
||||
lineNum, false);
|
||||
NS_WARNING("preserving invalid or incomplete hex escape");
|
||||
*ps->lbcur++ = '\\'; /* original escape slash */
|
||||
if ((ps->lbcur + ps->esclen) >= ps->lbend && !pref_GrowBuf(ps))
|
||||
@ -510,6 +544,8 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen)
|
||||
state = PREF_PARSE_COMMENT_MAYBE_START;
|
||||
}
|
||||
else if (!isspace(c)) {
|
||||
pref_ReportParseProblem(*ps, "need space, comment or open parentheses",
|
||||
lineNum, true);
|
||||
NS_WARNING("malformed pref file");
|
||||
return false;
|
||||
}
|
||||
@ -522,6 +558,8 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen)
|
||||
ps->nextstate = state; /* return here when done with comment */
|
||||
state = PREF_PARSE_COMMENT_MAYBE_START;
|
||||
} else if (!isspace(c)) {
|
||||
pref_ReportParseProblem(*ps, "need space, comment or closing parentheses",
|
||||
lineNum, true);
|
||||
NS_WARNING("malformed pref file");
|
||||
return false;
|
||||
}
|
||||
@ -540,6 +578,8 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen)
|
||||
state = PREF_PARSE_COMMENT_MAYBE_START;
|
||||
}
|
||||
else if (!isspace(c)) {
|
||||
pref_ReportParseProblem(*ps, "need space, comment or semicolon",
|
||||
lineNum, true);
|
||||
NS_WARNING("malformed pref file");
|
||||
return false;
|
||||
}
|
||||
@ -603,7 +643,7 @@ main(int argc, char **argv)
|
||||
return -1;
|
||||
}
|
||||
|
||||
PREF_InitParseState(&ps, pref_reader, nullptr);
|
||||
PREF_InitParseState(&ps, pref_reader, nullptr, nullptr);
|
||||
|
||||
while ((n = fread(buf, 1, sizeof(buf), fp)) > 0)
|
||||
PREF_ParseBuf(&ps, buf, n);
|
||||
|
@ -36,9 +36,15 @@ typedef void (*PrefReader)(void *closure,
|
||||
bool defPref,
|
||||
bool stickyPref);
|
||||
|
||||
/**
|
||||
* Report any errors or warnings we encounter during parsing.
|
||||
*/
|
||||
typedef void (*PrefParseErrorReporter)(const char* message, int line, bool error);
|
||||
|
||||
/* structure fields are private */
|
||||
typedef struct PrefParseState {
|
||||
PrefReader reader;
|
||||
PrefParseErrorReporter reporter;
|
||||
void *closure;
|
||||
int state; /* PREF_PARSE_... */
|
||||
int nextstate; /* sometimes used... */
|
||||
@ -62,16 +68,20 @@ typedef struct PrefParseState {
|
||||
* PREF_InitParseState
|
||||
*
|
||||
* Called to initialize a PrefParseState instance.
|
||||
*
|
||||
*
|
||||
* @param ps
|
||||
* PrefParseState instance.
|
||||
* @param reader
|
||||
* PrefReader callback function, which will be called once for each
|
||||
* preference name value pair extracted.
|
||||
* @param reporter
|
||||
* PrefParseErrorReporter callback function, which will be called if we
|
||||
* encounter any errors (stop) or warnings (continue) during parsing.
|
||||
* @param closure
|
||||
* PrefReader closure.
|
||||
*/
|
||||
void PREF_InitParseState(PrefParseState *ps, PrefReader reader, void *closure);
|
||||
void PREF_InitParseState(PrefParseState *ps, PrefReader reader,
|
||||
PrefParseErrorReporter reporter, void *closure);
|
||||
|
||||
/**
|
||||
* PREF_FinalizeParseState
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user