This commit is contained in:
Ms2ger 2013-01-11 15:11:42 +01:00
Родитель 3203dfee36 45914aa948
Коммит 34abe91f47
68 изменённых файлов: 1831 добавлений и 698 удалений

Просмотреть файл

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