зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to m-i.
This commit is contained in:
Коммит
34abe91f47
|
@ -121,12 +121,16 @@ var shell = {
|
|||
}
|
||||
} catch (e) { }
|
||||
|
||||
// Let Gaia notify the user of the crash.
|
||||
this.sendChromeEvent({
|
||||
type: "handle-crash",
|
||||
crashID: crashID,
|
||||
chrome: isChrome
|
||||
});
|
||||
// We can get here if we're just submitting old pending crashes.
|
||||
// Check that there's a valid crashID so that we only notify the
|
||||
// user if a crash just happened and not when we OOM. Bug 829477
|
||||
if (crashID) {
|
||||
this.sendChromeEvent({
|
||||
type: "handle-crash",
|
||||
crashID: crashID,
|
||||
chrome: isChrome
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// this function submit the pending crashes.
|
||||
|
@ -227,9 +231,7 @@ var shell = {
|
|||
let cr = Cc["@mozilla.org/xre/app-info;1"]
|
||||
.getService(Ci.nsICrashReporter);
|
||||
cr.annotateCrashReport("B2G_OS_Version", value);
|
||||
} catch(e) {
|
||||
dump("exception: " + e);
|
||||
}
|
||||
} catch(e) { }
|
||||
});
|
||||
#endif
|
||||
} catch(e) {
|
||||
|
|
|
@ -368,6 +368,11 @@ pref("browser.search.update.interval", 21600);
|
|||
// enable search suggestions by default
|
||||
pref("browser.search.suggest.enabled", true);
|
||||
|
||||
#ifdef MOZ_OFFICIAL_BRANDING
|
||||
// {moz:official} expands to "official"
|
||||
pref("browser.search.official", true);
|
||||
#endif
|
||||
|
||||
pref("browser.sessionhistory.max_entries", 50);
|
||||
|
||||
// handle links targeting new windows
|
||||
|
|
|
@ -1173,8 +1173,8 @@ var gBrowserInit = {
|
|||
allTabs.readPref();
|
||||
TabsOnTop.init();
|
||||
BookmarksMenuButton.init();
|
||||
TabsInTitlebar.init();
|
||||
gPrivateBrowsingUI.init();
|
||||
TabsInTitlebar.init();
|
||||
retrieveToolbarIconsizesFromTheme();
|
||||
|
||||
// Wait until chrome is painted before executing code not critical to making the window visible
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function test() {
|
||||
requestLongerTimeout(2); // only debug builds seem to need more time...
|
||||
waitForExplicitFinish();
|
||||
|
||||
let manifest = { // normal provider
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
this.EXPORTED_SYMBOLS = [ "CmdAddonFlags" ];
|
||||
this.EXPORTED_SYMBOLS = [ "CmdAddonFlags", "CmdCommands" ];
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
|
|
@ -22,7 +22,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "gcli",
|
|||
"resource:///modules/devtools/gcli.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "CmdCommands",
|
||||
"resource:///modules/devtools/CmdCmd.jsm");
|
||||
"resource:///modules/devtools/BuiltinCommands.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PageErrorListener",
|
||||
"resource://gre/modules/devtools/WebConsoleUtils.jsm");
|
||||
|
|
|
@ -3391,8 +3391,10 @@ chatbox[minimized="true"] {
|
|||
background-position: top left;
|
||||
}
|
||||
|
||||
#main-window[privatebrowsingmode=temporary] #appmenu-button {
|
||||
#main-window[privatebrowsingmode=temporary] #appmenu-button > .button-box > .box-inherit > .button-icon {
|
||||
list-style-image: url("chrome://browser/skin/privatebrowsing-light.png");
|
||||
width: 20px;
|
||||
height: 16px;
|
||||
}
|
||||
%endif
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
interface nsIDocShell;
|
||||
interface nsIURI;
|
||||
interface nsIFrame;
|
||||
interface nsSubDocumentFrame;
|
||||
interface nsIMessageSender;
|
||||
interface nsIVariant;
|
||||
interface nsIDOMElement;
|
||||
|
@ -108,7 +109,7 @@ interface nsIContentViewManager : nsISupports
|
|||
readonly attribute nsIContentView rootContentView;
|
||||
};
|
||||
|
||||
[scriptable, uuid(f234c232-bb17-4450-b324-bf1ef5ccfd34)]
|
||||
[scriptable, uuid(a4db652e-e3b0-4345-8107-cf6a30486759)]
|
||||
interface nsIFrameLoader : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -146,7 +147,7 @@ interface nsIFrameLoader : nsISupports
|
|||
*
|
||||
* @param aIFrame The nsIFrame for the content node that owns this frameloader
|
||||
*/
|
||||
[noscript] void updatePositionAndSize(in nsIFrame aIFrame);
|
||||
[noscript] void updatePositionAndSize(in nsSubDocumentFrame aIFrame);
|
||||
|
||||
/**
|
||||
* Activate remote frame.
|
||||
|
|
|
@ -817,26 +817,17 @@ nsFrameLoader::Show(int32_t marginWidth, int32_t marginHeight,
|
|||
}
|
||||
}
|
||||
|
||||
nsIntSize size = frame->GetSubdocumentSize();
|
||||
if (mRemoteFrame) {
|
||||
return ShowRemoteFrame(size, frame);
|
||||
}
|
||||
|
||||
nsView* view = frame->EnsureInnerView();
|
||||
if (!view)
|
||||
return false;
|
||||
|
||||
if (mRemoteFrame) {
|
||||
return ShowRemoteFrame(GetSubDocumentSize(frame));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(mDocShell);
|
||||
NS_ASSERTION(baseWindow, "Found a nsIDocShell that isn't a nsIBaseWindow.");
|
||||
nsIntSize size;
|
||||
if (!(frame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
|
||||
// We have a useful size already; use it, since we might get no
|
||||
// more size updates.
|
||||
size = GetSubDocumentSize(frame);
|
||||
} else {
|
||||
// Pick some default size for now. Using 10x10 because that's what the
|
||||
// code here used to do.
|
||||
size.SizeTo(10, 10);
|
||||
}
|
||||
baseWindow->InitWindow(nullptr, view->GetWidget(), 0, 0,
|
||||
size.width, size.height);
|
||||
// This is kinda whacky, this "Create()" call doesn't really
|
||||
|
@ -921,7 +912,8 @@ nsFrameLoader::MarginsChanged(uint32_t aMarginWidth,
|
|||
}
|
||||
|
||||
bool
|
||||
nsFrameLoader::ShowRemoteFrame(const nsIntSize& size)
|
||||
nsFrameLoader::ShowRemoteFrame(const nsIntSize& size,
|
||||
nsSubDocumentFrame *aFrame)
|
||||
{
|
||||
NS_ASSERTION(mRemoteFrame, "ShowRemote only makes sense on remote frames.");
|
||||
|
||||
|
@ -964,7 +956,11 @@ nsFrameLoader::ShowRemoteFrame(const nsIntSize& size)
|
|||
} else {
|
||||
nsRect dimensions;
|
||||
NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), false);
|
||||
mRemoteBrowser->UpdateDimensions(dimensions, size);
|
||||
|
||||
// Don't show remote iframe if we are waiting for the completion of reflow.
|
||||
if (!aFrame || !(aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
|
||||
mRemoteBrowser->UpdateDimensions(dimensions, size);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1836,11 +1832,11 @@ nsFrameLoader::GetWindowDimensions(nsRect& aRect)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameLoader::UpdatePositionAndSize(nsIFrame *aIFrame)
|
||||
nsFrameLoader::UpdatePositionAndSize(nsSubDocumentFrame *aIFrame)
|
||||
{
|
||||
if (mRemoteFrame) {
|
||||
if (mRemoteBrowser) {
|
||||
nsIntSize size = GetSubDocumentSize(aIFrame);
|
||||
nsIntSize size = aIFrame->GetSubdocumentSize();
|
||||
nsRect dimensions;
|
||||
NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), NS_ERROR_FAILURE);
|
||||
mRemoteBrowser->UpdateDimensions(dimensions, size);
|
||||
|
@ -1851,7 +1847,7 @@ nsFrameLoader::UpdatePositionAndSize(nsIFrame *aIFrame)
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsFrameLoader::UpdateBaseWindowPositionAndSize(nsIFrame *aIFrame)
|
||||
nsFrameLoader::UpdateBaseWindowPositionAndSize(nsSubDocumentFrame *aIFrame)
|
||||
{
|
||||
nsCOMPtr<nsIDocShell> docShell;
|
||||
GetDocShell(getter_AddRefs(docShell));
|
||||
|
@ -1871,7 +1867,7 @@ nsFrameLoader::UpdateBaseWindowPositionAndSize(nsIFrame *aIFrame)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIntSize size = GetSubDocumentSize(aIFrame);
|
||||
nsIntSize size = aIFrame->GetSubdocumentSize();
|
||||
|
||||
baseWindow->SetPositionAndSize(x, y, size.width, size.height, false);
|
||||
}
|
||||
|
@ -1975,22 +1971,6 @@ nsFrameLoader::SetClampScrollPosition(bool aClamp)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIntSize
|
||||
nsFrameLoader::GetSubDocumentSize(const nsIFrame *aIFrame)
|
||||
{
|
||||
nsSize docSizeAppUnits;
|
||||
nsPresContext* presContext = aIFrame->PresContext();
|
||||
nsCOMPtr<nsIDOMHTMLFrameElement> frameElem =
|
||||
do_QueryInterface(aIFrame->GetContent());
|
||||
if (frameElem) {
|
||||
docSizeAppUnits = aIFrame->GetSize();
|
||||
} else {
|
||||
docSizeAppUnits = aIFrame->GetContentRect().Size();
|
||||
}
|
||||
return nsIntSize(presContext->AppUnitsToDevPixels(docSizeAppUnits.width),
|
||||
presContext->AppUnitsToDevPixels(docSizeAppUnits.height));
|
||||
}
|
||||
|
||||
bool
|
||||
nsFrameLoader::TryRemoteBrowser()
|
||||
{
|
||||
|
|
|
@ -356,12 +356,11 @@ private:
|
|||
NS_HIDDEN_(void) GetURL(nsString& aURL);
|
||||
|
||||
// Properly retrieves documentSize of any subdocument type.
|
||||
NS_HIDDEN_(nsIntSize) GetSubDocumentSize(const nsIFrame *aIFrame);
|
||||
nsresult GetWindowDimensions(nsRect& aRect);
|
||||
|
||||
// Updates the subdocument position and size. This gets called only
|
||||
// when we have our own in-process DocShell.
|
||||
NS_HIDDEN_(nsresult) UpdateBaseWindowPositionAndSize(nsIFrame *aIFrame);
|
||||
NS_HIDDEN_(nsresult) UpdateBaseWindowPositionAndSize(nsSubDocumentFrame *aIFrame);
|
||||
nsresult CheckURILoad(nsIURI* aURI);
|
||||
void FireErrorEvent();
|
||||
nsresult ReallyStartLoadingInternal();
|
||||
|
@ -370,7 +369,8 @@ private:
|
|||
bool TryRemoteBrowser();
|
||||
|
||||
// Tell the remote browser that it's now "virtually visible"
|
||||
bool ShowRemoteFrame(const nsIntSize& size);
|
||||
bool ShowRemoteFrame(const nsIntSize& size,
|
||||
nsSubDocumentFrame *aFrame = nullptr);
|
||||
|
||||
bool AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem,
|
||||
nsIDocShellTreeOwner* aOwner,
|
||||
|
|
|
@ -139,7 +139,6 @@ ScaleAudioSamples(float* aBuffer, int aCount, float aScale)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
ScaleAudioSamples(short* aBuffer, int aCount, float aScale)
|
||||
{
|
||||
|
@ -149,6 +148,21 @@ ScaleAudioSamples(short* aBuffer, int aCount, float aScale)
|
|||
}
|
||||
}
|
||||
|
||||
inline const void*
|
||||
AddAudioSampleOffset(const void* aBase, AudioSampleFormat aFormat,
|
||||
int32_t aOffset)
|
||||
{
|
||||
switch (aFormat) {
|
||||
case AUDIO_FORMAT_FLOAT32:
|
||||
return static_cast<const float*>(aBase) + aOffset;
|
||||
case AUDIO_FORMAT_S16:
|
||||
return static_cast<const int16_t*>(aBase) + aOffset;
|
||||
default:
|
||||
NS_ERROR("Unknown format");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* MOZILLA_AUDIOSAMPLEFORMAT_H_ */
|
||||
|
|
|
@ -11,16 +11,15 @@ namespace mozilla {
|
|||
|
||||
template <class SrcT, class DestT>
|
||||
static void
|
||||
InterleaveAndConvertBuffer(const SrcT* aSource, int32_t aSourceLength,
|
||||
int32_t aLength,
|
||||
float aVolume,
|
||||
InterleaveAndConvertBuffer(const SrcT** aSourceChannels,
|
||||
int32_t aLength, float aVolume,
|
||||
int32_t aChannels,
|
||||
DestT* aOutput)
|
||||
{
|
||||
DestT* output = aOutput;
|
||||
for (int32_t i = 0; i < aLength; ++i) {
|
||||
for (int32_t channel = 0; channel < aChannels; ++channel) {
|
||||
float v = AudioSampleToFloat(aSource[channel*aSourceLength + i])*aVolume;
|
||||
float v = AudioSampleToFloat(aSourceChannels[channel][i])*aVolume;
|
||||
*output = FloatToAudioSample<DestT>(v);
|
||||
++output;
|
||||
}
|
||||
|
@ -28,9 +27,8 @@ InterleaveAndConvertBuffer(const SrcT* aSource, int32_t aSourceLength,
|
|||
}
|
||||
|
||||
static inline void
|
||||
InterleaveAndConvertBuffer(const int16_t* aSource, int32_t aSourceLength,
|
||||
int32_t aLength,
|
||||
float aVolume,
|
||||
InterleaveAndConvertBuffer(const int16_t** aSourceChannels,
|
||||
int32_t aLength, float aVolume,
|
||||
int32_t aChannels,
|
||||
int16_t* aOutput)
|
||||
{
|
||||
|
@ -39,7 +37,7 @@ InterleaveAndConvertBuffer(const int16_t* aSource, int32_t aSourceLength,
|
|||
int32_t scale = int32_t((1 << 16) * aVolume);
|
||||
for (int32_t i = 0; i < aLength; ++i) {
|
||||
for (int32_t channel = 0; channel < aChannels; ++channel) {
|
||||
int16_t s = aSource[channel*aSourceLength + i];
|
||||
int16_t s = aSourceChannels[channel][i];
|
||||
*output = int16_t((int32_t(s) * scale) >> 16);
|
||||
++output;
|
||||
}
|
||||
|
@ -49,7 +47,7 @@ InterleaveAndConvertBuffer(const int16_t* aSource, int32_t aSourceLength,
|
|||
|
||||
for (int32_t i = 0; i < aLength; ++i) {
|
||||
for (int32_t channel = 0; channel < aChannels; ++channel) {
|
||||
float v = AudioSampleToFloat(aSource[channel*aSourceLength + i])*aVolume;
|
||||
float v = AudioSampleToFloat(aSourceChannels[channel][i])*aVolume;
|
||||
*output = FloatToAudioSample<int16_t>(v);
|
||||
++output;
|
||||
}
|
||||
|
@ -57,25 +55,22 @@ InterleaveAndConvertBuffer(const int16_t* aSource, int32_t aSourceLength,
|
|||
}
|
||||
|
||||
static void
|
||||
InterleaveAndConvertBuffer(const void* aSource, AudioSampleFormat aSourceFormat,
|
||||
int32_t aSourceLength,
|
||||
int32_t aOffset, int32_t aLength,
|
||||
float aVolume,
|
||||
InterleaveAndConvertBuffer(const void** aSourceChannels,
|
||||
AudioSampleFormat aSourceFormat,
|
||||
int32_t aLength, float aVolume,
|
||||
int32_t aChannels,
|
||||
AudioDataValue* aOutput)
|
||||
{
|
||||
switch (aSourceFormat) {
|
||||
case AUDIO_FORMAT_FLOAT32:
|
||||
InterleaveAndConvertBuffer(static_cast<const float*>(aSource) + aOffset,
|
||||
aSourceLength,
|
||||
InterleaveAndConvertBuffer(reinterpret_cast<const float**>(aSourceChannels),
|
||||
aLength,
|
||||
aVolume,
|
||||
aChannels,
|
||||
aOutput);
|
||||
break;
|
||||
case AUDIO_FORMAT_S16:
|
||||
InterleaveAndConvertBuffer(static_cast<const int16_t*>(aSource) + aOffset,
|
||||
aSourceLength,
|
||||
InterleaveAndConvertBuffer(reinterpret_cast<const int16_t**>(aSourceChannels),
|
||||
aLength,
|
||||
aVolume,
|
||||
aChannels,
|
||||
|
@ -107,9 +102,8 @@ AudioSegment::WriteTo(AudioStream* aOutput)
|
|||
}
|
||||
buf.SetLength(int32_t(mChannels*c.mDuration));
|
||||
if (c.mBuffer) {
|
||||
InterleaveAndConvertBuffer(c.mBuffer->Data(), c.mBufferFormat, c.mBufferLength,
|
||||
c.mOffset, int32_t(c.mDuration),
|
||||
c.mVolume,
|
||||
InterleaveAndConvertBuffer(c.mChannelData.Elements(), c.mBufferFormat,
|
||||
int32_t(c.mDuration), c.mVolume,
|
||||
aOutput->GetChannels(),
|
||||
buf.Elements());
|
||||
} else {
|
||||
|
|
|
@ -15,6 +15,14 @@ namespace mozilla {
|
|||
|
||||
class AudioStream;
|
||||
|
||||
/**
|
||||
* An AudioChunk represents a multi-channel buffer of audio samples.
|
||||
* It references an underlying ThreadSharedObject which manages the lifetime
|
||||
* of the buffer. An AudioChunk maintains its own duration and channel data
|
||||
* pointers so it can represent a subinterval of a buffer without copying.
|
||||
* An AudioChunk can store its individual channels anywhere; it maintains
|
||||
* separate pointers to each channel's buffer.
|
||||
*/
|
||||
struct AudioChunk {
|
||||
typedef mozilla::AudioSampleFormat SampleFormat;
|
||||
|
||||
|
@ -24,7 +32,11 @@ struct AudioChunk {
|
|||
NS_ASSERTION(aStart >= 0 && aStart < aEnd && aEnd <= mDuration,
|
||||
"Slice out of bounds");
|
||||
if (mBuffer) {
|
||||
mOffset += int32_t(aStart);
|
||||
MOZ_ASSERT(aStart < INT32_MAX, "Can't slice beyond 32-bit sample lengths");
|
||||
for (uint32_t channel = 0; channel < mChannelData.Length(); ++channel) {
|
||||
mChannelData[channel] = AddAudioSampleOffset(mChannelData[channel],
|
||||
mBufferFormat, int32_t(aStart));
|
||||
}
|
||||
}
|
||||
mDuration = aEnd - aStart;
|
||||
}
|
||||
|
@ -35,9 +47,19 @@ struct AudioChunk {
|
|||
return false;
|
||||
}
|
||||
if (mBuffer) {
|
||||
NS_ASSERTION(aOther.mBufferFormat == mBufferFormat && aOther.mBufferLength == mBufferLength,
|
||||
NS_ASSERTION(aOther.mBufferFormat == mBufferFormat,
|
||||
"Wrong metadata about buffer");
|
||||
return aOther.mOffset == mOffset + mDuration && aOther.mVolume == mVolume;
|
||||
NS_ASSERTION(aOther.mChannelData.Length() == mChannelData.Length(),
|
||||
"Mismatched channel count");
|
||||
if (mDuration > INT32_MAX) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t channel = 0; channel < mChannelData.Length(); ++channel) {
|
||||
if (aOther.mChannelData[channel] != AddAudioSampleOffset(mChannelData[channel],
|
||||
mBufferFormat, int32_t(mDuration))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -45,17 +67,16 @@ struct AudioChunk {
|
|||
void SetNull(TrackTicks aDuration)
|
||||
{
|
||||
mBuffer = nullptr;
|
||||
mChannelData.Clear();
|
||||
mDuration = aDuration;
|
||||
mOffset = 0;
|
||||
mVolume = 1.0f;
|
||||
}
|
||||
|
||||
TrackTicks mDuration; // in frames within the buffer
|
||||
nsRefPtr<SharedBuffer> mBuffer; // null means data is all zeroes
|
||||
int32_t mBufferLength; // number of frames in mBuffer (only meaningful if mBuffer is nonnull)
|
||||
SampleFormat mBufferFormat; // format of frames in mBuffer (only meaningful if mBuffer is nonnull)
|
||||
int32_t mOffset; // in frames within the buffer (zero if mBuffer is null)
|
||||
float mVolume; // volume multiplier to apply (1.0f if mBuffer is nonnull)
|
||||
TrackTicks mDuration; // in frames within the buffer
|
||||
nsRefPtr<ThreadSharedObject> mBuffer; // the buffer object whose lifetime is managed; null means data is all zeroes
|
||||
nsTArray<const void*> mChannelData; // one pointer per channel; empty if and only if mBuffer is null
|
||||
float mVolume; // volume multiplier to apply (1.0f if mBuffer is nonnull)
|
||||
SampleFormat mBufferFormat; // format of frames in mBuffer (only meaningful if mBuffer is nonnull)
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -83,16 +104,35 @@ public:
|
|||
NS_ASSERTION(IsInitialized(), "Not initialized");
|
||||
return mChannels;
|
||||
}
|
||||
void AppendFrames(already_AddRefed<SharedBuffer> aBuffer, int32_t aBufferLength,
|
||||
int32_t aStart, int32_t aEnd, SampleFormat aFormat)
|
||||
void AppendFrames(already_AddRefed<ThreadSharedObject> aBuffer,
|
||||
const nsTArray<const float*>& aChannelData,
|
||||
int32_t aDuration)
|
||||
{
|
||||
NS_ASSERTION(mChannels > 0, "Not initialized");
|
||||
AudioChunk* chunk = AppendChunk(aEnd - aStart);
|
||||
NS_ASSERTION(!aBuffer.get() || aChannelData.Length() == uint32_t(mChannels),
|
||||
"Wrong number of channels");
|
||||
AudioChunk* chunk = AppendChunk(aDuration);
|
||||
chunk->mBuffer = aBuffer;
|
||||
chunk->mBufferFormat = aFormat;
|
||||
chunk->mBufferLength = aBufferLength;
|
||||
chunk->mOffset = aStart;
|
||||
for (uint32_t channel = 0; channel < aChannelData.Length(); ++channel) {
|
||||
chunk->mChannelData.AppendElement(aChannelData[channel]);
|
||||
}
|
||||
chunk->mVolume = 1.0f;
|
||||
chunk->mBufferFormat = AUDIO_FORMAT_FLOAT32;
|
||||
}
|
||||
void AppendFrames(already_AddRefed<ThreadSharedObject> aBuffer,
|
||||
const nsTArray<const int16_t*>& aChannelData,
|
||||
int32_t aDuration)
|
||||
{
|
||||
NS_ASSERTION(mChannels > 0, "Not initialized");
|
||||
NS_ASSERTION(!aBuffer.get() || aChannelData.Length() == uint32_t(mChannels),
|
||||
"Wrong number of channels");
|
||||
AudioChunk* chunk = AppendChunk(aDuration);
|
||||
chunk->mBuffer = aBuffer;
|
||||
for (uint32_t channel = 0; channel < aChannelData.Length(); ++channel) {
|
||||
chunk->mChannelData.AppendElement(aChannelData[channel]);
|
||||
}
|
||||
chunk->mVolume = 1.0f;
|
||||
chunk->mBufferFormat = AUDIO_FORMAT_S16;
|
||||
}
|
||||
void ApplyVolume(float aVolume);
|
||||
/**
|
||||
|
|
|
@ -549,8 +549,12 @@ void MediaDecoderStateMachine::SendStreamAudio(AudioData* aAudio,
|
|||
|
||||
aAudio->EnsureAudioBuffer();
|
||||
nsRefPtr<SharedBuffer> buffer = aAudio->mAudioBuffer;
|
||||
aOutput->AppendFrames(buffer.forget(), aAudio->mFrames, int32_t(offset), aAudio->mFrames,
|
||||
AUDIO_OUTPUT_FORMAT);
|
||||
AudioDataValue* bufferData = static_cast<AudioDataValue*>(buffer->Data());
|
||||
nsAutoTArray<const AudioDataValue*,2> channels;
|
||||
for (uint32_t i = 0; i < aAudio->mChannels; ++i) {
|
||||
channels.AppendElement(bufferData + i*aAudio->mFrames + offset);
|
||||
}
|
||||
aOutput->AppendFrames(buffer.forget(), channels, aAudio->mFrames);
|
||||
LOG(PR_LOG_DEBUG, ("%p Decoder writing %d frames of data to MediaStream for AudioData at %lld",
|
||||
mDecoder.get(), aAudio->mFrames - int32_t(offset), aAudio->mTime));
|
||||
aStream->mAudioFramesWritten += aAudio->mFrames - int32_t(offset);
|
||||
|
|
|
@ -12,6 +12,16 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* Base class for objects with a thread-safe refcount and a virtual
|
||||
* destructor.
|
||||
*/
|
||||
class ThreadSharedObject {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ThreadSharedObject)
|
||||
virtual ~ThreadSharedObject() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Heap-allocated chunk of arbitrary data with threadsafe refcounting.
|
||||
* Typically you would allocate one of these, fill it in, and then treat it as
|
||||
|
@ -20,15 +30,10 @@ namespace mozilla {
|
|||
* simply assume that the refcount is at least 4-byte aligned and its size
|
||||
* is divisible by 4.
|
||||
*/
|
||||
class SharedBuffer {
|
||||
class SharedBuffer : public ThreadSharedObject {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedBuffer)
|
||||
~SharedBuffer() {}
|
||||
|
||||
void* Data() { return this + 1; }
|
||||
|
||||
// Takes ownership of aData (which will be freed via moz_free()).
|
||||
// aData consists of aChannels consecutive buffers, each of aLength samples.
|
||||
static already_AddRefed<SharedBuffer> Create(size_t aSize)
|
||||
{
|
||||
void* m = moz_xmalloc(sizeof(SharedBuffer) + aSize);
|
||||
|
|
|
@ -300,7 +300,9 @@ MediaEngineWebRTCAudioSource::Process(const int channel,
|
|||
|
||||
AudioSegment segment;
|
||||
segment.Init(CHANNELS);
|
||||
segment.AppendFrames(buffer.forget(), length, 0, length, AUDIO_FORMAT_S16);
|
||||
nsAutoTArray<const sample*,1> channels;
|
||||
channels.AppendElement(dest);
|
||||
segment.AppendFrames(buffer.forget(), channels, length);
|
||||
|
||||
SourceMediaStream *source = mSources[i];
|
||||
if (source) {
|
||||
|
|
|
@ -164,7 +164,7 @@ this.AppsUtils = {
|
|||
* from https://developer.mozilla.org/en/OpenWebApps/The_Manifest
|
||||
* only the name property is mandatory
|
||||
*/
|
||||
checkManifest: function(aManifest) {
|
||||
checkManifest: function(aManifest, app) {
|
||||
if (aManifest.name == undefined)
|
||||
return false;
|
||||
|
||||
|
@ -219,6 +219,9 @@ this.AppsUtils = {
|
|||
}
|
||||
}
|
||||
|
||||
// Ensure that non-updatable fields contains the current app value
|
||||
AppsUtils.normalizeManifest(aManifest, app);
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
|
@ -234,6 +237,43 @@ this.AppsUtils = {
|
|||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method to apply modifications to webapp manifests file saved internally.
|
||||
* For now, only ensure app can't rename itself.
|
||||
*/
|
||||
normalizeManifest: function normalizeManifest(aManifest, aApp) {
|
||||
// As normalizeManifest isn't only called on update but also
|
||||
// during app install, we need to bail out on install.
|
||||
if (aApp.installState != "installed" &&
|
||||
aApp.installState != "updating") {
|
||||
return;
|
||||
}
|
||||
|
||||
let previousManifest = aApp.manifest;
|
||||
|
||||
// Ensure that app name can't be updated
|
||||
aManifest.name = aApp.name;
|
||||
|
||||
// Nor through localized names
|
||||
if ('locales' in aManifest) {
|
||||
let defaultName = new ManifestHelper(aManifest, aApp.origin).name;
|
||||
for (let locale in aManifest.locales) {
|
||||
let entry = aManifest.locales[locale];
|
||||
if (!entry.name) {
|
||||
continue;
|
||||
}
|
||||
// In case previous manifest didn't had a name,
|
||||
// we use the default app name
|
||||
let localizedName = defaultName;
|
||||
if (previousManifest && 'locales' in previousManifest &&
|
||||
locale in previousManifest.locales) {
|
||||
localizedName = previousManifest.locales[locale].name;
|
||||
}
|
||||
entry.name = localizedName;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines whether the manifest allows installs for the given origin.
|
||||
* @param object aManifest
|
||||
|
|
|
@ -202,8 +202,8 @@ this.PermissionsTable = { geolocation: {
|
|||
certified: ALLOW_ACTION
|
||||
},
|
||||
"storage": {
|
||||
app: DENY_ACTION,
|
||||
privileged: DENY_ACTION,
|
||||
app: ALLOW_ACTION,
|
||||
privileged: ALLOW_ACTION,
|
||||
certified: ALLOW_ACTION,
|
||||
substitute: [
|
||||
"indexedDB-unlimited",
|
||||
|
|
|
@ -523,6 +523,7 @@ WebappsApplication.prototype = {
|
|||
|
||||
if ("installState" in msg) {
|
||||
this.installState = msg.installState;
|
||||
this.progress = msg.progress;
|
||||
if (this.installState == "installed") {
|
||||
this._downloadError = null;
|
||||
this.downloading = false;
|
||||
|
|
|
@ -1324,7 +1324,7 @@ this.DOMApplicationRegistry = {
|
|||
sendError("MANIFEST_PARSE_ERROR");
|
||||
return;
|
||||
}
|
||||
if (!AppsUtils.checkManifest(manifest)) {
|
||||
if (!AppsUtils.checkManifest(manifest, app)) {
|
||||
sendError("INVALID_MANIFEST");
|
||||
return;
|
||||
} else if (!AppsUtils.checkInstallAllowed(manifest, app.installOrigin)) {
|
||||
|
@ -1439,7 +1439,7 @@ this.DOMApplicationRegistry = {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!AppsUtils.checkManifest(app.manifest)) {
|
||||
if (!AppsUtils.checkManifest(app.manifest, app)) {
|
||||
sendError("INVALID_MANIFEST");
|
||||
} else if (!AppsUtils.checkInstallAllowed(app.manifest, app.installOrigin)) {
|
||||
sendError("INSTALL_FROM_DENIED");
|
||||
|
@ -1501,7 +1501,7 @@ this.DOMApplicationRegistry = {
|
|||
sendError("MANIFEST_PARSE_ERROR");
|
||||
return;
|
||||
}
|
||||
if (!(AppsUtils.checkManifest(manifest) &&
|
||||
if (!(AppsUtils.checkManifest(manifest, app) &&
|
||||
manifest.package_path)) {
|
||||
sendError("INVALID_MANIFEST");
|
||||
} else if (!AppsUtils.checkInstallAllowed(manifest, app.installOrigin)) {
|
||||
|
@ -2023,15 +2023,18 @@ this.DOMApplicationRegistry = {
|
|||
let manifest = JSON.parse(converter.ConvertToUnicode(NetUtil.readInputStreamToString(istream,
|
||||
istream.available()) || ""));
|
||||
|
||||
// Call checkManifest before compareManifests, as checkManifest
|
||||
// will normalize some attributes that has already been normalized
|
||||
// for aManifest during checkForUpdate.
|
||||
if (!AppsUtils.checkManifest(manifest, app)) {
|
||||
throw "INVALID_MANIFEST";
|
||||
}
|
||||
|
||||
if (!AppsUtils.compareManifests(manifest,
|
||||
aManifest._manifest)) {
|
||||
throw "MANIFEST_MISMATCH";
|
||||
}
|
||||
|
||||
if (!AppsUtils.checkManifest(manifest)) {
|
||||
throw "INVALID_MANIFEST";
|
||||
}
|
||||
|
||||
if (!AppsUtils.checkInstallAllowed(manifest, aApp.installOrigin)) {
|
||||
throw "INSTALL_FROM_DENIED";
|
||||
}
|
||||
|
@ -2556,17 +2559,19 @@ AppcacheObserver.prototype = {
|
|||
|
||||
debug("Offline cache state change for " + app.origin + " : " + aState);
|
||||
|
||||
let setStatus = function appObs_setStatus(aStatus) {
|
||||
let setStatus = function appObs_setStatus(aStatus, aProgress) {
|
||||
debug("Offlinecache setStatus to " + aStatus + " for " + app.origin);
|
||||
mustSave = (app.installState != aStatus);
|
||||
app.installState = aStatus;
|
||||
app.progress = aProgress;
|
||||
if (aStatus == "installed") {
|
||||
app.downloading = false;
|
||||
app.downloadAvailable = false;
|
||||
}
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:OfflineCache",
|
||||
{ manifest: app.manifestURL,
|
||||
installState: app.installState });
|
||||
installState: app.installState,
|
||||
progress: app.progress });
|
||||
}
|
||||
|
||||
let setError = function appObs_setError(aError) {
|
||||
|
@ -2587,16 +2592,16 @@ AppcacheObserver.prototype = {
|
|||
case Ci.nsIOfflineCacheUpdateObserver.STATE_NOUPDATE:
|
||||
case Ci.nsIOfflineCacheUpdateObserver.STATE_FINISHED:
|
||||
aUpdate.removeObserver(this);
|
||||
setStatus("installed");
|
||||
setStatus("installed", aUpdate.byteProgress);
|
||||
break;
|
||||
case Ci.nsIOfflineCacheUpdateObserver.STATE_DOWNLOADING:
|
||||
case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMSTARTED:
|
||||
setStatus(this.startStatus);
|
||||
setStatus(this.startStatus, aUpdate.byteProgress);
|
||||
break;
|
||||
case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMPROGRESS:
|
||||
let now = Date.now();
|
||||
if (now - this.lastProgressTime > MIN_PROGRESS_EVENT_DELAY) {
|
||||
setStatus(this.startStatus);
|
||||
setStatus(this.startStatus, aUpdate.byteProgress);
|
||||
this.lastProgressTime = now;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -629,7 +629,7 @@ BluetoothHfpManager::ReceiveSocketData(UnixSocketRawData* aMessage)
|
|||
*/
|
||||
ParseAtCommand(msg, 8, atCommandValues);
|
||||
|
||||
if (atCommandValues.Length() <= 4) {
|
||||
if (atCommandValues.Length() < 4) {
|
||||
NS_WARNING("Could't get the value of command [AT+CMER=]");
|
||||
goto respond_with_ok;
|
||||
}
|
||||
|
|
|
@ -233,10 +233,19 @@ const ContentPanning = {
|
|||
}
|
||||
|
||||
let isPan = KineticPanning.isPan();
|
||||
if (!isPan) {
|
||||
// If panning distance is not large enough, both BES and APZC
|
||||
// should not perform scrolling
|
||||
evt.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
let isScroll = this.scrollCallback(delta.scale(-1));
|
||||
|
||||
if (this.detectingScrolling) {
|
||||
this.detectingScrolling = false;
|
||||
// Stop async-pan-zooming if the user is panning the subframe.
|
||||
if (isPan) {
|
||||
if (isScroll) {
|
||||
// We're going to drive synchronously scrolling an inner frame.
|
||||
Services.obs.notifyObservers(docShell, 'cancel-default-pan-zoom', null);
|
||||
} else {
|
||||
|
@ -246,8 +255,6 @@ const ContentPanning = {
|
|||
}
|
||||
}
|
||||
|
||||
this.scrollCallback(delta.scale(-1));
|
||||
|
||||
// If a pan action happens, cancel the active state of the
|
||||
// current target.
|
||||
if (!this.panning && isPan) {
|
||||
|
|
|
@ -52,6 +52,29 @@ using namespace mozilla::dom;
|
|||
using namespace mozilla::dom::indexedDB::ipc;
|
||||
using mozilla::dom::quota::FileOutputStream;
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
|
||||
struct FileHandleData
|
||||
{
|
||||
nsString type;
|
||||
nsString name;
|
||||
};
|
||||
|
||||
struct BlobOrFileData
|
||||
{
|
||||
BlobOrFileData()
|
||||
: tag(0), size(0), lastModifiedDate(UINT64_MAX)
|
||||
{ }
|
||||
|
||||
uint32_t tag;
|
||||
uint64_t size;
|
||||
nsString type;
|
||||
nsString name;
|
||||
uint64_t lastModifiedDate;
|
||||
};
|
||||
|
||||
END_INDEXEDDB_NAMESPACE
|
||||
|
||||
namespace {
|
||||
|
||||
inline
|
||||
|
@ -628,6 +651,187 @@ ResolveMysteryBlob(nsIDOMBlob* aBlob, const nsString& aContentType,
|
|||
return true;
|
||||
}
|
||||
|
||||
class MainThreadDeserializationTraits
|
||||
{
|
||||
public:
|
||||
static JSObject* CreateAndWrapFileHandle(JSContext* aCx,
|
||||
IDBDatabase* aDatabase,
|
||||
StructuredCloneFile& aFile,
|
||||
const FileHandleData& aData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsRefPtr<FileInfo>& fileInfo = aFile.mFileInfo;
|
||||
|
||||
nsRefPtr<IDBFileHandle> fileHandle = IDBFileHandle::Create(aDatabase,
|
||||
aData.name, aData.type, fileInfo.forget());
|
||||
|
||||
jsval wrappedFileHandle;
|
||||
nsresult rv =
|
||||
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx),
|
||||
static_cast<nsIDOMFileHandle*>(fileHandle),
|
||||
&NS_GET_IID(nsIDOMFileHandle),
|
||||
&wrappedFileHandle);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to wrap native!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return JSVAL_TO_OBJECT(wrappedFileHandle);
|
||||
}
|
||||
|
||||
static JSObject* CreateAndWrapBlobOrFile(JSContext* aCx,
|
||||
IDBDatabase* aDatabase,
|
||||
StructuredCloneFile& aFile,
|
||||
const BlobOrFileData& aData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE ||
|
||||
aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
|
||||
aData.tag == SCTAG_DOM_BLOB);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsRefPtr<FileInfo>& fileInfo = aFile.mFileInfo;
|
||||
|
||||
nsCOMPtr<nsIFile> nativeFile;
|
||||
if (!aFile.mFile) {
|
||||
FileManager* fileManager = aDatabase->Manager();
|
||||
NS_ASSERTION(fileManager, "This should never be null!");
|
||||
|
||||
nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
|
||||
if (!directory) {
|
||||
NS_WARNING("Failed to get directory!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nativeFile = fileManager->GetFileForId(directory, fileInfo->Id());
|
||||
if (!nativeFile) {
|
||||
NS_WARNING("Failed to get file!");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (aData.tag == SCTAG_DOM_BLOB) {
|
||||
nsCOMPtr<nsIDOMBlob> domBlob;
|
||||
if (aFile.mFile) {
|
||||
if (!ResolveMysteryBlob(aFile.mFile, aData.type, aData.size)) {
|
||||
return nullptr;
|
||||
}
|
||||
domBlob = aFile.mFile;
|
||||
}
|
||||
else {
|
||||
domBlob = new nsDOMFileFile(aData.type, aData.size, nativeFile,
|
||||
fileInfo);
|
||||
}
|
||||
|
||||
jsval wrappedBlob;
|
||||
rv =
|
||||
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), domBlob,
|
||||
&NS_GET_IID(nsIDOMBlob), &wrappedBlob);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to wrap native!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return JSVAL_TO_OBJECT(wrappedBlob);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMFile> domFile;
|
||||
if (aFile.mFile) {
|
||||
if (!ResolveMysteryFile(aFile.mFile, aData.name, aData.type, aData.size,
|
||||
aData.lastModifiedDate)) {
|
||||
return nullptr;
|
||||
}
|
||||
domFile = do_QueryInterface(aFile.mFile);
|
||||
NS_ASSERTION(domFile, "This should never fail!");
|
||||
}
|
||||
else {
|
||||
domFile = new nsDOMFileFile(aData.name, aData.type, aData.size,
|
||||
nativeFile, fileInfo);
|
||||
}
|
||||
|
||||
jsval wrappedFile;
|
||||
rv =
|
||||
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), domFile,
|
||||
&NS_GET_IID(nsIDOMFile), &wrappedFile);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to wrap native!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return JSVAL_TO_OBJECT(wrappedFile);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CreateIndexDeserializationTraits
|
||||
{
|
||||
public:
|
||||
static JSObject* CreateAndWrapFileHandle(JSContext* aCx,
|
||||
IDBDatabase* aDatabase,
|
||||
StructuredCloneFile& aFile,
|
||||
const FileHandleData& aData)
|
||||
{
|
||||
// FileHandle can't be used in index creation, so just make a dummy object.
|
||||
return JS_NewObject(aCx, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
static JSObject* CreateAndWrapBlobOrFile(JSContext* aCx,
|
||||
IDBDatabase* aDatabase,
|
||||
StructuredCloneFile& aFile,
|
||||
const BlobOrFileData& aData)
|
||||
{
|
||||
MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE ||
|
||||
aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
|
||||
aData.tag == SCTAG_DOM_BLOB);
|
||||
|
||||
// The following properties are available for use in index creation
|
||||
// Blob.size
|
||||
// Blob.type
|
||||
// File.name
|
||||
// File.lastModifiedDate
|
||||
|
||||
JSObject* obj = JS_NewObject(aCx, nullptr, nullptr, nullptr);
|
||||
if (!obj) {
|
||||
NS_WARNING("Failed to create object!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Technically these props go on the proto, but this detail won't change
|
||||
// the results of index creation.
|
||||
|
||||
JSString* type =
|
||||
JS_NewUCStringCopyN(aCx, aData.type.get(), aData.type.Length());
|
||||
if (!type ||
|
||||
!JS_DefineProperty(aCx, obj, "size",
|
||||
JS_NumberValue((double)aData.size),
|
||||
nullptr, nullptr, 0) ||
|
||||
!JS_DefineProperty(aCx, obj, "type", STRING_TO_JSVAL(type),
|
||||
nullptr, nullptr, 0)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aData.tag == SCTAG_DOM_BLOB) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
JSString* name =
|
||||
JS_NewUCStringCopyN(aCx, aData.name.get(), aData.name.Length());
|
||||
JSObject* date = JS_NewDateObjectMsec(aCx, aData.lastModifiedDate);
|
||||
if (!name || !date ||
|
||||
!JS_DefineProperty(aCx, obj, "name", STRING_TO_JSVAL(name),
|
||||
nullptr, nullptr, 0) ||
|
||||
!JS_DefineProperty(aCx, obj, "lastModifiedDate", OBJECT_TO_JSVAL(date),
|
||||
nullptr, nullptr, 0)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
JSClass IDBObjectStore::sDummyPropJSClass = {
|
||||
|
@ -1003,7 +1207,7 @@ IDBObjectStore::DeserializeValue(JSContext* aCx,
|
|||
JSAutoRequest ar(aCx);
|
||||
|
||||
JSStructuredCloneCallbacks callbacks = {
|
||||
IDBObjectStore::StructuredCloneReadCallback,
|
||||
IDBObjectStore::StructuredCloneReadCallback<MainThreadDeserializationTraits>,
|
||||
nullptr,
|
||||
nullptr
|
||||
};
|
||||
|
@ -1090,6 +1294,87 @@ StructuredCloneReadString(JSStructuredCloneReader* aReader,
|
|||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
IDBObjectStore::ReadFileHandle(JSStructuredCloneReader* aReader,
|
||||
FileHandleData* aRetval)
|
||||
{
|
||||
MOZ_STATIC_ASSERT(SCTAG_DOM_FILEHANDLE == 0xFFFF8004,
|
||||
"Update me!");
|
||||
MOZ_ASSERT(aReader && aRetval);
|
||||
|
||||
nsCString type;
|
||||
if (!StructuredCloneReadString(aReader, type)) {
|
||||
return false;
|
||||
}
|
||||
CopyUTF8toUTF16(type, aRetval->type);
|
||||
|
||||
nsCString name;
|
||||
if (!StructuredCloneReadString(aReader, name)) {
|
||||
return false;
|
||||
}
|
||||
CopyUTF8toUTF16(name, aRetval->name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
IDBObjectStore::ReadBlobOrFile(JSStructuredCloneReader* aReader,
|
||||
uint32_t aTag,
|
||||
BlobOrFileData* aRetval)
|
||||
{
|
||||
MOZ_STATIC_ASSERT(SCTAG_DOM_BLOB == 0xFFFF8001 &&
|
||||
SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE == 0xFFFF8002 &&
|
||||
SCTAG_DOM_FILE == 0xFFFF8005,
|
||||
"Update me!");
|
||||
MOZ_ASSERT(aReader && aRetval);
|
||||
MOZ_ASSERT(aTag == SCTAG_DOM_FILE ||
|
||||
aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
|
||||
aTag == SCTAG_DOM_FILE);
|
||||
|
||||
aRetval->tag = aTag;
|
||||
|
||||
// If it's not a FileHandle, it's a Blob or a File.
|
||||
uint64_t size;
|
||||
if (!JS_ReadBytes(aReader, &size, sizeof(uint64_t))) {
|
||||
NS_WARNING("Failed to read size!");
|
||||
return false;
|
||||
}
|
||||
aRetval->size = SwapBytes(size);
|
||||
|
||||
nsCString type;
|
||||
if (!StructuredCloneReadString(aReader, type)) {
|
||||
return false;
|
||||
}
|
||||
CopyUTF8toUTF16(type, aRetval->type);
|
||||
|
||||
// Blobs are done.
|
||||
if (aTag == SCTAG_DOM_BLOB) {
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_ASSERTION(aTag == SCTAG_DOM_FILE ||
|
||||
aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE, "Huh?!");
|
||||
|
||||
uint64_t lastModifiedDate = UINT64_MAX;
|
||||
if (aTag != SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE &&
|
||||
!JS_ReadBytes(aReader, &lastModifiedDate, sizeof(lastModifiedDate))) {
|
||||
NS_WARNING("Failed to read lastModifiedDate");
|
||||
return false;
|
||||
}
|
||||
aRetval->lastModifiedDate = lastModifiedDate;
|
||||
|
||||
nsCString name;
|
||||
if (!StructuredCloneReadString(aReader, name)) {
|
||||
return false;
|
||||
}
|
||||
CopyUTF8toUTF16(name, aRetval->name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
template <class DeserializationTraits>
|
||||
JSObject*
|
||||
IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
|
||||
JSStructuredCloneReader* aReader,
|
||||
|
@ -1118,137 +1403,26 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
StructuredCloneFile& file = cloneReadInfo->mFiles[aData];
|
||||
nsRefPtr<FileInfo>& fileInfo = file.mFileInfo;
|
||||
IDBDatabase* database = cloneReadInfo->mDatabase;
|
||||
|
||||
if (aTag == SCTAG_DOM_FILEHANDLE) {
|
||||
nsCString type;
|
||||
if (!StructuredCloneReadString(aReader, type)) {
|
||||
return nullptr;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 convType(type);
|
||||
|
||||
nsCString name;
|
||||
if (!StructuredCloneReadString(aReader, name)) {
|
||||
return nullptr;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 convName(name);
|
||||
|
||||
nsRefPtr<IDBFileHandle> fileHandle = IDBFileHandle::Create(database,
|
||||
convName, convType, fileInfo.forget());
|
||||
|
||||
jsval wrappedFileHandle;
|
||||
rv =
|
||||
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx),
|
||||
static_cast<nsIDOMFileHandle*>(fileHandle),
|
||||
&NS_GET_IID(nsIDOMFileHandle),
|
||||
&wrappedFileHandle);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to wrap native!");
|
||||
FileHandleData data;
|
||||
if (!ReadFileHandle(aReader, &data)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return JSVAL_TO_OBJECT(wrappedFileHandle);
|
||||
return DeserializationTraits::CreateAndWrapFileHandle(aCx, database,
|
||||
file, data);
|
||||
}
|
||||
|
||||
// If it's not a FileHandle, it's a Blob or a File.
|
||||
uint64_t size;
|
||||
if (!JS_ReadBytes(aReader, &size, sizeof(uint64_t))) {
|
||||
NS_WARNING("Failed to read size!");
|
||||
return nullptr;
|
||||
}
|
||||
size = SwapBytes(size);
|
||||
|
||||
nsCString type;
|
||||
if (!StructuredCloneReadString(aReader, type)) {
|
||||
return nullptr;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 convType(type);
|
||||
|
||||
nsCOMPtr<nsIFile> nativeFile;
|
||||
if (!file.mFile) {
|
||||
FileManager* fileManager = database->Manager();
|
||||
NS_ASSERTION(fileManager, "This should never be null!");
|
||||
|
||||
nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
|
||||
if (!directory) {
|
||||
NS_WARNING("Failed to get directory!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nativeFile = fileManager->GetFileForId(directory, fileInfo->Id());
|
||||
if (!nativeFile) {
|
||||
NS_WARNING("Failed to get file!");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (aTag == SCTAG_DOM_BLOB) {
|
||||
nsCOMPtr<nsIDOMBlob> domBlob;
|
||||
if (file.mFile) {
|
||||
if (!ResolveMysteryBlob(file.mFile, convType, size)) {
|
||||
return nullptr;
|
||||
}
|
||||
domBlob = file.mFile;
|
||||
}
|
||||
else {
|
||||
domBlob = new nsDOMFileFile(convType, size, nativeFile, fileInfo);
|
||||
}
|
||||
|
||||
jsval wrappedBlob;
|
||||
rv =
|
||||
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), domBlob,
|
||||
&NS_GET_IID(nsIDOMBlob), &wrappedBlob);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to wrap native!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return JSVAL_TO_OBJECT(wrappedBlob);
|
||||
}
|
||||
|
||||
NS_ASSERTION(aTag == SCTAG_DOM_FILE ||
|
||||
aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE, "Huh?!");
|
||||
|
||||
uint64_t lastModifiedDate = UINT64_MAX;
|
||||
if (aTag != SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE &&
|
||||
!JS_ReadBytes(aReader, &lastModifiedDate, sizeof(lastModifiedDate))) {
|
||||
NS_WARNING("Failed to read lastModifiedDate");
|
||||
BlobOrFileData data;
|
||||
if (!ReadBlobOrFile(aReader, aTag, &data)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCString name;
|
||||
if (!StructuredCloneReadString(aReader, name)) {
|
||||
return nullptr;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 convName(name);
|
||||
|
||||
nsCOMPtr<nsIDOMFile> domFile;
|
||||
if (file.mFile) {
|
||||
if (!ResolveMysteryFile(file.mFile, convName, convType, size, lastModifiedDate)) {
|
||||
return nullptr;
|
||||
}
|
||||
domFile = do_QueryInterface(file.mFile);
|
||||
NS_ASSERTION(domFile, "This should never fail!");
|
||||
}
|
||||
else {
|
||||
domFile = new nsDOMFileFile(convName, convType, size, nativeFile,
|
||||
fileInfo);
|
||||
}
|
||||
|
||||
jsval wrappedFile;
|
||||
rv =
|
||||
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), domFile,
|
||||
&NS_GET_IID(nsIDOMFile), &wrappedFile);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to wrap native!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return JSVAL_TO_OBJECT(wrappedFile);
|
||||
return DeserializationTraits::CreateAndWrapBlobOrFile(aCx, database,
|
||||
file, data);
|
||||
}
|
||||
|
||||
const JSStructuredCloneCallbacks* runtimeCallbacks =
|
||||
|
@ -3629,7 +3803,7 @@ CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection)
|
|||
JSAutoStructuredCloneBuffer& buffer = cloneReadInfo.mCloneBuffer;
|
||||
|
||||
JSStructuredCloneCallbacks callbacks = {
|
||||
IDBObjectStore::StructuredCloneReadCallback,
|
||||
IDBObjectStore::StructuredCloneReadCallback<CreateIndexDeserializationTraits>,
|
||||
nullptr,
|
||||
nullptr
|
||||
};
|
||||
|
|
|
@ -44,6 +44,9 @@ struct IndexInfo;
|
|||
struct IndexUpdateInfo;
|
||||
struct ObjectStoreInfo;
|
||||
|
||||
struct FileHandleData;
|
||||
struct BlobOrFileData;
|
||||
|
||||
class IDBObjectStore MOZ_FINAL : public nsIIDBObjectStore
|
||||
{
|
||||
public:
|
||||
|
@ -98,6 +101,7 @@ public:
|
|||
StructuredCloneWriteInfo& aCloneWriteInfo,
|
||||
jsval aValue);
|
||||
|
||||
template <class DeserializationTraits>
|
||||
static JSObject*
|
||||
StructuredCloneReadCallback(JSContext* aCx,
|
||||
JSStructuredCloneReader* aReader,
|
||||
|
@ -269,6 +273,14 @@ protected:
|
|||
static void
|
||||
ClearStructuredCloneBuffer(JSAutoStructuredCloneBuffer& aBuffer);
|
||||
|
||||
static bool
|
||||
ReadFileHandle(JSStructuredCloneReader* aReader,
|
||||
FileHandleData* aRetval);
|
||||
|
||||
static bool
|
||||
ReadBlobOrFile(JSStructuredCloneReader* aReader,
|
||||
uint32_t aTag,
|
||||
BlobOrFileData* aRetval);
|
||||
private:
|
||||
nsRefPtr<IDBTransaction> mTransaction;
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ GetJSValFromKeyPathString(JSContext* aCx,
|
|||
// If the property doesn't exist, fall into below path of starting
|
||||
// to define properties, if allowed.
|
||||
if (aOptions == DoNotCreateProperties) {
|
||||
return NS_OK;
|
||||
return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
|
||||
}
|
||||
|
||||
targetObject = obj;
|
||||
|
|
|
@ -73,6 +73,7 @@ MOCHITEST_FILES = \
|
|||
test_index_update_delete.html \
|
||||
test_indexes.html \
|
||||
test_indexes_bad_values.html \
|
||||
test_indexes_funny_things.html \
|
||||
test_key_requirements.html \
|
||||
test_keys.html \
|
||||
test_leaving_page.html \
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Property Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7" src="unit/test_indexes_funny_things.js"></script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
|
@ -35,6 +35,7 @@ MOCHITEST_FILES = \
|
|||
test_index_update_delete.js \
|
||||
test_indexes.js \
|
||||
test_indexes_bad_values.js \
|
||||
test_indexes_funny_things.js \
|
||||
test_key_requirements.js \
|
||||
test_keys.js \
|
||||
test_multientry.js \
|
||||
|
|
|
@ -7,7 +7,7 @@ var testGenerator = testSteps();
|
|||
|
||||
function testSteps()
|
||||
{
|
||||
const name = this.window ? this.window ? window.location.pathname : "Splendid Test" : "Splendid Test";
|
||||
const name = this.window ? window.location.pathname : "Splendid Test";
|
||||
|
||||
const objectStoreName = "People";
|
||||
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function testSteps()
|
||||
{
|
||||
// Blob constructor is not implemented outside of windows yet (Bug 827723).
|
||||
if (!this.window) {
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
|
||||
const name = this.window ? window.location.pathname : "Splendid Test";
|
||||
|
||||
const objectStoreName = "Things";
|
||||
|
||||
const blob1 = new Blob(["foo", "bar"], { type: "text/plain" });
|
||||
const blob2 = new Blob(["foobazybar"], { type: "text/plain" });
|
||||
const blob3 = new Blob(["2"], { type: "bogus/" });
|
||||
const str = "The Book of Mozilla";
|
||||
str.type = blob1;
|
||||
const arr = [1, 2, 3, 4, 5];
|
||||
|
||||
const objectStoreData = [
|
||||
{ key: "1", value: blob1},
|
||||
{ key: "2", value: blob2},
|
||||
{ key: "3", value: blob3},
|
||||
{ key: "4", value: str},
|
||||
{ key: "5", value: arr},
|
||||
];
|
||||
|
||||
const indexData = [
|
||||
{ name: "type", keyPath: "type", options: { } },
|
||||
{ name: "length", keyPath: "length", options: { unique: true } }
|
||||
];
|
||||
|
||||
const objectStoreDataTypeSort = [
|
||||
{ key: "3", value: blob3},
|
||||
{ key: "1", value: blob1},
|
||||
{ key: "2", value: blob2},
|
||||
];
|
||||
|
||||
const objectStoreDataLengthSort = [
|
||||
{ key: "5", value: arr},
|
||||
//{ key: "4", value: str},
|
||||
];
|
||||
|
||||
let request = indexedDB.open(name, 1);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
let db = event.target.result;
|
||||
|
||||
let objectStore = db.createObjectStore(objectStoreName, { keyPath: null });
|
||||
|
||||
// First, add all our data to the object store.
|
||||
let addedData = 0;
|
||||
for (let i in objectStoreData) {
|
||||
request = objectStore.add(objectStoreData[i].value,
|
||||
objectStoreData[i].key);
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = function(event) {
|
||||
if (++addedData == objectStoreData.length) {
|
||||
testGenerator.send(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
event = yield;
|
||||
// Now create the indexes.
|
||||
for (let i in indexData) {
|
||||
objectStore.createIndex(indexData[i].name, indexData[i].keyPath,
|
||||
indexData[i].options);
|
||||
}
|
||||
is(objectStore.indexNames.length, indexData.length, "Good index count");
|
||||
yield;
|
||||
objectStore = db.transaction(objectStoreName)
|
||||
.objectStore(objectStoreName);
|
||||
|
||||
// Check global properties to make sure they are correct.
|
||||
is(objectStore.indexNames.length, indexData.length, "Good index count");
|
||||
for (let i in indexData) {
|
||||
let found = false;
|
||||
for (let j = 0; j < objectStore.indexNames.length; j++) {
|
||||
if (objectStore.indexNames.item(j) == indexData[i].name) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
is(found, true, "objectStore has our index");
|
||||
let index = objectStore.index(indexData[i].name);
|
||||
is(index.name, indexData[i].name, "Correct name");
|
||||
is(index.storeName, objectStore.name, "Correct store name");
|
||||
is(index.keyPath, indexData[i].keyPath, "Correct keyPath");
|
||||
is(index.unique, indexData[i].options.unique ? true : false,
|
||||
"Correct unique value");
|
||||
}
|
||||
|
||||
ok(true, "Test group 1");
|
||||
|
||||
let keyIndex = 0;
|
||||
|
||||
request = objectStore.index("type").openKeyCursor();
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = function (event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
is(cursor.key, objectStoreDataTypeSort[keyIndex].value.type,
|
||||
"Correct key");
|
||||
is(cursor.primaryKey, objectStoreDataTypeSort[keyIndex].key,
|
||||
"Correct primary key");
|
||||
ok(!("value" in cursor), "No value");
|
||||
|
||||
cursor.continue();
|
||||
|
||||
is(cursor.key, objectStoreDataTypeSort[keyIndex].value.type,
|
||||
"Correct key");
|
||||
is(cursor.primaryKey, objectStoreDataTypeSort[keyIndex].key,
|
||||
"Correct value");
|
||||
ok(!("value" in cursor), "No value");
|
||||
|
||||
keyIndex++;
|
||||
}
|
||||
else {
|
||||
testGenerator.next();
|
||||
}
|
||||
}
|
||||
yield;
|
||||
|
||||
is(keyIndex, objectStoreDataTypeSort.length, "Saw all the expected keys");
|
||||
|
||||
ok(true, "Test group 2");
|
||||
|
||||
keyIndex = 0;
|
||||
|
||||
request = objectStore.index("length").openKeyCursor(null, "next");
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = function (event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
is(cursor.key, objectStoreDataLengthSort[keyIndex].value.length,
|
||||
"Correct key");
|
||||
is(cursor.primaryKey, objectStoreDataLengthSort[keyIndex].key,
|
||||
"Correct value");
|
||||
|
||||
cursor.continue();
|
||||
|
||||
is(cursor.key, objectStoreDataLengthSort[keyIndex].value.length,
|
||||
"Correct key");
|
||||
is(cursor.primaryKey, objectStoreDataLengthSort[keyIndex].key,
|
||||
"Correct value");
|
||||
|
||||
keyIndex++;
|
||||
}
|
||||
else {
|
||||
testGenerator.next();
|
||||
}
|
||||
}
|
||||
yield;
|
||||
|
||||
is(keyIndex, objectStoreDataLengthSort.length, "Saw all the expected keys");
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
|
@ -28,6 +28,7 @@ tail =
|
|||
[test_index_update_delete.js]
|
||||
[test_indexes.js]
|
||||
[test_indexes_bad_values.js]
|
||||
[test_indexes_funny_things.js]
|
||||
[test_key_requirements.js]
|
||||
[test_keys.js]
|
||||
[test_multientry.js]
|
||||
|
|
|
@ -229,8 +229,7 @@ ConsoleListener::Observe(nsIConsoleMessage* aMessage)
|
|||
ContentChild* ContentChild::sSingleton;
|
||||
|
||||
ContentChild::ContentChild()
|
||||
: TabContext()
|
||||
, mID(uint64_t(-1))
|
||||
: mID(uint64_t(-1))
|
||||
#ifdef ANDROID
|
||||
,mScreenSize(0, 0)
|
||||
#endif
|
||||
|
|
|
@ -42,7 +42,6 @@ class PStorageChild;
|
|||
class ClonedMessageData;
|
||||
|
||||
class ContentChild : public PContentChild
|
||||
, public TabContext
|
||||
{
|
||||
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
|
||||
typedef mozilla::ipc::OptionalURIParams OptionalURIParams;
|
||||
|
@ -199,6 +198,9 @@ public:
|
|||
|
||||
uint64_t GetID() { return mID; }
|
||||
|
||||
bool IsForApp() { return mIsForApp; }
|
||||
bool IsForBrowser() { return mIsForBrowser; }
|
||||
|
||||
bool GetParamsForBlob(nsDOMFileBase* aBlob,
|
||||
BlobConstructorParams* aOutParams);
|
||||
BlobChild* GetOrCreateActorForBlob(nsIDOMBlob* aBlob);
|
||||
|
|
|
@ -210,6 +210,9 @@ AudioManager::AudioManager() : mPhoneState(PHONE_STATE_CURRENT),
|
|||
AudioSystem::initStreamVolume(static_cast<audio_stream_type_t>(loop), 0,
|
||||
sMaxStreamVolumeTbl[loop]);
|
||||
}
|
||||
// Force publicnotification to output at maximal volume
|
||||
AudioSystem::setStreamVolumeIndex(static_cast<audio_stream_type_t>(AUDIO_STREAM_ENFORCED_AUDIBLE),
|
||||
sMaxStreamVolumeTbl[AUDIO_STREAM_ENFORCED_AUDIBLE]);
|
||||
}
|
||||
|
||||
AudioManager::~AudioManager() {
|
||||
|
|
|
@ -39,7 +39,9 @@ using namespace mozilla::services;
|
|||
namespace mozilla {
|
||||
namespace system {
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsVolumeService, nsIVolumeService, nsIDOMMozWakeLockListener)
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS2(nsVolumeService,
|
||||
nsIVolumeService,
|
||||
nsIDOMMozWakeLockListener)
|
||||
|
||||
StaticRefPtr<nsVolumeService> nsVolumeService::sSingleton;
|
||||
|
||||
|
|
|
@ -1421,7 +1421,7 @@ void AsyncPanZoomController::ContentReceivedTouch(bool aPreventDefault) {
|
|||
|
||||
while (!mTouchQueue.IsEmpty()) {
|
||||
// we need to reset mDelayPanning before handling scrolling gesture.
|
||||
if (mTouchQueue[0].mType == MultiTouchInput::MULTITOUCH_MOVE) {
|
||||
if (!aPreventDefault && mTouchQueue[0].mType == MultiTouchInput::MULTITOUCH_MOVE) {
|
||||
mDelayPanning = false;
|
||||
}
|
||||
if (!aPreventDefault) {
|
||||
|
|
|
@ -142,29 +142,6 @@ inline nscoord NSCoordSaturatingMultiply(nscoord aCoord, float aScale) {
|
|||
return _nscoordSaturatingMultiply(aCoord, aScale, false);
|
||||
}
|
||||
|
||||
inline nscoord NSCoordMultiply(nscoord aCoord, int32_t aScale) {
|
||||
VERIFY_COORD(aCoord);
|
||||
return aCoord * aScale;
|
||||
}
|
||||
|
||||
inline nscoord NSCoordDivide(nscoord aCoord, float aVal) {
|
||||
VERIFY_COORD(aCoord);
|
||||
#ifdef NS_COORD_IS_FLOAT
|
||||
return floorf(aCoord/aVal);
|
||||
#else
|
||||
return (int32_t)(aCoord/aVal);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline nscoord NSCoordDivide(nscoord aCoord, int32_t aVal) {
|
||||
VERIFY_COORD(aCoord);
|
||||
#ifdef NS_COORD_IS_FLOAT
|
||||
return floorf(aCoord/aVal);
|
||||
#else
|
||||
return aCoord/aVal;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a + b, capping the sum to nscoord_MAX.
|
||||
*
|
||||
|
@ -265,54 +242,6 @@ NSCoordSaturatingSubtract(nscoord a, nscoord b,
|
|||
}
|
||||
#endif
|
||||
}
|
||||
/** compare against a nscoord "b", which might be unconstrained
|
||||
* "a" must not be unconstrained.
|
||||
* Every number is smaller than a unconstrained one
|
||||
*/
|
||||
inline bool
|
||||
NSCoordLessThan(nscoord a,nscoord b)
|
||||
{
|
||||
NS_ASSERTION(a != nscoord_MAX,
|
||||
"This coordinate should be constrained");
|
||||
return ((a < b) || (b == nscoord_MAX));
|
||||
}
|
||||
|
||||
/** compare against a nscoord "b", which might be unconstrained
|
||||
* "a" must not be unconstrained
|
||||
* No number is larger than a unconstrained one.
|
||||
*/
|
||||
inline bool
|
||||
NSCoordGreaterThan(nscoord a,nscoord b)
|
||||
{
|
||||
NS_ASSERTION(a != nscoord_MAX,
|
||||
"This coordinate should be constrained");
|
||||
return ((a > b) && (b != nscoord_MAX));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an nscoord to a int32_t. This *does not* do rounding because
|
||||
* coords are never fractional. They can be out of range, so this does
|
||||
* clamp out of bounds coord values to INT32_MIN and INT32_MAX.
|
||||
*/
|
||||
inline int32_t NSCoordToInt(nscoord aCoord) {
|
||||
VERIFY_COORD(aCoord);
|
||||
#ifdef NS_COORD_IS_FLOAT
|
||||
NS_ASSERTION(!NS_IEEEIsNan(aCoord), "NaN encountered in int conversion");
|
||||
if (aCoord < -2147483648.0f) {
|
||||
// -2147483648 is the smallest 32-bit signed integer that can be
|
||||
// exactly represented as a float
|
||||
return INT32_MIN;
|
||||
} else if (aCoord > 2147483520.0f) {
|
||||
// 2147483520 is the largest 32-bit signed integer that can be
|
||||
// exactly represented as an IEEE float
|
||||
return INT32_MAX;
|
||||
} else {
|
||||
return (int32_t)aCoord;
|
||||
}
|
||||
#else
|
||||
return aCoord;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline float NSCoordToFloat(nscoord aCoord) {
|
||||
VERIFY_COORD(aCoord);
|
||||
|
@ -363,24 +292,6 @@ inline nscoord NSToCoordCeil(double aValue)
|
|||
return nscoord(ceil(aValue));
|
||||
}
|
||||
|
||||
inline nscoord NSToCoordCeilClamped(float aValue)
|
||||
{
|
||||
#ifndef NS_COORD_IS_FLOAT
|
||||
// Bounds-check before converting out of float, to avoid overflow
|
||||
NS_WARN_IF_FALSE(aValue <= nscoord_MAX,
|
||||
"Overflowed nscoord_MAX in conversion to nscoord");
|
||||
if (aValue >= nscoord_MAX) {
|
||||
return nscoord_MAX;
|
||||
}
|
||||
NS_WARN_IF_FALSE(aValue >= nscoord_MIN,
|
||||
"Overflowed nscoord_MIN in conversion to nscoord");
|
||||
if (aValue <= nscoord_MIN) {
|
||||
return nscoord_MIN;
|
||||
}
|
||||
#endif
|
||||
return NSToCoordCeil(aValue);
|
||||
}
|
||||
|
||||
inline nscoord NSToCoordCeilClamped(double aValue)
|
||||
{
|
||||
#ifndef NS_COORD_IS_FLOAT
|
||||
|
@ -422,11 +333,6 @@ inline int32_t NSToIntRound(double aValue)
|
|||
return NS_lround(aValue);
|
||||
}
|
||||
|
||||
inline int32_t NSToIntRoundUp(float aValue)
|
||||
{
|
||||
return int32_t(floorf(aValue + 0.5f));
|
||||
}
|
||||
|
||||
inline int32_t NSToIntRoundUp(double aValue)
|
||||
{
|
||||
return int32_t(floor(aValue + 0.5));
|
||||
|
@ -454,11 +360,6 @@ inline float NSAppUnitsToFloatPixels(nscoord aAppUnits, float aAppUnitsPerPixel)
|
|||
return (float(aAppUnits) / aAppUnitsPerPixel);
|
||||
}
|
||||
|
||||
inline double NSAppUnitsToDoublePixels(nscoord aAppUnits, nscoord aAppUnitsPerPixel)
|
||||
{
|
||||
return (double(aAppUnits) / double(aAppUnitsPerPixel));
|
||||
}
|
||||
|
||||
inline double NSAppUnitsToDoublePixels(nscoord aAppUnits, double aAppUnitsPerPixel)
|
||||
{
|
||||
return (double(aAppUnits) / aAppUnitsPerPixel);
|
||||
|
@ -501,20 +402,13 @@ inline float NSTwipsToUnits(float aTwips, float aUnitsPerPoint)
|
|||
#define NS_INCHES_TO_TWIPS(x) NSUnitsToTwips((x), POINTS_PER_INCH_FLOAT) // 72 points per inch
|
||||
|
||||
#define NS_MILLIMETERS_TO_TWIPS(x) NSUnitsToTwips((x), (POINTS_PER_INCH_FLOAT * 0.03937f))
|
||||
#define NS_CENTIMETERS_TO_TWIPS(x) NSUnitsToTwips((x), (POINTS_PER_INCH_FLOAT * 0.3937f))
|
||||
|
||||
#define NS_PICAS_TO_TWIPS(x) NSUnitsToTwips((x), 12.0f) // 12 points per pica
|
||||
|
||||
#define NS_POINTS_TO_INT_TWIPS(x) NSToIntRound(NS_POINTS_TO_TWIPS(x))
|
||||
#define NS_INCHES_TO_INT_TWIPS(x) NSToIntRound(NS_INCHES_TO_TWIPS(x))
|
||||
|
||||
#define NS_TWIPS_TO_POINTS(x) NSTwipsToUnits((x), 1.0f)
|
||||
#define NS_TWIPS_TO_INCHES(x) NSTwipsToUnits((x), 1.0f / POINTS_PER_INCH_FLOAT)
|
||||
|
||||
#define NS_TWIPS_TO_MILLIMETERS(x) NSTwipsToUnits((x), 1.0f / (POINTS_PER_INCH_FLOAT * 0.03937f))
|
||||
#define NS_TWIPS_TO_CENTIMETERS(x) NSTwipsToUnits((x), 1.0f / (POINTS_PER_INCH_FLOAT * 0.3937f))
|
||||
|
||||
#define NS_TWIPS_TO_PICAS(x) NSTwipsToUnits((x), 1.0f / 12.0f)
|
||||
//@}
|
||||
|
||||
#endif /* NSCOORD_H */
|
||||
|
|
|
@ -259,7 +259,7 @@ gfxAndroidPlatform::FontHintingEnabled()
|
|||
// Otherwise, enable hinting unless we're in a content process
|
||||
// that might be used for non-reflowing zoom.
|
||||
return XRE_GetProcessType() != GeckoProcessType_Content ||
|
||||
ContentChild::GetSingleton()->HasOwnApp();
|
||||
!ContentChild::GetSingleton()->IsForBrowser();
|
||||
#endif // MOZ_USING_ANDROID_JAVA_WIDGETS
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ LocalUTCDifferenceSeconds()
|
|||
{
|
||||
using js::SecondsPerDay;
|
||||
using js::SecondsPerHour;
|
||||
using js::SecondsPerMinute;
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// Windows doesn't follow POSIX: updates to the TZ environment variable are
|
||||
|
@ -57,21 +58,21 @@ LocalUTCDifferenceSeconds()
|
|||
if (!ComputeLocalTime(t, &local) || !ComputeUTCTime(t, &utc))
|
||||
return 0;
|
||||
|
||||
int utc_secs = utc.tm_hour * SecondsPerHour + utc.tm_min * 60;
|
||||
int local_secs = local.tm_hour * SecondsPerHour + local.tm_min * 60;
|
||||
int utc_secs = utc.tm_hour * SecondsPerHour + utc.tm_min * SecondsPerMinute;
|
||||
int local_secs = local.tm_hour * SecondsPerHour + local.tm_min * SecondsPerMinute;
|
||||
|
||||
// Callers expect the negative difference of the offset from local time
|
||||
// and UTC.
|
||||
|
||||
if (utc.tm_mday == local.tm_mday) {
|
||||
return utc_secs - local_secs;
|
||||
}
|
||||
if (utc_secs > local_secs) {
|
||||
// Local date comes before UTC (offset in the negative range).
|
||||
return utc_secs - SecondsPerDay - local_secs;
|
||||
}
|
||||
if (utc.tm_mday == local.tm_mday)
|
||||
return utc_secs - local_secs;
|
||||
|
||||
// Local date comes after UTC (offset in the positive range).
|
||||
return SecondsPerDay - local_secs + utc_secs;
|
||||
if (utc_secs > local_secs)
|
||||
return utc_secs - (SecondsPerDay + local_secs);
|
||||
|
||||
// Local date comes before UTC (offset in the negative range).
|
||||
return (utc_secs + SecondsPerDay) - local_secs;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -128,7 +128,7 @@ ValueToIdentifier(JSContext *cx, const Value &v, MutableHandleId id)
|
|||
*/
|
||||
class Debugger::FrameRange
|
||||
{
|
||||
StackFrame *fp;
|
||||
TaggedFramePtr frame;
|
||||
|
||||
/* The debuggers in |fp|'s compartment, or NULL if there are none. */
|
||||
GlobalObject::DebuggerVector *debuggers;
|
||||
|
@ -157,17 +157,17 @@ class Debugger::FrameRange
|
|||
* Similarly, if stack frames are added to or removed from frontDebugger(),
|
||||
* then the range's front is invalid until popFront is called.
|
||||
*/
|
||||
FrameRange(StackFrame *fp, GlobalObject *global = NULL)
|
||||
: fp(fp)
|
||||
FrameRange(TaggedFramePtr frame, GlobalObject *global = NULL)
|
||||
: frame(frame)
|
||||
{
|
||||
nextDebugger = 0;
|
||||
|
||||
/* Find our global, if we were not given one. */
|
||||
if (!global)
|
||||
global = &fp->global();
|
||||
global = &frame.script()->global();
|
||||
|
||||
/* The frame and global must match. */
|
||||
JS_ASSERT(&fp->global() == global);
|
||||
JS_ASSERT(&frame.script()->global() == global);
|
||||
|
||||
/* Find the list of debuggers we'll iterate over. There may be none. */
|
||||
debuggers = global->getDebuggers();
|
||||
|
@ -216,7 +216,7 @@ class Debugger::FrameRange
|
|||
void findNext() {
|
||||
while (!empty()) {
|
||||
Debugger *dbg = (*debuggers)[nextDebugger];
|
||||
entry = dbg->frames.lookup(fp);
|
||||
entry = dbg->frames.lookup(frame);
|
||||
if (entry)
|
||||
break;
|
||||
nextDebugger++;
|
||||
|
@ -415,9 +415,9 @@ Debugger::fromChildJSObject(JSObject *obj)
|
|||
}
|
||||
|
||||
bool
|
||||
Debugger::getScriptFrame(JSContext *cx, StackFrame *fp, Value *vp)
|
||||
Debugger::getScriptFrame(JSContext *cx, const ScriptFrameIter &iter, Value *vp)
|
||||
{
|
||||
FrameMap::AddPtr p = frames.lookupForAdd(fp);
|
||||
FrameMap::AddPtr p = frames.lookupForAdd(iter.taggedFramePtr());
|
||||
if (!p) {
|
||||
/* Create and populate the Debugger.Frame object. */
|
||||
JSObject *proto = &object->getReservedSlot(JSSLOT_DEBUG_FRAME_PROTO).toObject();
|
||||
|
@ -425,10 +425,13 @@ Debugger::getScriptFrame(JSContext *cx, StackFrame *fp, Value *vp)
|
|||
NewObjectWithGivenProto(cx, &DebuggerFrame_class, proto, NULL);
|
||||
if (!frameobj)
|
||||
return false;
|
||||
frameobj->setPrivate(fp);
|
||||
StackIter::Data *data = iter.copyData();
|
||||
if (!data)
|
||||
return false;
|
||||
frameobj->setPrivate(data);
|
||||
frameobj->setReservedSlot(JSSLOT_DEBUGFRAME_OWNER, ObjectValue(*object));
|
||||
|
||||
if (!frames.add(p, fp, frameobj)) {
|
||||
if (!frames.add(p, iter.taggedFramePtr(), frameobj)) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
@ -480,11 +483,15 @@ Debugger::slowPathOnEnterFrame(JSContext *cx, Value *vp)
|
|||
{
|
||||
/* Build the list of recipients. */
|
||||
AutoValueVector triggered(cx);
|
||||
Rooted<GlobalObject*> global(cx, &cx->fp()->global());
|
||||
Handle<GlobalObject*> global = cx->global();
|
||||
|
||||
ScriptFrameIter iter(cx);
|
||||
JS_ASSERT(!iter.done());
|
||||
|
||||
if (GlobalObject::DebuggerVector *debuggers = global->getDebuggers()) {
|
||||
for (Debugger **p = debuggers->begin(); p != debuggers->end(); p++) {
|
||||
Debugger *dbg = *p;
|
||||
JS_ASSERT(dbg->observesFrame(cx->fp()));
|
||||
JS_ASSERT(dbg->observesFrame(iter.taggedFramePtr()));
|
||||
if (dbg->observesEnterFrame() && !triggered.append(ObjectValue(*dbg->toJSObject())))
|
||||
return JSTRAP_ERROR;
|
||||
}
|
||||
|
@ -503,6 +510,9 @@ Debugger::slowPathOnEnterFrame(JSContext *cx, Value *vp)
|
|||
return JSTRAP_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
DebuggerFrame_freeStackIterData(FreeOp *fop, RawObject obj);
|
||||
|
||||
/*
|
||||
* Handle leaving a frame with debuggers watching. |frameOk| indicates whether
|
||||
* the frame is exiting normally or abruptly. Set |cx|'s exception and/or
|
||||
|
@ -511,17 +521,19 @@ Debugger::slowPathOnEnterFrame(JSContext *cx, Value *vp)
|
|||
bool
|
||||
Debugger::slowPathOnLeaveFrame(JSContext *cx, bool frameOk)
|
||||
{
|
||||
StackFrame *fp = cx->fp();
|
||||
Rooted<GlobalObject*> global(cx, &fp->global());
|
||||
ScriptFrameIter iter(cx);
|
||||
JS_ASSERT(!iter.done());
|
||||
|
||||
Handle<GlobalObject*> global = cx->global();
|
||||
|
||||
/* Save the frame's completion value. */
|
||||
JSTrapStatus status;
|
||||
RootedValue value(cx);
|
||||
Debugger::resultToCompletion(cx, frameOk, fp->returnValue(), &status, &value);
|
||||
Debugger::resultToCompletion(cx, frameOk, iter.returnValue(), &status, &value);
|
||||
|
||||
/* Build a list of the recipients. */
|
||||
AutoObjectVector frames(cx);
|
||||
for (FrameRange r(fp, global); !r.empty(); r.popFront()) {
|
||||
for (FrameRange r(iter.taggedFramePtr(), global); !r.empty(); r.popFront()) {
|
||||
if (!frames.append(r.frontFrame())) {
|
||||
cx->clearPendingException();
|
||||
return false;
|
||||
|
@ -573,37 +585,37 @@ Debugger::slowPathOnLeaveFrame(JSContext *cx, bool frameOk)
|
|||
* debugger's onPop handler could have caused another debugger to create its
|
||||
* own Debugger.Frame instance.
|
||||
*/
|
||||
for (FrameRange r(fp, global); !r.empty(); r.popFront()) {
|
||||
for (FrameRange r(iter.taggedFramePtr(), global); !r.empty(); r.popFront()) {
|
||||
RootedObject frameobj(cx, r.frontFrame());
|
||||
Debugger *dbg = r.frontDebugger();
|
||||
JS_ASSERT(dbg == Debugger::fromChildJSObject(frameobj));
|
||||
|
||||
frameobj->setPrivate(NULL);
|
||||
DebuggerFrame_freeStackIterData(cx->runtime->defaultFreeOp(), frameobj);
|
||||
|
||||
/* If this frame had an onStep handler, adjust the script's count. */
|
||||
if (!frameobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER).isUndefined() &&
|
||||
!fp->script()->changeStepModeCount(cx, -1))
|
||||
!iter.script()->changeStepModeCount(cx, -1))
|
||||
{
|
||||
status = JSTRAP_ERROR;
|
||||
/* Don't exit the loop; we must mark all frames as dead. */
|
||||
}
|
||||
|
||||
dbg->frames.remove(fp);
|
||||
dbg->frames.remove(iter.taggedFramePtr());
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is an eval frame, then from the debugger's perspective the
|
||||
* script is about to be destroyed. Remove any breakpoints in it.
|
||||
*/
|
||||
if (fp->isEvalFrame()) {
|
||||
RootedScript script(cx, fp->script());
|
||||
if (iter.isEvalFrame()) {
|
||||
RootedScript script(cx, iter.script());
|
||||
script->clearBreakpointsIn(cx->runtime->defaultFreeOp(), NULL, NULL);
|
||||
}
|
||||
|
||||
/* Establish (status, value) as our resumption value. */
|
||||
switch (status) {
|
||||
case JSTRAP_RETURN:
|
||||
fp->setReturnValue(value);
|
||||
iter.setReturnValue(value);
|
||||
return true;
|
||||
|
||||
case JSTRAP_THROW:
|
||||
|
@ -909,8 +921,10 @@ Debugger::fireDebuggerStatement(JSContext *cx, Value *vp)
|
|||
Maybe<AutoCompartment> ac;
|
||||
ac.construct(cx, object);
|
||||
|
||||
ScriptFrameIter iter(cx);
|
||||
|
||||
Value argv[1];
|
||||
if (!getScriptFrame(cx, cx->fp(), argv))
|
||||
if (!getScriptFrame(cx, iter, argv))
|
||||
return handleUncaughtException(ac, vp, false);
|
||||
|
||||
Value rv;
|
||||
|
@ -934,8 +948,10 @@ Debugger::fireExceptionUnwind(JSContext *cx, Value *vp)
|
|||
Value argv[2];
|
||||
AutoValueArray avr(cx, argv, 2);
|
||||
|
||||
ScriptFrameIter iter(cx);
|
||||
|
||||
argv[1] = exc;
|
||||
if (!getScriptFrame(cx, cx->fp(), &argv[0]) || !wrapDebuggeeValue(cx, avr.handleAt(1)))
|
||||
if (!getScriptFrame(cx, iter, &argv[0]) || !wrapDebuggeeValue(cx, avr.handleAt(1)))
|
||||
return handleUncaughtException(ac, vp, false);
|
||||
|
||||
Value rv;
|
||||
|
@ -953,12 +969,12 @@ Debugger::fireEnterFrame(JSContext *cx, Value *vp)
|
|||
JS_ASSERT(hook);
|
||||
JS_ASSERT(hook->isCallable());
|
||||
|
||||
StackFrame *fp = cx->fp();
|
||||
ScriptFrameIter iter(cx);
|
||||
Maybe<AutoCompartment> ac;
|
||||
ac.construct(cx, object);
|
||||
|
||||
Value argv[1];
|
||||
if (!getScriptFrame(cx, fp, &argv[0]))
|
||||
if (!getScriptFrame(cx, iter, &argv[0]))
|
||||
return handleUncaughtException(ac, vp, false);
|
||||
|
||||
Value rv;
|
||||
|
@ -1003,7 +1019,7 @@ Debugger::dispatchHook(JSContext *cx, Value *vp, Hook which)
|
|||
* different compartments--every compartment *except* this one.
|
||||
*/
|
||||
AutoValueVector triggered(cx);
|
||||
Rooted<GlobalObject*> global(cx, &cx->fp()->global());
|
||||
Handle<GlobalObject*> global = cx->global();
|
||||
if (GlobalObject::DebuggerVector *debuggers = global->getDebuggers()) {
|
||||
for (Debugger **p = debuggers->begin(); p != debuggers->end(); p++) {
|
||||
Debugger *dbg = *p;
|
||||
|
@ -1091,10 +1107,10 @@ Debugger::slowPathOnNewScript(JSContext *cx, HandleScript script, GlobalObject *
|
|||
JSTrapStatus
|
||||
Debugger::onTrap(JSContext *cx, Value *vp)
|
||||
{
|
||||
StackFrame *fp = cx->fp();
|
||||
RootedScript script(cx, fp->script());
|
||||
Rooted<GlobalObject*> scriptGlobal(cx, &fp->global());
|
||||
jsbytecode *pc = cx->regs().pc;
|
||||
ScriptFrameIter iter(cx);
|
||||
RootedScript script(cx, iter.script());
|
||||
Rooted<GlobalObject*> scriptGlobal(cx, &script->global());
|
||||
jsbytecode *pc = iter.pc();
|
||||
BreakpointSite *site = script->getBreakpointSite(pc);
|
||||
JSOp op = JSOp(*pc);
|
||||
|
||||
|
@ -1131,7 +1147,7 @@ Debugger::onTrap(JSContext *cx, Value *vp)
|
|||
|
||||
Value argv[1];
|
||||
AutoValueArray ava(cx, argv, 1);
|
||||
if (!dbg->getScriptFrame(cx, fp, &argv[0]))
|
||||
if (!dbg->getScriptFrame(cx, iter, &argv[0]))
|
||||
return dbg->handleUncaughtException(ac, vp, false);
|
||||
Value rv;
|
||||
Rooted<JSObject*> handler(cx, bp->handler);
|
||||
|
@ -1146,8 +1162,7 @@ Debugger::onTrap(JSContext *cx, Value *vp)
|
|||
}
|
||||
|
||||
if (site && site->trapHandler) {
|
||||
RootedScript fpscript(cx, fp->script());
|
||||
JSTrapStatus st = site->trapHandler(cx, fpscript, pc, vp, site->trapClosure);
|
||||
JSTrapStatus st = site->trapHandler(cx, script, pc, vp, site->trapClosure);
|
||||
if (st != JSTRAP_CONTINUE)
|
||||
return st;
|
||||
}
|
||||
|
@ -1160,7 +1175,7 @@ Debugger::onTrap(JSContext *cx, Value *vp)
|
|||
JSTrapStatus
|
||||
Debugger::onSingleStep(JSContext *cx, Value *vp)
|
||||
{
|
||||
StackFrame *fp = cx->fp();
|
||||
ScriptFrameIter iter(cx);
|
||||
|
||||
/*
|
||||
* We may be stepping over a JSOP_EXCEPTION, that pushes the context's
|
||||
|
@ -1180,7 +1195,7 @@ Debugger::onSingleStep(JSContext *cx, Value *vp)
|
|||
* onStep handlers.
|
||||
*/
|
||||
AutoObjectVector frames(cx);
|
||||
for (FrameRange r(fp); !r.empty(); r.popFront()) {
|
||||
for (FrameRange r(iter.taggedFramePtr()); !r.empty(); r.popFront()) {
|
||||
JSObject *frame = r.frontFrame();
|
||||
if (!frame->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER).isUndefined() &&
|
||||
!frames.append(frame))
|
||||
|
@ -1202,15 +1217,15 @@ Debugger::onSingleStep(JSContext *cx, Value *vp)
|
|||
{
|
||||
AutoAssertNoGC nogc;
|
||||
uint32_t stepperCount = 0;
|
||||
UnrootedScript trappingScript = fp->script();
|
||||
GlobalObject *global = &fp->global();
|
||||
UnrootedScript trappingScript = iter.script();
|
||||
Unrooted<GlobalObject*> global = cx->global();
|
||||
if (GlobalObject::DebuggerVector *debuggers = global->getDebuggers()) {
|
||||
for (Debugger **p = debuggers->begin(); p != debuggers->end(); p++) {
|
||||
Debugger *dbg = *p;
|
||||
for (FrameMap::Range r = dbg->frames.all(); !r.empty(); r.popFront()) {
|
||||
StackFrame *frame = r.front().key;
|
||||
TaggedFramePtr frame = r.front().key;
|
||||
JSObject *frameobj = r.front().value;
|
||||
if (frame->script() == trappingScript &&
|
||||
if (frame.script() == trappingScript &&
|
||||
!frameobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER).isUndefined())
|
||||
{
|
||||
stepperCount++;
|
||||
|
@ -1976,8 +1991,12 @@ Debugger::getNewestFrame(JSContext *cx, unsigned argc, Value *vp)
|
|||
*/
|
||||
if (i.isIon())
|
||||
continue;
|
||||
if (dbg->observesFrame(i.interpFrame()))
|
||||
return dbg->getScriptFrame(cx, i.interpFrame(), vp);
|
||||
if (dbg->observesFrame(i.taggedFramePtr())) {
|
||||
ScriptFrameIter iter(i.seg()->cx(), StackIter::GO_THROUGH_SAVED);
|
||||
while (iter.isIon() || iter.taggedFramePtr() != i.taggedFramePtr())
|
||||
++iter;
|
||||
return dbg->getScriptFrame(cx, iter, vp);
|
||||
}
|
||||
}
|
||||
args.rval().setNull();
|
||||
return true;
|
||||
|
@ -2163,9 +2182,9 @@ Debugger::removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global,
|
|||
* which slowPathOnLeaveFrame would have to examine.
|
||||
*/
|
||||
for (FrameMap::Enum e(frames); !e.empty(); e.popFront()) {
|
||||
StackFrame *fp = e.front().key;
|
||||
if (&fp->global() == global) {
|
||||
e.front().value->setPrivate(NULL);
|
||||
TaggedFramePtr frame = e.front().key;
|
||||
if (&frame.script()->global() == global) {
|
||||
DebuggerFrame_freeStackIterData(fop, e.front().value);
|
||||
e.removeFront();
|
||||
}
|
||||
}
|
||||
|
@ -3251,10 +3270,23 @@ static JSFunctionSpec DebuggerScript_methods[] = {
|
|||
|
||||
/*** Debugger.Frame ******************************************************************************/
|
||||
|
||||
static void
|
||||
DebuggerFrame_freeStackIterData(FreeOp *fop, RawObject obj)
|
||||
{
|
||||
fop->delete_((StackIter::Data *)obj->getPrivate());
|
||||
obj->setPrivate(NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
DebuggerFrame_finalize(FreeOp *fop, RawObject obj)
|
||||
{
|
||||
DebuggerFrame_freeStackIterData(fop, obj);
|
||||
}
|
||||
|
||||
Class DebuggerFrame_class = {
|
||||
"Frame", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGFRAME_COUNT),
|
||||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
|
||||
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, DebuggerFrame_finalize
|
||||
};
|
||||
|
||||
static JSObject *
|
||||
|
@ -3292,30 +3324,29 @@ CheckThisFrame(JSContext *cx, const CallArgs &args, const char *fnname, bool che
|
|||
return thisobj;
|
||||
}
|
||||
|
||||
#define THIS_FRAME(cx, argc, vp, fnname, args, thisobj, fp) \
|
||||
#define THIS_FRAME(cx, argc, vp, fnname, args, thisobj, iter) \
|
||||
CallArgs args = CallArgsFromVp(argc, vp); \
|
||||
RootedObject thisobj(cx, CheckThisFrame(cx, args, fnname, true)); \
|
||||
if (!thisobj) \
|
||||
return false; \
|
||||
StackFrame *fp = (StackFrame *) thisobj->getPrivate(); \
|
||||
JS_ASSERT(cx->stack.space().containsSlow(fp))
|
||||
ScriptFrameIter iter(*(StackIter::Data *)thisobj->getPrivate());
|
||||
|
||||
#define THIS_FRAME_OWNER(cx, argc, vp, fnname, args, thisobj, fp, dbg) \
|
||||
THIS_FRAME(cx, argc, vp, fnname, args, thisobj, fp); \
|
||||
#define THIS_FRAME_OWNER(cx, argc, vp, fnname, args, thisobj, iter, dbg) \
|
||||
THIS_FRAME(cx, argc, vp, fnname, args, thisobj, iter); \
|
||||
Debugger *dbg = Debugger::fromChildJSObject(thisobj)
|
||||
|
||||
static JSBool
|
||||
DebuggerFrame_getType(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_FRAME(cx, argc, vp, "get type", args, thisobj, fp);
|
||||
THIS_FRAME(cx, argc, vp, "get type", args, thisobj, iter);
|
||||
|
||||
/*
|
||||
* Indirect eval frames are both isGlobalFrame() and isEvalFrame(), so the
|
||||
* order of checks here is significant.
|
||||
*/
|
||||
args.rval().setString(fp->isEvalFrame()
|
||||
args.rval().setString(iter.isEvalFrame()
|
||||
? cx->names().eval
|
||||
: fp->isGlobalFrame()
|
||||
: iter.isGlobalFrame()
|
||||
? cx->names().global
|
||||
: cx->names().call);
|
||||
return true;
|
||||
|
@ -3324,12 +3355,12 @@ DebuggerFrame_getType(JSContext *cx, unsigned argc, Value *vp)
|
|||
static JSBool
|
||||
DebuggerFrame_getEnvironment(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_FRAME_OWNER(cx, argc, vp, "get environment", args, thisobj, fp, dbg);
|
||||
THIS_FRAME_OWNER(cx, argc, vp, "get environment", args, thisobj, iter, dbg);
|
||||
|
||||
Rooted<Env*> env(cx);
|
||||
{
|
||||
AutoCompartment ac(cx, fp->scopeChain());
|
||||
env = GetDebugScopeForFrame(cx, fp);
|
||||
AutoCompartment ac(cx, iter.scopeChain());
|
||||
env = GetDebugScopeForFrame(cx, iter.interpFrame());
|
||||
if (!env)
|
||||
return false;
|
||||
}
|
||||
|
@ -3340,8 +3371,8 @@ DebuggerFrame_getEnvironment(JSContext *cx, unsigned argc, Value *vp)
|
|||
static JSBool
|
||||
DebuggerFrame_getCallee(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_FRAME(cx, argc, vp, "get callee", args, thisobj, fp);
|
||||
RootedValue calleev(cx, (fp->isFunctionFrame() && !fp->isEvalFrame()) ? fp->calleev() : NullValue());
|
||||
THIS_FRAME(cx, argc, vp, "get callee", args, thisobj, iter);
|
||||
RootedValue calleev(cx, (iter.isFunctionFrame() && !iter.isEvalFrame()) ? iter.calleev() : NullValue());
|
||||
if (!Debugger::fromChildJSObject(thisobj)->wrapDebuggeeValue(cx, &calleev))
|
||||
return false;
|
||||
args.rval().set(calleev);
|
||||
|
@ -3351,29 +3382,29 @@ DebuggerFrame_getCallee(JSContext *cx, unsigned argc, Value *vp)
|
|||
static JSBool
|
||||
DebuggerFrame_getGenerator(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_FRAME(cx, argc, vp, "get generator", args, thisobj, fp);
|
||||
args.rval().setBoolean(fp->isGeneratorFrame());
|
||||
THIS_FRAME(cx, argc, vp, "get generator", args, thisobj, iter);
|
||||
args.rval().setBoolean(iter.isGeneratorFrame());
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
DebuggerFrame_getConstructing(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_FRAME(cx, argc, vp, "get constructing", args, thisobj, fp);
|
||||
args.rval().setBoolean(fp->isFunctionFrame() && fp->isConstructing());
|
||||
THIS_FRAME(cx, argc, vp, "get constructing", args, thisobj, iter);
|
||||
args.rval().setBoolean(iter.isFunctionFrame() && iter.isConstructing());
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
DebuggerFrame_getThis(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_FRAME(cx, argc, vp, "get this", args, thisobj, fp);
|
||||
THIS_FRAME(cx, argc, vp, "get this", args, thisobj, iter);
|
||||
RootedValue thisv(cx);
|
||||
{
|
||||
AutoCompartment ac(cx, fp->scopeChain());
|
||||
if (!ComputeThis(cx, fp))
|
||||
AutoCompartment ac(cx, iter.scopeChain());
|
||||
if (!iter.computeThis())
|
||||
return false;
|
||||
thisv = fp->thisValue();
|
||||
thisv = iter.thisv();
|
||||
}
|
||||
if (!Debugger::fromChildJSObject(thisobj)->wrapDebuggeeValue(cx, &thisv))
|
||||
return false;
|
||||
|
@ -3384,11 +3415,14 @@ DebuggerFrame_getThis(JSContext *cx, unsigned argc, Value *vp)
|
|||
static JSBool
|
||||
DebuggerFrame_getOlder(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_FRAME(cx, argc, vp, "get this", args, thisobj, thisfp);
|
||||
THIS_FRAME(cx, argc, vp, "get this", args, thisobj, iter);
|
||||
Debugger *dbg = Debugger::fromChildJSObject(thisobj);
|
||||
for (StackFrame *fp = thisfp->prev(); fp; fp = fp->prev()) {
|
||||
if (dbg->observesFrame(fp))
|
||||
return dbg->getScriptFrame(cx, fp, vp);
|
||||
|
||||
for (++iter; !iter.done(); ++iter) {
|
||||
if (iter.isIon())
|
||||
continue;
|
||||
if (dbg->observesFrame(iter.taggedFramePtr()))
|
||||
return dbg->getScriptFrame(cx, iter, vp);
|
||||
}
|
||||
args.rval().setNull();
|
||||
return true;
|
||||
|
@ -3425,7 +3459,7 @@ DebuggerArguments_getArg(JSContext *cx, unsigned argc, Value *vp)
|
|||
* to check that it is still live and get the fp.
|
||||
*/
|
||||
args.setThis(argsobj->getReservedSlot(JSSLOT_DEBUGARGUMENTS_FRAME));
|
||||
THIS_FRAME(cx, argc, vp, "get argument", ca2, thisobj, fp);
|
||||
THIS_FRAME(cx, argc, vp, "get argument", ca2, thisobj, iter);
|
||||
|
||||
/*
|
||||
* Since getters can be extracted and applied to other objects,
|
||||
|
@ -3434,19 +3468,19 @@ DebuggerArguments_getArg(JSContext *cx, unsigned argc, Value *vp)
|
|||
JS_ASSERT(i >= 0);
|
||||
RootedValue arg(cx);
|
||||
RootedScript script(cx);
|
||||
if (unsigned(i) < fp->numActualArgs()) {
|
||||
script = fp->script();
|
||||
if (unsigned(i) < fp->numFormalArgs() && script->formalIsAliased(i)) {
|
||||
if (unsigned(i) < iter.numActualArgs()) {
|
||||
script = iter.script();
|
||||
if (unsigned(i) < iter.numFormalArgs() && script->formalIsAliased(i)) {
|
||||
for (AliasedFormalIter fi(script); ; fi++) {
|
||||
if (fi.frameIndex() == unsigned(i)) {
|
||||
arg = fp->callObj().aliasedVar(fi);
|
||||
arg = iter.callObj().aliasedVar(fi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (script->argsObjAliasesFormals() && fp->hasArgsObj()) {
|
||||
arg = fp->argsObj().arg(i);
|
||||
} else if (script->argsObjAliasesFormals() && iter.hasArgsObj()) {
|
||||
arg = iter.argsObj().arg(i);
|
||||
} else {
|
||||
arg = fp->unaliasedActual(i, DONT_CHECK_ALIASING);
|
||||
arg = iter.unaliasedActual(i, DONT_CHECK_ALIASING);
|
||||
}
|
||||
} else {
|
||||
arg.setUndefined();
|
||||
|
@ -3461,7 +3495,7 @@ DebuggerArguments_getArg(JSContext *cx, unsigned argc, Value *vp)
|
|||
static JSBool
|
||||
DebuggerFrame_getArguments(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_FRAME(cx, argc, vp, "get arguments", args, thisobj, fp);
|
||||
THIS_FRAME(cx, argc, vp, "get arguments", args, thisobj, iter);
|
||||
Value argumentsv = thisobj->getReservedSlot(JSSLOT_DEBUGFRAME_ARGUMENTS);
|
||||
if (!argumentsv.isUndefined()) {
|
||||
JS_ASSERT(argumentsv.isObjectOrNull());
|
||||
|
@ -3470,7 +3504,7 @@ DebuggerFrame_getArguments(JSContext *cx, unsigned argc, Value *vp)
|
|||
}
|
||||
|
||||
RootedObject argsobj(cx);
|
||||
if (fp->hasArgs()) {
|
||||
if (iter.hasArgs()) {
|
||||
/* Create an arguments object. */
|
||||
Rooted<GlobalObject*> global(cx);
|
||||
global = &args.callee().global();
|
||||
|
@ -3482,8 +3516,8 @@ DebuggerFrame_getArguments(JSContext *cx, unsigned argc, Value *vp)
|
|||
return false;
|
||||
SetReservedSlot(argsobj, JSSLOT_DEBUGARGUMENTS_FRAME, ObjectValue(*thisobj));
|
||||
|
||||
JS_ASSERT(fp->numActualArgs() <= 0x7fffffff);
|
||||
unsigned fargc = fp->numActualArgs();
|
||||
JS_ASSERT(iter.numActualArgs() <= 0x7fffffff);
|
||||
unsigned fargc = iter.numActualArgs();
|
||||
RootedValue fargcVal(cx, Int32Value(fargc));
|
||||
if (!DefineNativeProperty(cx, argsobj, cx->names().length,
|
||||
fargcVal, NULL, NULL,
|
||||
|
@ -3522,14 +3556,14 @@ DebuggerFrame_getArguments(JSContext *cx, unsigned argc, Value *vp)
|
|||
static JSBool
|
||||
DebuggerFrame_getScript(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_FRAME(cx, argc, vp, "get script", args, thisobj, fp);
|
||||
THIS_FRAME(cx, argc, vp, "get script", args, thisobj, iter);
|
||||
Debugger *debug = Debugger::fromChildJSObject(thisobj);
|
||||
|
||||
RootedObject scriptObject(cx);
|
||||
if (fp->isFunctionFrame() && !fp->isEvalFrame()) {
|
||||
JSFunction &callee = fp->callee();
|
||||
if (callee.isInterpreted()) {
|
||||
RootedScript script(cx, callee.nonLazyScript());
|
||||
if (iter.isFunctionFrame() && !iter.isEvalFrame()) {
|
||||
RootedFunction callee(cx, iter.callee());
|
||||
if (callee->isInterpreted()) {
|
||||
RootedScript script(cx, callee->nonLazyScript());
|
||||
scriptObject = debug->wrapScript(cx, script);
|
||||
if (!scriptObject)
|
||||
return false;
|
||||
|
@ -3539,7 +3573,7 @@ DebuggerFrame_getScript(JSContext *cx, unsigned argc, Value *vp)
|
|||
* We got eval, JS_Evaluate*, or JS_ExecuteScript non-function script
|
||||
* frames.
|
||||
*/
|
||||
RootedScript script(cx, fp->script());
|
||||
RootedScript script(cx, iter.script());
|
||||
scriptObject = debug->wrapScript(cx, script);
|
||||
if (!scriptObject)
|
||||
return false;
|
||||
|
@ -3551,10 +3585,11 @@ DebuggerFrame_getScript(JSContext *cx, unsigned argc, Value *vp)
|
|||
static JSBool
|
||||
DebuggerFrame_getOffset(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_FRAME(cx, argc, vp, "get offset", args, thisobj, fp);
|
||||
THIS_FRAME(cx, argc, vp, "get offset", args, thisobj, iter);
|
||||
AutoAssertNoGC nogc;
|
||||
UnrootedScript script = fp->script();
|
||||
jsbytecode *pc = fp->pcQuadratic(cx);
|
||||
UnrootedScript script = iter.script();
|
||||
iter.updatePcQuadratic();
|
||||
jsbytecode *pc = iter.pc();
|
||||
JS_ASSERT(script->code <= pc);
|
||||
JS_ASSERT(pc < script->code + script->length);
|
||||
size_t offset = pc - script->code;
|
||||
|
@ -3569,8 +3604,8 @@ DebuggerFrame_getLive(JSContext *cx, unsigned argc, Value *vp)
|
|||
JSObject *thisobj = CheckThisFrame(cx, args, "get live", false);
|
||||
if (!thisobj)
|
||||
return false;
|
||||
StackFrame *fp = (StackFrame *) thisobj->getPrivate();
|
||||
args.rval().setBoolean(!!fp);
|
||||
bool hasFrame = !!thisobj->getPrivate();
|
||||
args.rval().setBoolean(hasFrame);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3583,8 +3618,8 @@ IsValidHook(const Value &v)
|
|||
static JSBool
|
||||
DebuggerFrame_getOnStep(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_FRAME(cx, argc, vp, "get onStep", args, thisobj, fp);
|
||||
(void) fp; // Silence GCC warning
|
||||
THIS_FRAME(cx, argc, vp, "get onStep", args, thisobj, iter);
|
||||
(void) iter; // Silence GCC warning
|
||||
Value handler = thisobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER);
|
||||
JS_ASSERT(IsValidHook(handler));
|
||||
args.rval().set(handler);
|
||||
|
@ -3595,7 +3630,7 @@ static JSBool
|
|||
DebuggerFrame_setOnStep(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
REQUIRE_ARGC("Debugger.Frame.set onStep", 1);
|
||||
THIS_FRAME(cx, argc, vp, "set onStep", args, thisobj, fp);
|
||||
THIS_FRAME(cx, argc, vp, "set onStep", args, thisobj, iter);
|
||||
if (!IsValidHook(args[0])) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_CALLABLE_OR_UNDEFINED);
|
||||
return false;
|
||||
|
@ -3605,8 +3640,8 @@ DebuggerFrame_setOnStep(JSContext *cx, unsigned argc, Value *vp)
|
|||
int delta = !args[0].isUndefined() - !prior.isUndefined();
|
||||
if (delta != 0) {
|
||||
/* Try to adjust this frame's script single-step mode count. */
|
||||
AutoCompartment ac(cx, fp->scopeChain());
|
||||
if (!fp->script()->changeStepModeCount(cx, delta))
|
||||
AutoCompartment ac(cx, iter.scopeChain());
|
||||
if (!iter.script()->changeStepModeCount(cx, delta))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3619,8 +3654,8 @@ DebuggerFrame_setOnStep(JSContext *cx, unsigned argc, Value *vp)
|
|||
static JSBool
|
||||
DebuggerFrame_getOnPop(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_FRAME(cx, argc, vp, "get onPop", args, thisobj, fp);
|
||||
(void) fp; // Silence GCC warning
|
||||
THIS_FRAME(cx, argc, vp, "get onPop", args, thisobj, iter);
|
||||
(void) iter; // Silence GCC warning
|
||||
Value handler = thisobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER);
|
||||
JS_ASSERT(IsValidHook(handler));
|
||||
args.rval().set(handler);
|
||||
|
@ -3631,8 +3666,8 @@ static JSBool
|
|||
DebuggerFrame_setOnPop(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
REQUIRE_ARGC("Debugger.Frame.set onPop", 1);
|
||||
THIS_FRAME(cx, argc, vp, "set onPop", args, thisobj, fp);
|
||||
(void) fp; // Silence GCC warning
|
||||
THIS_FRAME(cx, argc, vp, "set onPop", args, thisobj, iter);
|
||||
(void) iter; // Silence GCC warning
|
||||
if (!IsValidHook(args[0])) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_CALLABLE_OR_UNDEFINED);
|
||||
return false;
|
||||
|
@ -3687,11 +3722,11 @@ js::EvaluateInEnv(JSContext *cx, Handle<Env*> env, HandleValue thisv, StackFrame
|
|||
static JSBool
|
||||
DebuggerGenericEval(JSContext *cx, const char *fullMethodName,
|
||||
const Value &code, Value *bindings, MutableHandleValue vp,
|
||||
Debugger *dbg, HandleObject scope, StackFrame *fp)
|
||||
Debugger *dbg, HandleObject scope, ScriptFrameIter *iter)
|
||||
{
|
||||
/* Either we're specifying the frame, or a global. */
|
||||
JS_ASSERT_IF(fp, !scope);
|
||||
JS_ASSERT_IF(!fp, scope && scope->isGlobal());
|
||||
JS_ASSERT_IF(iter, !scope);
|
||||
JS_ASSERT_IF(!iter, scope && scope->isGlobal());
|
||||
|
||||
/* Check the first argument, the eval code string. */
|
||||
if (!code.isString()) {
|
||||
|
@ -3730,19 +3765,19 @@ DebuggerGenericEval(JSContext *cx, const char *fullMethodName,
|
|||
}
|
||||
|
||||
Maybe<AutoCompartment> ac;
|
||||
if (fp)
|
||||
ac.construct(cx, fp->scopeChain());
|
||||
if (iter)
|
||||
ac.construct(cx, iter->scopeChain());
|
||||
else
|
||||
ac.construct(cx, scope);
|
||||
|
||||
RootedValue thisv(cx);
|
||||
Rooted<Env *> env(cx);
|
||||
if (fp) {
|
||||
if (iter) {
|
||||
/* ExecuteInEnv requires 'fp' to have a computed 'this" value. */
|
||||
if (!ComputeThis(cx, fp))
|
||||
if (!iter->computeThis())
|
||||
return false;
|
||||
thisv = fp->thisValue();
|
||||
env = GetDebugScopeForFrame(cx, fp);
|
||||
thisv = iter->thisv();
|
||||
env = GetDebugScopeForFrame(cx, iter->interpFrame());
|
||||
if (!env)
|
||||
return false;
|
||||
} else {
|
||||
|
@ -3771,6 +3806,7 @@ DebuggerGenericEval(JSContext *cx, const char *fullMethodName,
|
|||
/* Run the code and produce the completion value. */
|
||||
Value rval;
|
||||
JS::Anchor<JSString *> anchor(stable);
|
||||
StackFrame *fp = iter ? iter->interpFrame() : NULL;
|
||||
bool ok = EvaluateInEnv(cx, env, thisv, fp, stable->chars(), stable->length(),
|
||||
"debugger eval code", 1, &rval);
|
||||
return dbg->receiveCompletionValue(ac, ok, rval, vp);
|
||||
|
@ -3779,21 +3815,21 @@ DebuggerGenericEval(JSContext *cx, const char *fullMethodName,
|
|||
static JSBool
|
||||
DebuggerFrame_eval(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_FRAME(cx, argc, vp, "eval", args, thisobj, fp);
|
||||
THIS_FRAME(cx, argc, vp, "eval", args, thisobj, iter);
|
||||
REQUIRE_ARGC("Debugger.Frame.prototype.eval", 1);
|
||||
Debugger *dbg = Debugger::fromChildJSObject(thisobj);
|
||||
return DebuggerGenericEval(cx, "Debugger.Frame.prototype.eval",
|
||||
args[0], NULL, args.rval(), dbg, NullPtr(), fp);
|
||||
args[0], NULL, args.rval(), dbg, NullPtr(), &iter);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
DebuggerFrame_evalWithBindings(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_FRAME(cx, argc, vp, "evalWithBindings", args, thisobj, fp);
|
||||
THIS_FRAME(cx, argc, vp, "evalWithBindings", args, thisobj, iter);
|
||||
REQUIRE_ARGC("Debugger.Frame.prototype.evalWithBindings", 2);
|
||||
Debugger *dbg = Debugger::fromChildJSObject(thisobj);
|
||||
return DebuggerGenericEval(cx, "Debugger.Frame.prototype.evalWithBindings",
|
||||
args[0], &args[1], args.rval(), dbg, NullPtr(), fp);
|
||||
args[0], &args[1], args.rval(), dbg, NullPtr(), &iter);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
|
|
@ -204,9 +204,9 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||
* that way, but since stack frames are not gc-things, the implementation
|
||||
* has to be different.
|
||||
*/
|
||||
typedef HashMap<StackFrame *,
|
||||
typedef HashMap<TaggedFramePtr,
|
||||
RelocatablePtrObject,
|
||||
DefaultHasher<StackFrame *>,
|
||||
DefaultHasher<TaggedFramePtr>,
|
||||
RuntimeAllocPolicy> FrameMap;
|
||||
FrameMap frames;
|
||||
|
||||
|
@ -403,7 +403,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||
inline bool observesNewScript() const;
|
||||
inline bool observesNewGlobalObject() const;
|
||||
inline bool observesGlobal(GlobalObject *global) const;
|
||||
inline bool observesFrame(StackFrame *fp) const;
|
||||
inline bool observesFrame(TaggedFramePtr frame) const;
|
||||
bool observesScript(JSScript *script) const;
|
||||
|
||||
/*
|
||||
|
@ -453,8 +453,8 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||
*/
|
||||
bool unwrapDebuggeeValue(JSContext *cx, MutableHandleValue vp);
|
||||
|
||||
/* Store the Debugger.Frame object for the frame fp in *vp. */
|
||||
bool getScriptFrame(JSContext *cx, StackFrame *fp, Value *vp);
|
||||
/* Store the Debugger.Frame object for iter in *vp. */
|
||||
bool getScriptFrame(JSContext *cx, const ScriptFrameIter &iter, Value *vp);
|
||||
|
||||
/*
|
||||
* Set |*status| and |*value| to a (JSTrapStatus, Value) pair reflecting a
|
||||
|
@ -633,9 +633,9 @@ Debugger::observesGlobal(GlobalObject *global) const
|
|||
}
|
||||
|
||||
bool
|
||||
Debugger::observesFrame(StackFrame *fp) const
|
||||
Debugger::observesFrame(TaggedFramePtr frame) const
|
||||
{
|
||||
return observesGlobal(&fp->global());
|
||||
return observesGlobal(&frame.script()->global());
|
||||
}
|
||||
|
||||
JSTrapStatus
|
||||
|
|
|
@ -940,7 +940,7 @@ ContextStack::ensureOnTop(JSContext *cx, MaybeReportError report, unsigned nvars
|
|||
calls = NULL;
|
||||
}
|
||||
|
||||
seg_ = new(firstUnused) StackSegment(seg_, space().seg_, regs, calls);
|
||||
seg_ = new(firstUnused) StackSegment(cx, seg_, space().seg_, regs, calls);
|
||||
space().seg_ = seg_;
|
||||
*pushedSeg = true;
|
||||
return seg_->slotsBegin();
|
||||
|
@ -1072,7 +1072,7 @@ ContextStack::pushExecuteFrame(JSContext *cx, JSScript *script, const Value &thi
|
|||
++iter;
|
||||
JS_ASSERT_IF(evalInFrame->compartment() == iter.compartment(), !iter.isIon());
|
||||
}
|
||||
evalInFrameCalls = iter.calls_;
|
||||
evalInFrameCalls = iter.data_.calls_;
|
||||
extend = CANT_EXTEND;
|
||||
} else {
|
||||
extend = CAN_EXTEND;
|
||||
|
@ -1246,23 +1246,21 @@ ContextStack::restoreFrameChain()
|
|||
void
|
||||
StackIter::poisonRegs()
|
||||
{
|
||||
pc_ = (jsbytecode *)0xbad;
|
||||
script_ = (RawScript)0xbad;
|
||||
data_.pc_ = (jsbytecode *)0xbad;
|
||||
}
|
||||
|
||||
void
|
||||
StackIter::popFrame()
|
||||
{
|
||||
AutoAssertNoGC nogc;
|
||||
StackFrame *oldfp = fp_;
|
||||
JS_ASSERT(seg_->contains(oldfp));
|
||||
fp_ = fp_->prev();
|
||||
StackFrame *oldfp = data_.fp_;
|
||||
JS_ASSERT(data_.seg_->contains(oldfp));
|
||||
data_.fp_ = data_.fp_->prev();
|
||||
|
||||
if (seg_->contains(fp_)) {
|
||||
if (data_.seg_->contains(data_.fp_)) {
|
||||
InlinedSite *inline_;
|
||||
pc_ = oldfp->prevpc(&inline_);
|
||||
data_.pc_ = oldfp->prevpc(&inline_);
|
||||
JS_ASSERT(!inline_);
|
||||
script_ = fp_->script();
|
||||
} else {
|
||||
poisonRegs();
|
||||
}
|
||||
|
@ -1271,10 +1269,10 @@ StackIter::popFrame()
|
|||
void
|
||||
StackIter::popCall()
|
||||
{
|
||||
DebugOnly<CallArgsList*> oldCall = calls_;
|
||||
JS_ASSERT(seg_->contains(oldCall));
|
||||
calls_ = calls_->prev();
|
||||
if (!seg_->contains(fp_))
|
||||
DebugOnly<CallArgsList*> oldCall = data_.calls_;
|
||||
JS_ASSERT(data_.seg_->contains(oldCall));
|
||||
data_.calls_ = data_.calls_->prev();
|
||||
if (!data_.seg_->contains(data_.fp_))
|
||||
poisonRegs();
|
||||
}
|
||||
|
||||
|
@ -1282,21 +1280,18 @@ void
|
|||
StackIter::settleOnNewSegment()
|
||||
{
|
||||
AutoAssertNoGC nogc;
|
||||
if (FrameRegs *regs = seg_->maybeRegs()) {
|
||||
pc_ = regs->pc;
|
||||
if (fp_)
|
||||
script_ = fp_->script();
|
||||
} else {
|
||||
if (FrameRegs *regs = data_.seg_->maybeRegs())
|
||||
data_.pc_ = regs->pc;
|
||||
else
|
||||
poisonRegs();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StackIter::startOnSegment(StackSegment *seg)
|
||||
{
|
||||
seg_ = seg;
|
||||
fp_ = seg_->maybefp();
|
||||
calls_ = seg_->maybeCalls();
|
||||
data_.seg_ = seg;
|
||||
data_.fp_ = data_.seg_->maybefp();
|
||||
data_.calls_ = data_.seg_->maybeCalls();
|
||||
settleOnNewSegment();
|
||||
}
|
||||
|
||||
|
@ -1325,45 +1320,47 @@ StackIter::settleOnNewState()
|
|||
AutoAssertNoGC nogc;
|
||||
|
||||
/* Reset whether or we popped a call last time we settled. */
|
||||
poppedCallDuringSettle_ = false;
|
||||
data_.poppedCallDuringSettle_ = false;
|
||||
|
||||
/*
|
||||
* There are elements of the calls_ and fp_ chains that we want to skip
|
||||
* over so iterate until we settle on one or until there are no more.
|
||||
*/
|
||||
while (true) {
|
||||
if (!fp_ && !calls_) {
|
||||
if (savedOption_ == GO_THROUGH_SAVED && seg_->prevInContext()) {
|
||||
startOnSegment(seg_->prevInContext());
|
||||
if (!data_.fp_ && !data_.calls_) {
|
||||
if (data_.savedOption_ == GO_THROUGH_SAVED && data_.seg_->prevInContext()) {
|
||||
startOnSegment(data_.seg_->prevInContext());
|
||||
continue;
|
||||
}
|
||||
state_ = DONE;
|
||||
data_.state_ = DONE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if popFrame/popCall changed segment. */
|
||||
bool containsFrame = seg_->contains(fp_);
|
||||
bool containsCall = seg_->contains(calls_);
|
||||
bool containsFrame = data_.seg_->contains(data_.fp_);
|
||||
bool containsCall = data_.seg_->contains(data_.calls_);
|
||||
while (!containsFrame && !containsCall) {
|
||||
/* Eval-in-frame can cross contexts, so use prevInMemory. */
|
||||
seg_ = seg_->prevInMemory();
|
||||
containsFrame = seg_->contains(fp_);
|
||||
containsCall = seg_->contains(calls_);
|
||||
data_.seg_ = data_.seg_->prevInMemory();
|
||||
containsFrame = data_.seg_->contains(data_.fp_);
|
||||
containsCall = data_.seg_->contains(data_.calls_);
|
||||
|
||||
/* Eval-in-frame allows jumping into the middle of a segment. */
|
||||
if (containsFrame && seg_->fp() != fp_) {
|
||||
if (containsFrame && data_.seg_->fp() != data_.fp_) {
|
||||
/* Avoid duplicating logic; seg_ contains fp_, so no iloop. */
|
||||
StackIter tmp = *this;
|
||||
tmp.startOnSegment(seg_);
|
||||
while (!tmp.isScript() || tmp.fp_ != fp_)
|
||||
tmp.startOnSegment(data_.seg_);
|
||||
while (!tmp.isScript() || tmp.data_.fp_ != data_.fp_)
|
||||
++tmp;
|
||||
JS_ASSERT(tmp.isScript() && tmp.seg_ == seg_ && tmp.fp_ == fp_);
|
||||
JS_ASSERT(tmp.isScript() &&
|
||||
tmp.data_.seg_ == data_.seg_ &&
|
||||
tmp.data_.fp_ == data_.fp_);
|
||||
*this = tmp;
|
||||
return;
|
||||
}
|
||||
|
||||
/* There is no eval-in-frame equivalent for native calls. */
|
||||
JS_ASSERT_IF(containsCall, &seg_->calls() == calls_);
|
||||
JS_ASSERT_IF(containsCall, &data_.seg_->calls() == data_.calls_);
|
||||
|
||||
settleOnNewSegment();
|
||||
}
|
||||
|
@ -1372,37 +1369,34 @@ StackIter::settleOnNewState()
|
|||
* In case of both a scripted frame and call record, use linear memory
|
||||
* ordering to decide which was the most recent.
|
||||
*/
|
||||
if (containsFrame && (!containsCall || (Value *)fp_ >= calls_->array())) {
|
||||
if (containsFrame && (!containsCall || (Value *)data_.fp_ >= data_.calls_->array())) {
|
||||
#ifdef JS_ION
|
||||
if (fp_->beginsIonActivation()) {
|
||||
ionFrames_ = ion::IonFrameIterator(ionActivations_);
|
||||
if (data_.fp_->beginsIonActivation()) {
|
||||
data_.ionFrames_ = ion::IonFrameIterator(data_.ionActivations_);
|
||||
|
||||
if (ionFrames_.isNative()) {
|
||||
state_ = ION;
|
||||
if (data_.ionFrames_.isNative()) {
|
||||
data_.state_ = ION;
|
||||
return;
|
||||
}
|
||||
|
||||
while (!ionFrames_.isScripted() && !ionFrames_.done())
|
||||
++ionFrames_;
|
||||
while (!data_.ionFrames_.isScripted() && !data_.ionFrames_.done())
|
||||
++data_.ionFrames_;
|
||||
|
||||
// When invoked from JM, we don't re-use the entryfp, so we
|
||||
// may have an empty Ion activation.
|
||||
if (ionFrames_.done()) {
|
||||
state_ = SCRIPTED;
|
||||
script_ = fp_->script();
|
||||
if (data_.ionFrames_.done()) {
|
||||
data_.state_ = SCRIPTED;
|
||||
return;
|
||||
}
|
||||
|
||||
state_ = ION;
|
||||
ionInlineFrames_ = ion::InlineFrameIterator(&ionFrames_);
|
||||
pc_ = ionInlineFrames_.pc();
|
||||
script_ = ionInlineFrames_.script();
|
||||
data_.state_ = ION;
|
||||
ionInlineFrames_ = ion::InlineFrameIterator(&data_.ionFrames_);
|
||||
data_.pc_ = ionInlineFrames_.pc();
|
||||
return;
|
||||
}
|
||||
#endif /* JS_ION */
|
||||
|
||||
state_ = SCRIPTED;
|
||||
script_ = fp_->script();
|
||||
data_.state_ = SCRIPTED;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1416,28 +1410,64 @@ StackIter::settleOnNewState()
|
|||
* necessarily clobbers the callee, "active" is also necessary to
|
||||
* ensure that the callee slot is valid.)
|
||||
*/
|
||||
if (calls_->active() && IsNativeFunction(calls_->calleev())) {
|
||||
state_ = NATIVE;
|
||||
args_ = *calls_;
|
||||
if (data_.calls_->active() && IsNativeFunction(data_.calls_->calleev())) {
|
||||
data_.state_ = NATIVE;
|
||||
data_.args_ = *data_.calls_;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Pop the call and keep looking. */
|
||||
popCall();
|
||||
poppedCallDuringSettle_ = true;
|
||||
data_.poppedCallDuringSettle_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
StackIter::StackIter(JSContext *cx, SavedOption savedOption)
|
||||
: perThread_(&cx->runtime->mainThread),
|
||||
StackIter::Data::Data(JSContext *cx, PerThreadData *perThread, SavedOption savedOption)
|
||||
: perThread_(perThread),
|
||||
maybecx_(cx),
|
||||
savedOption_(savedOption),
|
||||
script_(cx, NULL),
|
||||
poppedCallDuringSettle_(false)
|
||||
#ifdef JS_ION
|
||||
, ionActivations_(cx),
|
||||
ionFrames_((uint8_t *)NULL),
|
||||
ionInlineFrames_((js::ion::IonFrameIterator*) NULL)
|
||||
ionFrames_((uint8_t *)NULL)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
StackIter::Data::Data(JSRuntime *rt, StackSegment *seg)
|
||||
: perThread_(&rt->mainThread),
|
||||
maybecx_(NULL),
|
||||
savedOption_(STOP_AT_SAVED),
|
||||
poppedCallDuringSettle_(false)
|
||||
#ifdef JS_ION
|
||||
, ionActivations_(rt),
|
||||
ionFrames_((uint8_t *)NULL)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
StackIter::Data::Data(const StackIter::Data &other)
|
||||
: perThread_(other.perThread_),
|
||||
maybecx_(other.maybecx_),
|
||||
savedOption_(other.savedOption_),
|
||||
state_(other.state_),
|
||||
fp_(other.fp_),
|
||||
calls_(other.calls_),
|
||||
seg_(other.seg_),
|
||||
pc_(other.pc_),
|
||||
args_(other.args_),
|
||||
poppedCallDuringSettle_(other.poppedCallDuringSettle_)
|
||||
#ifdef JS_ION
|
||||
, ionActivations_(other.ionActivations_),
|
||||
ionFrames_(other.ionFrames_)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
StackIter::StackIter(JSContext *cx, SavedOption savedOption)
|
||||
: data_(cx, &cx->runtime->mainThread, savedOption)
|
||||
#ifdef JS_ION
|
||||
, ionInlineFrames_((js::ion::IonFrameIterator*) NULL)
|
||||
#endif
|
||||
{
|
||||
#ifdef JS_METHODJIT
|
||||
|
@ -1450,20 +1480,14 @@ StackIter::StackIter(JSContext *cx, SavedOption savedOption)
|
|||
startOnSegment(seg);
|
||||
settleOnNewState();
|
||||
} else {
|
||||
state_ = DONE;
|
||||
data_.state_ = DONE;
|
||||
}
|
||||
}
|
||||
|
||||
StackIter::StackIter(JSRuntime *rt, StackSegment &seg)
|
||||
: perThread_(&rt->mainThread),
|
||||
maybecx_(NULL),
|
||||
savedOption_(STOP_AT_SAVED),
|
||||
script_(rt, NULL),
|
||||
poppedCallDuringSettle_(false)
|
||||
: data_(rt, &seg)
|
||||
#ifdef JS_ION
|
||||
, ionActivations_(rt),
|
||||
ionFrames_((uint8_t *)NULL),
|
||||
ionInlineFrames_((js::ion::IonFrameIterator*) NULL)
|
||||
, ionInlineFrames_((js::ion::IonFrameIterator*) NULL)
|
||||
#endif
|
||||
{
|
||||
#ifdef JS_METHODJIT
|
||||
|
@ -1476,21 +1500,17 @@ StackIter::StackIter(JSRuntime *rt, StackSegment &seg)
|
|||
}
|
||||
|
||||
StackIter::StackIter(const StackIter &other)
|
||||
: perThread_(other.perThread_),
|
||||
maybecx_(other.maybecx_),
|
||||
savedOption_(other.savedOption_),
|
||||
state_(other.state_),
|
||||
fp_(other.fp_),
|
||||
calls_(other.calls_),
|
||||
seg_(other.seg_),
|
||||
pc_(other.pc_),
|
||||
script_(perThread_, other.script_),
|
||||
args_(other.args_),
|
||||
poppedCallDuringSettle_(other.poppedCallDuringSettle_)
|
||||
: data_(other.data_)
|
||||
#ifdef JS_ION
|
||||
, ionActivations_(other.ionActivations_),
|
||||
ionFrames_(other.ionFrames_),
|
||||
ionInlineFrames_(other.ionInlineFrames_)
|
||||
, ionInlineFrames_(other.ionInlineFrames_)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
StackIter::StackIter(const Data &data)
|
||||
: data_(data)
|
||||
#ifdef JS_ION
|
||||
, ionInlineFrames_(data_.ionFrames_.isScripted() ? &data_.ionFrames_ : NULL)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
@ -1502,43 +1522,40 @@ StackIter::popIonFrame()
|
|||
AutoAssertNoGC nogc;
|
||||
// Keep fp which describes all ion frames.
|
||||
poisonRegs();
|
||||
if (ionFrames_.isScripted() && ionInlineFrames_.more()) {
|
||||
if (data_.ionFrames_.isScripted() && ionInlineFrames_.more()) {
|
||||
++ionInlineFrames_;
|
||||
pc_ = ionInlineFrames_.pc();
|
||||
script_ = ionInlineFrames_.script();
|
||||
data_.pc_ = ionInlineFrames_.pc();
|
||||
} else {
|
||||
++ionFrames_;
|
||||
while (!ionFrames_.done() && !ionFrames_.isScripted())
|
||||
++ionFrames_;
|
||||
++data_.ionFrames_;
|
||||
while (!data_.ionFrames_.done() && !data_.ionFrames_.isScripted())
|
||||
++data_.ionFrames_;
|
||||
|
||||
if (!ionFrames_.done()) {
|
||||
ionInlineFrames_ = ion::InlineFrameIterator(&ionFrames_);
|
||||
pc_ = ionInlineFrames_.pc();
|
||||
script_ = ionInlineFrames_.script();
|
||||
if (!data_.ionFrames_.done()) {
|
||||
ionInlineFrames_ = ion::InlineFrameIterator(&data_.ionFrames_);
|
||||
data_.pc_ = ionInlineFrames_.pc();
|
||||
return;
|
||||
}
|
||||
|
||||
// The activation has no other frames. If entryfp is NULL, it was invoked
|
||||
// by a native written in C++, using FastInvoke, on top of another activation.
|
||||
ion::IonActivation *activation = ionActivations_.activation();
|
||||
ion::IonActivation *activation = data_.ionActivations_.activation();
|
||||
if (!activation->entryfp()) {
|
||||
JS_ASSERT(activation->prevpc());
|
||||
JS_ASSERT(fp_->beginsIonActivation());
|
||||
++ionActivations_;
|
||||
JS_ASSERT(data_.fp_->beginsIonActivation());
|
||||
++data_.ionActivations_;
|
||||
settleOnNewState();
|
||||
return;
|
||||
}
|
||||
|
||||
if (fp_->runningInIon()) {
|
||||
++ionActivations_;
|
||||
if (data_.fp_->runningInIon()) {
|
||||
++data_.ionActivations_;
|
||||
popFrame();
|
||||
settleOnNewState();
|
||||
} else {
|
||||
JS_ASSERT(fp_->callingIntoIon());
|
||||
state_ = SCRIPTED;
|
||||
script_ = fp_->script();
|
||||
pc_ = ionActivations_.activation()->prevpc();
|
||||
++ionActivations_;
|
||||
JS_ASSERT(data_.fp_->callingIntoIon());
|
||||
data_.state_ = SCRIPTED;
|
||||
data_.pc_ = data_.ionActivations_.activation()->prevpc();
|
||||
++data_.ionActivations_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1547,7 +1564,7 @@ StackIter::popIonFrame()
|
|||
StackIter &
|
||||
StackIter::operator++()
|
||||
{
|
||||
switch (state_) {
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
JS_NOT_REACHED("Unexpected state");
|
||||
case SCRIPTED:
|
||||
|
@ -1575,26 +1592,39 @@ StackIter::operator==(const StackIter &rhs) const
|
|||
return done() == rhs.done() &&
|
||||
(done() ||
|
||||
(isScript() == rhs.isScript() &&
|
||||
((isScript() && fp_ == rhs.fp_) ||
|
||||
((isScript() && data_.fp_ == rhs.data_.fp_) ||
|
||||
(!isScript() && nativeArgs().base() == rhs.nativeArgs().base()))));
|
||||
}
|
||||
|
||||
StackIter::Data *
|
||||
StackIter::copyData() const
|
||||
{
|
||||
#ifdef JS_ION
|
||||
/*
|
||||
* This doesn't work for optimized Ion frames since ionInlineFrames_ is
|
||||
* not copied.
|
||||
*/
|
||||
JS_ASSERT(data_.ionFrames_.type() != ion::IonFrame_OptimizedJS);
|
||||
#endif
|
||||
return data_.maybecx_->new_<Data>(data_);
|
||||
}
|
||||
|
||||
JSCompartment *
|
||||
StackIter::compartment() const
|
||||
{
|
||||
switch (state_) {
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case SCRIPTED:
|
||||
return fp_->compartment();
|
||||
return data_.fp_->compartment();
|
||||
case ION:
|
||||
#ifdef JS_ION
|
||||
return ionActivations_.activation()->compartment();
|
||||
return data_.ionActivations_.activation()->compartment();
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
case NATIVE:
|
||||
return calls_->callee().compartment();
|
||||
return data_.calls_->callee().compartment();
|
||||
}
|
||||
JS_NOT_REACHED("Unexpected state");
|
||||
return NULL;
|
||||
|
@ -1603,7 +1633,7 @@ StackIter::compartment() const
|
|||
bool
|
||||
StackIter::isFunctionFrame() const
|
||||
{
|
||||
switch (state_) {
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case SCRIPTED:
|
||||
|
@ -1621,10 +1651,28 @@ StackIter::isFunctionFrame() const
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
StackIter::isGlobalFrame() const
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case SCRIPTED:
|
||||
return interpFrame()->isGlobalFrame();
|
||||
case ION:
|
||||
JS_ASSERT(!script()->isForEval());
|
||||
return !script()->function();
|
||||
case NATIVE:
|
||||
return false;
|
||||
}
|
||||
JS_NOT_REACHED("Unexpected state");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
StackIter::isEvalFrame() const
|
||||
{
|
||||
switch (state_) {
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case SCRIPTED:
|
||||
|
@ -1641,7 +1689,7 @@ bool
|
|||
StackIter::isNonEvalFunctionFrame() const
|
||||
{
|
||||
JS_ASSERT(!done());
|
||||
switch (state_) {
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case SCRIPTED:
|
||||
|
@ -1654,10 +1702,26 @@ StackIter::isNonEvalFunctionFrame() const
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
StackIter::isGeneratorFrame() const
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case SCRIPTED:
|
||||
return interpFrame()->isGeneratorFrame();
|
||||
case ION:
|
||||
case NATIVE:
|
||||
return false;
|
||||
}
|
||||
JS_NOT_REACHED("Unexpected state");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
StackIter::isConstructing() const
|
||||
{
|
||||
switch (state_) {
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case ION:
|
||||
|
@ -1668,16 +1732,51 @@ StackIter::isConstructing() const
|
|||
#endif
|
||||
case SCRIPTED:
|
||||
case NATIVE:
|
||||
return fp_->isConstructing();
|
||||
return interpFrame()->isConstructing();
|
||||
}
|
||||
JS_NOT_REACHED("Unexpected state");
|
||||
return false;
|
||||
}
|
||||
|
||||
TaggedFramePtr
|
||||
StackIter::taggedFramePtr() const
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case ION:
|
||||
break;
|
||||
case SCRIPTED:
|
||||
JS_ASSERT(interpFrame());
|
||||
return TaggedFramePtr(interpFrame());
|
||||
case NATIVE:
|
||||
break;
|
||||
}
|
||||
JS_NOT_REACHED("Unexpected state");
|
||||
return TaggedFramePtr();
|
||||
}
|
||||
|
||||
void
|
||||
StackIter::updatePcQuadratic()
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case SCRIPTED:
|
||||
data_.pc_ = interpFrame()->pcQuadratic(data_.maybecx_);
|
||||
return;
|
||||
case ION:
|
||||
break;
|
||||
case NATIVE:
|
||||
break;
|
||||
}
|
||||
JS_NOT_REACHED("Unexpected state");
|
||||
}
|
||||
|
||||
JSFunction *
|
||||
StackIter::callee() const
|
||||
{
|
||||
switch (state_) {
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case SCRIPTED:
|
||||
|
@ -1685,10 +1784,10 @@ StackIter::callee() const
|
|||
return &interpFrame()->callee();
|
||||
case ION:
|
||||
#ifdef JS_ION
|
||||
if (ionFrames_.isScripted())
|
||||
if (data_.ionFrames_.isScripted())
|
||||
return ionInlineFrames_.callee();
|
||||
JS_ASSERT(ionFrames_.isNative());
|
||||
return ionFrames_.callee();
|
||||
JS_ASSERT(data_.ionFrames_.isNative());
|
||||
return data_.ionFrames_.callee();
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
|
@ -1702,7 +1801,7 @@ StackIter::callee() const
|
|||
Value
|
||||
StackIter::calleev() const
|
||||
{
|
||||
switch (state_) {
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case SCRIPTED:
|
||||
|
@ -1724,7 +1823,7 @@ StackIter::calleev() const
|
|||
unsigned
|
||||
StackIter::numActualArgs() const
|
||||
{
|
||||
switch (state_) {
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case SCRIPTED:
|
||||
|
@ -1743,10 +1842,27 @@ StackIter::numActualArgs() const
|
|||
return 0;
|
||||
}
|
||||
|
||||
Value
|
||||
StackIter::unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing) const
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case SCRIPTED:
|
||||
return interpFrame()->unaliasedActual(i, checkAliasing);
|
||||
case ION:
|
||||
break;
|
||||
case NATIVE:
|
||||
break;
|
||||
}
|
||||
JS_NOT_REACHED("Unexpected state");
|
||||
return NullValue();
|
||||
}
|
||||
|
||||
JSObject *
|
||||
StackIter::scopeChain() const
|
||||
{
|
||||
switch (state_) {
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case ION:
|
||||
|
@ -1764,12 +1880,59 @@ StackIter::scopeChain() const
|
|||
return NULL;
|
||||
}
|
||||
|
||||
CallObject &
|
||||
StackIter::callObj() const
|
||||
{
|
||||
JS_ASSERT(callee()->isHeavyweight());
|
||||
|
||||
JSObject *pobj = scopeChain();
|
||||
while (!pobj->isCall())
|
||||
pobj = pobj->enclosingScope();
|
||||
return pobj->asCall();
|
||||
}
|
||||
|
||||
bool
|
||||
StackIter::hasArgsObj() const
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case ION:
|
||||
break;
|
||||
case SCRIPTED:
|
||||
return interpFrame()->hasArgsObj();
|
||||
case NATIVE:
|
||||
break;
|
||||
}
|
||||
JS_NOT_REACHED("Unexpected state");
|
||||
return false;
|
||||
}
|
||||
|
||||
ArgumentsObject &
|
||||
StackIter::argsObj() const
|
||||
{
|
||||
JS_ASSERT(hasArgsObj());
|
||||
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case ION:
|
||||
break;
|
||||
case SCRIPTED:
|
||||
return interpFrame()->argsObj();
|
||||
case NATIVE:
|
||||
break;
|
||||
}
|
||||
JS_NOT_REACHED("Unexpected state");
|
||||
return interpFrame()->argsObj();
|
||||
}
|
||||
|
||||
bool
|
||||
StackIter::computeThis() const
|
||||
{
|
||||
if (isScript() && !isIon()) {
|
||||
JS_ASSERT(maybecx_);
|
||||
return ComputeThis(maybecx_, interpFrame());
|
||||
JS_ASSERT(data_.maybecx_);
|
||||
return ComputeThis(data_.maybecx_, interpFrame());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1777,7 +1940,7 @@ StackIter::computeThis() const
|
|||
Value
|
||||
StackIter::thisv() const
|
||||
{
|
||||
switch (state_) {
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case ION:
|
||||
|
@ -1788,17 +1951,51 @@ StackIter::thisv() const
|
|||
#endif
|
||||
case SCRIPTED:
|
||||
case NATIVE:
|
||||
return fp_->thisValue();
|
||||
return interpFrame()->thisValue();
|
||||
}
|
||||
JS_NOT_REACHED("Unexpected state");
|
||||
return NullValue();
|
||||
}
|
||||
|
||||
Value
|
||||
StackIter::returnValue() const
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case ION:
|
||||
break;
|
||||
case SCRIPTED:
|
||||
return interpFrame()->returnValue();
|
||||
case NATIVE:
|
||||
break;
|
||||
}
|
||||
JS_NOT_REACHED("Unexpected state");
|
||||
return NullValue();
|
||||
}
|
||||
|
||||
void
|
||||
StackIter::setReturnValue(const Value &v)
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case ION:
|
||||
break;
|
||||
case SCRIPTED:
|
||||
interpFrame()->setReturnValue(v);
|
||||
return;
|
||||
case NATIVE:
|
||||
break;
|
||||
}
|
||||
JS_NOT_REACHED("Unexpected state");
|
||||
}
|
||||
|
||||
size_t
|
||||
StackIter::numFrameSlots() const
|
||||
{
|
||||
AutoAssertNoGC nogc;
|
||||
switch (state_) {
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
case NATIVE:
|
||||
break;
|
||||
|
@ -1809,9 +2006,9 @@ StackIter::numFrameSlots() const
|
|||
break;
|
||||
#endif
|
||||
case SCRIPTED:
|
||||
JS_ASSERT(maybecx_);
|
||||
JS_ASSERT(maybecx_->regs().spForStackDepth(0) == interpFrame()->base());
|
||||
return maybecx_->regs().sp - interpFrame()->base();
|
||||
JS_ASSERT(data_.maybecx_);
|
||||
JS_ASSERT(data_.maybecx_->regs().spForStackDepth(0) == interpFrame()->base());
|
||||
return data_.maybecx_->regs().sp - interpFrame()->base();
|
||||
}
|
||||
JS_NOT_REACHED("Unexpected state");
|
||||
return 0;
|
||||
|
@ -1821,7 +2018,7 @@ Value
|
|||
StackIter::frameSlotValue(size_t index) const
|
||||
{
|
||||
AutoAssertNoGC nogc;
|
||||
switch (state_) {
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
case NATIVE:
|
||||
break;
|
||||
|
@ -1871,3 +2068,9 @@ AllFramesIter::settle()
|
|||
JS_ASSERT(!!seg_ == !!fp_);
|
||||
JS_ASSERT_IF(fp_, seg_->contains(fp_));
|
||||
}
|
||||
|
||||
TaggedFramePtr
|
||||
AllFramesIter::taggedFramePtr() const
|
||||
{
|
||||
return TaggedFramePtr(interpFrame());
|
||||
}
|
||||
|
|
|
@ -1225,6 +1225,8 @@ class FrameRegs
|
|||
|
||||
class StackSegment
|
||||
{
|
||||
JSContext *cx_;
|
||||
|
||||
/* Previous segment within same context stack. */
|
||||
StackSegment *const prevInContext_;
|
||||
|
||||
|
@ -1237,12 +1239,23 @@ class StackSegment
|
|||
/* Call args for most recent native call in this segment (or null). */
|
||||
CallArgsList *calls_;
|
||||
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
/*
|
||||
* Ensure StackSegment is Value-aligned. Protected to silence Clang warning
|
||||
* about unused private fields.
|
||||
*/
|
||||
protected:
|
||||
uint32_t padding_;
|
||||
#endif
|
||||
|
||||
public:
|
||||
StackSegment(StackSegment *prevInContext,
|
||||
StackSegment(JSContext *cx,
|
||||
StackSegment *prevInContext,
|
||||
StackSegment *prevInMemory,
|
||||
FrameRegs *regs,
|
||||
CallArgsList *calls)
|
||||
: prevInContext_(prevInContext),
|
||||
: cx_(cx),
|
||||
prevInContext_(prevInContext),
|
||||
prevInMemory_(prevInMemory),
|
||||
regs_(regs),
|
||||
calls_(calls)
|
||||
|
@ -1294,6 +1307,10 @@ class StackSegment
|
|||
return calls_ ? calls_->array() : NULL;
|
||||
}
|
||||
|
||||
JSContext *cx() const {
|
||||
return cx_;
|
||||
}
|
||||
|
||||
StackSegment *prevInContext() const {
|
||||
return prevInContext_;
|
||||
}
|
||||
|
@ -1690,6 +1707,59 @@ class GeneratorFrameGuard : public FrameGuard
|
|||
~GeneratorFrameGuard() { if (pushed()) stack_->popGeneratorFrame(*this); }
|
||||
};
|
||||
|
||||
/* Pointer to either a StackFrame or a baseline JIT frame. */
|
||||
class TaggedFramePtr
|
||||
{
|
||||
uintptr_t ptr_;
|
||||
|
||||
bool isStackFrame() const {
|
||||
return ptr_ & 0x1;
|
||||
}
|
||||
|
||||
StackFrame *asStackFrame() const {
|
||||
JS_ASSERT(isStackFrame());
|
||||
StackFrame *res = (StackFrame *)(ptr_ & ~0x1);
|
||||
JS_ASSERT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
public:
|
||||
TaggedFramePtr()
|
||||
: ptr_(0)
|
||||
{}
|
||||
|
||||
explicit TaggedFramePtr(StackFrame *fp)
|
||||
: ptr_(uintptr_t(fp) | 0x1)
|
||||
{
|
||||
JS_ASSERT(fp);
|
||||
}
|
||||
|
||||
void *raw() const { return reinterpret_cast<void *>(ptr_); }
|
||||
|
||||
bool operator ==(const TaggedFramePtr &other) const { return ptr_ == other.ptr_; }
|
||||
bool operator !=(const TaggedFramePtr &other) const { return ptr_ != other.ptr_; }
|
||||
|
||||
JSScript *script() const {
|
||||
if (isStackFrame())
|
||||
return asStackFrame()->script();
|
||||
JS_NOT_REACHED("Invalid frame");
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DefaultHasher<TaggedFramePtr> {
|
||||
typedef TaggedFramePtr Lookup;
|
||||
|
||||
static js::HashNumber hash(const Lookup &key) {
|
||||
return size_t(key.raw());
|
||||
}
|
||||
|
||||
static bool match(const TaggedFramePtr &k, const Lookup &l) {
|
||||
return k == l;
|
||||
}
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
|
@ -1712,31 +1782,45 @@ class GeneratorFrameGuard : public FrameGuard
|
|||
*/
|
||||
class StackIter
|
||||
{
|
||||
friend class ContextStack;
|
||||
PerThreadData *perThread_;
|
||||
JSContext *maybecx_;
|
||||
public:
|
||||
enum SavedOption { STOP_AT_SAVED, GO_THROUGH_SAVED };
|
||||
private:
|
||||
SavedOption savedOption_;
|
||||
|
||||
enum State { DONE, SCRIPTED, NATIVE, ION };
|
||||
|
||||
State state_;
|
||||
/*
|
||||
* Unlike StackIter itself, StackIter::Data can be allocated on the heap,
|
||||
* so this structure should not contain any GC things.
|
||||
*/
|
||||
struct Data
|
||||
{
|
||||
PerThreadData *perThread_;
|
||||
JSContext *maybecx_;
|
||||
SavedOption savedOption_;
|
||||
|
||||
StackFrame *fp_;
|
||||
CallArgsList *calls_;
|
||||
State state_;
|
||||
|
||||
StackSegment *seg_;
|
||||
jsbytecode *pc_;
|
||||
RootedScript script_;
|
||||
CallArgs args_;
|
||||
StackFrame *fp_;
|
||||
CallArgsList *calls_;
|
||||
|
||||
bool poppedCallDuringSettle_;
|
||||
StackSegment *seg_;
|
||||
jsbytecode *pc_;
|
||||
CallArgs args_;
|
||||
|
||||
bool poppedCallDuringSettle_;
|
||||
|
||||
#ifdef JS_ION
|
||||
ion::IonActivationIterator ionActivations_;
|
||||
ion::IonFrameIterator ionFrames_;
|
||||
ion::IonActivationIterator ionActivations_;
|
||||
ion::IonFrameIterator ionFrames_;
|
||||
#endif
|
||||
|
||||
Data(JSContext *cx, PerThreadData *perThread, SavedOption savedOption);
|
||||
Data(JSRuntime *rt, StackSegment *seg);
|
||||
Data(const Data &other);
|
||||
};
|
||||
|
||||
friend class ContextStack;
|
||||
private:
|
||||
Data data_;
|
||||
#ifdef JS_ION
|
||||
ion::InlineFrameIterator ionInlineFrames_;
|
||||
#endif
|
||||
|
||||
|
@ -1754,63 +1838,92 @@ class StackIter
|
|||
StackIter(JSContext *cx, SavedOption = STOP_AT_SAVED);
|
||||
StackIter(JSRuntime *rt, StackSegment &seg);
|
||||
StackIter(const StackIter &iter);
|
||||
StackIter(const Data &data);
|
||||
|
||||
bool done() const { return state_ == DONE; }
|
||||
bool done() const { return data_.state_ == DONE; }
|
||||
StackIter &operator++();
|
||||
|
||||
Data *copyData() const;
|
||||
|
||||
bool operator==(const StackIter &rhs) const;
|
||||
bool operator!=(const StackIter &rhs) const { return !(*this == rhs); }
|
||||
|
||||
JSCompartment *compartment() const;
|
||||
|
||||
bool poppedCallDuringSettle() const { return poppedCallDuringSettle_; }
|
||||
bool poppedCallDuringSettle() const { return data_.poppedCallDuringSettle_; }
|
||||
|
||||
bool isScript() const {
|
||||
JS_ASSERT(!done());
|
||||
#ifdef JS_ION
|
||||
if (state_ == ION)
|
||||
return ionFrames_.isScripted();
|
||||
if (data_.state_ == ION)
|
||||
return data_.ionFrames_.isScripted();
|
||||
#endif
|
||||
return data_.state_ == SCRIPTED;
|
||||
}
|
||||
UnrootedScript script() const {
|
||||
JS_ASSERT(isScript());
|
||||
if (data_.state_ == SCRIPTED)
|
||||
return interpFrame()->script();
|
||||
#ifdef JS_ION
|
||||
JS_ASSERT(data_.state_ == ION);
|
||||
return ionInlineFrames_.script();
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
return state_ == SCRIPTED;
|
||||
}
|
||||
bool isIon() const {
|
||||
JS_ASSERT(!done());
|
||||
return state_ == ION;
|
||||
return data_.state_ == ION;
|
||||
}
|
||||
bool isNativeCall() const {
|
||||
JS_ASSERT(!done());
|
||||
#ifdef JS_ION
|
||||
if (state_ == ION)
|
||||
return ionFrames_.isNative();
|
||||
if (data_.state_ == ION)
|
||||
return data_.ionFrames_.isNative();
|
||||
#endif
|
||||
return state_ == NATIVE;
|
||||
return data_.state_ == NATIVE;
|
||||
}
|
||||
|
||||
bool isFunctionFrame() const;
|
||||
bool isGlobalFrame() const;
|
||||
bool isEvalFrame() const;
|
||||
bool isNonEvalFunctionFrame() const;
|
||||
bool isGeneratorFrame() const;
|
||||
bool isConstructing() const;
|
||||
|
||||
bool hasArgs() const { return isNonEvalFunctionFrame(); }
|
||||
|
||||
TaggedFramePtr taggedFramePtr() const;
|
||||
|
||||
/*
|
||||
* When entering IonMonkey, the top interpreter frame (pushed by the caller)
|
||||
* is kept on the stack as bookkeeping (with runningInIon() set). The
|
||||
* contents of the frame are ignored by Ion code (and GC) and thus
|
||||
* immediately become garbage and must not be touched directly.
|
||||
*/
|
||||
StackFrame *interpFrame() const { JS_ASSERT(isScript() && !isIon()); return fp_; }
|
||||
StackFrame *interpFrame() const { JS_ASSERT(isScript() && !isIon()); return data_.fp_; }
|
||||
|
||||
jsbytecode *pc() const { JS_ASSERT(isScript()); return pc_; }
|
||||
UnrootedScript script() const { JS_ASSERT(isScript()); return script_; }
|
||||
jsbytecode *pc() const { JS_ASSERT(isScript()); return data_.pc_; }
|
||||
void updatePcQuadratic();
|
||||
JSFunction *callee() const;
|
||||
Value calleev() const;
|
||||
unsigned numActualArgs() const;
|
||||
unsigned numFormalArgs() const { return script()->function()->nargs; }
|
||||
Value unaliasedActual(unsigned i, MaybeCheckAliasing = CHECK_ALIASING) const;
|
||||
|
||||
JSObject *scopeChain() const;
|
||||
CallObject &callObj() const;
|
||||
|
||||
bool hasArgsObj() const;
|
||||
ArgumentsObject &argsObj() const;
|
||||
|
||||
// Ensure that thisv is correct, see ComputeThis.
|
||||
bool computeThis() const;
|
||||
Value thisv() const;
|
||||
|
||||
Value returnValue() const;
|
||||
void setReturnValue(const Value &v);
|
||||
|
||||
JSFunction *maybeCallee() const {
|
||||
return isFunctionFrame() ? callee() : NULL;
|
||||
}
|
||||
|
@ -1819,7 +1932,7 @@ class StackIter
|
|||
size_t numFrameSlots() const;
|
||||
Value frameSlotValue(size_t index) const;
|
||||
|
||||
CallArgs nativeArgs() const { JS_ASSERT(isNativeCall()); return args_; }
|
||||
CallArgs nativeArgs() const { JS_ASSERT(isNativeCall()); return data_.args_; }
|
||||
|
||||
template <class Op>
|
||||
inline void ionForEachCanonicalActualArg(Op op);
|
||||
|
@ -1835,7 +1948,11 @@ class ScriptFrameIter : public StackIter
|
|||
|
||||
public:
|
||||
ScriptFrameIter(JSContext *cx, StackIter::SavedOption opt = StackIter::STOP_AT_SAVED)
|
||||
: StackIter(cx, opt) { settle(); }
|
||||
: StackIter(cx, opt) { settle(); }
|
||||
|
||||
ScriptFrameIter(const StackIter::Data &data)
|
||||
: StackIter(data)
|
||||
{}
|
||||
|
||||
ScriptFrameIter &operator++() { StackIter::operator++(); settle(); return *this; }
|
||||
};
|
||||
|
@ -1871,6 +1988,9 @@ class AllFramesIter
|
|||
|
||||
bool isIon() const { return fp_->runningInIon(); }
|
||||
StackFrame *interpFrame() const { return fp_; }
|
||||
StackSegment *seg() const { return seg_; }
|
||||
|
||||
TaggedFramePtr taggedFramePtr() const;
|
||||
|
||||
private:
|
||||
void settle();
|
||||
|
|
|
@ -683,16 +683,19 @@ public:
|
|||
~nsFrameConstructorSaveState();
|
||||
|
||||
private:
|
||||
nsAbsoluteItems* mItems; // pointer to struct whose data we save/restore
|
||||
bool* mFixedPosIsAbsPos;
|
||||
|
||||
nsAbsoluteItems mSavedItems; // copy of original data
|
||||
bool mSavedFixedPosIsAbsPos;
|
||||
nsAbsoluteItems* mItems; // pointer to struct whose data we save/restore
|
||||
nsAbsoluteItems mSavedItems; // copy of original data
|
||||
|
||||
// The name of the child list in which our frames would belong
|
||||
ChildListID mChildListID;
|
||||
nsFrameConstructorState* mState;
|
||||
|
||||
// State used only when we're saving the abs-pos state for a transformed
|
||||
// element.
|
||||
nsAbsoluteItems mSavedFixedItems;
|
||||
|
||||
bool mSavedFixedPosIsAbsPos;
|
||||
|
||||
friend class nsFrameConstructorState;
|
||||
};
|
||||
|
||||
|
@ -781,6 +784,8 @@ public:
|
|||
// Function to push the existing absolute containing block state and
|
||||
// create a new scope. Code that uses this function should get matching
|
||||
// logic in GetAbsoluteContainingBlock.
|
||||
// Also makes aNewAbsoluteContainingBlock the containing block for
|
||||
// fixed-pos elements if necessary.
|
||||
void PushAbsoluteContainingBlock(nsIFrame* aNewAbsoluteContainingBlock,
|
||||
nsFrameConstructorSaveState& aSaveState);
|
||||
|
||||
|
@ -1027,11 +1032,15 @@ nsFrameConstructorState::PushAbsoluteContainingBlock(nsIFrame* aNewAbsoluteConta
|
|||
aSaveState.mSavedItems = mAbsoluteItems;
|
||||
aSaveState.mChildListID = nsIFrame::kAbsoluteList;
|
||||
aSaveState.mState = this;
|
||||
|
||||
/* Store whether we're wiring the abs-pos and fixed-pos lists together. */
|
||||
aSaveState.mFixedPosIsAbsPos = &mFixedPosIsAbsPos;
|
||||
aSaveState.mSavedFixedPosIsAbsPos = mFixedPosIsAbsPos;
|
||||
|
||||
if (mFixedPosIsAbsPos) {
|
||||
// Since we're going to replace mAbsoluteItems, we need to save it into
|
||||
// mFixedItems now (and save the current value of mFixedItems).
|
||||
aSaveState.mSavedFixedItems = mFixedItems;
|
||||
mFixedItems = mAbsoluteItems;
|
||||
}
|
||||
|
||||
mAbsoluteItems =
|
||||
nsAbsoluteItems(AdjustAbsoluteContainingBlock(aNewAbsoluteContainingBlock));
|
||||
|
||||
|
@ -1235,7 +1244,13 @@ nsFrameConstructorState::ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
|
|||
|
||||
NS_ASSERTION(containingBlock,
|
||||
"Child list without containing block?");
|
||||
|
||||
|
||||
if (aChildListID == nsIFrame::kFixedList &&
|
||||
containingBlock->GetStyleDisplay()->HasTransform(containingBlock)) {
|
||||
// Put this frame on the transformed-frame's abs-pos list instead.
|
||||
aChildListID = nsIFrame::kAbsoluteList;
|
||||
}
|
||||
|
||||
// Insert the frames hanging out in aItems. We can use SetInitialChildList()
|
||||
// if the containing block hasn't been reflowed yet (so NS_FRAME_FIRST_REFLOW
|
||||
// is set) and doesn't have any frames in the aChildListID child list yet.
|
||||
|
@ -1299,11 +1314,11 @@ nsFrameConstructorState::ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
|
|||
|
||||
nsFrameConstructorSaveState::nsFrameConstructorSaveState()
|
||||
: mItems(nullptr),
|
||||
mFixedPosIsAbsPos(nullptr),
|
||||
mSavedItems(nullptr),
|
||||
mSavedFixedPosIsAbsPos(false),
|
||||
mChildListID(kPrincipalList),
|
||||
mState(nullptr)
|
||||
mState(nullptr),
|
||||
mSavedFixedItems(nullptr),
|
||||
mSavedFixedPosIsAbsPos(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1319,9 +1334,20 @@ nsFrameConstructorSaveState::~nsFrameConstructorSaveState()
|
|||
// Note that this only matters for the assert in ~nsAbsoluteItems.
|
||||
mSavedItems.Clear();
|
||||
#endif
|
||||
}
|
||||
if (mFixedPosIsAbsPos) {
|
||||
*mFixedPosIsAbsPos = mSavedFixedPosIsAbsPos;
|
||||
if (mItems == &mState->mAbsoluteItems) {
|
||||
mState->mFixedPosIsAbsPos = mSavedFixedPosIsAbsPos;
|
||||
if (mSavedFixedPosIsAbsPos) {
|
||||
// mAbsoluteItems was moved to mFixedItems, so move mFixedItems back
|
||||
// and repair the old mFixedItems now.
|
||||
mState->mAbsoluteItems = mState->mFixedItems;
|
||||
mState->mFixedItems = mSavedFixedItems;
|
||||
#ifdef DEBUG
|
||||
mSavedFixedItems.Clear();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
NS_ASSERTION(!mItems->LastChild() || !mItems->LastChild()->GetNextSibling(),
|
||||
"Something corrupted our list");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5613,6 +5639,21 @@ nsCSSFrameConstructor::GetAbsoluteContainingBlock(nsIFrame* aFrame)
|
|||
return mHasRootAbsPosContainingBlock ? mDocElementContainingBlock : nullptr;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsCSSFrameConstructor::GetFixedContainingBlock(nsIFrame* aFrame)
|
||||
{
|
||||
NS_PRECONDITION(nullptr != mRootElementFrame, "no root element frame");
|
||||
|
||||
// Starting with aFrame, look for a frame that is CSS-transformed
|
||||
for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
|
||||
if (frame->GetStyleDisplay()->HasTransform(frame)) {
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
|
||||
return mFixedContainingBlock;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsCSSFrameConstructor::GetFloatContainingBlock(nsIFrame* aFrame)
|
||||
{
|
||||
|
@ -6607,7 +6648,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
|
|||
&parentAfterFrame);
|
||||
|
||||
// Create some new frames
|
||||
nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
|
||||
nsFrameConstructorState state(mPresShell, GetFixedContainingBlock(parentFrame),
|
||||
GetAbsoluteContainingBlock(parentFrame),
|
||||
GetFloatContainingBlock(parentFrame));
|
||||
state.mTreeMatchContext.InitAncestors(aContainer->AsElement());
|
||||
|
@ -7042,7 +7083,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
|
||||
nsFrameConstructorState state(mPresShell, GetFixedContainingBlock(parentFrame),
|
||||
GetAbsoluteContainingBlock(parentFrame),
|
||||
GetFloatContainingBlock(parentFrame),
|
||||
aFrameState);
|
||||
|
|
|
@ -1464,6 +1464,7 @@ private:
|
|||
*/
|
||||
public:
|
||||
nsIFrame* GetAbsoluteContainingBlock(nsIFrame* aFrame);
|
||||
nsIFrame* GetFixedContainingBlock(nsIFrame* aFrame);
|
||||
private:
|
||||
nsIFrame* GetFloatContainingBlock(nsIFrame* aFrame);
|
||||
|
||||
|
|
|
@ -1984,8 +1984,8 @@ nsObjectFrame::PaintPlugin(nsDisplayListBuilder* aBuilder,
|
|||
return;
|
||||
}
|
||||
|
||||
origin.x = NSToIntRound(float(ctxMatrix.GetTranslation().x));
|
||||
origin.y = NSToIntRound(float(ctxMatrix.GetTranslation().y));
|
||||
origin.x = NSToIntRound(ctxMatrix.GetTranslation().x);
|
||||
origin.y = NSToIntRound(ctxMatrix.GetTranslation().y);
|
||||
|
||||
/* Need to force the clip to be set */
|
||||
ctx->UpdateSurfaceClip();
|
||||
|
|
|
@ -236,6 +236,40 @@ nsSubDocumentFrame::GetSubdocumentRootFrame()
|
|||
return subdocView ? subdocView->GetFrame() : nullptr;
|
||||
}
|
||||
|
||||
nsIntSize
|
||||
nsSubDocumentFrame::GetSubdocumentSize()
|
||||
{
|
||||
if (GetStateBits() & NS_FRAME_FIRST_REFLOW) {
|
||||
nsRefPtr<nsFrameLoader> frameloader = FrameLoader();
|
||||
if (frameloader) {
|
||||
nsCOMPtr<nsIDocument> oldContainerDoc;
|
||||
nsView* detachedViews =
|
||||
frameloader->GetDetachedSubdocView(getter_AddRefs(oldContainerDoc));
|
||||
if (detachedViews) {
|
||||
nsSize size = detachedViews->GetBounds().Size();
|
||||
nsPresContext* presContext = detachedViews->GetFrame()->PresContext();
|
||||
return nsIntSize(presContext->AppUnitsToDevPixels(size.width),
|
||||
presContext->AppUnitsToDevPixels(size.height));
|
||||
}
|
||||
}
|
||||
// Pick some default size for now. Using 10x10 because that's what the
|
||||
// code used to do.
|
||||
return nsIntSize(10, 10);
|
||||
} else {
|
||||
nsSize docSizeAppUnits;
|
||||
nsPresContext* presContext = PresContext();
|
||||
nsCOMPtr<nsIDOMHTMLFrameElement> frameElem =
|
||||
do_QueryInterface(GetContent());
|
||||
if (frameElem) {
|
||||
docSizeAppUnits = GetSize();
|
||||
} else {
|
||||
docSizeAppUnits = GetContentRect().Size();
|
||||
}
|
||||
return nsIntSize(presContext->AppUnitsToDevPixels(docSizeAppUnits.width),
|
||||
presContext->AppUnitsToDevPixels(docSizeAppUnits.height));
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsSubDocumentFrame::PassPointerEventsToChildren()
|
||||
{
|
||||
|
|
|
@ -89,6 +89,7 @@ public:
|
|||
void EndSwapDocShells(nsIFrame* aOther);
|
||||
nsView* EnsureInnerView();
|
||||
nsIFrame* GetSubdocumentRootFrame();
|
||||
nsIntSize GetSubdocumentSize();
|
||||
|
||||
// nsIReflowCallback
|
||||
virtual bool ReflowFinished() MOZ_OVERRIDE;
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<div style="margin-left:100px; width:200px; height:200px; border:1px solid black">
|
||||
<div style="margin-left:150px; width:50px; height:80px; background:yellow;">
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<div style="transform:translateX(100px); width:200px; height:200px; border:1px solid black">
|
||||
<div style="position:absolute;">
|
||||
</div>
|
||||
<div style="position:absolute;">
|
||||
<div style="position:fixed; right:0; width:50px; height:80px; background:yellow;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<body>
|
||||
<div style="transform:translateX(100px); width:200px; height:200px; border:1px solid black">
|
||||
<div style="position:absolute;">
|
||||
</div>
|
||||
<div style="position:absolute;">
|
||||
<div id="d" style="display:none; position:fixed; right:0; width:50px; height:80px; background:yellow;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function doTest() {
|
||||
document.getElementById("d").style.display = "";
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
window.addEventListener("MozReftestInvalidate", doTest, false);
|
||||
</script>
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait>
|
||||
<body>
|
||||
<div style="transform:translateX(100px); width:200px; height:200px; border:1px solid black">
|
||||
<div style="position:absolute;">
|
||||
</div>
|
||||
<div style="position:absolute;">
|
||||
<div style="position:fixed; right:0; width:50px; height:80px; background:yellow;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1738,3 +1738,5 @@ skip-if(B2G) == 814952-1.html 814952-1-ref.html
|
|||
== 816458-1.html 816458-1-ref.html
|
||||
== 816359-1.html 816359-1-ref.html
|
||||
skip-if(B2G) == 818276-1.html 818276-1-ref.html
|
||||
== 827577-1a.html 827577-1-ref.html
|
||||
== 827577-1b.html 827577-1-ref.html
|
||||
|
|
|
@ -667,7 +667,7 @@ void MediaPipelineTransmit::PipelineListener::ProcessAudioChunk(
|
|||
nsAutoArrayPtr<int16_t> samples(new int16_t[chunk.mDuration]);
|
||||
|
||||
if (chunk.mBuffer) {
|
||||
switch(chunk.mBufferFormat) {
|
||||
switch (chunk.mBufferFormat) {
|
||||
case AUDIO_FORMAT_FLOAT32:
|
||||
MOZ_MTLOG(PR_LOG_ERROR, "Can't process audio except in 16-bit PCM yet");
|
||||
MOZ_ASSERT(PR_FALSE);
|
||||
|
@ -675,8 +675,7 @@ void MediaPipelineTransmit::PipelineListener::ProcessAudioChunk(
|
|||
break;
|
||||
case AUDIO_FORMAT_S16:
|
||||
{
|
||||
const short* buf = static_cast<const short *>(chunk.mBuffer->Data()) +
|
||||
chunk.mOffset;
|
||||
const short* buf = static_cast<const short *>(chunk.mChannelData[0]);
|
||||
ConvertAudioSamplesWithScale(buf, samples, chunk.mDuration, chunk.mVolume);
|
||||
}
|
||||
break;
|
||||
|
@ -833,11 +832,12 @@ NotifyPull(MediaStreamGraph* graph, StreamTime desired_time) {
|
|||
while (MillisecondsToMediaTime(played_) < desired_time) {
|
||||
// TODO(ekr@rtfm.com): Is there a way to avoid mallocating here?
|
||||
nsRefPtr<SharedBuffer> samples = SharedBuffer::Create(1000);
|
||||
int16_t *samples_data = static_cast<int16_t *>(samples->Data());
|
||||
int samples_length;
|
||||
|
||||
MediaConduitErrorCode err =
|
||||
static_cast<AudioSessionConduit*>(conduit_.get())->GetAudioFrame(
|
||||
static_cast<int16_t *>(samples->Data()),
|
||||
samples_data,
|
||||
16000, // Sampling rate fixed at 16 kHz for now
|
||||
0, // TODO(ekr@rtfm.com): better estimate of capture delay
|
||||
samples_length);
|
||||
|
@ -849,8 +849,9 @@ NotifyPull(MediaStreamGraph* graph, StreamTime desired_time) {
|
|||
|
||||
AudioSegment segment;
|
||||
segment.Init(1);
|
||||
segment.AppendFrames(samples.forget(), samples_length,
|
||||
0, samples_length, AUDIO_FORMAT_S16);
|
||||
nsAutoTArray<const int16_t*,1> channels;
|
||||
channels.AppendElement(samples_data);
|
||||
segment.AppendFrames(samples.forget(), channels, samples_length);
|
||||
|
||||
source_->AppendToTrack(1, // TODO(ekr@rtfm.com): Track ID
|
||||
&segment);
|
||||
|
|
|
@ -63,17 +63,18 @@ Fake_AudioGenerator(nsDOMMediaStream* aStream) : mStream(aStream), mCount(0) {
|
|||
static void Callback(nsITimer* timer, void *arg) {
|
||||
Fake_AudioGenerator* gen = static_cast<Fake_AudioGenerator*>(arg);
|
||||
|
||||
nsRefPtr<mozilla::SharedBuffer> samples = mozilla::SharedBuffer::Create(1600 * 2 * sizeof(int16_t));
|
||||
for (int i=0; i<1600*2; i++) {
|
||||
reinterpret_cast<int16_t *>(samples->Data())[i] = ((gen->mCount % 8) * 4000) - (7*4000)/2;
|
||||
nsRefPtr<mozilla::SharedBuffer> samples = mozilla::SharedBuffer::Create(1600 * sizeof(int16_t));
|
||||
int16_t* data = static_cast<int16_t*>(samples->Data());
|
||||
for (int i=0; i<1600; i++) {
|
||||
data[i] = ((gen->mCount % 8) * 4000) - (7*4000)/2;
|
||||
++gen->mCount;
|
||||
}
|
||||
|
||||
mozilla::AudioSegment segment;
|
||||
segment.Init(1);
|
||||
segment.AppendFrames(samples.forget(), 1600,
|
||||
0, 1600, mozilla::AUDIO_FORMAT_S16);
|
||||
|
||||
nsAutoTArray<const int16_t*,1> channelData;
|
||||
channelData.AppendElement(data);
|
||||
segment.AppendFrames(samples.forget(), channelData, 1600);
|
||||
gen->mStream->GetStream()->AsSourceStream()->AppendToTrack(1, &segment);
|
||||
}
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ class Fake_SourceMediaStream : public Fake_MediaStream {
|
|||
mozilla::AudioChunk& chunk = *(iter);
|
||||
MOZ_ASSERT(chunk.mBuffer);
|
||||
const int16_t* buf =
|
||||
static_cast<const int16_t*>(chunk.mBuffer->Data());
|
||||
static_cast<const int16_t*>(chunk.mChannelData[0]);
|
||||
for(int i=0; i<chunk.mDuration; i++) {
|
||||
if(buf[i]) {
|
||||
//atleast one non-zero sample found.
|
||||
|
|
|
@ -91,20 +91,18 @@ void Fake_AudioStreamSource::Periodic() {
|
|||
//Generate Signed 16 Bit Audio samples
|
||||
nsRefPtr<mozilla::SharedBuffer> samples =
|
||||
mozilla::SharedBuffer::Create(AUDIO_BUFFER_SIZE * NUM_CHANNELS * sizeof(int16_t));
|
||||
int16_t* data = reinterpret_cast<int16_t *>(samples->Data());
|
||||
for(int i=0; i<(1600*2); i++) {
|
||||
//saw tooth audio sample
|
||||
reinterpret_cast<int16_t *>(samples->Data())[i] =
|
||||
((mCount % 8) * 4000) - (7*4000)/2;
|
||||
data[i] = ((mCount % 8) * 4000) - (7*4000)/2;
|
||||
mCount++;
|
||||
}
|
||||
|
||||
mozilla::AudioSegment segment;
|
||||
segment.Init(1);
|
||||
segment.AppendFrames(samples.forget(),
|
||||
AUDIO_BUFFER_SIZE,
|
||||
0,
|
||||
AUDIO_BUFFER_SIZE,
|
||||
mozilla::AUDIO_FORMAT_S16);
|
||||
nsAutoTArray<const int16_t *,1> channels;
|
||||
channels.AppendElement(data);
|
||||
segment.AppendFrames(samples.forget(), channels, AUDIO_BUFFER_SIZE);
|
||||
|
||||
for(std::set<Fake_MediaStreamListener *>::iterator it = mListeners.begin();
|
||||
it != mListeners.end(); ++it) {
|
||||
|
|
|
@ -262,6 +262,11 @@ pref("browser.search.jarURIs", "chrome://browser/locale/searchplugins/");
|
|||
// tell the search service that we don't really expose the "current engine"
|
||||
pref("browser.search.noCurrentEngine", true);
|
||||
|
||||
#ifdef MOZ_OFFICIAL_BRANDING
|
||||
// {moz:official} expands to "official"
|
||||
pref("browser.search.official", true);
|
||||
#endif
|
||||
|
||||
// enable xul error pages
|
||||
pref("browser.xul.error_pages.enabled", true);
|
||||
|
||||
|
|
|
@ -1885,6 +1885,16 @@ abstract public class GeckoApp
|
|||
GeckoAppShell.setLayerClient(mLayerView.getLayerClient());
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null));
|
||||
}
|
||||
|
||||
// Homescreen Widget requests awesome bar
|
||||
if (ACTION_WIDGET.equals(action)) {
|
||||
if (mRestoreMode != RESTORE_NONE && !mIsRestoringActivity) {
|
||||
addTab();
|
||||
} else {
|
||||
onSearchRequested();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public GeckoProfile getProfile() {
|
||||
|
|
|
@ -256,6 +256,11 @@ pref("browser.search.jarURIs", "chrome://browser/locale/searchplugins/");
|
|||
// tell the search service that we don't really expose the "current engine"
|
||||
pref("browser.search.noCurrentEngine", true);
|
||||
|
||||
#ifdef MOZ_OFFICIAL_BRANDING
|
||||
// {moz:official} expands to "official"
|
||||
pref("browser.search.official", true);
|
||||
#endif
|
||||
|
||||
// enable xul error pages
|
||||
pref("browser.xul.error_pages.enabled", true);
|
||||
|
||||
|
|
|
@ -368,6 +368,9 @@ pref("toolkit.telemetry.debugSlowSql", false);
|
|||
pref("toolkit.identity.enabled", false);
|
||||
pref("toolkit.identity.debug", false);
|
||||
|
||||
// Enable deprecation warnings.
|
||||
pref("devtools.errorconsole.deprecation_warnings", true);
|
||||
|
||||
// Disable remote debugging protocol logging
|
||||
pref("devtools.debugger.log", false);
|
||||
// Disable remote debugging connections
|
||||
|
|
|
@ -197,12 +197,13 @@ public:
|
|||
/* The Gecko crash reporter is confused by adjacent memory mappings of
|
||||
* the same file. On Android, subsequent mappings are growing in memory
|
||||
* address, and chances are we're going to map from the same file
|
||||
* descriptor right away. Allocate one page more than requested so that
|
||||
* there is a gap between this mapping and the subsequent one. */
|
||||
* descriptor right away. To avoid problems with the crash reporter,
|
||||
* create an empty anonymous page after the ashmem mapping. To do so,
|
||||
* allocate one page more than requested, then replace the last page with
|
||||
* an anonymous mapping. */
|
||||
void *buf = ::mmap(NULL, length + PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (buf != MAP_FAILED) {
|
||||
/* Actually create the gap with anonymous memory */
|
||||
::mmap(reinterpret_cast<char *>(buf) + ((length + PAGE_SIZE) & PAGE_MASK),
|
||||
::mmap(reinterpret_cast<char *>(buf) + ((length + PAGE_SIZE - 1) & PAGE_MASK),
|
||||
PAGE_SIZE, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
debug("Decompression buffer of size %d in ashmem \"%s\", mapped @%p",
|
||||
|
@ -248,7 +249,7 @@ public:
|
|||
#ifdef ANDROID
|
||||
~_MappableBuffer() {
|
||||
/* Free the additional page we allocated. See _MappableBuffer::Create */
|
||||
::munmap(*this + ((GetLength() + PAGE_SIZE) & ~(PAGE_SIZE - 1)), PAGE_SIZE);
|
||||
::munmap(*this + ((GetLength() + PAGE_SIZE - 1) & PAGE_MASK), PAGE_SIZE);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -803,13 +803,21 @@ function ParamSubstitution(aParamValue, aSearchTerms, aEngine) {
|
|||
distributionID = Services.prefs.getCharPref(BROWSER_SEARCH_PREF + "distributionID");
|
||||
}
|
||||
catch (ex) { }
|
||||
var official = MOZ_OFFICIAL;
|
||||
try {
|
||||
if (Services.prefs.getBoolPref(BROWSER_SEARCH_PREF + "official"))
|
||||
official = "official";
|
||||
else
|
||||
official = "unofficial";
|
||||
}
|
||||
catch (ex) { }
|
||||
|
||||
// Custom search parameters. These are only available to default search
|
||||
// engines.
|
||||
if (aEngine._isDefault) {
|
||||
value = value.replace(MOZ_PARAM_LOCALE, getLocale());
|
||||
value = value.replace(MOZ_PARAM_DIST_ID, distributionID);
|
||||
value = value.replace(MOZ_PARAM_OFFICIAL, MOZ_OFFICIAL);
|
||||
value = value.replace(MOZ_PARAM_OFFICIAL, official);
|
||||
}
|
||||
|
||||
// Insert the OpenSearch parameters we're confident about
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = [ "Deprecated" ];
|
||||
|
||||
const Cu = Components.utils;
|
||||
const Ci = Components.interfaces;
|
||||
const PREF_DEPRECATION_WARNINGS = "devtools.errorconsole.deprecation_warnings";
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// A flag that indicates whether deprecation warnings should be logged.
|
||||
let logWarnings = Services.prefs.getBoolPref(PREF_DEPRECATION_WARNINGS);
|
||||
|
||||
Services.prefs.addObserver(PREF_DEPRECATION_WARNINGS,
|
||||
function (aSubject, aTopic, aData) {
|
||||
logWarnings = Services.prefs.getBoolPref(PREF_DEPRECATION_WARNINGS);
|
||||
}, false);
|
||||
|
||||
/**
|
||||
* Build a callstack log message.
|
||||
*
|
||||
* @param nsIStackFrame aStack
|
||||
* A callstack to be converted into a string log message.
|
||||
*/
|
||||
function stringifyCallstack (aStack) {
|
||||
// If aStack is invalid, use Components.stack (ignoring the last frame).
|
||||
if (!aStack || !(aStack instanceof Ci.nsIStackFrame)) {
|
||||
aStack = Components.stack.caller;
|
||||
}
|
||||
|
||||
let frame = aStack.caller;
|
||||
let msg = "";
|
||||
// Get every frame in the callstack.
|
||||
while (frame) {
|
||||
msg += frame.filename + " " + frame.lineNumber +
|
||||
" " + frame.name + "\n";
|
||||
frame = frame.caller;
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
const Deprecated = {
|
||||
/**
|
||||
* Log a deprecation warning.
|
||||
*
|
||||
* @param string aText
|
||||
* Deprecation warning text.
|
||||
* @param string aUrl
|
||||
* A URL pointing to documentation describing deprecation
|
||||
* and the way to address it.
|
||||
* @param nsIStackFrame aStack
|
||||
* An optional callstack. If it is not provided a
|
||||
* snapshot of the current JavaScript callstack will be
|
||||
* logged.
|
||||
*/
|
||||
warning: function (aText, aUrl, aStack) {
|
||||
if (!logWarnings) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If URL is not provided, report an error.
|
||||
if (!aUrl) {
|
||||
Cu.reportError("Error in Deprecated.warning: warnings must " +
|
||||
"provide a URL documenting this deprecation.");
|
||||
return;
|
||||
}
|
||||
|
||||
let textMessage = "DEPRECATION WARNING: " + aText +
|
||||
"\nYou may find more details about this deprecation at: " +
|
||||
aUrl + "\n" +
|
||||
// Append a callstack part to the deprecation message.
|
||||
stringifyCallstack(aStack);
|
||||
|
||||
// Report deprecation warning.
|
||||
Cu.reportError(textMessage);
|
||||
}
|
||||
};
|
|
@ -59,6 +59,7 @@ TEST_DIRS += tests
|
|||
EXTRA_JS_MODULES = \
|
||||
debug.js \
|
||||
DeferredTask.jsm \
|
||||
Deprecated.jsm \
|
||||
Dict.jsm \
|
||||
Geometry.jsm \
|
||||
InlineSpellChecker.jsm \
|
||||
|
|
|
@ -29,6 +29,7 @@ MOCHITEST_BROWSER_FILES = \
|
|||
browser_DeferredTask.js \
|
||||
browser_default_image_filename.js \
|
||||
browser_Troubleshoot.js \
|
||||
browser_Deprecated.js \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const PREF_DEPRECATION_WARNINGS = "devtools.errorconsole.deprecation_warnings";
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
Cu.import("resource://gre/modules/Deprecated.jsm", this);
|
||||
|
||||
// Using this named functions to test deprecation and the properly logged
|
||||
// callstacks.
|
||||
function basicDeprecatedFunction () {
|
||||
Deprecated.warning("this method is deprecated.", "http://example.com");
|
||||
return true;
|
||||
}
|
||||
|
||||
function deprecationFunctionBogusCallstack () {
|
||||
Deprecated.warning("this method is deprecated.", "http://example.com", {
|
||||
caller: {}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
function deprecationFunctionCustomCallstack () {
|
||||
// Get the nsIStackFrame that will contain the name of this function.
|
||||
function getStack () {
|
||||
return Components.stack;
|
||||
}
|
||||
Deprecated.warning("this method is deprecated.", "http://example.com",
|
||||
getStack());
|
||||
return true;
|
||||
}
|
||||
|
||||
let tests = [
|
||||
// Test deprecation warning without passing the callstack.
|
||||
{
|
||||
deprecatedFunction: basicDeprecatedFunction,
|
||||
expectedObservation: function (aMessage) {
|
||||
testAMessage(aMessage);
|
||||
ok(aMessage.errorMessage.indexOf("basicDeprecatedFunction") > 0,
|
||||
"Callstack is correctly logged.");
|
||||
}
|
||||
},
|
||||
// Test a reported error when URL to documentation is not passed.
|
||||
{
|
||||
deprecatedFunction: function () {
|
||||
Deprecated.warning("this method is deprecated.");
|
||||
return true;
|
||||
},
|
||||
expectedObservation: function (aMessage) {
|
||||
ok(aMessage.errorMessage.indexOf("must provide a URL") > 0,
|
||||
"Deprecation warning logged an empty URL argument.");
|
||||
}
|
||||
},
|
||||
// Test deprecation with a bogus callstack passed as an argument (it will be
|
||||
// replaced with the current call stack).
|
||||
{
|
||||
deprecatedFunction: deprecationFunctionBogusCallstack,
|
||||
expectedObservation: function (aMessage) {
|
||||
testAMessage(aMessage);
|
||||
ok(aMessage.errorMessage.indexOf("deprecationFunctionBogusCallstack") > 0,
|
||||
"Callstack is correctly logged.");
|
||||
}
|
||||
},
|
||||
// When pref is unset Deprecated.warning should not log anything.
|
||||
{
|
||||
deprecatedFunction: basicDeprecatedFunction,
|
||||
expectedObservation: function (aMessage) {
|
||||
// Nothing should be logged when pref is false.
|
||||
ok(false, "Deprecated warning should not log anything when pref is unset.");
|
||||
},
|
||||
// Set pref to false.
|
||||
logWarnings: false
|
||||
},
|
||||
// Test deprecation with a valid custom callstack passed as an argument.
|
||||
{
|
||||
deprecatedFunction: deprecationFunctionCustomCallstack,
|
||||
expectedObservation: function (aMessage) {
|
||||
testAMessage(aMessage);
|
||||
ok(aMessage.errorMessage.indexOf("deprecationFunctionCustomCallstack") > 0,
|
||||
"Callstack is correctly logged.");
|
||||
finish();
|
||||
},
|
||||
// Set pref to true.
|
||||
logWarnings: true
|
||||
}];
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
// Check if Deprecated is loaded.
|
||||
ok(Deprecated, "Deprecated object exists");
|
||||
|
||||
// Run all test cases.
|
||||
tests.forEach(testDeprecated);
|
||||
}
|
||||
|
||||
// Test Consle Message attributes.
|
||||
function testAMessage (aMessage) {
|
||||
ok(aMessage.errorMessage.indexOf("DEPRECATION WARNING: " +
|
||||
"this method is deprecated.") === 0,
|
||||
"Deprecation is correctly logged.");
|
||||
ok(aMessage.errorMessage.indexOf("http://example.com") > 0,
|
||||
"URL is correctly logged.");
|
||||
}
|
||||
|
||||
function testDeprecated (test) {
|
||||
// Deprecation warnings will be logged only when the preference is set.
|
||||
if (typeof test.logWarnings !== "undefined") {
|
||||
Services.prefs.setBoolPref(PREF_DEPRECATION_WARNINGS, test.logWarnings);
|
||||
}
|
||||
|
||||
// Create a console listener.
|
||||
let consoleListener = {
|
||||
observe: function (aMessage) {
|
||||
// Ignore unexpected messages.
|
||||
if (!(aMessage instanceof Ci.nsIScriptError)) {
|
||||
return;
|
||||
}
|
||||
if (aMessage.errorMessage.indexOf("DEPRECATION WARNING: ") < 0 &&
|
||||
aMessage.errorMessage.indexOf("must provide a URL") < 0) {
|
||||
return;
|
||||
}
|
||||
ok(aMessage instanceof Ci.nsIScriptError,
|
||||
"Deprecation log message is an instance of type nsIScriptError.");
|
||||
test.expectedObservation(aMessage);
|
||||
}
|
||||
};
|
||||
// Register a listener that contains the tests.
|
||||
Services.console.registerListener(consoleListener);
|
||||
// Run the deprecated function.
|
||||
test.deprecatedFunction();
|
||||
// Unregister a listener.
|
||||
Services.console.unregisterListener(consoleListener);
|
||||
}
|
|
@ -1169,6 +1169,15 @@ nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, uint8_t aWidgetType,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
static bool
|
||||
AssumeThemePartAndStateAreTransparent(int32_t aPart, int32_t aState)
|
||||
{
|
||||
if (aPart == MENU_POPUPITEM && aState == MBI_NORMAL) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNativeThemeWin::DrawWidgetBackground(nsRenderingContext* aContext,
|
||||
nsIFrame* aFrame,
|
||||
|
@ -1214,6 +1223,10 @@ nsNativeThemeWin::DrawWidgetBackground(nsRenderingContext* aContext,
|
|||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (AssumeThemePartAndStateAreTransparent(part, state)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
gfxFloat p2a = gfxFloat(aContext->AppUnitsPerDevPixel());
|
||||
RECT widgetRect;
|
||||
RECT clipRect;
|
||||
|
@ -3149,6 +3162,10 @@ nsresult nsNativeThemeWin::ClassicDrawWidgetBackground(nsRenderingContext* aCont
|
|||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (AssumeThemePartAndStateAreTransparent(part, state)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
gfxFloat p2a = gfxFloat(aContext->AppUnitsPerDevPixel());
|
||||
RECT widgetRect;
|
||||
gfxRect tr(aRect.x, aRect.y, aRect.width, aRect.height),
|
||||
|
|
Загрузка…
Ссылка в новой задаче