mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 11:25:00 +00:00
Merge mozilla-central to autoland
This commit is contained in:
commit
b704584332
@ -21,7 +21,7 @@
|
||||
<?xml-stylesheet href="chrome://browser/skin/customizableui/panelUI.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/downloads/downloads.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/searchbar.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/tree-icons.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/editBookmark.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/compacttheme.css" type="text/css" alternate="yes" title="Light/Dark"?>
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/editBookmark.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/tree-icons.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
|
||||
|
||||
<!DOCTYPE dialog [
|
||||
|
@ -5,7 +5,8 @@
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/tree-icons.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/sidebar.css"?>
|
||||
|
||||
<!DOCTYPE page [
|
||||
<!ENTITY % placesDTD SYSTEM "chrome://browser/locale/places/places.dtd">
|
||||
|
@ -5,7 +5,8 @@
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/tree-icons.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/sidebar.css"?>
|
||||
|
||||
<!DOCTYPE page [
|
||||
<!ENTITY % placesDTD SYSTEM "chrome://browser/locale/places/places.dtd">
|
||||
|
@ -7,7 +7,7 @@
|
||||
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/tree-icons.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/organizer.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/editBookmark.css"?>
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
type="text/css"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/tree-icons.css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="510634: Wrong icons on bookmarks sidebar"
|
||||
|
@ -10,7 +10,7 @@
|
||||
type="text/css"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/tree-icons.css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="1163447: selectItems in Places no longer selects items within Toolbar or Sidebar folders"
|
||||
|
@ -10,7 +10,7 @@
|
||||
type="text/css"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/tree-icons.css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="549192: History view not updated after deleting entry"
|
||||
|
@ -10,7 +10,7 @@
|
||||
type="text/css"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/tree-icons.css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="549491: 'The root node is never visible' exception when details of the root node are modified "
|
||||
|
@ -10,7 +10,7 @@
|
||||
type="text/css"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/tree-icons.css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="549192: History view not updated after deleting entry"
|
||||
|
@ -9,7 +9,7 @@
|
||||
type="text/css"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/tree-icons.css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="435322: Places tree view's formatting"
|
||||
|
@ -7,7 +7,7 @@
|
||||
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/tree-icons.css"?>
|
||||
|
||||
<dialog id="selectBookmarkDialog"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
|
@ -32,7 +32,7 @@ browser.jar:
|
||||
skin/classic/browser/places/allBookmarks.png (places/allBookmarks.png)
|
||||
skin/classic/browser/places/editBookmark.css (places/editBookmark.css)
|
||||
skin/classic/browser/places/livemark-item.png (places/livemark-item.png)
|
||||
* skin/classic/browser/places/places.css (places/places.css)
|
||||
* skin/classic/browser/places/sidebar.css (places/sidebar.css)
|
||||
skin/classic/browser/places/organizer.css (places/organizer.css)
|
||||
skin/classic/browser/places/organizer.xml (places/organizer.xml)
|
||||
skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png)
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
/* Sidebars */
|
||||
|
||||
%include ../../shared/places/places.inc.css
|
||||
%include ../../shared/places/sidebar.inc.css
|
||||
|
||||
#sidebar-search-container {
|
||||
padding: 8px;
|
||||
@ -48,7 +48,3 @@
|
||||
.sidebar-placesTreechildren::-moz-tree-cell(separator) {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* Trees */
|
||||
|
||||
%include ../../shared/places/tree-icons.inc.css
|
@ -34,7 +34,7 @@ browser.jar:
|
||||
skin/classic/browser/notification-icons/geo-blocked.svg (notification-icons/geo-blocked.svg)
|
||||
skin/classic/browser/notification-icons/geo.svg (notification-icons/geo.svg)
|
||||
skin/classic/browser/places/allBookmarks.png (places/allBookmarks.png)
|
||||
* skin/classic/browser/places/places.css (places/places.css)
|
||||
* skin/classic/browser/places/sidebar.css (places/sidebar.css)
|
||||
skin/classic/browser/places/organizer.css (places/organizer.css)
|
||||
skin/classic/browser/places/toolbar.png (places/toolbar.png)
|
||||
skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png)
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
/* Sidebars */
|
||||
|
||||
%include ../../shared/places/places.inc.css
|
||||
%include ../../shared/places/sidebar.inc.css
|
||||
|
||||
.sidebar-placesTree {
|
||||
margin: 0;
|
||||
@ -66,7 +66,3 @@
|
||||
#viewButton:focus {
|
||||
box-shadow: var(--focus-ring-box-shadow);
|
||||
}
|
||||
|
||||
/* Trees */
|
||||
|
||||
%include ../../shared/places/tree-icons.inc.css
|
@ -239,6 +239,7 @@
|
||||
skin/classic/browser/places/history.svg (../shared/places/history.svg)
|
||||
skin/classic/browser/places/tag.svg (../shared/places/tag.svg)
|
||||
skin/classic/browser/places/unfiledBookmarks.svg (../shared/places/unfiledBookmarks.svg)
|
||||
skin/classic/browser/places/tree-icons.css (../shared/places/tree-icons.css)
|
||||
skin/classic/browser/privatebrowsing/aboutPrivateBrowsing.css (../shared/privatebrowsing/aboutPrivateBrowsing.css)
|
||||
skin/classic/browser/privatebrowsing/favicon.svg (../shared/privatebrowsing/favicon.svg)
|
||||
skin/classic/browser/privatebrowsing/private-browsing.svg (../shared/privatebrowsing/private-browsing.svg)
|
||||
|
@ -98,11 +98,6 @@ treechildren::-moz-tree-cell-text(title, separator, selected, focus) {
|
||||
color: HighlightText;
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-twisty(title, separator) {
|
||||
-moz-appearance: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-image(cutting) {
|
||||
opacity: 0.5;
|
||||
}
|
@ -27,7 +27,7 @@ browser.jar:
|
||||
skin/classic/browser/notification-icons/geo-blocked.svg (notification-icons/geo-blocked.svg)
|
||||
skin/classic/browser/notification-icons/geo-detailed.svg (notification-icons/geo-detailed.svg)
|
||||
skin/classic/browser/notification-icons/geo.svg (notification-icons/geo.svg)
|
||||
* skin/classic/browser/places/places.css (places/places.css)
|
||||
* skin/classic/browser/places/sidebar.css (places/sidebar.css)
|
||||
* skin/classic/browser/places/organizer.css (places/organizer.css)
|
||||
skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png)
|
||||
skin/classic/browser/places/editBookmark.css (places/editBookmark.css)
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
/* Sidebars */
|
||||
|
||||
%include ../../shared/places/places.inc.css
|
||||
%include ../../shared/places/sidebar.inc.css
|
||||
|
||||
.sidebar-placesTree {
|
||||
-moz-appearance: none;
|
||||
@ -44,12 +44,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Trees */
|
||||
|
||||
%include ../../shared/places/tree-icons.inc.css
|
||||
|
||||
/* Browser Sidebars */
|
||||
|
||||
/* Default button vert. margins are 1px/2px, and this can cause misalignment */
|
||||
#viewButton {
|
||||
margin: 0;
|
@ -134,7 +134,7 @@ IndexedDBHelper.prototype = {
|
||||
* be invoked with the transaction and the `store' object store.
|
||||
* @param successCb
|
||||
* Success callback to call on a successful transaction commit.
|
||||
* The result is stored in txn.result.
|
||||
* The result is stored in txn.result (in the callback function).
|
||||
* @param failureCb
|
||||
* Error callback to call when an error is encountered.
|
||||
*/
|
||||
@ -162,6 +162,14 @@ IndexedDBHelper.prototype = {
|
||||
|
||||
txn.oncomplete = function () {
|
||||
if (DEBUG) debug("Transaction complete. Returning to callback.");
|
||||
/*
|
||||
* txn.result property is not part of the transaction object returned
|
||||
* by this._db.transaction method called above.
|
||||
* The property is expected to be set in the callback function.
|
||||
* However, it can happen that the property is not set for some reason,
|
||||
* so we have to check if the property exists before calling the
|
||||
* success callback.
|
||||
*/
|
||||
if (successCb) {
|
||||
if ("result" in txn) {
|
||||
successCb(txn.result);
|
||||
@ -173,6 +181,12 @@ IndexedDBHelper.prototype = {
|
||||
|
||||
txn.onabort = function () {
|
||||
if (DEBUG) debug("Caught error on transaction");
|
||||
/*
|
||||
* txn.error property is part of the transaction object returned by
|
||||
* this._db.transaction method called above.
|
||||
* The attribute is defined in IDBTranscation WebIDL interface.
|
||||
* It may be null.
|
||||
*/
|
||||
if (failureCb) {
|
||||
failureCb(getErrorName(txn.error));
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
#define PREF_VOLUME_SCALE "media.volume_scale"
|
||||
#define PREF_CUBEB_BACKEND "media.cubeb.backend"
|
||||
#define PREF_CUBEB_OUTPUT_DEVICE "media.cubeb.output_device"
|
||||
#define PREF_CUBEB_LATENCY_PLAYBACK "media.cubeb_latency_playback_ms"
|
||||
#define PREF_CUBEB_LATENCY_MSG "media.cubeb_latency_msg_frames"
|
||||
// Allows to get something non-default for the preferred sample-rate, to allow
|
||||
@ -142,6 +143,7 @@ size_t sAudioIPCStackSize;
|
||||
#endif
|
||||
StaticAutoPtr<char> sBrandName;
|
||||
StaticAutoPtr<char> sCubebBackendName;
|
||||
StaticAutoPtr<char> sCubebOutputDeviceName;
|
||||
|
||||
const char kBrandBundleURL[] = "chrome://branding/locale/brand.properties";
|
||||
|
||||
@ -188,6 +190,19 @@ static const uint32_t CUBEB_NORMAL_LATENCY_FRAMES = 1024;
|
||||
namespace CubebUtils {
|
||||
cubeb* GetCubebContextUnlocked();
|
||||
|
||||
void GetPrefAndSetString(const char* aPref, StaticAutoPtr<char>& aStorage)
|
||||
{
|
||||
nsAutoCString value;
|
||||
Preferences::GetCString(aPref, value);
|
||||
if (value.IsEmpty()) {
|
||||
aStorage = nullptr;
|
||||
} else {
|
||||
aStorage = new char[value.Length() + 1];
|
||||
PodCopy(aStorage.get(), value.get(), value.Length());
|
||||
aStorage[value.Length()] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void PrefChanged(const char* aPref, void* aClosure)
|
||||
{
|
||||
if (strcmp(aPref, PREF_VOLUME_SCALE) == 0) {
|
||||
@ -235,15 +250,10 @@ void PrefChanged(const char* aPref, void* aClosure)
|
||||
}
|
||||
} else if (strcmp(aPref, PREF_CUBEB_BACKEND) == 0) {
|
||||
StaticMutexAutoLock lock(sMutex);
|
||||
nsAutoCString value;
|
||||
Preferences::GetCString(aPref, value);
|
||||
if (value.IsEmpty()) {
|
||||
sCubebBackendName = nullptr;
|
||||
} else {
|
||||
sCubebBackendName = new char[value.Length() + 1];
|
||||
PodCopy(sCubebBackendName.get(), value.get(), value.Length());
|
||||
sCubebBackendName[value.Length()] = 0;
|
||||
}
|
||||
GetPrefAndSetString(aPref, sCubebBackendName);
|
||||
} else if (strcmp(aPref, PREF_CUBEB_OUTPUT_DEVICE) == 0) {
|
||||
StaticMutexAutoLock lock(sMutex);
|
||||
GetPrefAndSetString(aPref, sCubebOutputDeviceName);
|
||||
} else if (strcmp(aPref, PREF_CUBEB_FORCE_NULL_CONTEXT) == 0) {
|
||||
StaticMutexAutoLock lock(sMutex);
|
||||
sCubebForceNullContext = Preferences::GetBool(aPref, false);
|
||||
@ -538,15 +548,11 @@ uint32_t GetCubebMSGLatencyInFrames(cubeb_stream_params * params)
|
||||
}
|
||||
|
||||
static const char* gInitCallbackPrefs[] = {
|
||||
PREF_VOLUME_SCALE,
|
||||
PREF_CUBEB_LATENCY_PLAYBACK,
|
||||
PREF_CUBEB_LATENCY_MSG,
|
||||
PREF_CUBEB_BACKEND,
|
||||
PREF_CUBEB_FORCE_NULL_CONTEXT,
|
||||
PREF_CUBEB_SANDBOX,
|
||||
PREF_AUDIOIPC_POOL_SIZE,
|
||||
PREF_AUDIOIPC_STACK_SIZE,
|
||||
nullptr,
|
||||
PREF_VOLUME_SCALE, PREF_CUBEB_OUTPUT_DEVICE,
|
||||
PREF_CUBEB_LATENCY_PLAYBACK, PREF_CUBEB_LATENCY_MSG,
|
||||
PREF_CUBEB_BACKEND, PREF_CUBEB_FORCE_NULL_CONTEXT,
|
||||
PREF_CUBEB_SANDBOX, PREF_AUDIOIPC_POOL_SIZE,
|
||||
PREF_AUDIOIPC_STACK_SIZE, nullptr,
|
||||
};
|
||||
static const char* gCallbackPrefs[] = {
|
||||
PREF_CUBEB_FORCE_SAMPLE_RATE,
|
||||
@ -627,6 +633,12 @@ void GetCurrentBackend(nsAString& aBackend)
|
||||
aBackend.AssignLiteral("unknown");
|
||||
}
|
||||
|
||||
char* GetForcedOutputDevice()
|
||||
{
|
||||
StaticMutexAutoLock lock(sMutex);
|
||||
return sCubebOutputDeviceName;
|
||||
}
|
||||
|
||||
uint16_t ConvertCubebType(cubeb_device_type aType)
|
||||
{
|
||||
uint16_t map[] = {
|
||||
|
@ -49,6 +49,7 @@ void GetCurrentBackend(nsAString& aBackend);
|
||||
void GetDeviceCollection(nsTArray<RefPtr<AudioDeviceInfo>>& aDeviceInfos,
|
||||
Side aSide);
|
||||
cubeb_stream_prefs GetDefaultStreamPrefs();
|
||||
char* GetForcedOutputDevice();
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
uint32_t AndroidGetAudioOutputSampleRate();
|
||||
|
@ -659,6 +659,22 @@ AudioCallbackDriver::Init()
|
||||
return true;
|
||||
}
|
||||
|
||||
CubebUtils::AudioDeviceID forcedOutputDeviceId = nullptr;
|
||||
|
||||
char* forcedOutputDeviceName = CubebUtils::GetForcedOutputDevice();
|
||||
if (forcedOutputDeviceName) {
|
||||
nsTArray<RefPtr<AudioDeviceInfo>> deviceInfos;
|
||||
GetDeviceCollection(deviceInfos, CubebUtils::Output);
|
||||
for (const auto& device : deviceInfos) {
|
||||
const nsString& name = device->Name();
|
||||
if (name.Equals(NS_ConvertUTF8toUTF16(forcedOutputDeviceName))) {
|
||||
if (device->DeviceID()) {
|
||||
forcedOutputDeviceId = device->DeviceID();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mBuffer = AudioCallbackBufferWrapper<AudioDataValue>(mOutputChannels);
|
||||
mScratchBuffer = SpillBuffer<AudioDataValue, WEBAUDIO_BLOCK_SIZE * 2>(mOutputChannels);
|
||||
|
||||
@ -690,7 +706,7 @@ AudioCallbackDriver::Init()
|
||||
"AudioCallbackDriver",
|
||||
input_id,
|
||||
inputWanted ? &input : nullptr,
|
||||
output_id,
|
||||
forcedOutputDeviceId ? forcedOutputDeviceId : output_id,
|
||||
&output,
|
||||
latency_frames,
|
||||
DataCallback_s,
|
||||
|
@ -681,7 +681,7 @@ MediaStreamGraphImpl::PlayAudio(MediaStream* aStream)
|
||||
|
||||
float volume = 0.0f;
|
||||
for (uint32_t i = 0; i < aStream->mAudioOutputs.Length(); ++i) {
|
||||
volume += aStream->mAudioOutputs[i].mVolume;
|
||||
volume += aStream->mAudioOutputs[i].mVolume * mGlobalVolume;
|
||||
}
|
||||
|
||||
StreamTime ticksWritten = 0;
|
||||
@ -3711,6 +3711,7 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(GraphDriverType aDriverRequested,
|
||||
, mAbstractMainThread(aMainThread)
|
||||
, mSelfRef(this)
|
||||
, mOutputChannels(std::min<uint32_t>(8, CubebUtils::MaxNumberOfChannels()))
|
||||
, mGlobalVolume(CubebUtils::GetVolumeScale())
|
||||
#ifdef DEBUG
|
||||
, mCanRunMessagesSynchronously(false)
|
||||
#endif
|
||||
|
@ -922,6 +922,12 @@ private:
|
||||
*/
|
||||
const uint32_t mOutputChannels;
|
||||
|
||||
/**
|
||||
* Global volume scale. Used when running tests so that the output is not too
|
||||
* loud.
|
||||
*/
|
||||
const float mGlobalVolume;
|
||||
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
* Used to assert when AppendMessage() runs ControlMessages synchronously.
|
||||
|
@ -426,12 +426,6 @@ function setupEnvironment() {
|
||||
]
|
||||
};
|
||||
|
||||
if (!WANT_FAKE_AUDIO) {
|
||||
defaultMochitestPrefs.set.push(
|
||||
["media.volume_scale", "1"],
|
||||
);
|
||||
}
|
||||
|
||||
const isAndroid = !!navigator.userAgent.includes("Android");
|
||||
|
||||
if (isAndroid) {
|
||||
|
@ -4200,10 +4200,8 @@ EditorBase::EndUpdateViewBatch()
|
||||
return;
|
||||
}
|
||||
|
||||
DebugOnly<nsresult> rv =
|
||||
htmlEditor->CheckSelectionStateForAnonymousButtons(selection);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"CheckSelectionStateForAnonymousButtons() failed");
|
||||
DebugOnly<nsresult> rv = htmlEditor->RefereshEditingUI(*selection);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "RefereshEditingUI() failed");
|
||||
}
|
||||
|
||||
TextComposition*
|
||||
|
@ -418,7 +418,11 @@ HTMLEditor::EndMoving()
|
||||
if (!selection) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
return CheckSelectionStateForAnonymousButtons(selection);
|
||||
nsresult rv = RefereshEditingUI(*selection);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
nsresult
|
||||
HTMLEditor::SetFinalPosition(int32_t aX,
|
||||
|
@ -282,21 +282,75 @@ HTMLEditor::DeleteRefToAnonymousNode(ManualNACPtr aContent,
|
||||
// The ManualNACPtr destructor will invoke UnbindFromTree.
|
||||
}
|
||||
|
||||
// The following method is mostly called by a selection listener. When a
|
||||
// selection change is notified, the method is called to check if resizing
|
||||
// handles, a grabber and/or inline table editing UI need to be displayed
|
||||
// or refreshed
|
||||
void
|
||||
HTMLEditor::HideAnonymousEditingUIs()
|
||||
{
|
||||
if (mAbsolutelyPositionedObject) {
|
||||
HideGrabber();
|
||||
NS_ASSERTION(!mAbsolutelyPositionedObject, "HideGrabber failed");
|
||||
}
|
||||
if (mInlineEditedCell) {
|
||||
HideInlineTableEditingUI();
|
||||
NS_ASSERTION(!mInlineEditedCell, "HideInlineTableEditingUI failed");
|
||||
}
|
||||
if (mResizedObject) {
|
||||
DebugOnly<nsresult> rv = HideResizers();
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HideResizers() failed");
|
||||
NS_ASSERTION(!mResizedObject, "HideResizers failed");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLEditor::HideAnonymousEditingUIsIfUnnecessary()
|
||||
{
|
||||
// XXX Perhaps, this is wrong approach to hide multiple UIs because
|
||||
// hiding one UI may causes overwriting existing UI with newly
|
||||
// created one. In such case, we will leak ovewritten UI.
|
||||
if (!IsAbsolutePositionEditorEnabled() && mAbsolutelyPositionedObject) {
|
||||
// XXX If we're moving something, we need to cancel or commit the
|
||||
// operation now.
|
||||
HideGrabber();
|
||||
NS_ASSERTION(!mAbsolutelyPositionedObject, "HideGrabber failed");
|
||||
}
|
||||
if (!IsInlineTableEditorEnabled() && mInlineEditedCell) {
|
||||
// XXX If we're resizing a table element, we need to cancel or commit the
|
||||
// operation now.
|
||||
HideInlineTableEditingUI();
|
||||
NS_ASSERTION(!mInlineEditedCell, "HideInlineTableEditingUI failed");
|
||||
}
|
||||
if (!IsObjectResizerEnabled() && mResizedObject) {
|
||||
// XXX If we're resizing something, we need to cancel or commit the
|
||||
// operation now.
|
||||
DebugOnly<nsresult> rv = HideResizers();
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HideResizers() failed");
|
||||
NS_ASSERTION(!mResizedObject, "HideResizers failed");
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLEditor::CheckSelectionStateForAnonymousButtons(Selection* aSelection)
|
||||
{
|
||||
if (NS_WARN_IF(!aSelection)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
nsresult rv = RefereshEditingUI(*aSelection);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLEditor::RefereshEditingUI(Selection& aSelection)
|
||||
{
|
||||
// First, we need to remove unnecessary editing UI now since some of them
|
||||
// may be disabled while them are visible.
|
||||
HideAnonymousEditingUIsIfUnnecessary();
|
||||
|
||||
// early way out if all contextual UI extensions are disabled
|
||||
if (NS_WARN_IF(!IsObjectResizerEnabled() &&
|
||||
!IsAbsolutePositionEditorEnabled() &&
|
||||
!IsInlineTableEditorEnabled())) {
|
||||
if (!IsObjectResizerEnabled() &&
|
||||
!IsAbsolutePositionEditorEnabled() &&
|
||||
!IsInlineTableEditorEnabled()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -306,7 +360,7 @@ HTMLEditor::CheckSelectionStateForAnonymousButtons(Selection* aSelection)
|
||||
}
|
||||
|
||||
// let's get the containing element of the selection
|
||||
RefPtr<Element> focusElement = GetSelectionContainerElement(*aSelection);
|
||||
RefPtr<Element> focusElement = GetSelectionContainerElement(aSelection);
|
||||
if (NS_WARN_IF(!focusElement)) {
|
||||
return NS_OK;
|
||||
}
|
||||
@ -331,7 +385,7 @@ HTMLEditor::CheckSelectionStateForAnonymousButtons(Selection* aSelection)
|
||||
// Resizing or Inline Table Editing is enabled, we need to check if the
|
||||
// selection is contained in a table cell
|
||||
cellElement =
|
||||
GetElementOrParentByTagNameAtSelection(*aSelection, *nsGkAtoms::td);
|
||||
GetElementOrParentByTagNameAtSelection(aSelection, *nsGkAtoms::td);
|
||||
}
|
||||
|
||||
if (IsObjectResizerEnabled() && cellElement) {
|
||||
@ -342,6 +396,9 @@ HTMLEditor::CheckSelectionStateForAnonymousButtons(Selection* aSelection)
|
||||
if (nsGkAtoms::img != focusTagAtom) {
|
||||
// the element container of the selection is not an image, so we'll show
|
||||
// the resizers around the table
|
||||
// XXX There may be a bug. cellElement may be not in <table> in invalid
|
||||
// tree. So, perhaps, GetEnclosingTable() returns nullptr, we should
|
||||
// not set focusTagAtom to nsGkAtoms::table.
|
||||
focusElement = GetEnclosingTable(cellElement);
|
||||
focusTagAtom = nsGkAtoms::table;
|
||||
}
|
||||
@ -369,15 +426,21 @@ HTMLEditor::CheckSelectionStateForAnonymousButtons(Selection* aSelection)
|
||||
|
||||
if (IsObjectResizerEnabled() && mResizedObject &&
|
||||
mResizedObject != focusElement) {
|
||||
// Perhaps, even if HideResizers() failed, we should try to hide inline
|
||||
// table editing UI. However, it returns error only when we cannot do
|
||||
// anything. So, it's okay for now.
|
||||
nsresult rv = HideResizers();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
NS_ASSERTION(!mResizedObject, "HideResizers failed");
|
||||
}
|
||||
|
||||
if (mIsInlineTableEditingEnabled && mInlineEditedCell &&
|
||||
if (IsInlineTableEditorEnabled() && mInlineEditedCell &&
|
||||
mInlineEditedCell != cellElement) {
|
||||
nsresult rv = HideInlineTableEditingUI();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// XXX HideInlineTableEditingUI() won't return error. Should be change it
|
||||
// void later.
|
||||
HideInlineTableEditingUI();
|
||||
NS_ASSERTION(!mInlineEditedCell, "HideInlineTableEditingUI failed");
|
||||
}
|
||||
|
||||
@ -417,7 +480,7 @@ HTMLEditor::CheckSelectionStateForAnonymousButtons(Selection* aSelection)
|
||||
}
|
||||
}
|
||||
|
||||
if (mIsInlineTableEditingEnabled && cellElement &&
|
||||
if (IsInlineTableEditorEnabled() && cellElement &&
|
||||
IsModifiableNode(*cellElement) && cellElement != hostContent) {
|
||||
if (mInlineEditedCell) {
|
||||
nsresult rv = RefreshInlineTableEditingUI();
|
||||
|
@ -258,20 +258,6 @@ HTMLEditor::~HTMLEditor()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLEditor::HideAnonymousEditingUIs()
|
||||
{
|
||||
if (mAbsolutelyPositionedObject) {
|
||||
HideGrabber();
|
||||
}
|
||||
if (mInlineEditedCell) {
|
||||
HideInlineTableEditingUI();
|
||||
}
|
||||
if (mResizedObject) {
|
||||
HideResizers();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLEditor)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLEditor, TextEditor)
|
||||
@ -434,9 +420,9 @@ HTMLEditor::NotifySelectionChanged(nsIDocument* aDocument,
|
||||
typeInState->OnSelectionChange(*aSelection);
|
||||
|
||||
// We used a class which derived from nsISelectionListener to call
|
||||
// HTMLEditor::CheckSelectionStateForAnonymousButtons(). The lifetime of
|
||||
// the class was exactly same as mTypeInState. So, call it only when
|
||||
// mTypeInState is not nullptr.
|
||||
// HTMLEditor::RefereshEditingUI(). The lifetime of the class was
|
||||
// exactly same as mTypeInState. So, call it only when mTypeInState
|
||||
// is not nullptr.
|
||||
if ((aReason & (nsISelectionListener::MOUSEDOWN_REASON |
|
||||
nsISelectionListener::KEYPRESS_REASON |
|
||||
nsISelectionListener::SELECTALL_REASON)) && aSelection) {
|
||||
@ -445,7 +431,8 @@ HTMLEditor::NotifySelectionChanged(nsIDocument* aDocument,
|
||||
// FYI: This is an XPCOM method. So, the caller, Selection, guarantees
|
||||
// the lifetime of this instance. So, don't need to grab this with
|
||||
// local variable.
|
||||
CheckSelectionStateForAnonymousButtons(aSelection);
|
||||
DebugOnly<nsresult> rv = RefereshEditingUI(*aSelection);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "RefereshEditingUI() failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,7 +227,15 @@ public:
|
||||
*/
|
||||
void EnableObjectResizer(bool aEnable)
|
||||
{
|
||||
if (mIsObjectResizingEnabled == aEnable) {
|
||||
return;
|
||||
}
|
||||
mIsObjectResizingEnabled = aEnable;
|
||||
RefPtr<Selection> selection = GetSelection();
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return;
|
||||
}
|
||||
RefereshEditingUI(*selection);
|
||||
}
|
||||
bool IsObjectResizerEnabled() const
|
||||
{
|
||||
@ -240,7 +248,15 @@ public:
|
||||
*/
|
||||
void EnableInlineTableEditor(bool aEnable)
|
||||
{
|
||||
if (mIsInlineTableEditingEnabled == aEnable) {
|
||||
return;
|
||||
}
|
||||
mIsInlineTableEditingEnabled = aEnable;
|
||||
RefPtr<Selection> selection = GetSelection();
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return;
|
||||
}
|
||||
RefereshEditingUI(*selection);
|
||||
}
|
||||
bool IsInlineTableEditorEnabled() const
|
||||
{
|
||||
@ -254,7 +270,15 @@ public:
|
||||
*/
|
||||
void EnableAbsolutePositionEditor(bool aEnable)
|
||||
{
|
||||
if (mIsAbsolutelyPositioningEnabled == aEnable) {
|
||||
return;
|
||||
}
|
||||
mIsAbsolutelyPositioningEnabled = aEnable;
|
||||
RefPtr<Selection> selection = GetSelection();
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return;
|
||||
}
|
||||
RefereshEditingUI(*selection);
|
||||
}
|
||||
bool IsAbsolutePositionEditorEnabled() const
|
||||
{
|
||||
@ -1510,6 +1534,13 @@ protected: // Shouldn't be used by friend classes
|
||||
void DeleteRefToAnonymousNode(ManualNACPtr aContent,
|
||||
nsIPresShell* aShell);
|
||||
|
||||
/**
|
||||
* RefereshEditingUI() may refresh editing UIs for current Selection, focus,
|
||||
* etc. If this shows or hides some UIs, it causes reflow. So, this is
|
||||
* not safe method.
|
||||
*/
|
||||
nsresult RefereshEditingUI(Selection& aSelection);
|
||||
|
||||
nsresult ShowResizersInner(Element& aResizedElement);
|
||||
|
||||
/**
|
||||
@ -1570,8 +1601,19 @@ protected: // Shouldn't be used by friend classes
|
||||
void SetFinalSize(int32_t aX, int32_t aY);
|
||||
void SetResizeIncrements(int32_t aX, int32_t aY, int32_t aW, int32_t aH,
|
||||
bool aPreserveRatio);
|
||||
|
||||
/**
|
||||
* HideAnonymousEditingUIs() forcibly hides all editing UIs (resizers,
|
||||
* inline-table-editing UI, absolute positioning UI).
|
||||
*/
|
||||
void HideAnonymousEditingUIs();
|
||||
|
||||
/**
|
||||
* HideAnonymousEditingUIsIfUnnecessary() hides all editing UIs if some of
|
||||
* visible UIs are now unnecessary.
|
||||
*/
|
||||
void HideAnonymousEditingUIsIfUnnecessary();
|
||||
|
||||
/**
|
||||
* sets the z-index of an element.
|
||||
* @param aElement [IN] the element
|
||||
@ -1612,7 +1654,7 @@ protected: // Shouldn't be used by friend classes
|
||||
/**
|
||||
* Hide all inline table editing UI
|
||||
*/
|
||||
nsresult HideInlineTableEditingUI();
|
||||
void HideInlineTableEditingUI();
|
||||
|
||||
/**
|
||||
* IsEmptyTextNode() returns true if aNode is a text node and does not have
|
||||
|
@ -94,7 +94,7 @@ HTMLEditor::ShowInlineTableEditingUI(Element* aCell)
|
||||
return RefreshInlineTableEditingUI();
|
||||
}
|
||||
|
||||
nsresult
|
||||
void
|
||||
HTMLEditor::HideInlineTableEditingUI()
|
||||
{
|
||||
mInlineEditedCell = nullptr;
|
||||
@ -112,14 +112,23 @@ HTMLEditor::HideInlineTableEditingUI()
|
||||
// are no document observers to notify, but we still want to
|
||||
// UnbindFromTree.
|
||||
|
||||
DeleteRefToAnonymousNode(std::move(mAddColumnBeforeButton), ps);
|
||||
DeleteRefToAnonymousNode(std::move(mRemoveColumnButton), ps);
|
||||
DeleteRefToAnonymousNode(std::move(mAddColumnAfterButton), ps);
|
||||
DeleteRefToAnonymousNode(std::move(mAddRowBeforeButton), ps);
|
||||
DeleteRefToAnonymousNode(std::move(mRemoveRowButton), ps);
|
||||
DeleteRefToAnonymousNode(std::move(mAddRowAfterButton), ps);
|
||||
// Calling DeleteRefToAnonymousNode() may cause showing the UI again.
|
||||
// Therefore, we should forget all anonymous contents first.
|
||||
// Otherwise, we could leak the old content because of overwritten by
|
||||
// ShowInlineTableEditingUI().
|
||||
ManualNACPtr addColumnBeforeButton(std::move(mAddColumnBeforeButton));
|
||||
ManualNACPtr removeColumnButton(std::move(mRemoveColumnButton));
|
||||
ManualNACPtr addColumnAfterButton(std::move(mAddColumnAfterButton));
|
||||
ManualNACPtr addRowBeforeButton(std::move(mAddRowBeforeButton));
|
||||
ManualNACPtr removeRowButton(std::move(mRemoveRowButton));
|
||||
ManualNACPtr addRowAfterButton(std::move(mAddRowAfterButton));
|
||||
|
||||
return NS_OK;
|
||||
DeleteRefToAnonymousNode(std::move(addColumnBeforeButton), ps);
|
||||
DeleteRefToAnonymousNode(std::move(removeColumnButton), ps);
|
||||
DeleteRefToAnonymousNode(std::move(addColumnAfterButton), ps);
|
||||
DeleteRefToAnonymousNode(std::move(addRowBeforeButton), ps);
|
||||
DeleteRefToAnonymousNode(std::move(removeRowButton), ps);
|
||||
DeleteRefToAnonymousNode(std::move(addRowAfterButton), ps);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -78,6 +78,16 @@ SimpleTest.waitForFocus(async function() {
|
||||
is(target.hasAttribute("_moz_abspos"), kTest.movable,
|
||||
kDescription + (kTest.movable ? "While enableAbsolutePositionEditing is enabled, positioner should appear" :
|
||||
"Even while enableAbsolutePositionEditing is enabled, positioner shouldn't appear"));
|
||||
|
||||
document.execCommand("enableAbsolutePositionEditing", false, false);
|
||||
ok(!target.hasAttribute("_moz_abspos"),
|
||||
kDescription + "When enableAbsolutePositionEditing is disabled even while positioner is visible, positioner should disappear");
|
||||
|
||||
document.execCommand("enableAbsolutePositionEditing", false, true);
|
||||
is(target.hasAttribute("_moz_abspos"), kTest.movable,
|
||||
kDescription + (kTest.movable ?
|
||||
"When enableAbsolutePositionEditing is enabled when absolute positioned element is selected, positioner should appear" :
|
||||
"Even if enableAbsolutePositionEditing is enabled when static positioned element is selected, positioner shouldn't appear"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,6 +89,15 @@ SimpleTest.waitForFocus(async function() {
|
||||
is(target.hasAttribute("_moz_resizing"), kResizable,
|
||||
kDescription + (kResizable ? "While enableObjectResizing is enabled, resizers should appear" :
|
||||
"Even while enableObjectResizing is enabled, resizers shouldn't appear"));
|
||||
|
||||
document.execCommand("enableObjectResizing", false, false);
|
||||
ok(!target.hasAttribute("_moz_resizing"),
|
||||
kDescription + "enableObjectResizing is disabled even while resizers are visible, resizers should disappear");
|
||||
|
||||
document.execCommand("enableObjectResizing", false, true);
|
||||
is(target.hasAttribute("_moz_resizing"), kResizable,
|
||||
kDescription + (kResizable ? "enableObjectResizing is enabled when resizable object is selected, resizers should appear" :
|
||||
"Even if enableObjectResizing is enabled when non-resizable object is selected, resizers shouldn't appear"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -399,9 +399,14 @@ interface nsIHTMLEditor : nsISupports
|
||||
attribute boolean isCSSEnabled;
|
||||
|
||||
/**
|
||||
* Checks if the anonymous nodes created by the HTML editor have to be
|
||||
* refreshed or hidden depending on a possible new state of the selection
|
||||
* @param aSelection [IN] a selection
|
||||
* checkSelectionStateForAnonymousButtons() may refresh editing UI such as
|
||||
* resizers, inline-table-editing UI, absolute positioning UI for current
|
||||
* Selection and focus state. When this method shows or hides UI, the
|
||||
* editor (and/or its document/window) could be broken by mutation observers.
|
||||
* FYI: Current user in script is only BlueGriffon.
|
||||
*
|
||||
* @param aSelection Selection instance for the normal selection of the
|
||||
* document.
|
||||
*/
|
||||
void checkSelectionStateForAnonymousButtons(in Selection aSelection);
|
||||
|
||||
|
@ -773,8 +773,15 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
|
||||
|
||||
mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
|
||||
|
||||
// If id namespaces do not match, it means the command is obsolete, probably
|
||||
// because the tab just moved to a new window.
|
||||
// In that case do not send the commands to webrender.
|
||||
bool validTransaction = aIdNamespace == mIdNamespace;
|
||||
wr::TransactionBuilder txn;
|
||||
wr::AutoTransactionSender sender(mApi, &txn);
|
||||
Maybe<wr::AutoTransactionSender> sender;
|
||||
if (validTransaction) {
|
||||
sender.emplace(mApi, &txn);
|
||||
}
|
||||
|
||||
ProcessWebRenderParentCommands(aCommands, txn);
|
||||
|
||||
@ -795,10 +802,7 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
|
||||
|
||||
wr::Vec<uint8_t> dlData(std::move(dl));
|
||||
|
||||
// If id namespaces do not match, it means the command is obsolete, probably
|
||||
// because the tab just moved to a new window.
|
||||
// In that case do not send the commands to webrender.
|
||||
if (mIdNamespace == aIdNamespace) {
|
||||
if (validTransaction) {
|
||||
if (IsRootWebRenderBridgeParent()) {
|
||||
LayoutDeviceIntSize widgetSize = mWidget->GetClientSize();
|
||||
LayoutDeviceIntRect docRect(LayoutDeviceIntPoint(), widgetSize);
|
||||
@ -817,7 +821,7 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
|
||||
|
||||
HoldPendingTransactionId(wrEpoch, aTransactionId, aRefreshStartTime, aTxnStartTime, aFwdTime);
|
||||
|
||||
if (mIdNamespace != aIdNamespace) {
|
||||
if (!validTransaction) {
|
||||
// Pretend we composited since someone is wating for this event,
|
||||
// though DisplayList was not pushed to webrender.
|
||||
if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
typedef uint32_t HashNumber;
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/Conversions.h"
|
||||
#include "js/Initialization.h"
|
||||
|
@ -5333,6 +5333,15 @@ BaselineCompile(JSContext* cx, unsigned argc, Value* vp)
|
||||
|
||||
const char* returnedStr = nullptr;
|
||||
do {
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
// In order to check for differential behaviour, baselineCompile should have
|
||||
// the same output whether --no-baseline is used or not.
|
||||
if (fuzzingSafe) {
|
||||
returnedStr = "skipped (fuzzing-safe)";
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
AutoRealm ar(cx, script);
|
||||
if (script->hasBaselineScript()) {
|
||||
if (forceDebug && !script->baselineScript()->hasDebugInstrumentation()) {
|
||||
@ -6056,7 +6065,8 @@ gc::ZealModeHelpText),
|
||||
" that extra boilerplate is needed afterwards to cause the VM to start\n"
|
||||
" running the jitcode rather than staying in the interpreter:\n"
|
||||
" baselineCompile(); for (var i=0; i<1; i++) {} ...\n"
|
||||
" The interpreter will enter the new jitcode at the loop header.\n"),
|
||||
" The interpreter will enter the new jitcode at the loop header unless\n"
|
||||
" baselineCompile returned a string or threw an error.\n"),
|
||||
|
||||
JS_FS_HELP_END
|
||||
};
|
||||
|
32
js/src/jit-test/tests/debug/Debugger-debuggees-30.js
Normal file
32
js/src/jit-test/tests/debug/Debugger-debuggees-30.js
Normal file
@ -0,0 +1,32 @@
|
||||
// Debugger and debuggees must be in different compartments.
|
||||
|
||||
load(libdir + "asserts.js");
|
||||
|
||||
function testConstructor() {
|
||||
var g = newGlobal({sameCompartmentAs: this});
|
||||
assertTypeErrorMessage(() => new Debugger(g),
|
||||
"Debugger: argument must be an object from a different compartment");
|
||||
}
|
||||
testConstructor();
|
||||
|
||||
function testAddDebuggee() {
|
||||
var g = newGlobal({sameCompartmentAs: this});
|
||||
var dbg = new Debugger();
|
||||
assertTypeErrorMessage(() => dbg.addDebuggee(this),
|
||||
"debugger and debuggee must be in different compartments");
|
||||
}
|
||||
testAddDebuggee();
|
||||
|
||||
function testAddAllGlobalsAsDebuggees() {
|
||||
var g1 = newGlobal({sameCompartmentAs: this});
|
||||
var g2 = newGlobal();
|
||||
var g3 = newGlobal({sameCompartmentAs: g2});
|
||||
var g4 = newGlobal({sameZoneAs: this});
|
||||
var dbg = new Debugger();
|
||||
dbg.addAllGlobalsAsDebuggees();
|
||||
assertEq(dbg.hasDebuggee(g1), false);
|
||||
assertEq(dbg.hasDebuggee(g2), true);
|
||||
assertEq(dbg.hasDebuggee(g3), true);
|
||||
assertEq(dbg.hasDebuggee(g4), true);
|
||||
}
|
||||
testAddAllGlobalsAsDebuggees();
|
6
js/src/jit-test/tests/realms/bug1479430.js
Normal file
6
js/src/jit-test/tests/realms/bug1479430.js
Normal file
@ -0,0 +1,6 @@
|
||||
function f(a) {
|
||||
return a.toString();
|
||||
}
|
||||
var g = newGlobal({sameCompartmentAs: this});
|
||||
g.evaluate("function Obj() {}");
|
||||
f(f(new g.Obj()));
|
@ -1,9 +1,10 @@
|
||||
// |jit-test| test-also=--fuzzing-safe
|
||||
// Check that the help text for baselineCompile() is accurate.
|
||||
|
||||
if (typeof inJit == "function" && typeof baselineCompile == "function") {
|
||||
if (!inJit()) {
|
||||
|
||||
baselineCompile(); // compile the current script
|
||||
var res = baselineCompile(); // compile the current script
|
||||
|
||||
assertEq(inJit(), false,
|
||||
"We have compiled this script to baseline jitcode, but shouldn't " +
|
||||
@ -13,7 +14,7 @@ if (typeof inJit == "function" && typeof baselineCompile == "function") {
|
||||
|
||||
for (var i=0; i<1; i++) {} // exact boilerplate suggested by the help text
|
||||
|
||||
assertEq(inJit(), true,
|
||||
assertEq(typeof res != "string" ? inJit() : true, true,
|
||||
"help text in TestingFunctions.cpp claims the above loop causes " +
|
||||
"the interpreter to start running the new baseline jitcode");
|
||||
}
|
||||
|
@ -4563,7 +4563,7 @@ CodeGenerator::visitCallDOMNative(LCallDOMNative* call)
|
||||
MOZ_ASSERT(obj == argObj);
|
||||
|
||||
// Push a Value containing the callee object: natives are allowed to access their callee before
|
||||
// setitng the return value. After this the StackPointer points to &vp[0].
|
||||
// setting the return value. After this the StackPointer points to &vp[0].
|
||||
masm.Push(ObjectValue(*target->rawJSFunction()));
|
||||
|
||||
// Now compute the argv value. Since StackPointer is pointing to &vp[0] and
|
||||
|
@ -2087,6 +2087,7 @@ IonCompile(JSContext* cx, JSScript* script,
|
||||
const MIRGenerator::ObjectGroupVector& groups = builder->abortedPreliminaryGroups();
|
||||
for (size_t i = 0; i < groups.length(); i++) {
|
||||
ObjectGroup* group = groups[i];
|
||||
AutoRealm ar(cx, group);
|
||||
AutoSweepObjectGroup sweep(group);
|
||||
if (auto* newScript = group->newScript(sweep)) {
|
||||
if (!newScript->maybeAnalyze(cx, group, nullptr, /* force = */ true))
|
||||
|
@ -93,7 +93,7 @@ JSJitFrameIter::callee() const
|
||||
JSFunction*
|
||||
JSJitFrameIter::maybeCallee() const
|
||||
{
|
||||
if (isScripted() && (isFunctionFrame()))
|
||||
if (isScripted() && isFunctionFrame())
|
||||
return callee();
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -190,6 +190,7 @@ class OsiIndex
|
||||
// [ frame size | has cached saved frame bit | frame header size | frame type ]
|
||||
// < highest - - - - - - - - - - - - - - lowest >
|
||||
static const uintptr_t FRAMETYPE_BITS = 4;
|
||||
static const uintptr_t FRAMETYPE_MASK = (1 << FRAMETYPE_BITS) - 1;
|
||||
static const uintptr_t FRAME_HEADER_SIZE_SHIFT = FRAMETYPE_BITS;
|
||||
static const uintptr_t FRAME_HEADER_SIZE_BITS = 3;
|
||||
static const uintptr_t FRAME_HEADER_SIZE_MASK = (1 << FRAME_HEADER_SIZE_BITS) - 1;
|
||||
@ -342,8 +343,6 @@ class CommonFrameLayout
|
||||
uint8_t* returnAddress_;
|
||||
uintptr_t descriptor_;
|
||||
|
||||
static const uintptr_t FrameTypeMask = (1 << FRAMETYPE_BITS) - 1;
|
||||
|
||||
public:
|
||||
static size_t offsetOfDescriptor() {
|
||||
return offsetof(CommonFrameLayout, descriptor_);
|
||||
@ -355,10 +354,10 @@ class CommonFrameLayout
|
||||
return offsetof(CommonFrameLayout, returnAddress_);
|
||||
}
|
||||
FrameType prevType() const {
|
||||
return FrameType(descriptor_ & FrameTypeMask);
|
||||
return FrameType(descriptor_ & FRAMETYPE_MASK);
|
||||
}
|
||||
void changePrevType(FrameType type) {
|
||||
descriptor_ &= ~FrameTypeMask;
|
||||
descriptor_ &= ~FRAMETYPE_MASK;
|
||||
descriptor_ |= type;
|
||||
}
|
||||
size_t prevFrameLocalSize() const {
|
||||
|
@ -658,6 +658,8 @@ class LSafepoint;
|
||||
class LInstruction;
|
||||
class LElementVisitor;
|
||||
|
||||
constexpr size_t MaxNumLInstructionOperands = 63;
|
||||
|
||||
// The common base class for LPhi and LInstruction.
|
||||
class LNode
|
||||
{
|
||||
@ -672,9 +674,12 @@ class LNode
|
||||
// Bitfields below are all uint32_t to make sure MSVC packs them correctly.
|
||||
uint32_t op_ : 10;
|
||||
uint32_t isCall_ : 1;
|
||||
|
||||
// LPhi::numOperands() may not fit in this bitfield, so we only use this
|
||||
// field for LInstruction.
|
||||
uint32_t nonPhiNumOperands_ : 6;
|
||||
static_assert((1 << 6) - 1 == MaxNumLInstructionOperands, "packing constraints");
|
||||
|
||||
// For LInstruction, the first operand is stored at offset
|
||||
// sizeof(LInstruction) + nonPhiOperandsOffset_ * sizeof(uintptr_t).
|
||||
uint32_t nonPhiOperandsOffset_ : 5;
|
||||
|
@ -2656,7 +2656,7 @@ IonBuilder::inlineGuardToClass(CallInfo& callInfo, const Class* clasp)
|
||||
{
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
|
||||
TemporaryTypeSet* types = callInfo.getArg(0)->resultTypeSet();
|
||||
const Class* knownClass = types ? types->getKnownClass(constraints()) : nullptr;
|
||||
|
||||
|
@ -239,8 +239,8 @@ class MUse : public TempObject, public InlineListNode<MUse>
|
||||
|
||||
#ifdef DEBUG
|
||||
// Return the operand index of this MUse in its consumer. This is DEBUG-only
|
||||
// as normal code should instead to call indexOf on the casted consumer
|
||||
// directly, to allow it to be devirtualized and inlined.
|
||||
// as normal code should instead call indexOf on the cast consumer directly,
|
||||
// to allow it to be devirtualized and inlined.
|
||||
size_t index() const;
|
||||
#endif
|
||||
};
|
||||
|
@ -828,7 +828,6 @@ LIRGeneratorShared::useBoxOrTyped(MDefinition* mir)
|
||||
if (mir->type() == MIRType::Value)
|
||||
return useBox(mir);
|
||||
|
||||
|
||||
#if defined(JS_NUNBOX32)
|
||||
return LBoxAllocation(useRegister(mir), LAllocation());
|
||||
#else
|
||||
|
@ -301,9 +301,6 @@ CodeGenerator::visitWasmStackArg(LWasmStackArg* ins)
|
||||
case MIRType::Float32:
|
||||
masm.storeFloat32(ToFloatRegister(ins->arg()), dst);
|
||||
return;
|
||||
case MIRType::Int32x4:
|
||||
case MIRType::Bool32x4:
|
||||
case MIRType::Float32x4:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -335,7 +335,7 @@ MacroAssembler::flexibleDivMod32(Register rhs, Register lhsOutput, Register remO
|
||||
MOZ_ASSERT(lhsOutput != remOutput);
|
||||
|
||||
// Choose a register that is not edx, or eax to hold the rhs;
|
||||
// ebx is chosen arbitrarily, and will be preserved if necessary.
|
||||
// ebx is chosen arbitrarily, and will be preserved if necessary.
|
||||
Register regForRhs = (rhs == eax || rhs == edx) ? ebx : rhs;
|
||||
|
||||
// Add registers we will be clobbering as live, but
|
||||
|
@ -461,6 +461,7 @@ MSG_DEF(JSMSG_DEBUG_BAD_REFERENT, 2, JSEXN_TYPEERR, "{0} does not refer to
|
||||
MSG_DEF(JSMSG_DEBUG_BAD_RESUMPTION, 0, JSEXN_TYPEERR, "debugger resumption value must be undefined, {throw: val}, {return: val}, or null")
|
||||
MSG_DEF(JSMSG_DEBUG_BAD_YIELD, 0, JSEXN_TYPEERR, "generator yielded invalid value")
|
||||
MSG_DEF(JSMSG_DEBUG_CANT_DEBUG_GLOBAL, 0, JSEXN_TYPEERR, "passing non-debuggable global to addDebuggee")
|
||||
MSG_DEF(JSMSG_DEBUG_SAME_COMPARTMENT, 0, JSEXN_TYPEERR, "debugger and debuggee must be in different compartments")
|
||||
MSG_DEF(JSMSG_DEBUG_CCW_REQUIRED, 1, JSEXN_TYPEERR, "{0}: argument must be an object from a different compartment")
|
||||
MSG_DEF(JSMSG_DEBUG_COMPARTMENT_MISMATCH, 2, JSEXN_TYPEERR, "{0}: descriptor .{1} property is an object in a different compartment than the target object")
|
||||
MSG_DEF(JSMSG_DEBUG_LOOP, 0, JSEXN_TYPEERR, "cannot debug an object in same compartment as debugger or a compartment that is already debugging the debugger")
|
||||
|
@ -3723,9 +3723,11 @@ Debugger::addDebuggee(JSContext* cx, unsigned argc, Value* vp)
|
||||
Debugger::addAllGlobalsAsDebuggees(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
THIS_DEBUGGER(cx, argc, vp, "addAllGlobalsAsDebuggees", args, dbg);
|
||||
for (ZonesIter zone(cx->runtime(), SkipAtoms); !zone.done(); zone.next()) {
|
||||
for (RealmsInZoneIter r(zone); !r.done(); r.next()) {
|
||||
if (r == dbg->object->realm() || r->creationOptions().invisibleToDebugger())
|
||||
for (CompartmentsIter comp(cx->runtime()); !comp.done(); comp.next()) {
|
||||
if (comp == dbg->object->compartment())
|
||||
continue;
|
||||
for (RealmsInCompartmentIter r(comp); !r.done(); r.next()) {
|
||||
if (r->creationOptions().invisibleToDebugger())
|
||||
continue;
|
||||
r->compartment()->gcState.scheduledForDestruction = false;
|
||||
GlobalObject* global = r->maybeGlobal();
|
||||
@ -3921,7 +3923,7 @@ Debugger::construct(JSContext* cx, unsigned argc, Value* vp)
|
||||
// Add the initial debuggees, if any.
|
||||
for (unsigned i = 0; i < args.length(); i++) {
|
||||
JSObject& wrappedObj = args[i].toObject().as<ProxyObject>().private_().toObject();
|
||||
Rooted<GlobalObject*> debuggee(cx, &wrappedObj.deprecatedGlobal());
|
||||
Rooted<GlobalObject*> debuggee(cx, &wrappedObj.nonCCWGlobal());
|
||||
if (!debugger->addDebuggeeGlobal(cx, debuggee))
|
||||
return false;
|
||||
}
|
||||
@ -3946,6 +3948,12 @@ Debugger::addDebuggeeGlobal(JSContext* cx, Handle<GlobalObject*> global)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Debugger and debuggee must be in different compartments.
|
||||
if (debuggeeRealm->compartment() == object->compartment()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_SAME_COMPARTMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for cycles. If global's realm is reachable from this Debugger
|
||||
// object's realm by following debuggee-to-debugger links, then adding
|
||||
// global would create a cycle. (Typically nobody is debugging the
|
||||
|
@ -648,7 +648,7 @@ LazyStubTier::createMany(HasGcTypes gcTypesEnabled, const Uint32Vector& funcExpo
|
||||
const FuncExport& fe = funcExports[funcExportIndex];
|
||||
numExpectedRanges += fe.funcType().temporarilyUnsupportedAnyRef() ? 1 : 2;
|
||||
void* calleePtr = moduleSegmentBase +
|
||||
moduleRanges[fe.interpCodeRangeIndex()].funcNormalEntry();
|
||||
moduleRanges[fe.funcCodeRangeIndex()].funcNormalEntry();
|
||||
Maybe<ImmPtr> callee;
|
||||
callee.emplace(calleePtr, ImmPtr::NoCheckToken());
|
||||
if (!GenerateEntryStubs(masm, funcExportIndex, fe, callee, /* asmjs */ false,
|
||||
@ -803,7 +803,7 @@ LazyStubTier::lookupInterpEntry(uint32_t funcIndex) const
|
||||
&match));
|
||||
const LazyFuncExport& fe = exports_[match];
|
||||
const LazyStubSegment& stub = *stubSegments_[fe.lazyStubSegmentIndex];
|
||||
return stub.base() + stub.codeRanges()[fe.interpCodeRangeIndex].begin();
|
||||
return stub.base() + stub.codeRanges()[fe.funcCodeRangeIndex].begin();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -190,7 +190,7 @@ class FuncExport
|
||||
FuncType funcType_;
|
||||
MOZ_INIT_OUTSIDE_CTOR struct CacheablePod {
|
||||
uint32_t funcIndex_;
|
||||
uint32_t interpCodeRangeIndex_;
|
||||
uint32_t funcCodeRangeIndex_;
|
||||
uint32_t eagerInterpEntryOffset_; // Machine code offset
|
||||
bool hasEagerStubs_;
|
||||
} pod;
|
||||
@ -201,7 +201,7 @@ class FuncExport
|
||||
: funcType_(std::move(funcType))
|
||||
{
|
||||
pod.funcIndex_ = funcIndex;
|
||||
pod.interpCodeRangeIndex_ = UINT32_MAX;
|
||||
pod.funcCodeRangeIndex_ = UINT32_MAX;
|
||||
pod.eagerInterpEntryOffset_ = UINT32_MAX;
|
||||
pod.hasEagerStubs_ = hasEagerStubs;
|
||||
}
|
||||
@ -210,9 +210,9 @@ class FuncExport
|
||||
MOZ_ASSERT(hasEagerStubs());
|
||||
pod.eagerInterpEntryOffset_ = entryOffset;
|
||||
}
|
||||
void initInterpCodeRangeIndex(uint32_t codeRangeIndex) {
|
||||
MOZ_ASSERT(pod.interpCodeRangeIndex_ == UINT32_MAX);
|
||||
pod.interpCodeRangeIndex_ = codeRangeIndex;
|
||||
void initFuncCodeRangeIndex(uint32_t codeRangeIndex) {
|
||||
MOZ_ASSERT(pod.funcCodeRangeIndex_ == UINT32_MAX);
|
||||
pod.funcCodeRangeIndex_ = codeRangeIndex;
|
||||
}
|
||||
|
||||
bool hasEagerStubs() const {
|
||||
@ -224,9 +224,9 @@ class FuncExport
|
||||
uint32_t funcIndex() const {
|
||||
return pod.funcIndex_;
|
||||
}
|
||||
uint32_t interpCodeRangeIndex() const {
|
||||
MOZ_ASSERT(pod.interpCodeRangeIndex_ != UINT32_MAX);
|
||||
return pod.interpCodeRangeIndex_;
|
||||
uint32_t funcCodeRangeIndex() const {
|
||||
MOZ_ASSERT(pod.funcCodeRangeIndex_ != UINT32_MAX);
|
||||
return pod.funcCodeRangeIndex_;
|
||||
}
|
||||
uint32_t eagerInterpEntryOffset() const {
|
||||
MOZ_ASSERT(pod.eagerInterpEntryOffset_ != UINT32_MAX);
|
||||
@ -532,11 +532,11 @@ struct LazyFuncExport
|
||||
{
|
||||
size_t funcIndex;
|
||||
size_t lazyStubSegmentIndex;
|
||||
size_t interpCodeRangeIndex;
|
||||
LazyFuncExport(size_t funcIndex, size_t lazyStubSegmentIndex, size_t interpCodeRangeIndex)
|
||||
size_t funcCodeRangeIndex;
|
||||
LazyFuncExport(size_t funcIndex, size_t lazyStubSegmentIndex, size_t funcCodeRangeIndex)
|
||||
: funcIndex(funcIndex),
|
||||
lazyStubSegmentIndex(lazyStubSegmentIndex),
|
||||
interpCodeRangeIndex(interpCodeRangeIndex)
|
||||
funcCodeRangeIndex(funcCodeRangeIndex)
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -862,7 +862,7 @@ ModuleGenerator::finishMetadata(const ShareableBytes& bytecode)
|
||||
// now that every function has a code range.
|
||||
|
||||
for (FuncExport& fe : metadataTier_->funcExports)
|
||||
fe.initInterpCodeRangeIndex(funcToCodeRange_[fe.funcIndex()]);
|
||||
fe.initFuncCodeRangeIndex(funcToCodeRange_[fe.funcIndex()]);
|
||||
|
||||
for (ElemSegment& elems : env_->elemSegments) {
|
||||
Uint32Vector& codeRangeIndices = elems.elemCodeRangeIndices(tier());
|
||||
|
@ -118,7 +118,7 @@ class Instance
|
||||
#endif
|
||||
|
||||
// This method returns a pointer to the GC object that owns this Instance.
|
||||
// Instances may be reached via weak edges (e.g., Compartment::instances_)
|
||||
// Instances may be reached via weak edges (e.g., Realm::instances_)
|
||||
// so this perform a read-barrier on the returned object unless the barrier
|
||||
// is explicitly waived.
|
||||
|
||||
|
@ -1384,7 +1384,7 @@ WasmInstanceObject::getExportedFunctionCodeRange(HandleFunction fun, Tier tier)
|
||||
uint32_t funcIndex = ExportedFunctionToFuncIndex(fun);
|
||||
MOZ_ASSERT(exports().lookup(funcIndex)->value() == fun);
|
||||
const FuncExport& funcExport = instance().metadata(tier).lookupFuncExport(funcIndex);
|
||||
return instance().metadata(tier).codeRanges[funcExport.interpCodeRangeIndex()];
|
||||
return instance().metadata(tier).codeRanges[funcExport.funcCodeRangeIndex()];
|
||||
}
|
||||
|
||||
/* static */ WasmInstanceScope*
|
||||
@ -2051,7 +2051,7 @@ WasmTableObject::setImpl(JSContext* cx, const CallArgs& args)
|
||||
Tier tier = instance.code().bestTier();
|
||||
const MetadataTier& metadata = instance.metadata(tier);
|
||||
const FuncExport& funcExport = metadata.lookupFuncExport(funcIndex);
|
||||
const CodeRange& codeRange = metadata.codeRanges[funcExport.interpCodeRangeIndex()];
|
||||
const CodeRange& codeRange = metadata.codeRanges[funcExport.funcCodeRangeIndex()];
|
||||
void* code = instance.codeBase(tier) + codeRange.funcTableEntry();
|
||||
table.set(index, code, instance);
|
||||
} else {
|
||||
|
@ -229,23 +229,26 @@ wasm::UnregisterCodeSegment(const CodeSegment* cs)
|
||||
}
|
||||
|
||||
const CodeSegment*
|
||||
wasm::LookupCodeSegment(const void* pc, const CodeRange** cr /*= nullptr */)
|
||||
wasm::LookupCodeSegment(const void* pc, const CodeRange** codeRange /*= nullptr */)
|
||||
{
|
||||
if (const CodeSegment* found = processCodeSegmentMap.lookup(pc)) {
|
||||
if (cr) {
|
||||
*cr = found->isModule()
|
||||
? found->asModule()->lookupRange(pc)
|
||||
: found->asLazyStub()->lookupRange(pc);
|
||||
if (codeRange) {
|
||||
*codeRange = found->isModule()
|
||||
? found->asModule()->lookupRange(pc)
|
||||
: found->asLazyStub()->lookupRange(pc);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
if (codeRange)
|
||||
*codeRange = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Code*
|
||||
wasm::LookupCode(const void* pc, const CodeRange** cr /* = nullptr */)
|
||||
wasm::LookupCode(const void* pc, const CodeRange** codeRange /* = nullptr */)
|
||||
{
|
||||
const CodeSegment* found = LookupCodeSegment(pc, cr);
|
||||
const CodeSegment* found = LookupCodeSegment(pc, codeRange);
|
||||
MOZ_ASSERT_IF(!found && codeRange, !*codeRange);
|
||||
return found ? &found->code() : nullptr;
|
||||
}
|
||||
|
||||
|
@ -1853,6 +1853,18 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The mCallee holds a strong ref to us since the refresh driver doesn't.
|
||||
* Our dtor and mCallee's Destroy() method both call RemoveObserver() -
|
||||
* whichever comes first removes us from the refresh driver.
|
||||
*/
|
||||
void RemoveObserver() {
|
||||
if (mCallee) {
|
||||
RefreshDriver(mCallee)->RemoveRefreshObserver(this, FlushType::Style);
|
||||
mCallee = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Private destructor, to discourage deletion outside of Release():
|
||||
~AsyncSmoothMSDScroll() {
|
||||
@ -1865,17 +1877,6 @@ private:
|
||||
return aCallee->mOuter->PresContext()->RefreshDriver();
|
||||
}
|
||||
|
||||
/*
|
||||
* The refresh driver doesn't hold a reference to its observers,
|
||||
* so releasing this object can (and is) used to remove the observer on DTOR.
|
||||
* Currently, this object is released once the scrolling ends.
|
||||
*/
|
||||
void RemoveObserver() {
|
||||
if (mCallee) {
|
||||
RefreshDriver(mCallee)->RemoveRefreshObserver(this, FlushType::Style);
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::layers::AxisPhysicsMSDModel mXAxisModel, mYAxisModel;
|
||||
nsRect mRange;
|
||||
mozilla::TimeStamp mLastRefreshTime;
|
||||
@ -1974,17 +1975,10 @@ public:
|
||||
ScrollFrameHelper::AsyncScrollCallback(mCallee, aTime);
|
||||
}
|
||||
|
||||
private:
|
||||
ScrollFrameHelper *mCallee;
|
||||
|
||||
nsRefreshDriver* RefreshDriver(ScrollFrameHelper* aCallee) {
|
||||
return aCallee->mOuter->PresContext()->RefreshDriver();
|
||||
}
|
||||
|
||||
/*
|
||||
* The refresh driver doesn't hold a reference to its observers,
|
||||
* so releasing this object can (and is) used to remove the observer on DTOR.
|
||||
* Currently, this object is released once the scrolling ends.
|
||||
/**
|
||||
* The mCallee holds a strong ref to us since the refresh driver doesn't.
|
||||
* Our dtor and mCallee's Destroy() method both call RemoveObserver() -
|
||||
* whichever comes first removes us from the refresh driver.
|
||||
*/
|
||||
void RemoveObserver() {
|
||||
if (mCallee) {
|
||||
@ -1992,8 +1986,15 @@ private:
|
||||
if (nsIPresShell* shell = mCallee->mOuter->PresShell()) {
|
||||
shell->SuppressDisplayport(false);
|
||||
}
|
||||
mCallee = nullptr;
|
||||
}
|
||||
}
|
||||
private:
|
||||
ScrollFrameHelper *mCallee;
|
||||
|
||||
nsRefreshDriver* RefreshDriver(ScrollFrameHelper* aCallee) {
|
||||
return aCallee->mOuter->PresContext()->RefreshDriver();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@ -4891,6 +4892,12 @@ ScrollFrameHelper::Destroy(PostDestroyData& aPostDestroyData)
|
||||
mScrollActivityTimer->Cancel();
|
||||
mScrollActivityTimer = nullptr;
|
||||
}
|
||||
if (mAsyncScroll) {
|
||||
mAsyncScroll->RemoveObserver();
|
||||
}
|
||||
if (mAsyncSmoothMSDScroll) {
|
||||
mAsyncSmoothMSDScroll->RemoveObserver();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,6 +71,7 @@
|
||||
#include "nsQuickSort.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsRelativeFilePref.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsThreadUtils.h"
|
||||
@ -2309,21 +2310,6 @@ private:
|
||||
nsCOMPtr<nsISupportsString> mUnicodeString;
|
||||
};
|
||||
|
||||
class nsRelativeFilePref final : public nsIRelativeFilePref
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRELATIVEFILEPREF
|
||||
|
||||
nsRelativeFilePref();
|
||||
|
||||
private:
|
||||
virtual ~nsRelativeFilePref();
|
||||
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
nsCString mRelativeToKey;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// nsPrefBranch
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -26,6 +26,7 @@ XPIDL_MODULE = 'pref'
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'init/StaticPrefList.h',
|
||||
'nsRelativeFilePref.h',
|
||||
'Preferences.h',
|
||||
'StaticPrefs.h',
|
||||
]
|
||||
|
34
modules/libpref/nsRelativeFilePref.h
Normal file
34
modules/libpref/nsRelativeFilePref.h
Normal file
@ -0,0 +1,34 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_nsRelativeFilePref_h
|
||||
#define mozilla_nsRelativeFilePref_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsString.h"
|
||||
|
||||
// Note: This class is in its own file because it is needed by Mailnews.
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class nsRelativeFilePref final : public nsIRelativeFilePref
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRELATIVEFILEPREF
|
||||
|
||||
nsRelativeFilePref();
|
||||
|
||||
private:
|
||||
virtual ~nsRelativeFilePref();
|
||||
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
nsCString mRelativeToKey;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_nsRelativeFilePref_h
|
@ -554,7 +554,7 @@ impl WebDriverHandler<GeckoExtensionRoute> for MarionetteHandler {
|
||||
},
|
||||
_ => {
|
||||
return Err(WebDriverError::new(
|
||||
ErrorStatus::SessionNotCreated,
|
||||
ErrorStatus::InvalidSessionId,
|
||||
"Tried to run command without establishing a connection"));
|
||||
}
|
||||
}
|
||||
|
@ -740,9 +740,8 @@ class Marionette(object):
|
||||
:returns: Full response from the server, or if `key` is given,
|
||||
the value of said key in the response.
|
||||
"""
|
||||
|
||||
if not self.session_id and name != "WebDriver:NewSession":
|
||||
raise errors.MarionetteException("Please start a session")
|
||||
raise errors.InvalidSessionIdException("Please start a session")
|
||||
|
||||
try:
|
||||
msg = self.client.request(name, params)
|
||||
@ -1277,7 +1276,10 @@ class Marionette(object):
|
||||
"""
|
||||
try:
|
||||
if send_request:
|
||||
self._send_message("WebDriver:DeleteSession")
|
||||
try:
|
||||
self._send_message("WebDriver:DeleteSession")
|
||||
except errors.InvalidSessionIdException:
|
||||
pass
|
||||
finally:
|
||||
self.process_id = None
|
||||
self.profile = None
|
||||
|
@ -10,7 +10,7 @@ import shutil
|
||||
|
||||
from marionette_driver import Wait
|
||||
from marionette_driver.errors import (
|
||||
MarionetteException,
|
||||
InvalidSessionIdException,
|
||||
NoSuchWindowException,
|
||||
TimeoutException
|
||||
)
|
||||
@ -106,8 +106,8 @@ class TestCrash(BaseCrashTestCase):
|
||||
|
||||
self.assertEqual(self.marionette.crashed, 1)
|
||||
self.assertIsNone(self.marionette.session)
|
||||
self.assertRaisesRegexp(MarionetteException, 'Please start a session',
|
||||
self.marionette.get_url)
|
||||
with self.assertRaisesRegexp(InvalidSessionIdException, 'Please start a session'):
|
||||
self.marionette.get_url()
|
||||
|
||||
self.marionette.start_session()
|
||||
self.assertNotEqual(self.marionette.process_id, self.pid)
|
||||
@ -134,8 +134,8 @@ class TestCrash(BaseCrashTestCase):
|
||||
|
||||
self.assertEqual(self.marionette.crashed, 1)
|
||||
self.assertIsNone(self.marionette.session)
|
||||
self.assertRaisesRegexp(MarionetteException, 'Please start a session',
|
||||
self.marionette.get_url)
|
||||
with self.assertRaisesRegexp(InvalidSessionIdException, 'Please start a session'):
|
||||
self.marionette.get_url()
|
||||
|
||||
self.marionette.start_session()
|
||||
self.assertNotEqual(self.marionette.process_id, self.pid)
|
||||
|
@ -140,7 +140,7 @@ class TestQuitRestart(MarionetteTestCase):
|
||||
self.marionette.quit(clean=True)
|
||||
|
||||
self.assertEqual(self.marionette.session, None)
|
||||
with self.assertRaisesRegexp(errors.MarionetteException, "Please start a session"):
|
||||
with self.assertRaisesRegexp(errors.InvalidSessionIdException, "Please start a session"):
|
||||
self.marionette.get_url()
|
||||
|
||||
self.marionette.start_session()
|
||||
@ -153,7 +153,7 @@ class TestQuitRestart(MarionetteTestCase):
|
||||
self.marionette.quit()
|
||||
|
||||
self.assertEqual(self.marionette.session, None)
|
||||
with self.assertRaisesRegexp(errors.MarionetteException, "Please start a session"):
|
||||
with self.assertRaisesRegexp(errors.InvalidSessionIdException, "Please start a session"):
|
||||
self.marionette.get_url()
|
||||
|
||||
self.marionette.start_session()
|
||||
@ -245,7 +245,7 @@ class TestQuitRestart(MarionetteTestCase):
|
||||
self.marionette.quit(in_app=True)
|
||||
|
||||
self.assertEqual(self.marionette.session, None)
|
||||
with self.assertRaisesRegexp(errors.MarionetteException, "Please start a session"):
|
||||
with self.assertRaisesRegexp(errors.InvalidSessionIdException, "Please start a session"):
|
||||
self.marionette.get_url()
|
||||
|
||||
self.marionette.start_session()
|
||||
@ -257,7 +257,7 @@ class TestQuitRestart(MarionetteTestCase):
|
||||
def test_in_app_quit_with_callback(self):
|
||||
self.marionette.quit(in_app=True, callback=self.shutdown)
|
||||
self.assertEqual(self.marionette.session, None)
|
||||
with self.assertRaisesRegexp(errors.MarionetteException, "Please start a session"):
|
||||
with self.assertRaisesRegexp(errors.InvalidSessionIdException, "Please start a session"):
|
||||
self.marionette.get_url()
|
||||
|
||||
self.marionette.start_session()
|
||||
|
@ -47,7 +47,7 @@ class TestSession(MarionetteTestCase):
|
||||
self.marionette._send_message("WebDriver:NewSession", {})
|
||||
|
||||
def test_no_session(self):
|
||||
with self.assertRaisesRegexp(errors.MarionetteException, "Please start a session"):
|
||||
with self.assertRaises(errors.InvalidSessionIdException):
|
||||
self.marionette.get_url()
|
||||
|
||||
self.marionette.start_session()
|
||||
|
@ -290,8 +290,9 @@ class TCPConnection {
|
||||
throw new UnknownCommandError(cmd.name);
|
||||
}
|
||||
|
||||
if (!["newSession", "WebDriver:NewSession"].includes(cmd.name)) {
|
||||
assert.session(this.driver);
|
||||
if (cmd.name != "WebDriver:NewSession") {
|
||||
assert.session(this.driver,
|
||||
"Tried to run command without establishing a connection");
|
||||
}
|
||||
|
||||
let rv = await fn.bind(this.driver)(cmd);
|
||||
|
@ -759,7 +759,6 @@ def findTestMediaDevices(log):
|
||||
info['video'] = name
|
||||
|
||||
pactl = spawn.find_executable("pactl")
|
||||
pacmd = spawn.find_executable("pacmd")
|
||||
|
||||
# Use pactl to see if the PulseAudio module-null-sink module is loaded.
|
||||
def null_sink_loaded():
|
||||
@ -776,9 +775,6 @@ def findTestMediaDevices(log):
|
||||
log.error('Couldn\'t load module-null-sink')
|
||||
return None
|
||||
|
||||
# Whether it was loaded or not make it the default output
|
||||
subprocess.check_call([pacmd, 'set-default-sink', 'null'])
|
||||
|
||||
# Hardcode the name since it's always the same.
|
||||
info['audio'] = 'Monitor of Null Output'
|
||||
return info
|
||||
@ -1930,6 +1926,8 @@ toolbar#nav-bar {
|
||||
if options.useTestMediaDevices:
|
||||
prefs['media.audio_loopback_dev'] = self.mediaDevices['audio']
|
||||
prefs['media.video_loopback_dev'] = self.mediaDevices['video']
|
||||
prefs['media.cubeb.output_device'] = "Null Output"
|
||||
prefs['media.volume_scale'] = "1.0"
|
||||
|
||||
# Disable web replay rewinding by default if recordings are being saved.
|
||||
if options.recordingPath:
|
||||
|
@ -1,3 +0,0 @@
|
||||
[modifier_click.py]
|
||||
disabled:
|
||||
if os == "linux": https://bugzilla.mozilla.org/show_bug.cgi?id=1447844
|
@ -1,3 +0,0 @@
|
||||
[mouse_pause_dblclick.py]
|
||||
disabled:
|
||||
if os == "linux": https://bugzilla.mozilla.org/show_bug.cgi?id=1447449
|
@ -1,4 +0,0 @@
|
||||
[delete.py]
|
||||
[test_dismissed_beforeunload_prompt]
|
||||
expected: FAIL
|
||||
|
@ -404,6 +404,13 @@ class Session(object):
|
||||
self.end()
|
||||
|
||||
def start(self):
|
||||
"""Start a new WebDriver session.
|
||||
|
||||
:return: Dictionary with `capabilities` and `sessionId`.
|
||||
|
||||
:raises error.WebDriverException: If the remote end returns
|
||||
an error.
|
||||
"""
|
||||
if self.session_id is not None:
|
||||
return
|
||||
|
||||
@ -422,13 +429,13 @@ class Session(object):
|
||||
return value
|
||||
|
||||
def end(self):
|
||||
"""Tries to close the active session."""
|
||||
"""Try to close the active session."""
|
||||
if self.session_id is None:
|
||||
return
|
||||
|
||||
try:
|
||||
self.send_command("DELETE", "session/%s" % self.session_id)
|
||||
except error.SessionNotCreatedException:
|
||||
except error.InvalidSessionIdException:
|
||||
pass
|
||||
finally:
|
||||
self.session_id = None
|
||||
@ -446,10 +453,10 @@ class Session(object):
|
||||
the `value` field returned after parsing the response
|
||||
body as JSON.
|
||||
|
||||
:raises ValueError: If the response body does not contain a
|
||||
`value` key.
|
||||
:raises error.WebDriverException: If the remote end returns
|
||||
an error.
|
||||
:raises ValueError: If the response body does not contain a
|
||||
`value` key.
|
||||
"""
|
||||
response = self.transport.send(
|
||||
method, url, body,
|
||||
@ -459,7 +466,7 @@ class Session(object):
|
||||
if response.status != 200:
|
||||
err = error.from_response(response)
|
||||
|
||||
if isinstance(err, error.SessionNotCreatedException):
|
||||
if isinstance(err, error.InvalidSessionIdException):
|
||||
# The driver could have already been deleted the session.
|
||||
self.session_id = None
|
||||
|
||||
@ -495,14 +502,9 @@ class Session(object):
|
||||
:return: `None` if the HTTP response body was empty, otherwise
|
||||
the result of parsing the body as JSON.
|
||||
|
||||
:raises error.SessionNotCreatedException: If there is no active
|
||||
session.
|
||||
:raises error.WebDriverException: If the remote end returns
|
||||
an error.
|
||||
"""
|
||||
if self.session_id is None:
|
||||
raise error.SessionNotCreatedException()
|
||||
|
||||
url = urlparse.urljoin("session/%s/" % self.session_id, uri)
|
||||
return self.send_command(method, url, body)
|
||||
|
||||
|
@ -13,6 +13,7 @@ def test_null_response_value(session):
|
||||
response = delete_session(session)
|
||||
value = assert_success(response)
|
||||
assert value is None
|
||||
|
||||
# Need an explicit call to session.end() to notify the test harness
|
||||
# that a new session needs to be created for subsequent tests.
|
||||
session.end()
|
||||
|
Loading…
Reference in New Issue
Block a user