Merge inbound to central, a=merge

MozReview-Commit-ID: 4igUgM6r0wO
This commit is contained in:
Wes Kocher 2016-04-25 17:11:09 -07:00
commit d509baac11
153 changed files with 1791 additions and 1084 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -106,6 +106,11 @@ void
ProxyShowHideEvent(ProxyAccessible*, ProxyAccessible*, bool, bool)
{
}
void
ProxySelectionEvent(ProxyAccessible*, ProxyAccessible*, uint32_t)
{
}
} // namespace a11y
} // namespace mozilla

View File

@ -54,3 +54,8 @@ void
a11y::ProxyShowHideEvent(ProxyAccessible*, ProxyAccessible*, bool, bool)
{
}
void
a11y::ProxySelectionEvent(ProxyAccessible*, ProxyAccessible*, uint32_t)
{
}

View File

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

View File

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

View File

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

View File

@ -96,6 +96,7 @@ public:
, mIDType(eUnknown)
, mOuterIDNumber(0)
, mInnerIDNumber(0)
, mStatus(eUnused)
#ifdef DEBUG
, mOwningThread(PR_GetCurrentThread())
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -86,6 +86,12 @@ public:
void InputMuted(bool aInputMuted);
void ResolvePromise(AudioBuffer* aRenderedBuffer);
unsigned long Length()
{
MOZ_ASSERT(mIsOffline);
return mFramesToProduce;
}
protected:
virtual ~AudioDestinationNode();

View File

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

View File

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

View File

@ -19,5 +19,6 @@ interface OfflineAudioContext : AudioContext {
Promise<AudioBuffer> startRendering();
attribute EventHandler oncomplete;
readonly attribute unsigned long length;
};

View File

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

View File

@ -138,6 +138,7 @@ enum class LogReason : int {
TextureAliveAfterShutdown,
InvalidContext,
InvalidCommandList,
AsyncTransactionTimeout,
// End
MustBeLessThanThis = 101,
};

View File

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

View File

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

View File

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

View File

@ -211,6 +211,8 @@ public:
return mDraw->mSamples;
}
uint32_t DepthBits() const;
void DeletingFB(GLuint fb);
const gfx::IntSize& Size() const {

View File

@ -898,7 +898,7 @@ struct ParamTraits<mozilla::StereoMode>
: public ContiguousEnumSerializer<
mozilla::StereoMode,
mozilla::StereoMode::MONO,
mozilla::StereoMode::TOP_BOTTOM>
mozilla::StereoMode::MAX>
{};
template <>

View File

@ -99,7 +99,8 @@ enum class StereoMode {
LEFT_RIGHT,
RIGHT_LEFT,
BOTTOM_TOP,
TOP_BOTTOM
TOP_BOTTOM,
MAX,
};
} // namespace mozilla

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

@ -12,5 +12,6 @@ evalcx(`
}\
');
oomTest(() => eval('Array(..."")'));
Intl.NumberFormat.prototype.format(0);
if ('Intl' in this)
Intl.NumberFormat.prototype.format(0);
`, newGlobal());

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

View File

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

View File

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

View File

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

View File

@ -70,6 +70,7 @@
_(IsRegExpObject) \
_(RegExpPrototypeOptimizable) \
_(RegExpInstanceOptimizable) \
_(GetFirstDollarIndex) \
\
_(String) \
_(StringCharCodeAt) \

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -151,6 +151,7 @@ namespace jit {
_(RegExpTester) \
_(RegExpPrototypeOptimizable) \
_(RegExpInstanceOptimizable) \
_(GetFirstDollarIndex) \
_(StringReplace) \
_(Lambda) \
_(LambdaArrow) \

View File

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

View File

@ -211,6 +211,7 @@
_(RegExpTester) \
_(RegExpPrototypeOptimizable) \
_(RegExpInstanceOptimizable) \
_(GetFirstDollarIndex) \
_(StringReplace) \
_(Substr) \
_(BinarySharedStub) \

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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'. */
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -196,6 +196,8 @@ public:
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
static void ReportToConsole(const nsAString& aMessage);
protected:
virtual ~nsPrefBranch();

View File

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

View File

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