mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-26 11:45:37 +00:00
Merge mozilla-central into services-central
This commit is contained in:
commit
c172cb0b78
@ -48,6 +48,7 @@ enum AccType {
|
||||
* Other accessible types.
|
||||
*/
|
||||
eApplicationType,
|
||||
eHTMLOptGroupType,
|
||||
eImageMapType,
|
||||
eMenuPopupType,
|
||||
eProgressType,
|
||||
|
@ -488,6 +488,8 @@ public:
|
||||
bool IsHTMLListItem() const { return mType == eHTMLLiType; }
|
||||
HTMLLIAccessible* AsHTMLListItem();
|
||||
|
||||
bool IsHTMLOptGroup() const { return mType == eHTMLOptGroupType; }
|
||||
|
||||
bool IsHTMLTable() const { return mType == eHTMLTableType; }
|
||||
bool IsHTMLTableRow() const { return mType == eHTMLTableRowType; }
|
||||
|
||||
|
@ -1748,25 +1748,6 @@ DocAccessible::UpdateTree(Accessible* aContainer, nsIContent* aChildNode,
|
||||
|
||||
if (child) {
|
||||
updateFlags |= UpdateTreeInternal(child, aIsInsert, reorderEvent);
|
||||
|
||||
// XXX: since select change insertion point of option contained by optgroup
|
||||
// then we need to have special processing for them (bug 690417).
|
||||
if (!aIsInsert && aChildNode->IsHTML(nsGkAtoms::optgroup) &&
|
||||
aContainer->GetContent() &&
|
||||
aContainer->GetContent()->IsHTML(nsGkAtoms::select)) {
|
||||
for (nsIContent* optContent = aChildNode->GetFirstChild(); optContent;
|
||||
optContent = optContent->GetNextSibling()) {
|
||||
if (optContent->IsHTML(nsGkAtoms::option)) {
|
||||
Accessible* option = GetAccessible(optContent);
|
||||
if (option) {
|
||||
NS_ASSERTION(option->Parent() == aContainer,
|
||||
"Not expected hierarchy on HTML select!");
|
||||
if (option->Parent() == aContainer)
|
||||
updateFlags |= UpdateTreeInternal(option, aIsInsert, reorderEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TreeWalker walker(aContainer, aChildNode, true);
|
||||
|
||||
|
@ -1829,8 +1829,10 @@ void
|
||||
HyperTextAccessible::GetSelectionDOMRanges(int16_t aType,
|
||||
nsTArray<nsRange*>* aRanges)
|
||||
{
|
||||
// Ignore selection if it is not visible.
|
||||
nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
|
||||
if (!frameSelection)
|
||||
if (!frameSelection ||
|
||||
frameSelection->GetDisplaySelection() <= nsISelectionController::SELECTION_HIDDEN)
|
||||
return;
|
||||
|
||||
Selection* domSel = frameSelection->GetSelection(aType);
|
||||
|
@ -125,16 +125,7 @@ HTMLSelectListAccessible::CacheChildren()
|
||||
// as well as the accessibles for them. Avoid whitespace text nodes. We want
|
||||
// to count all the <optgroup>s and <option>s as children because we want
|
||||
// a flat tree under the Select List.
|
||||
CacheOptSiblings(mContent);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// HTMLSelectListAccessible protected
|
||||
|
||||
void
|
||||
HTMLSelectListAccessible::CacheOptSiblings(nsIContent* aParentContent)
|
||||
{
|
||||
for (nsIContent* childContent = aParentContent->GetFirstChild(); childContent;
|
||||
for (nsIContent* childContent = mContent->GetFirstChild(); childContent;
|
||||
childContent = childContent->GetNextSibling()) {
|
||||
if (!childContent->IsHTML()) {
|
||||
continue;
|
||||
@ -149,10 +140,6 @@ HTMLSelectListAccessible::CacheOptSiblings(nsIContent* aParentContent)
|
||||
GetAccService()->GetOrCreateAccessible(childContent, this);
|
||||
if (accessible)
|
||||
AppendChild(accessible);
|
||||
|
||||
// Deep down into optgroup element.
|
||||
if (tag == nsGkAtoms::optgroup)
|
||||
CacheOptSiblings(childContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -174,7 +161,7 @@ HTMLSelectOptionAccessible::
|
||||
role
|
||||
HTMLSelectOptionAccessible::NativeRole()
|
||||
{
|
||||
if (mParent && mParent->Role() == roles::COMBOBOX_LIST)
|
||||
if (GetCombobox())
|
||||
return roles::COMBOBOX_OPTION;
|
||||
|
||||
return roles::OPTION;
|
||||
@ -333,23 +320,21 @@ HTMLSelectOptionAccessible::SetSelected(bool aSelect)
|
||||
Accessible*
|
||||
HTMLSelectOptionAccessible::ContainerWidget() const
|
||||
{
|
||||
return mParent && mParent->IsListControl() ? mParent : nullptr;
|
||||
Accessible* parent = Parent();
|
||||
if (parent && parent->IsHTMLOptGroup())
|
||||
parent = parent->Parent();
|
||||
|
||||
return parent && parent->IsListControl() ? parent : nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// HTMLSelectOptGroupAccessible
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HTMLSelectOptGroupAccessible::
|
||||
HTMLSelectOptGroupAccessible(nsIContent* aContent, DocAccessible* aDoc) :
|
||||
HTMLSelectOptionAccessible(aContent, aDoc)
|
||||
{
|
||||
}
|
||||
|
||||
role
|
||||
HTMLSelectOptGroupAccessible::NativeRole()
|
||||
{
|
||||
return roles::HEADING;
|
||||
return roles::GROUPING;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
@ -376,20 +361,6 @@ HTMLSelectOptGroupAccessible::ActionCount()
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// HTMLSelectOptGroupAccessible: Accessible protected
|
||||
|
||||
void
|
||||
HTMLSelectOptGroupAccessible::CacheChildren()
|
||||
{
|
||||
// XXX To do (bug 378612) - create text child for the anonymous attribute
|
||||
// content, so that nsIAccessibleText is supported for the <optgroup> as it is
|
||||
// for an <option>. Attribute content is what layout creates for
|
||||
// the label="foo" on the <optgroup>. See eStyleContentType_Attr and
|
||||
// CreateAttributeContent() in nsCSSFrameConstructor
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// HTMLComboboxAccessible
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -57,13 +57,6 @@ protected:
|
||||
|
||||
// Accessible
|
||||
virtual void CacheChildren();
|
||||
|
||||
// HTMLSelectListAccessible
|
||||
|
||||
/**
|
||||
* Recursive helper for CacheChildren().
|
||||
*/
|
||||
void CacheOptSiblings(nsIContent* aParentContent);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -107,8 +100,12 @@ private:
|
||||
*/
|
||||
Accessible* GetSelect() const
|
||||
{
|
||||
if (mParent && mParent->IsListControl()) {
|
||||
Accessible* combobox = mParent->Parent();
|
||||
Accessible* parent = mParent;
|
||||
if (parent && parent->IsHTMLOptGroup())
|
||||
parent = parent->Parent();
|
||||
|
||||
if (parent && parent->IsListControl()) {
|
||||
Accessible* combobox = parent->Parent();
|
||||
return combobox && combobox->IsCombobox() ? combobox : mParent.get();
|
||||
}
|
||||
|
||||
@ -120,8 +117,12 @@ private:
|
||||
*/
|
||||
Accessible* GetCombobox() const
|
||||
{
|
||||
if (mParent && mParent->IsListControl()) {
|
||||
Accessible* combobox = mParent->Parent();
|
||||
Accessible* parent = mParent;
|
||||
if (parent && parent->IsHTMLOptGroup())
|
||||
parent = parent->Parent();
|
||||
|
||||
if (parent && parent->IsListControl()) {
|
||||
Accessible* combobox = parent->Parent();
|
||||
return combobox && combobox->IsCombobox() ? combobox : nullptr;
|
||||
}
|
||||
|
||||
@ -136,7 +137,9 @@ class HTMLSelectOptGroupAccessible : public HTMLSelectOptionAccessible
|
||||
{
|
||||
public:
|
||||
|
||||
HTMLSelectOptGroupAccessible(nsIContent* aContent, DocAccessible* aDoc);
|
||||
HTMLSelectOptGroupAccessible(nsIContent* aContent, DocAccessible* aDoc) :
|
||||
HTMLSelectOptionAccessible(aContent, aDoc)
|
||||
{ mType = eHTMLOptGroupType; }
|
||||
virtual ~HTMLSelectOptGroupAccessible() {}
|
||||
|
||||
// nsIAccessible
|
||||
@ -149,10 +152,6 @@ public:
|
||||
|
||||
// ActionAccessible
|
||||
virtual uint8_t ActionCount();
|
||||
|
||||
protected:
|
||||
// Accessible
|
||||
virtual void CacheChildren();
|
||||
};
|
||||
|
||||
/** ------------------------------------------------------ */
|
||||
|
@ -9,8 +9,9 @@
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsView.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsViewManager.h"
|
||||
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
|
@ -57,6 +57,10 @@
|
||||
gQueue.push(new takeFocusInvoker("plugin"));
|
||||
gQueue.push(new takeFocusInvoker(document));
|
||||
gQueue.push(new takeFocusInvoker("lb_item2"));
|
||||
gQueue.push(new takeFocusInvoker(document));
|
||||
gQueue.push(new takeFocusInvoker("lb_item3.2"));
|
||||
gQueue.push(new takeFocusInvoker(document));
|
||||
gQueue.push(new takeFocusInvoker("lb_item3.1"));
|
||||
|
||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||
}
|
||||
@ -114,6 +118,10 @@
|
||||
<select id="listbox" size="5">
|
||||
<option id="lb_item1">item1</option>
|
||||
<option id="lb_item2">item2</option>
|
||||
<optgroup>
|
||||
<option id="lb_item3.1">item 3.1</option>
|
||||
<option id="lb_item3.2">item 3.2</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -13,6 +13,7 @@ include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MOCHITEST_A11Y_FILES = \
|
||||
test_general.html \
|
||||
test_userinput.html \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
95
accessible/tests/mochitest/textselection/test_userinput.html
Normal file
95
accessible/tests/mochitest/textselection/test_userinput.html
Normal file
@ -0,0 +1,95 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Text selection by user input</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../role.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../states.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../events.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
/**
|
||||
* Invokers
|
||||
*/
|
||||
function synthTabAndCheckPrevTabbed(aID, aPrevID)
|
||||
{
|
||||
this.__proto__ = new synthTab(aID, new focusChecker(aID));
|
||||
|
||||
this.finalCheck = function changeSelection_finalCheck()
|
||||
{
|
||||
var prevTabbed = getAccessible(aPrevID, [ nsIAccessibleText ]);
|
||||
is(prevTabbed.selectionCount, 0,
|
||||
"Wrong selection count for " + aPrevID);
|
||||
|
||||
var exceptionCaught = false;
|
||||
try {
|
||||
var startOffsetObj = {}, endOffsetObj = {};
|
||||
prevTabbed.getSelectionBounds(0, startOffsetObj, endOffsetObj);
|
||||
} catch (e) {
|
||||
exceptionCaught = true;
|
||||
}
|
||||
|
||||
ok(exceptionCaught, "No selection was expected for " + aPrevID);
|
||||
}
|
||||
|
||||
this.getID = function changeSelection_getID()
|
||||
{
|
||||
return "Hidden selection check for " + aPrevID;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do tests
|
||||
*/
|
||||
|
||||
//gA11yEventDumpToConsole = true; // debug stuff
|
||||
|
||||
var gQueue = null;
|
||||
function doTests()
|
||||
{
|
||||
gQueue = new eventQueue();
|
||||
|
||||
// Tab to 't2' and then tab out it: it must has no selection.
|
||||
gQueue.push(new synthFocus("t1"));
|
||||
gQueue.push(new synthTab("t2", new focusChecker("t2")));
|
||||
gQueue.push(new synthTabAndCheckPrevTabbed("t3", "t2"));
|
||||
|
||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTests);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=440590"
|
||||
title="Text selection information is not updated when HTML and XUL entries lose focus">
|
||||
Bug 440590
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<input type="text" id="t1" maxlength="3" size="3" value="1">
|
||||
<input type="text" id="t2" maxlength="3" size="3" value="1">
|
||||
<input type="text" id="t3" maxlength="3" size="3" value="1">
|
||||
|
||||
</body>
|
||||
</html>
|
@ -20,21 +20,27 @@
|
||||
role: ROLE_LISTBOX,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_HEADING
|
||||
},
|
||||
{
|
||||
role: ROLE_OPTION,
|
||||
role: ROLE_GROUPING,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
role: ROLE_OPTION,
|
||||
children: [
|
||||
role: ROLE_STATICTEXT,
|
||||
children: [ ]
|
||||
},
|
||||
{
|
||||
role: ROLE_TEXT_LEAF
|
||||
role: ROLE_OPTION,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
role: ROLE_OPTION,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -57,24 +63,30 @@
|
||||
role: ROLE_COMBOBOX_LIST,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_HEADING
|
||||
},
|
||||
{
|
||||
role: ROLE_COMBOBOX_OPTION,
|
||||
role: ROLE_GROUPING,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
role: ROLE_COMBOBOX_OPTION,
|
||||
children: [
|
||||
role: ROLE_STATICTEXT,
|
||||
children: [ ]
|
||||
},
|
||||
{
|
||||
role: ROLE_TEXT_LEAF
|
||||
}
|
||||
role: ROLE_COMBOBOX_OPTION,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
role: ROLE_COMBOBOX_OPTION,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
},
|
||||
{
|
||||
role: ROLE_COMBOBOX_OPTION,
|
||||
children: [
|
||||
|
@ -67,4 +67,7 @@ else if (isTabPBSupported) {
|
||||
};
|
||||
}
|
||||
|
||||
// Test disabled because of bug 855771
|
||||
module.exports = {};
|
||||
|
||||
require('test').run(exports);
|
||||
|
@ -91,7 +91,7 @@ DirectoryProvider.prototype = {
|
||||
if (!Services.volumeService) {
|
||||
return false;
|
||||
}
|
||||
let volume = Services.volumeService.getVolumeByPath(volumePath);
|
||||
let volume = Services.volumeService.createOrGetVolumeByPath(volumePath);
|
||||
if (!volume || volume.state !== Ci.nsIVolume.STATE_MOUNTED) {
|
||||
return false;
|
||||
}
|
||||
@ -201,7 +201,7 @@ DirectoryProvider.prototype = {
|
||||
}
|
||||
|
||||
if (Services.volumeService) {
|
||||
let extVolume = Services.volumeService.getVolumeByPath(path);
|
||||
let extVolume = Services.volumeService.createOrGetVolumeByPath(path);
|
||||
if (!extVolume) {
|
||||
path = LOCAL_DIR;
|
||||
}
|
||||
|
@ -918,9 +918,7 @@ pref("dom.ipc.plugins.enabled.x86_64", true);
|
||||
pref("dom.ipc.plugins.enabled", true);
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_E10S_COMPAT
|
||||
pref("browser.tabs.remote", true);
|
||||
#endif
|
||||
pref("browser.tabs.remote", false);
|
||||
|
||||
// This pref governs whether we attempt to work around problems caused by
|
||||
// plugins using OS calls to manipulate the cursor while running out-of-
|
||||
@ -1084,6 +1082,7 @@ pref("devtools.netmonitor.enabled", true);
|
||||
|
||||
// The default Network Monitor UI settings
|
||||
pref("devtools.netmonitor.panes-network-details-width", 450);
|
||||
pref("devtools.netmonitor.panes-network-details-height", 450);
|
||||
|
||||
// Enable the Tilt inspector
|
||||
pref("devtools.tilt.enabled", true);
|
||||
@ -1128,6 +1127,8 @@ pref("devtools.webconsole.filter.error", true);
|
||||
pref("devtools.webconsole.filter.warn", true);
|
||||
pref("devtools.webconsole.filter.info", true);
|
||||
pref("devtools.webconsole.filter.log", true);
|
||||
pref("devtools.webconsole.filter.secerror", true);
|
||||
pref("devtools.webconsole.filter.secwarn", true);
|
||||
|
||||
// Text size in the Web Console. Use 0 for the system default size.
|
||||
pref("devtools.webconsole.fontSize", 0);
|
||||
|
@ -40,6 +40,10 @@ var FullZoom = {
|
||||
// Initialization & Destruction
|
||||
|
||||
init: function FullZoom_init() {
|
||||
// Bug 691614 - zooming support for electrolysis
|
||||
if (gMultiProcessBrowser)
|
||||
return;
|
||||
|
||||
// Listen for scrollwheel events so we can save scrollwheel-based changes.
|
||||
window.addEventListener("DOMMouseScroll", this, false);
|
||||
|
||||
@ -58,6 +62,10 @@ var FullZoom = {
|
||||
},
|
||||
|
||||
destroy: function FullZoom_destroy() {
|
||||
// Bug 691614 - zooming support for electrolysis
|
||||
if (gMultiProcessBrowser)
|
||||
return;
|
||||
|
||||
gPrefService.removeObserver("browser.zoom.", this);
|
||||
this._cps2.removeObserverForName(this.name, this);
|
||||
window.removeEventListener("DOMMouseScroll", this, false);
|
||||
@ -210,6 +218,10 @@ var FullZoom = {
|
||||
* (optional) browser object displaying the document
|
||||
*/
|
||||
onLocationChange: function FullZoom_onLocationChange(aURI, aIsTabSwitch, aBrowser) {
|
||||
// Bug 691614 - zooming support for electrolysis
|
||||
if (gMultiProcessBrowser)
|
||||
return;
|
||||
|
||||
if (!aURI || (aIsTabSwitch && !this.siteSpecific)) {
|
||||
this._notifyOnLocationChange();
|
||||
return;
|
||||
|
@ -25,6 +25,10 @@ let gGestureSupport = {
|
||||
* True to add/init listeners and false to remove/uninit
|
||||
*/
|
||||
init: function GS_init(aAddListener) {
|
||||
// Bug 863514 - Make gesture support work in electrolysis
|
||||
if (gMultiProcessBrowser)
|
||||
return;
|
||||
|
||||
const gestureEvents = ["SwipeGestureStart",
|
||||
"SwipeGestureUpdate", "SwipeGestureEnd", "SwipeGesture",
|
||||
"MagnifyGestureStart", "MagnifyGestureUpdate", "MagnifyGesture",
|
||||
@ -501,6 +505,10 @@ let gGestureSupport = {
|
||||
* image
|
||||
*/
|
||||
restoreRotationState: function() {
|
||||
// Bug 863514 - Make gesture support work in electrolysis
|
||||
if (gMultiProcessBrowser)
|
||||
return;
|
||||
|
||||
if (!(content.document instanceof ImageDocument))
|
||||
return;
|
||||
|
||||
|
@ -465,23 +465,7 @@ var gPluginHandler = {
|
||||
}
|
||||
|
||||
if (overlay) {
|
||||
overlay.addEventListener("click", function(aEvent) {
|
||||
// Have to check that the target is not the link to update the plugin
|
||||
if (!(aEvent.originalTarget instanceof HTMLAnchorElement) &&
|
||||
(aEvent.originalTarget.getAttribute('anonid') != 'closeIcon') &&
|
||||
aEvent.button == 0 && aEvent.isTrusted) {
|
||||
if (objLoadingContent.pluginFallbackType ==
|
||||
Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE ||
|
||||
objLoadingContent.pluginFallbackType ==
|
||||
Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE)
|
||||
gPluginHandler._showClickToPlayNotification(browser, true);
|
||||
else
|
||||
gPluginHandler.activateSinglePlugin(aEvent.target.ownerDocument.defaultView.top, aPlugin);
|
||||
aEvent.stopPropagation();
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
}, true);
|
||||
|
||||
overlay.addEventListener("click", gPluginHandler._overlayClickListener, true);
|
||||
let closeIcon = doc.getAnonymousElementByAttribute(aPlugin, "anonid", "closeIcon");
|
||||
closeIcon.addEventListener("click", function(aEvent) {
|
||||
if (aEvent.button == 0 && aEvent.isTrusted)
|
||||
@ -492,6 +476,40 @@ var gPluginHandler = {
|
||||
gPluginHandler._showClickToPlayNotification(browser);
|
||||
},
|
||||
|
||||
_overlayClickListener: {
|
||||
handleEvent: function PH_handleOverlayClick(aEvent) {
|
||||
let plugin = document.getBindingParent(aEvent.target);
|
||||
let contentWindow = plugin.ownerDocument.defaultView.top;
|
||||
// gBrowser.getBrowserForDocument does not exist in the case where we
|
||||
// drag-and-dropped a tab from a window containing only that tab. In
|
||||
// that case, the window gets destroyed.
|
||||
let browser = gBrowser.getBrowserForDocument ?
|
||||
gBrowser.getBrowserForDocument(contentWindow.document) :
|
||||
null;
|
||||
// If browser is null here, we've been drag-and-dropped from another
|
||||
// window, and this is the wrong click handler.
|
||||
if (!browser) {
|
||||
aEvent.target.removeEventListener("click", gPluginHandler._overlayClickListener, true);
|
||||
return;
|
||||
}
|
||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
||||
// Have to check that the target is not the link to update the plugin
|
||||
if (!(aEvent.originalTarget instanceof HTMLAnchorElement) &&
|
||||
(aEvent.originalTarget.getAttribute('anonid') != 'closeIcon') &&
|
||||
aEvent.button == 0 && aEvent.isTrusted) {
|
||||
if (objLoadingContent.pluginFallbackType ==
|
||||
Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE ||
|
||||
objLoadingContent.pluginFallbackType ==
|
||||
Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE)
|
||||
gPluginHandler._showClickToPlayNotification(browser, true);
|
||||
else
|
||||
gPluginHandler.activateSinglePlugin(contentWindow, plugin);
|
||||
aEvent.stopPropagation();
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_handlePlayPreviewEvent: function PH_handlePlayPreviewEvent(aPlugin) {
|
||||
let doc = aPlugin.ownerDocument;
|
||||
let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
|
||||
@ -546,8 +564,23 @@ var gPluginHandler = {
|
||||
|
||||
reshowClickToPlayNotification: function PH_reshowClickToPlayNotification() {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
if (gPluginHandler._pluginNeedsActivationExceptThese([]))
|
||||
gPluginHandler._showClickToPlayNotification(browser);
|
||||
if (!browser._clickToPlayPluginsActivated)
|
||||
browser._clickToPlayPluginsActivated = new Map();
|
||||
if (!browser._pluginScriptedState)
|
||||
browser._pluginScriptedState = gPluginHandler.PLUGIN_SCRIPTED_STATE_NONE;
|
||||
let contentWindow = browser.contentWindow;
|
||||
let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
let doc = contentWindow.document;
|
||||
let plugins = cwu.plugins;
|
||||
for (let plugin of plugins) {
|
||||
let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
|
||||
if (overlay)
|
||||
overlay.removeEventListener("click", gPluginHandler._overlayClickListener, true);
|
||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
||||
if (gPluginHandler.canActivatePlugin(objLoadingContent))
|
||||
gPluginHandler._handleClickToPlayEvent(plugin);
|
||||
}
|
||||
},
|
||||
|
||||
// returns true if there is a plugin on this page that needs activation
|
||||
|
@ -31,6 +31,10 @@ let gBrowserThumbnails = {
|
||||
_tabEvents: ["TabClose", "TabSelect"],
|
||||
|
||||
init: function Thumbnails_init() {
|
||||
// Bug 863512 - Make page thumbnails work in electrolysis
|
||||
if (gMultiProcessBrowser)
|
||||
return;
|
||||
|
||||
try {
|
||||
if (Services.prefs.getBoolPref("browser.pagethumbnails.capturing_disabled"))
|
||||
return;
|
||||
@ -51,6 +55,10 @@ let gBrowserThumbnails = {
|
||||
},
|
||||
|
||||
uninit: function Thumbnails_uninit() {
|
||||
// Bug 863512 - Make page thumbnails work in electrolysis
|
||||
if (gMultiProcessBrowser)
|
||||
return;
|
||||
|
||||
PageThumbs.removeExpirationFilter(this);
|
||||
gBrowser.removeTabsProgressListener(this);
|
||||
Services.prefs.removeObserver(this.PREF_DISK_CACHE_SSL, this);
|
||||
|
@ -18,6 +18,7 @@ var gProxyFavIcon = null;
|
||||
var gLastValidURLStr = "";
|
||||
var gInPrintPreviewMode = false;
|
||||
var gContextMenu = null; // nsContextMenu instance
|
||||
var gMultiProcessBrowser = false;
|
||||
|
||||
#ifndef XP_MACOSX
|
||||
var gEditUIVisible = true;
|
||||
@ -739,6 +740,8 @@ var gBrowserInit = {
|
||||
if ("arguments" in window && window.arguments[0])
|
||||
var uriToLoad = window.arguments[0];
|
||||
|
||||
gMultiProcessBrowser = gPrefService.getBoolPref("browser.tabs.remote");
|
||||
|
||||
var mustLoadSidebar = false;
|
||||
|
||||
Cc["@mozilla.org/eventlistenerservice;1"]
|
||||
@ -801,18 +804,18 @@ var gBrowserInit = {
|
||||
|
||||
// enable global history
|
||||
try {
|
||||
gBrowser.docShell.QueryInterface(Ci.nsIDocShellHistory).useGlobalHistory = true;
|
||||
if (!gMultiProcessBrowser)
|
||||
gBrowser.docShell.QueryInterface(Ci.nsIDocShellHistory).useGlobalHistory = true;
|
||||
} catch(ex) {
|
||||
Cu.reportError("Places database may be locked: " + ex);
|
||||
}
|
||||
|
||||
#ifdef MOZ_E10S_COMPAT
|
||||
// Bug 666801 - WebProgress support for e10s
|
||||
#else
|
||||
// hook up UI through progress listener
|
||||
gBrowser.addProgressListener(window.XULBrowserWindow);
|
||||
gBrowser.addTabsProgressListener(window.TabsProgressListener);
|
||||
#endif
|
||||
if (!gMultiProcessBrowser) {
|
||||
// hook up UI through progress listener
|
||||
gBrowser.addProgressListener(window.XULBrowserWindow);
|
||||
gBrowser.addTabsProgressListener(window.TabsProgressListener);
|
||||
}
|
||||
|
||||
// setup our common DOMLinkAdded listener
|
||||
gBrowser.addEventListener("DOMLinkAdded", DOMLinkHandler, false);
|
||||
@ -975,7 +978,7 @@ var gBrowserInit = {
|
||||
gBrowser.addEventListener("pageshow", function(event) {
|
||||
// Filter out events that are not about the document load we are interested in
|
||||
if (content && event.target == content.document)
|
||||
setTimeout(pageShowEventHandlers, 0, event);
|
||||
setTimeout(pageShowEventHandlers, 0, event.persisted);
|
||||
}, true);
|
||||
|
||||
if (uriToLoad && uriToLoad != "about:blank") {
|
||||
@ -1084,13 +1087,12 @@ var gBrowserInit = {
|
||||
// apply full zoom settings to tabs restored by the session restore service.
|
||||
FullZoom.init();
|
||||
|
||||
#ifdef MOZ_E10S_COMPAT
|
||||
// Bug 666804 - NetworkPrioritizer support for e10s
|
||||
#else
|
||||
let NP = {};
|
||||
Cu.import("resource:///modules/NetworkPrioritizer.jsm", NP);
|
||||
NP.trackBrowserWindow(window);
|
||||
#endif
|
||||
if (!gMultiProcessBrowser) {
|
||||
let NP = {};
|
||||
Cu.import("resource:///modules/NetworkPrioritizer.jsm", NP);
|
||||
NP.trackBrowserWindow(window);
|
||||
}
|
||||
|
||||
// initialize the session-restore service (in case it's not already running)
|
||||
let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
|
||||
@ -1134,12 +1136,11 @@ var gBrowserInit = {
|
||||
gBrowser.mPanelContainer.addEventListener("PreviewBrowserTheme", LightWeightThemeWebInstaller, false, true);
|
||||
gBrowser.mPanelContainer.addEventListener("ResetBrowserThemePreview", LightWeightThemeWebInstaller, false, true);
|
||||
|
||||
#ifdef MOZ_E10S_COMPAT
|
||||
// Bug 666808 - AeroPeek support for e10s
|
||||
#else
|
||||
if (Win7Features)
|
||||
Win7Features.onOpenWindow();
|
||||
#endif
|
||||
if (!gMultiProcessBrowser) {
|
||||
if (Win7Features)
|
||||
Win7Features.onOpenWindow();
|
||||
}
|
||||
|
||||
// called when we go into full screen, even if initiated by a web page script
|
||||
window.addEventListener("fullscreen", onFullScreen, true);
|
||||
@ -2132,8 +2133,9 @@ function URLBarSetURI(aURI) {
|
||||
|
||||
// Replace initial page URIs with an empty string
|
||||
// only if there's no opener (bug 370555).
|
||||
// Bug 863515 - Make content.opener checks work in electrolysis.
|
||||
if (gInitialPages.indexOf(uri.spec) != -1)
|
||||
value = content.opener ? uri.spec : "";
|
||||
value = !gMultiProcessBrowser && content.opener ? uri.spec : "";
|
||||
else
|
||||
value = losslessDecodeURI(uri);
|
||||
|
||||
@ -3625,15 +3627,15 @@ var XULBrowserWindow = {
|
||||
init: function () {
|
||||
this.throbberElement = document.getElementById("navigator-throbber");
|
||||
|
||||
#ifdef MOZ_E10S_COMPAT
|
||||
// Bug 666809 - SecurityUI support for e10s
|
||||
#else
|
||||
if (gMultiProcessBrowser)
|
||||
return;
|
||||
|
||||
// Initialize the security button's state and tooltip text. Remember to reset
|
||||
// _hostChanged, otherwise onSecurityChange will short circuit.
|
||||
var securityUI = gBrowser.securityUI;
|
||||
this._hostChanged = true;
|
||||
this.onSecurityChange(null, null, securityUI.state);
|
||||
#endif
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
@ -3800,7 +3802,7 @@ var XULBrowserWindow = {
|
||||
this.setDefaultStatus(msg);
|
||||
|
||||
// Disable menu entries for images, enable otherwise
|
||||
if (content.document && mimeTypeIsTextBased(content.document.contentType))
|
||||
if (!gMultiProcessBrowser && content.document && mimeTypeIsTextBased(content.document.contentType))
|
||||
this.isImage.removeAttribute('disabled');
|
||||
else
|
||||
this.isImage.setAttribute('disabled', 'true');
|
||||
@ -3850,7 +3852,7 @@ var XULBrowserWindow = {
|
||||
}
|
||||
|
||||
// Disable menu entries for images, enable otherwise
|
||||
if (content.document && mimeTypeIsTextBased(content.document.contentType))
|
||||
if (!gMultiProcessBrowser && content.document && mimeTypeIsTextBased(content.document.contentType))
|
||||
this.isImage.removeAttribute('disabled');
|
||||
else
|
||||
this.isImage.setAttribute('disabled', 'true');
|
||||
@ -3866,7 +3868,7 @@ var XULBrowserWindow = {
|
||||
|
||||
var browser = gBrowser.selectedBrowser;
|
||||
if (aWebProgress.DOMWindow == content) {
|
||||
if ((location == "about:blank" && !content.opener) ||
|
||||
if ((location == "about:blank" && (gMultiProcessBrowser || !content.opener)) ||
|
||||
location == "") { // Second condition is for new tabs, otherwise
|
||||
// reload function is enabled until tab is refreshed.
|
||||
this.reloadCommand.setAttribute("disabled", "true");
|
||||
@ -3920,7 +3922,7 @@ var XULBrowserWindow = {
|
||||
}
|
||||
|
||||
// Disable find commands in documents that ask for them to be disabled.
|
||||
if (aLocationURI &&
|
||||
if (!gMultiProcessBrowser && aLocationURI &&
|
||||
(aLocationURI.schemeIs("about") || aLocationURI.schemeIs("chrome"))) {
|
||||
// Don't need to re-enable/disable find commands for same-document location changes
|
||||
// (e.g. the replaceStates in about:addons)
|
||||
@ -4033,6 +4035,9 @@ var XULBrowserWindow = {
|
||||
gURLBar.removeAttribute("level");
|
||||
}
|
||||
|
||||
if (gMultiProcessBrowser)
|
||||
return;
|
||||
|
||||
// Don't pass in the actual location object, since it can cause us to
|
||||
// hold on to the window object too long. Just pass in the fields we
|
||||
// care about. (bug 424829)
|
||||
@ -4253,8 +4258,9 @@ var TabsProgressListener = {
|
||||
// We can't look for this during onLocationChange since at that point the
|
||||
// document URI is not yet the about:-uri of the error page.
|
||||
|
||||
let doc = aWebProgress.DOMWindow.document;
|
||||
if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
|
||||
let doc = gMultiProcessBrowser ? null : aWebProgress.DOMWindow.document;
|
||||
if (!gMultiProcessBrowser &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
|
||||
Components.isSuccessCode(aStatus) &&
|
||||
doc.documentURI.startsWith("about:") &&
|
||||
!doc.documentURI.toLowerCase().startsWith("about:blank") &&
|
||||
@ -6133,7 +6139,12 @@ function AddKeywordForSearchField() {
|
||||
}
|
||||
|
||||
function SwitchDocumentDirection(aWindow) {
|
||||
aWindow.document.dir = (aWindow.document.dir == "ltr" ? "rtl" : "ltr");
|
||||
// document.dir can also be "auto", in which case it won't change
|
||||
if (aWindow.document.dir == "ltr" || aWindow.document.dir == "") {
|
||||
aWindow.document.dir = "rtl";
|
||||
} else if (aWindow.document.dir == "rtl") {
|
||||
aWindow.document.dir = "ltr";
|
||||
}
|
||||
for (var run = 0; run < aWindow.frames.length; run++)
|
||||
SwitchDocumentDirection(aWindow.frames[run]);
|
||||
}
|
||||
@ -6207,7 +6218,8 @@ function isTabEmpty(aTab) {
|
||||
if (!isBlankPageURL(browser.currentURI.spec))
|
||||
return false;
|
||||
|
||||
if (browser.contentWindow.opener)
|
||||
// Bug 863515 - Make content.opener checks work in electrolysis.
|
||||
if (!gMultiProcessBrowser && browser.contentWindow.opener)
|
||||
return false;
|
||||
|
||||
if (browser.sessionHistory && browser.sessionHistory.count >= 2)
|
||||
@ -6754,8 +6766,10 @@ let gPrivateBrowsingUI = {
|
||||
}
|
||||
}
|
||||
|
||||
if (gURLBar) {
|
||||
// Disable switch to tab autocompletion for private windows
|
||||
if (gURLBar &&
|
||||
!PrivateBrowsingUtils.permanentPrivateBrowsing) {
|
||||
// Disable switch to tab autocompletion for private windows
|
||||
// (not for "Always use private browsing" mode)
|
||||
gURLBar.setAttribute("autocompletesearchparam", "");
|
||||
}
|
||||
}
|
||||
@ -6778,9 +6792,10 @@ function switchToTabHavingURI(aURI, aOpenNew) {
|
||||
// This will switch to the tab in aWindow having aURI, if present.
|
||||
function switchIfURIInWindow(aWindow) {
|
||||
// Only switch to the tab if neither the source and desination window are
|
||||
// private.
|
||||
if (PrivateBrowsingUtils.isWindowPrivate(window) ||
|
||||
PrivateBrowsingUtils.isWindowPrivate(aWindow)) {
|
||||
// private and they are not in permanent private borwsing mode
|
||||
if ((PrivateBrowsingUtils.isWindowPrivate(window) ||
|
||||
PrivateBrowsingUtils.isWindowPrivate(aWindow)) &&
|
||||
!PrivateBrowsingUtils.permanentPrivateBrowsing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -452,6 +452,9 @@
|
||||
if (this.mBlank)
|
||||
return false;
|
||||
|
||||
if (gMultiProcessBrowser)
|
||||
return true;
|
||||
|
||||
// Don't show progress indicators in tabs for about: URIs
|
||||
// pointing to local resources.
|
||||
try {
|
||||
@ -529,8 +532,10 @@
|
||||
if (this._shouldShowProgress(aRequest)) {
|
||||
if (!(aStateFlags & nsIWebProgressListener.STATE_RESTORING)) {
|
||||
this.mTab.setAttribute("busy", "true");
|
||||
if (!(this.mBrowser.docShell.loadType & Ci.nsIDocShell.LOAD_CMD_RELOAD))
|
||||
this.mTabBrowser.setTabTitleLoading(this.mTab);
|
||||
if (!gMultiProcessBrowser) {
|
||||
if (!(this.mBrowser.docShell.loadType & Ci.nsIDocShell.LOAD_CMD_RELOAD))
|
||||
this.mTabBrowser.setTabTitleLoading(this.mTab);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.mTab.selected)
|
||||
@ -631,9 +636,11 @@
|
||||
|
||||
// Don't clear the favicon if this onLocationChange was
|
||||
// triggered by a pushState or a replaceState. See bug 550565.
|
||||
if (aWebProgress.isLoadingDocument &&
|
||||
!(this.mBrowser.docShell.loadType & Ci.nsIDocShell.LOAD_CMD_PUSHSTATE))
|
||||
this.mBrowser.mIconURL = null;
|
||||
if (!gMultiProcessBrowser) {
|
||||
if (aWebProgress.isLoadingDocument &&
|
||||
!(this.mBrowser.docShell.loadType & Ci.nsIDocShell.LOAD_CMD_PUSHSTATE))
|
||||
this.mBrowser.mIconURL = null;
|
||||
}
|
||||
|
||||
let autocomplete = this.mTabBrowser._placesAutocomplete;
|
||||
if (this.mBrowser.registeredOpenURI) {
|
||||
@ -643,7 +650,8 @@
|
||||
// Tabs in private windows aren't registered as "Open" so
|
||||
// that they don't appear as switch-to-tab candidates.
|
||||
if (!isBlankPageURL(aLocation.spec) &&
|
||||
!PrivateBrowsingUtils.isWindowPrivate(window)) {
|
||||
(!PrivateBrowsingUtils.isWindowPrivate(window) ||
|
||||
PrivateBrowsingUtils.permanentPrivateBrowsing)) {
|
||||
autocomplete.registerOpenPage(aLocation);
|
||||
this.mBrowser.registeredOpenURI = aLocation;
|
||||
}
|
||||
@ -755,6 +763,10 @@
|
||||
<parameter name="aTab"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
// Bug 691610 - e10s support for useDefaultIcon
|
||||
if (gMultiProcessBrowser)
|
||||
return;
|
||||
|
||||
var browser = this.getBrowserForTab(aTab);
|
||||
var docURIObject = browser.contentDocument.documentURIObject;
|
||||
var icon = null;
|
||||
@ -916,22 +928,21 @@
|
||||
// Update the URL bar.
|
||||
var loc = this.mCurrentBrowser.currentURI;
|
||||
|
||||
#ifdef MOZ_E10S_COMPAT
|
||||
// Bug 666801 - WebProgress support for e10s and
|
||||
// Bug 666809 - SecurityUI support for e10s
|
||||
#else
|
||||
var webProgress = this.mCurrentBrowser.webProgress;
|
||||
var securityUI = this.mCurrentBrowser.securityUI;
|
||||
if (!gMultiProcessBrowser) {
|
||||
var webProgress = this.mCurrentBrowser.webProgress;
|
||||
var securityUI = this.mCurrentBrowser.securityUI;
|
||||
|
||||
this._callProgressListeners(null, "onLocationChange",
|
||||
[webProgress, null, loc, 0], true,
|
||||
false);
|
||||
this._callProgressListeners(null, "onLocationChange",
|
||||
[webProgress, null, loc, 0], true,
|
||||
false);
|
||||
|
||||
if (securityUI) {
|
||||
this._callProgressListeners(null, "onSecurityChange",
|
||||
[webProgress, null, securityUI.state], true, false);
|
||||
if (securityUI) {
|
||||
this._callProgressListeners(null, "onSecurityChange",
|
||||
[webProgress, null, securityUI.state], true, false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
var listener = this.mTabListeners[this.tabContainer.selectedIndex] || null;
|
||||
if (listener && listener.mStateFlags) {
|
||||
@ -945,11 +956,9 @@
|
||||
this.mCurrentTab.removeAttribute("unread");
|
||||
this.selectedTab.lastAccessed = Date.now();
|
||||
|
||||
#ifdef MOZ_E10S_COMPAT
|
||||
// Bug 666816 - TypeAheadFind support for e10s
|
||||
#else
|
||||
this._fastFind.setDocShell(this.mCurrentBrowser.docShell);
|
||||
#endif
|
||||
if (!gMultiProcessBrowser)
|
||||
this._fastFind.setDocShell(this.mCurrentBrowser.docShell);
|
||||
|
||||
this.updateTitlebar();
|
||||
|
||||
@ -1038,15 +1047,18 @@
|
||||
|
||||
// Otherwise, focus the content area.
|
||||
let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
|
||||
let newFocusedElement = fm.getFocusedElementForWindow(window.content, true, {});
|
||||
|
||||
// for anchors, use FLAG_SHOWRING so that it is clear what link was
|
||||
// last clicked when switching back to that tab
|
||||
let focusFlags = fm.FLAG_NOSCROLL;
|
||||
if (newFocusedElement &&
|
||||
(newFocusedElement instanceof HTMLAnchorElement ||
|
||||
newFocusedElement.getAttributeNS("http://www.w3.org/1999/xlink", "type") == "simple"))
|
||||
focusFlags |= fm.FLAG_SHOWRING;
|
||||
|
||||
if (!gMultiProcessBrowser) {
|
||||
let newFocusedElement = fm.getFocusedElementForWindow(window.content, true, {});
|
||||
|
||||
// for anchors, use FLAG_SHOWRING so that it is clear what link was
|
||||
// last clicked when switching back to that tab
|
||||
if (newFocusedElement &&
|
||||
(newFocusedElement instanceof HTMLAnchorElement ||
|
||||
newFocusedElement.getAttributeNS("http://www.w3.org/1999/xlink", "type") == "simple"))
|
||||
focusFlags |= fm.FLAG_SHOWRING;
|
||||
}
|
||||
fm.setFocus(newBrowser, focusFlags);
|
||||
} while (false);
|
||||
}
|
||||
@ -1105,12 +1117,14 @@
|
||||
// At this point, we now have a URI.
|
||||
// Let's try to unescape it using a character set
|
||||
// in case the URI is not ASCII.
|
||||
try {
|
||||
var characterSet = browser.contentDocument.characterSet;
|
||||
const textToSubURI = Components.classes["@mozilla.org/intl/texttosuburi;1"]
|
||||
.getService(Components.interfaces.nsITextToSubURI);
|
||||
title = textToSubURI.unEscapeNonAsciiURI(characterSet, title);
|
||||
} catch(ex) { /* Do nothing. */ }
|
||||
if (!gMultiProcessBrowser) {
|
||||
try {
|
||||
var characterSet = browser.contentDocument.characterSet;
|
||||
const textToSubURI = Components.classes["@mozilla.org/intl/texttosuburi;1"]
|
||||
.getService(Components.interfaces.nsITextToSubURI);
|
||||
title = textToSubURI.unEscapeNonAsciiURI(characterSet, title);
|
||||
} catch(ex) { /* Do nothing. */ }
|
||||
}
|
||||
|
||||
crop = "center";
|
||||
|
||||
@ -1386,11 +1400,9 @@
|
||||
const filter = Components.classes["@mozilla.org/appshell/component/browser-status-filter;1"]
|
||||
.createInstance(Components.interfaces.nsIWebProgress);
|
||||
filter.addProgressListener(tabListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
|
||||
#ifdef MOZ_E10S_COMPAT
|
||||
// Bug 666801 - WebProgress support for e10s
|
||||
#else
|
||||
b.webProgress.addProgressListener(filter, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
|
||||
#endif
|
||||
if (!gMultiProcessBrowser)
|
||||
b.webProgress.addProgressListener(filter, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
|
||||
this.mTabListeners[position] = tabListener;
|
||||
this.mTabFilters[position] = filter;
|
||||
|
||||
@ -1685,18 +1697,20 @@
|
||||
evt.initUIEvent("TabClose", true, false, window, aTabWillBeMoved ? 1 : 0);
|
||||
aTab.dispatchEvent(evt);
|
||||
|
||||
// Prevent this tab from showing further dialogs, since we're closing it
|
||||
var windowUtils = browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).
|
||||
getInterface(Ci.nsIDOMWindowUtils);
|
||||
windowUtils.preventFurtherDialogs();
|
||||
if (!gMultiProcessBrowser) {
|
||||
// Prevent this tab from showing further dialogs, since we're closing it
|
||||
var windowUtils = browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).
|
||||
getInterface(Ci.nsIDOMWindowUtils);
|
||||
windowUtils.preventFurtherDialogs();
|
||||
}
|
||||
|
||||
// Remove the tab's filter and progress listener.
|
||||
const filter = this.mTabFilters[aTab._tPos];
|
||||
#ifdef MOZ_E10S_COMPAT
|
||||
|
||||
// Bug 666801 - WebProgress support for e10s
|
||||
#else
|
||||
browser.webProgress.removeProgressListener(filter);
|
||||
#endif
|
||||
if (!gMultiProcessBrowser)
|
||||
browser.webProgress.removeProgressListener(filter);
|
||||
|
||||
filter.removeProgressListener(this.mTabListeners[aTab._tPos]);
|
||||
this.mTabListeners[aTab._tPos].destroy();
|
||||
|
||||
|
@ -51,6 +51,117 @@ function part3() {
|
||||
function part4() {
|
||||
ok(PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser), "Should have a click-to-play notification in the initial tab again");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
gBrowser.selectedBrowser.addEventListener("PluginBindingAttached", handleEvent, true, true);
|
||||
gNextTest = part5;
|
||||
gBrowser.selectedBrowser.contentDocument.location = gHttpTestRoot + "plugin_test.html";
|
||||
}
|
||||
|
||||
function part5() {
|
||||
gBrowser.selectedBrowser.removeEventListener("PluginBindingAttached", handleEvent);
|
||||
ok(PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser), "Should have a click-to-play notification in the initial tab");
|
||||
|
||||
gNextTest = part6;
|
||||
gNewWindow = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
|
||||
gNewWindow.addEventListener("load", handleEvent, true);
|
||||
}
|
||||
|
||||
function part6() {
|
||||
gNewWindow.removeEventListener("load", handleEvent);
|
||||
let condition = function() PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser);
|
||||
waitForCondition(condition, part7, "Waited too long for click-to-play notification");
|
||||
}
|
||||
|
||||
function part7() {
|
||||
ok(PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser), "Should have a click-to-play notification in the tab in the new window");
|
||||
ok(!PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser), "Should not have a click-to-play notification in the old window now");
|
||||
|
||||
let plugin = gNewWindow.gBrowser.selectedBrowser.contentDocument.getElementById("test");
|
||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
||||
ok(!objLoadingContent.activated, "plugin should not be activated");
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(plugin, {}, gNewWindow.gBrowser.selectedBrowser.contentWindow);
|
||||
let condition = function() objLoadingContent.activated;
|
||||
waitForCondition(condition, part8, "waited too long for plugin to activate");
|
||||
}
|
||||
|
||||
function part8() {
|
||||
ok(!PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser), "Should not have a click-to-play notification in the tab in the new window now");
|
||||
let plugin = gNewWindow.gBrowser.selectedBrowser.contentDocument.getElementById("test");
|
||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
||||
ok(objLoadingContent.activated, "plugin should be activated now");
|
||||
|
||||
gNewWindow.close();
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gNextTest = part9;
|
||||
gBrowser.selectedBrowser.addEventListener("PluginBindingAttached", handleEvent, true, true);
|
||||
// This test page contains an "invisible" plugin. It doesn't script it,
|
||||
// but when we do later in this test, it will trigger the popup notification.
|
||||
gBrowser.selectedBrowser.contentDocument.location = gHttpTestRoot + "plugin_test_noScriptNoPopup.html";
|
||||
}
|
||||
|
||||
function part9() {
|
||||
gBrowser.selectedBrowser.removeEventListener("PluginBindingAttached", handleEvent);
|
||||
ok(PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser), "Should have a click-to-play notification in the initial tab");
|
||||
|
||||
gNextTest = part10;
|
||||
gNewWindow = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
|
||||
gNewWindow.addEventListener("load", handleEvent, true);
|
||||
}
|
||||
|
||||
function part10() {
|
||||
gNewWindow.removeEventListener("load", handleEvent);
|
||||
let condition = function() PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser);
|
||||
waitForCondition(condition, part11, "Waited too long for click-to-play notification");
|
||||
}
|
||||
|
||||
function part11() {
|
||||
ok(!PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser), "Should not have a click-to-play notification in the old window now");
|
||||
let notification = PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser);
|
||||
ok(notification, "Should have a click-to-play notification in the tab in the new window");
|
||||
// we have to actually show the panel to get the bindings to instantiate
|
||||
notification.options.eventCallback = part12;
|
||||
// this scripts the plugin, triggering the popup notification
|
||||
try {
|
||||
gNewWindow.gBrowser.selectedBrowser.contentDocument.getElementById("test").wrappedJSObject.getObjectValue();
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function part12() {
|
||||
let notification = PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser);
|
||||
notification.options.eventCallback = null;
|
||||
let centerAction = null;
|
||||
for (let action of notification.options.centerActions) {
|
||||
if (action.message == "Test") {
|
||||
centerAction = action;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ok(centerAction, "Found center action for the Test plugin");
|
||||
|
||||
let centerItem = null;
|
||||
for (let item of centerAction.popupnotification.childNodes) {
|
||||
if (item.action == centerAction) {
|
||||
centerItem = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ok(centerItem, "Found center item for the Test plugin");
|
||||
|
||||
// "click" the button to activate the Test plugin
|
||||
centerItem.runCallback.apply(centerItem);
|
||||
|
||||
let plugin = gNewWindow.gBrowser.selectedBrowser.contentDocument.getElementById("test");
|
||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
||||
let condition = function() objLoadingContent.activated;
|
||||
waitForCondition(condition, part13, "Waited too long for plugin to activate via center action");
|
||||
}
|
||||
|
||||
function part13() {
|
||||
ok(!PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser), "Should not have a click-to-play notification in the tab in the new window");
|
||||
let plugin = gNewWindow.gBrowser.selectedBrowser.contentDocument.getElementById("test");
|
||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
||||
ok(objLoadingContent.activated, "Plugin should be activated via center action");
|
||||
|
||||
gNewWindow.close();
|
||||
finish();
|
||||
}
|
||||
|
@ -319,6 +319,10 @@ let SessionStoreInternal = {
|
||||
// Whether session has been initialized
|
||||
_sessionInitialized: false,
|
||||
|
||||
// True if session store is disabled by multi-process browsing.
|
||||
// See bug 516755.
|
||||
_disabledForMultiProcess: false,
|
||||
|
||||
// The original "sessionstore.resume_session_once" preference value before it
|
||||
// was modified by saveState. saveState will set the
|
||||
// "sessionstore.resume_session_once" to true when the
|
||||
@ -367,6 +371,8 @@ let SessionStoreInternal = {
|
||||
// Do pref migration before we store any values and start observing changes
|
||||
this._migratePrefs();
|
||||
|
||||
this._disabledForMultiProcess = this._prefBranch.getBoolPref("tabs.remote");
|
||||
|
||||
// this pref is only read at startup, so no need to observe it
|
||||
this._sessionhistory_max_entries =
|
||||
this._prefBranch.getIntPref("sessionhistory.max_entries");
|
||||
@ -591,6 +597,9 @@ let SessionStoreInternal = {
|
||||
* Handle notifications
|
||||
*/
|
||||
observe: function ssi_observe(aSubject, aTopic, aData) {
|
||||
if (this._disabledForMultiProcess)
|
||||
return;
|
||||
|
||||
switch (aTopic) {
|
||||
case "domwindowopened": // catch new windows
|
||||
this.onOpen(aSubject);
|
||||
@ -654,6 +663,9 @@ let SessionStoreInternal = {
|
||||
* Implement nsIDOMEventListener for handling various window and tab events
|
||||
*/
|
||||
handleEvent: function ssi_handleEvent(aEvent) {
|
||||
if (this._disabledForMultiProcess)
|
||||
return;
|
||||
|
||||
var win = aEvent.currentTarget.ownerDocument.defaultView;
|
||||
switch (aEvent.type) {
|
||||
case "load":
|
||||
|
@ -7308,12 +7308,10 @@ exports.Output = Output;
|
||||
* Functions and data related to the execution of a command
|
||||
*/
|
||||
exports.createExecutionContext = function(requisition) {
|
||||
return {
|
||||
var context = {
|
||||
exec: requisition.exec.bind(requisition),
|
||||
update: requisition.update.bind(requisition),
|
||||
updateExec: requisition.updateExec.bind(requisition),
|
||||
document: requisition.document,
|
||||
environment: requisition.environment,
|
||||
createView: view.createView,
|
||||
typedData: function(data, type) {
|
||||
return {
|
||||
@ -7334,6 +7332,18 @@ exports.createExecutionContext = function(requisition) {
|
||||
return Promise.defer();
|
||||
}
|
||||
};
|
||||
|
||||
Object.defineProperty(context, 'environment', {
|
||||
get: function() { return requisition.environment; },
|
||||
enumerable : true
|
||||
});
|
||||
|
||||
Object.defineProperty(context, 'document', {
|
||||
get: function() { return requisition.document; },
|
||||
enumerable : true
|
||||
});
|
||||
|
||||
return context;
|
||||
};
|
||||
|
||||
|
||||
|
@ -653,12 +653,12 @@ function testKeyboardAccessibility(callback) {
|
||||
"The 0 item should be focused now.");
|
||||
|
||||
EventUtils.sendKey("END", gDebugger);
|
||||
is(gVariablesView.getFocusedItem().name, "foo",
|
||||
"The foo item should be focused now.");
|
||||
is(gVariablesView.getFocusedItem().name, "bar",
|
||||
"The bar item should be focused now.");
|
||||
|
||||
EventUtils.sendKey("DOWN", gDebugger);
|
||||
is(gVariablesView.getFocusedItem().name, "bar",
|
||||
"The bar item should be focused now.");
|
||||
"The bar item should still be focused now.");
|
||||
|
||||
EventUtils.sendKey("UP", gDebugger);
|
||||
is(gVariablesView.getFocusedItem().name, "foo",
|
||||
@ -669,10 +669,14 @@ function testKeyboardAccessibility(callback) {
|
||||
"The foo item should still be focused now.");
|
||||
|
||||
EventUtils.sendKey("PAGE_DOWN", gDebugger);
|
||||
is(gVariablesView.getFocusedItem().name, "foo",
|
||||
"The foo item should still be focused now.");
|
||||
is(gVariablesView.getFocusedItem().name, "bar",
|
||||
"The bar item should be focused now.");
|
||||
|
||||
EventUtils.sendKey("PAGE_UP", gDebugger);
|
||||
is(gVariablesView.getFocusedItem().name, "someProp7",
|
||||
"The someProp7 item should be focused now.");
|
||||
|
||||
EventUtils.sendKey("UP", gDebugger);
|
||||
is(gVariablesView.getFocusedItem().name, "__proto__",
|
||||
"The __proto__ item should be focused now.");
|
||||
|
||||
@ -684,10 +688,6 @@ function testKeyboardAccessibility(callback) {
|
||||
is(gVariablesView.getFocusedItem().name, "get",
|
||||
"The get item should be focused now.");
|
||||
|
||||
EventUtils.sendKey("UP", gDebugger);
|
||||
is(gVariablesView.getFocusedItem().name, "p8",
|
||||
"The p8 item should be focused now.");
|
||||
|
||||
EventUtils.sendKey("HOME", gDebugger);
|
||||
is(gVariablesView.getFocusedItem().name, "someProp0",
|
||||
"The someProp0 item should be focused now.");
|
||||
@ -828,6 +828,18 @@ function testKeyboardAccessibility(callback) {
|
||||
is(gVariablesView.getFocusedItem().expanded, false,
|
||||
"The top-level __proto__ item should not be expanded.");
|
||||
|
||||
EventUtils.sendKey("END", gDebugger);
|
||||
is(gVariablesView.getFocusedItem().name, "foo",
|
||||
"The foo scope should be focused.");
|
||||
|
||||
EventUtils.sendKey("PAGE_UP", gDebugger);
|
||||
is(gVariablesView.getFocusedItem().name, "__proto__",
|
||||
"The __proto__ property should be focused.");
|
||||
|
||||
EventUtils.sendKey("PAGE_DOWN", gDebugger);
|
||||
is(gVariablesView.getFocusedItem().name, "foo",
|
||||
"The foo scope should be focused.");
|
||||
|
||||
executeSoon(callback);
|
||||
});
|
||||
});
|
||||
|
@ -275,25 +275,31 @@ TabTarget.prototype = {
|
||||
|
||||
this._setupRemoteListeners();
|
||||
|
||||
if (this.isRemote) {
|
||||
// In the remote debugging case, the protocol connection will have been
|
||||
// already initialized in the connection screen code.
|
||||
this._remote.resolve(null);
|
||||
} else {
|
||||
let attachTab = () => {
|
||||
this._client.attachTab(this._form.actor, (aResponse, aTabClient) => {
|
||||
if (!aTabClient) {
|
||||
this._remote.reject("Unable to attach to the tab");
|
||||
return;
|
||||
}
|
||||
this.threadActor = aResponse.threadActor;
|
||||
this._remote.resolve(null);
|
||||
});
|
||||
};
|
||||
|
||||
if (this.isLocalTab) {
|
||||
this._client.connect((aType, aTraits) => {
|
||||
this._client.listTabs(aResponse => {
|
||||
this._form = aResponse.tabs[aResponse.selected];
|
||||
|
||||
this._client.attachTab(this._form.actor, (aResponse, aTabClient) => {
|
||||
if (!aTabClient) {
|
||||
this._remote.reject("Unable to attach to the tab");
|
||||
return;
|
||||
}
|
||||
this.threadActor = aResponse.threadActor;
|
||||
this._remote.resolve(null);
|
||||
});
|
||||
attachTab();
|
||||
});
|
||||
});
|
||||
} else if (!this.chrome) {
|
||||
// In the remote debugging case, the protocol connection will have been
|
||||
// already initialized in the connection screen code.
|
||||
attachTab();
|
||||
} else {
|
||||
// Remote chrome debugging doesn't need anything at this point.
|
||||
this._remote.resolve(null);
|
||||
}
|
||||
|
||||
return this._remote.promise;
|
||||
|
@ -515,7 +515,8 @@ let L10N = new ViewHelpers.L10N(NET_STRINGS_URI);
|
||||
* Shortcuts for accessing various network monitor preferences.
|
||||
*/
|
||||
let Prefs = new ViewHelpers.Prefs("devtools.netmonitor", {
|
||||
networkDetailsWidth: ["Int", "panes-network-details-width"]
|
||||
networkDetailsWidth: ["Int", "panes-network-details-width"],
|
||||
networkDetailsHeight: ["Int", "panes-network-details-height"]
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
const EPSILON = 0.001;
|
||||
const REQUESTS_REFRESH_RATE = 50; // ms
|
||||
const REQUESTS_HEADERS_SAFE_BOUNDS = 30; // px
|
||||
const REQUESTS_WATERFALL_SAFE_BOUNDS = 100; // px
|
||||
const REQUESTS_WATERFALL_BACKGROUND_PATTERN = [5, 250, 1000, 2000]; // ms
|
||||
const DEFAULT_HTTP_VERSION = "HTTP/1.1";
|
||||
@ -102,6 +103,7 @@ let NetMonitorView = {
|
||||
this._expandPaneString = L10N.getStr("expandDetailsPane");
|
||||
|
||||
this._detailsPane.setAttribute("width", Prefs.networkDetailsWidth);
|
||||
this._detailsPane.setAttribute("height", Prefs.networkDetailsHeight);
|
||||
this.toggleDetailsPane({ visible: false });
|
||||
},
|
||||
|
||||
@ -112,6 +114,7 @@ let NetMonitorView = {
|
||||
dumpn("Destroying the NetMonitorView panes");
|
||||
|
||||
Prefs.networkDetailsWidth = this._detailsPane.getAttribute("width");
|
||||
Prefs.networkDetailsHeight = this._detailsPane.getAttribute("height");
|
||||
|
||||
this._detailsPane = null;
|
||||
this._detailsPaneToggleButton = null;
|
||||
@ -592,6 +595,27 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
|
||||
// the window is resized, this needs to be invalidated.
|
||||
if (aReset) {
|
||||
this._cachedWaterfallWidth = 0;
|
||||
|
||||
let table = $("#network-table");
|
||||
let toolbar = $("#requests-menu-toolbar");
|
||||
let columns = [
|
||||
[".requests-menu-waterfall", "waterfall-overflows"],
|
||||
[".requests-menu-size", "size-overflows"],
|
||||
[".requests-menu-type", "type-overflows"],
|
||||
[".requests-menu-domain", "domain-overflows"]
|
||||
];
|
||||
|
||||
// Flush headers.
|
||||
columns.forEach(([, attribute]) => table.removeAttribute(attribute));
|
||||
let availableWidth = toolbar.getBoundingClientRect().width;
|
||||
|
||||
// Hide overflowing columns.
|
||||
columns.forEach(([className, attribute]) => {
|
||||
let bounds = $(".requests-menu-header" + className).getBoundingClientRect();
|
||||
if (bounds.right > availableWidth - REQUESTS_HEADERS_SAFE_BOUNDS) {
|
||||
table.setAttribute(attribute, "");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Determine the scaling to be applied to all the waterfalls so that
|
||||
|
@ -13,8 +13,36 @@
|
||||
|
||||
/* Responsive sidebar */
|
||||
@media (max-width: 700px) {
|
||||
#toolbar-spacer,
|
||||
#details-pane-toggle,
|
||||
#details-pane[pane-collapsed],
|
||||
.requests-menu-waterfall {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 701px) {
|
||||
#network-table[waterfall-overflows] .requests-menu-waterfall {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#network-table[size-overflows] .requests-menu-size {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#network-table[type-overflows] .requests-menu-type {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#network-table[domain-overflows] .requests-menu-domain {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#network-table[type-overflows] .requests-menu-domain {
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
#network-table[domain-overflows] .requests-menu-file {
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@
|
||||
class="plain requests-menu-header requests-menu-waterfall"
|
||||
value="&netmonitorUI.toolbar.waterfall;"
|
||||
crop="end"/>
|
||||
<spacer flex="1"/>
|
||||
<spacer id="toolbar-spacer" flex="1"/>
|
||||
<toolbarbutton id="details-pane-toggle"
|
||||
class="devtools-toolbarbutton"
|
||||
tooltiptext="&netmonitorUI.panesButton.tooltip;"
|
||||
|
@ -25,7 +25,7 @@ function test() {
|
||||
statusText: "OK",
|
||||
type: "json",
|
||||
fullMimeType: "text/json; charset=utf-8",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 83.95),
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", L10N.numberWithDecimals(85975/1024, 2)),
|
||||
time: true
|
||||
});
|
||||
|
||||
|
@ -9,13 +9,20 @@ function test() {
|
||||
initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
|
||||
info("Starting test... ");
|
||||
|
||||
// This test reopens the network monitor a bunch of times, for different
|
||||
// hosts (bottom, side, window). This seems to be slow on debug builds.
|
||||
requestLongerTimeout(2);
|
||||
|
||||
let prefsToCheck = {
|
||||
networkDetailsWidth: {
|
||||
newValue: ~~(Math.random() * 200 + 100),
|
||||
validate: () =>
|
||||
~~aMonitor._view._detailsPane.getAttribute("width"),
|
||||
modifyFrontend: (aValue) =>
|
||||
aMonitor._view._detailsPane.setAttribute("width", aValue)
|
||||
validate: ($) => ~~$("#details-pane").getAttribute("width"),
|
||||
modifyFrontend: ($, aValue) => $("#details-pane").setAttribute("width", aValue)
|
||||
},
|
||||
networkDetailsHeight: {
|
||||
newValue: ~~(Math.random() * 300 + 100),
|
||||
validate: ($) => ~~$("#details-pane").getAttribute("height"),
|
||||
modifyFrontend: ($, aValue) => $("#details-pane").setAttribute("height", aValue)
|
||||
},
|
||||
/* add more prefs here... */
|
||||
};
|
||||
@ -39,7 +46,7 @@ function test() {
|
||||
|
||||
is(currentValue, firstValue,
|
||||
"Pref " + name + " should be equal to first value: " + firstValue);
|
||||
is(currentValue, validate(),
|
||||
is(currentValue, validate(aMonitor.panelWin.$),
|
||||
"Pref " + name + " should validate: " + currentValue);
|
||||
}
|
||||
}
|
||||
@ -54,14 +61,14 @@ function test() {
|
||||
let validate = prefsToCheck[name].validate;
|
||||
let modifyFrontend = prefsToCheck[name].modifyFrontend;
|
||||
|
||||
modifyFrontend(newValue);
|
||||
modifyFrontend(aMonitor.panelWin.$, newValue);
|
||||
info("Modified UI element affecting " + name + " to: " + newValue);
|
||||
|
||||
is(currentValue, firstValue,
|
||||
"Pref " + name + " should still be equal to first value: " + firstValue);
|
||||
isnot(currentValue, newValue,
|
||||
"Pref " + name + " should't yet be equal to second value: " + newValue);
|
||||
is(newValue, validate(),
|
||||
is(newValue, validate(aMonitor.panelWin.$),
|
||||
"The UI element affecting " + name + " should validate: " + newValue);
|
||||
}
|
||||
}
|
||||
@ -74,13 +81,12 @@ function test() {
|
||||
let firstValue = prefsToCheck[name].firstValue;
|
||||
let newValue = prefsToCheck[name].newValue;
|
||||
let validate = prefsToCheck[name].validate;
|
||||
let modifyFrontend = prefsToCheck[name].modifyFrontend;
|
||||
|
||||
isnot(currentValue, firstValue,
|
||||
"Pref " + name + " should't be equal to first value: " + firstValue);
|
||||
is(currentValue, newValue,
|
||||
"Pref " + name + " should now be equal to second value: " + newValue);
|
||||
is(newValue, validate(),
|
||||
is(newValue, validate(aMonitor.panelWin.$),
|
||||
"The UI element affecting " + name + " should validate: " + newValue);
|
||||
}
|
||||
}
|
||||
@ -95,36 +101,117 @@ function test() {
|
||||
let validate = prefsToCheck[name].validate;
|
||||
let modifyFrontend = prefsToCheck[name].modifyFrontend;
|
||||
|
||||
modifyFrontend(firstValue);
|
||||
modifyFrontend(aMonitor.panelWin.$, firstValue);
|
||||
info("Modified UI element affecting " + name + " to: " + firstValue);
|
||||
|
||||
isnot(currentValue, firstValue,
|
||||
"Pref " + name + " should't yet be equal to first value: " + firstValue);
|
||||
is(currentValue, newValue,
|
||||
"Pref " + name + " should still be equal to second value: " + newValue);
|
||||
is(firstValue, validate(),
|
||||
is(firstValue, validate(aMonitor.panelWin.$),
|
||||
"The UI element affecting " + name + " should validate: " + firstValue);
|
||||
}
|
||||
}
|
||||
|
||||
storeFirstPrefValues();
|
||||
function testBottom() {
|
||||
info("Testing prefs reload for a bottom host.");
|
||||
storeFirstPrefValues();
|
||||
|
||||
// Validate and modify.
|
||||
validateFirstPrefValues();
|
||||
modifyFrontend();
|
||||
restartNetMonitor(aMonitor).then(([,, aNewMonitor]) => {
|
||||
aMonitor = aNewMonitor;
|
||||
// Validate and modify while toolbox is on the bottom.
|
||||
validateFirstPrefValues();
|
||||
modifyFrontend();
|
||||
|
||||
// Revalidate and reset.
|
||||
validateNewPrefValues();
|
||||
resetFrontend();
|
||||
restartNetMonitor(aMonitor).then(([,, aNewMonitor]) => {
|
||||
aMonitor = aNewMonitor;
|
||||
return restartNetMonitor(aMonitor)
|
||||
.then(([,, aNewMonitor]) => {
|
||||
aMonitor = aNewMonitor;
|
||||
|
||||
// Revalidate and finish.
|
||||
validateFirstPrefValues();
|
||||
teardown(aMonitor).then(finish);
|
||||
});
|
||||
});
|
||||
// Revalidate and reset frontend while toolbox is on the bottom.
|
||||
validateNewPrefValues();
|
||||
resetFrontend();
|
||||
|
||||
return restartNetMonitor(aMonitor);
|
||||
})
|
||||
.then(([,, aNewMonitor]) => {
|
||||
aMonitor = aNewMonitor;
|
||||
|
||||
// Revalidate.
|
||||
validateFirstPrefValues();
|
||||
});
|
||||
}
|
||||
|
||||
function testSide() {
|
||||
info("Moving toolbox to the side...");
|
||||
|
||||
return aMonitor._toolbox.switchHost(Toolbox.HostType.SIDE)
|
||||
.then(() => {
|
||||
info("Testing prefs reload for a side host.");
|
||||
storeFirstPrefValues();
|
||||
|
||||
// Validate and modify frontend while toolbox is on the side.
|
||||
validateFirstPrefValues();
|
||||
modifyFrontend();
|
||||
|
||||
return restartNetMonitor(aMonitor);
|
||||
})
|
||||
.then(([,, aNewMonitor]) => {
|
||||
aMonitor = aNewMonitor;
|
||||
|
||||
// Revalidate and reset frontend while toolbox is on the side.
|
||||
validateNewPrefValues();
|
||||
resetFrontend();
|
||||
|
||||
return restartNetMonitor(aMonitor);
|
||||
})
|
||||
.then(([,, aNewMonitor]) => {
|
||||
aMonitor = aNewMonitor;
|
||||
|
||||
// Revalidate.
|
||||
validateFirstPrefValues();
|
||||
});
|
||||
}
|
||||
|
||||
function testWindow() {
|
||||
info("Moving toolbox into a window...");
|
||||
|
||||
return aMonitor._toolbox.switchHost(Toolbox.HostType.WINDOW)
|
||||
.then(() => {
|
||||
info("Testing prefs reload for a window host.");
|
||||
storeFirstPrefValues();
|
||||
|
||||
// Validate and modify frontend while toolbox is in a window.
|
||||
validateFirstPrefValues();
|
||||
modifyFrontend();
|
||||
|
||||
return restartNetMonitor(aMonitor);
|
||||
})
|
||||
.then(([,, aNewMonitor]) => {
|
||||
aMonitor = aNewMonitor;
|
||||
|
||||
// Revalidate and reset frontend while toolbox is in a window.
|
||||
validateNewPrefValues();
|
||||
resetFrontend();
|
||||
|
||||
return restartNetMonitor(aMonitor);
|
||||
})
|
||||
.then(([,, aNewMonitor]) => {
|
||||
aMonitor = aNewMonitor;
|
||||
|
||||
// Revalidate.
|
||||
validateFirstPrefValues();
|
||||
});
|
||||
}
|
||||
|
||||
function cleanupAndFinish() {
|
||||
info("Moving toolbox back to the bottom...");
|
||||
|
||||
aMonitor._toolbox.switchHost(Toolbox.HostType.BOTTOM)
|
||||
.then(() => teardown(aMonitor))
|
||||
.then(finish);
|
||||
}
|
||||
|
||||
testBottom()
|
||||
.then(testSide)
|
||||
.then(testWindow)
|
||||
.then(cleanupAndFinish);
|
||||
});
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ function test() {
|
||||
|
||||
is(responseScope.querySelector(".name").getAttribute("value"),
|
||||
L10N.getStr("responseHeaders") + " (" +
|
||||
L10N.getFormatStr("networkMenu.sizeKB", L10N.numberWithDecimals(0.168, 3)) + ")",
|
||||
L10N.getFormatStr("networkMenu.sizeKB", L10N.numberWithDecimals(173/1024, 3)) + ")",
|
||||
"The response headers scope doesn't have the correct title.");
|
||||
|
||||
ok(requestScope.querySelector(".name").getAttribute("value").contains(
|
||||
|
@ -7,6 +7,7 @@ const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
let { Promise } = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
|
||||
let { TargetFactory } = Cu.import("resource:///modules/devtools/Target.jsm", {});
|
||||
let { Toolbox } = Cu.import("resource:///modules/devtools/Toolbox.jsm", {});
|
||||
let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
|
||||
|
||||
const EXAMPLE_URL = "http://example.com/browser/browser/devtools/netmonitor/test/";
|
||||
|
@ -506,7 +506,7 @@ DeveloperToolbar.prototype.destroy = function DT_destroy()
|
||||
let tabbrowser = this._chromeWindow.getBrowser();
|
||||
tabbrowser.tabContainer.removeEventListener("TabSelect", this, false);
|
||||
tabbrowser.tabContainer.removeEventListener("TabClose", this, false);
|
||||
tabbrowser.removeEventListener("load", this, true);
|
||||
tabbrowser.removeEventListener("load", this, true);
|
||||
tabbrowser.removeEventListener("beforeunload", this, true);
|
||||
|
||||
Array.prototype.forEach.call(tabbrowser.tabs, this._stopErrorsCount, this);
|
||||
|
@ -52,6 +52,7 @@ const STR = Services.strings.createBundle(DBG_STRINGS_URI);
|
||||
*/
|
||||
this.VariablesView = function VariablesView(aParentNode, aFlags = {}) {
|
||||
this._store = new Map();
|
||||
this._items = [];
|
||||
this._itemsByElement = new WeakMap();
|
||||
this._prevHierarchy = new Map();
|
||||
this._currHierarchy = new Map();
|
||||
@ -103,6 +104,7 @@ VariablesView.prototype = {
|
||||
|
||||
let scope = new Scope(this, aName);
|
||||
this._store.set(scope.id, scope);
|
||||
this._items.push(scope);
|
||||
this._currHierarchy.set(aName, scope);
|
||||
this._itemsByElement.set(scope._target, scope);
|
||||
scope.header = !!aName;
|
||||
@ -135,6 +137,7 @@ VariablesView.prototype = {
|
||||
}
|
||||
|
||||
this._store.clear();
|
||||
this._items.length = 0;
|
||||
this._itemsByElement.clear();
|
||||
|
||||
this._appendEmptyNotice();
|
||||
@ -161,6 +164,7 @@ VariablesView.prototype = {
|
||||
let currList = this._list = this.document.createElement("scrollbox");
|
||||
|
||||
this._store.clear();
|
||||
this._items.length = 0;
|
||||
this._itemsByElement.clear();
|
||||
|
||||
this._emptyTimeout = this.window.setTimeout(function() {
|
||||
@ -529,64 +533,73 @@ VariablesView.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Focuses the first visible variable or property in this container.
|
||||
* Find the first item in the tree of visible items in this container that
|
||||
* matches the predicate. Searches in visual order (the order seen by the
|
||||
* user). Descends into each scope to check the scope and its children.
|
||||
*
|
||||
* @param function aPredicate
|
||||
* A function that returns true when a match is found.
|
||||
* @return Scope | Variable | Property
|
||||
* The first visible scope, variable or property, or null if nothing
|
||||
* is found.
|
||||
*/
|
||||
focusFirstVisibleNode: function VV_focusFirstVisibleNode() {
|
||||
let property, variable, scope;
|
||||
|
||||
for (let [, item] of this._currHierarchy) {
|
||||
if (!item.focusable) {
|
||||
continue;
|
||||
}
|
||||
if (item instanceof Property) {
|
||||
property = item;
|
||||
break;
|
||||
} else if (item instanceof Variable) {
|
||||
variable = item;
|
||||
break;
|
||||
} else if (item instanceof Scope) {
|
||||
scope = item;
|
||||
break;
|
||||
_findInVisibleItems: function VV__findInVisibleItems(aPredicate) {
|
||||
for (let scope of this._items) {
|
||||
let result = scope._findInVisibleItems(aPredicate);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (scope) {
|
||||
this._focusItem(scope);
|
||||
} else if (variable) {
|
||||
this._focusItem(variable);
|
||||
} else if (property) {
|
||||
this._focusItem(property);
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Find the last item in the tree of visible items in this container that
|
||||
* matches the predicate. Searches in reverse visual order (opposite of the
|
||||
* order seen by the user). Descends into each scope to check the scope and
|
||||
* its children.
|
||||
*
|
||||
* @param function aPredicate
|
||||
* A function that returns true when a match is found.
|
||||
* @return Scope | Variable | Property
|
||||
* The last visible scope, variable or property, or null if nothing
|
||||
* is found.
|
||||
*/
|
||||
_findInVisibleItemsReverse: function VV__findInVisibleItemsReverse(aPredicate) {
|
||||
for (let i = this._items.length - 1; i >= 0; i--) {
|
||||
let scope = this._items[i];
|
||||
let result = scope._findInVisibleItemsReverse(aPredicate);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Focuses the first visible scope, variable, or property in this container.
|
||||
*/
|
||||
focusFirstVisibleNode: function VV_focusFirstVisibleNode() {
|
||||
let focusableItem = this._findInVisibleItems(item => item.focusable);
|
||||
|
||||
if (focusableItem) {
|
||||
this._focusItem(focusableItem);
|
||||
}
|
||||
this._parent.scrollTop = 0;
|
||||
this._parent.scrollLeft = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Focuses the last visible variable or property in this container.
|
||||
* Focuses the last visible scope, variable, or property in this container.
|
||||
*/
|
||||
focusLastVisibleNode: function VV_focusLastVisibleNode() {
|
||||
let property, variable, scope;
|
||||
let focusableItem = this._findInVisibleItemsReverse(item => item.focusable);
|
||||
|
||||
for (let [, item] of this._currHierarchy) {
|
||||
if (!item.focusable) {
|
||||
continue;
|
||||
}
|
||||
if (item instanceof Property) {
|
||||
property = item;
|
||||
} else if (item instanceof Variable) {
|
||||
variable = item;
|
||||
} else if (item instanceof Scope) {
|
||||
scope = item;
|
||||
}
|
||||
}
|
||||
if (property && (!variable || property.isDescendantOf(variable))) {
|
||||
this._focusItem(property);
|
||||
} else if (variable && (!scope || variable.isDescendantOf(scope))) {
|
||||
this._focusItem(variable);
|
||||
} else if (scope) {
|
||||
this._focusItem(scope);
|
||||
this._parent.scrollTop = this._parent.scrollHeight;
|
||||
this._parent.scrollLeft = 0;
|
||||
if (focusableItem) {
|
||||
this._focusItem(focusableItem);
|
||||
}
|
||||
this._parent.scrollTop = this._parent.scrollHeight;
|
||||
this._parent.scrollLeft = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -888,6 +901,7 @@ VariablesView.prototype = {
|
||||
_window: null,
|
||||
|
||||
_store: null,
|
||||
_items: null,
|
||||
_prevHierarchy: null,
|
||||
_currHierarchy: null,
|
||||
_enumVisible: true,
|
||||
@ -1082,6 +1096,8 @@ function Scope(aView, aName, aFlags = {}) {
|
||||
this.separatorStr = aView.separatorStr;
|
||||
|
||||
this._store = new Map();
|
||||
this._enumItems = [];
|
||||
this._nonEnumItems = [];
|
||||
this._init(aName.trim(), aFlags);
|
||||
}
|
||||
|
||||
@ -1785,6 +1801,89 @@ Scope.prototype = {
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Find the first item in the tree of visible items in this item that matches
|
||||
* the predicate. Searches in visual order (the order seen by the user).
|
||||
* Tests itself, then descends into first the enumerable children and then
|
||||
* the non-enumerable children (since they are presented in separate groups).
|
||||
*
|
||||
* @param function aPredicate
|
||||
* A function that returns true when a match is found.
|
||||
* @return Scope | Variable | Property
|
||||
* The first visible scope, variable or property, or null if nothing
|
||||
* is found.
|
||||
*/
|
||||
_findInVisibleItems: function S__findInVisibleItems(aPredicate) {
|
||||
if (aPredicate(this)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (this._isExpanded) {
|
||||
if (this._variablesView._enumVisible) {
|
||||
for (let item of this._enumItems) {
|
||||
let result = item._findInVisibleItems(aPredicate);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this._variablesView._nonEnumVisible) {
|
||||
for (let item of this._nonEnumItems) {
|
||||
let result = item._findInVisibleItems(aPredicate);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Find the last item in the tree of visible items in this item that matches
|
||||
* the predicate. Searches in reverse visual order (opposite of the order
|
||||
* seen by the user). Descends into first the non-enumerable children, then
|
||||
* the enumerable children (since they are presented in separate groups), and
|
||||
* finally tests itself.
|
||||
*
|
||||
* @param function aPredicate
|
||||
* A function that returns true when a match is found.
|
||||
* @return Scope | Variable | Property
|
||||
* The last visible scope, variable or property, or null if nothing
|
||||
* is found.
|
||||
*/
|
||||
_findInVisibleItemsReverse: function S__findInVisibleItemsReverse(aPredicate) {
|
||||
if (this._isExpanded) {
|
||||
if (this._variablesView._nonEnumVisible) {
|
||||
for (let i = this._nonEnumItems.length - 1; i >= 0; i--) {
|
||||
let item = this._nonEnumItems[i];
|
||||
let result = item._findInVisibleItemsReverse(aPredicate);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this._variablesView._enumVisible) {
|
||||
for (let i = this._enumItems.length - 1; i >= 0; i--) {
|
||||
let item = this._enumItems[i];
|
||||
let result = item._findInVisibleItemsReverse(aPredicate);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aPredicate(this)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets top level variables view instance.
|
||||
* @return VariablesView
|
||||
@ -1854,7 +1953,9 @@ Scope.prototype = {
|
||||
_name: null,
|
||||
_title: null,
|
||||
_enum: null,
|
||||
_enumItems: null,
|
||||
_nonenum: null,
|
||||
_nonEnumItems: null,
|
||||
_throbber: null
|
||||
};
|
||||
|
||||
@ -2167,8 +2268,10 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
|
||||
this._nameString == "this" ||
|
||||
this._nameString == "<exception>") {
|
||||
this.ownerView._lazyAppend(aImmediateFlag, true, this._target);
|
||||
this.ownerView._enumItems.push(this);
|
||||
} else {
|
||||
this.ownerView._lazyAppend(aImmediateFlag, false, this._target);
|
||||
this.ownerView._nonEnumItems.push(this);
|
||||
}
|
||||
},
|
||||
|
||||
@ -2674,8 +2777,10 @@ ViewHelpers.create({ constructor: Property, proto: Variable.prototype }, {
|
||||
_onInit: function P__onInit(aImmediateFlag) {
|
||||
if (this._initialDescriptor.enumerable) {
|
||||
this.ownerView._lazyAppend(aImmediateFlag, true, this._target);
|
||||
this.ownerView._enumItems.push(this);
|
||||
} else {
|
||||
this.ownerView._lazyAppend(aImmediateFlag, false, this._target);
|
||||
this.ownerView._nonEnumItems.push(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -663,9 +663,19 @@ var HeadsUpDisplayUICommands = {
|
||||
|
||||
let client = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
client.connect(() =>
|
||||
client.listTabs((aResponse) =>
|
||||
deferred.resolve({ form: aResponse, client: client })
|
||||
));
|
||||
client.listTabs((aResponse) => {
|
||||
// Add Global Process debugging...
|
||||
let globals = JSON.parse(JSON.stringify(aResponse));
|
||||
delete globals.tabs;
|
||||
delete globals.selected;
|
||||
// ...only if there are appropriate actors (a 'from' property will
|
||||
// always be there).
|
||||
if (Object.keys(globals).length > 1) {
|
||||
deferred.resolve({ form: globals, client: client, chrome: true });
|
||||
} else {
|
||||
deferred.reject("Global console not found!");
|
||||
}
|
||||
}));
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
@ -122,6 +122,7 @@ MOCHITEST_BROWSER_FILES = \
|
||||
browser_console.js \
|
||||
browser_longstring_hang.js \
|
||||
browser_console_consolejsm_output.js \
|
||||
browser_webconsole_bug_837351_securityerrors.js \
|
||||
head.js \
|
||||
$(NULL)
|
||||
|
||||
@ -224,6 +225,7 @@ MOCHITEST_BROWSER_FILES += \
|
||||
test-bug-821877-csperrors.html^headers^ \
|
||||
test-eval-in-stackframe.html \
|
||||
test-bug-859170-longstring-hang.html \
|
||||
test-bug-837351-security-errors.html \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -53,13 +53,13 @@ function testCSSPruning(hudRef) {
|
||||
},
|
||||
successFn: function()
|
||||
{
|
||||
is(Object.keys(hudRef.ui._cssNodes).length, LOG_LIMIT,
|
||||
"repeated nodes pruned from cssNodes");
|
||||
is(Object.keys(hudRef.ui._repeatNodes).length, LOG_LIMIT,
|
||||
"repeated nodes pruned from repeatNodes");
|
||||
|
||||
let msg = hudRef.outputNode.querySelector(".webconsole-msg-cssparser " +
|
||||
".webconsole-msg-repeat");
|
||||
is(msg.getAttribute("value"), 1,
|
||||
"repeated nodes pruned from cssNodes (confirmed)");
|
||||
"repeated nodes pruned from repeatNodes (confirmed)");
|
||||
|
||||
finishTest();
|
||||
},
|
||||
|
@ -0,0 +1,34 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const TEST_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-bug-837351-security-errors.html";
|
||||
|
||||
function run_test()
|
||||
{
|
||||
addTab(TEST_URI);
|
||||
browser.addEventListener("load", function onLoad(aEvent) {
|
||||
browser.removeEventListener(aEvent.type, onLoad, true);
|
||||
openConsole(null, function testSecurityErrorLogged (hud) {
|
||||
let button = hud.ui.rootElement.querySelector(".webconsole-filter-button[category=\"security\"]");
|
||||
ok(button, "Found security button in the web console");
|
||||
|
||||
waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [
|
||||
{
|
||||
name: "Logged blocking mixed active content",
|
||||
text: "Blocked loading mixed active content \"http://example.com/\"",
|
||||
category: CATEGORY_SECURITY,
|
||||
severity: SEVERITY_ERROR
|
||||
},
|
||||
],
|
||||
}).then(finishTest);
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
|
||||
function test()
|
||||
{
|
||||
SpecialPowers.pushPrefEnv({'set': [["security.mixed_content.block_active_content", true]]}, run_test);
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ const CATEGORY_JS = 2;
|
||||
const CATEGORY_WEBDEV = 3;
|
||||
const CATEGORY_INPUT = 4;
|
||||
const CATEGORY_OUTPUT = 5;
|
||||
const CATEGORY_SECURITY = 6;
|
||||
|
||||
// The possible message severities.
|
||||
const SEVERITY_ERROR = 0;
|
||||
|
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html dir="ltr" xml:lang="en-US" lang="en-US"><head>
|
||||
<meta charset="utf8">
|
||||
<title>Mixed Content test - http on https</title>
|
||||
<script src="testscript.js"></script>
|
||||
<!--
|
||||
- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
</head>
|
||||
<body>
|
||||
<iframe src = "http://example.com"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -81,6 +81,7 @@ const CATEGORY_JS = 2;
|
||||
const CATEGORY_WEBDEV = 3;
|
||||
const CATEGORY_INPUT = 4; // always on
|
||||
const CATEGORY_OUTPUT = 5; // always on
|
||||
const CATEGORY_SECURITY = 6;
|
||||
|
||||
// The possible message severities. As before, we start at zero so we can use
|
||||
// these as indexes into MESSAGE_PREFERENCE_KEYS.
|
||||
@ -97,6 +98,7 @@ const CATEGORY_CLASS_FRAGMENTS = [
|
||||
"console",
|
||||
"input",
|
||||
"output",
|
||||
"security",
|
||||
];
|
||||
|
||||
// The fragment of a CSS class name that identifies each severity.
|
||||
@ -120,6 +122,7 @@ const MESSAGE_PREFERENCE_KEYS = [
|
||||
[ "error", "warn", "info", "log", ], // Web Developer
|
||||
[ null, null, null, null, ], // Input
|
||||
[ null, null, null, null, ], // Output
|
||||
[ "secerror", "secwarn", null, null, ], // Security
|
||||
];
|
||||
|
||||
// A mapping from the console API log event levels to the Web Console
|
||||
@ -192,7 +195,7 @@ function WebConsoleFrame(aWebConsoleOwner)
|
||||
this.owner = aWebConsoleOwner;
|
||||
this.hudId = this.owner.hudId;
|
||||
|
||||
this._cssNodes = {};
|
||||
this._repeatNodes = {};
|
||||
this._outputQueue = [];
|
||||
this._pruneCategoriesQueue = {};
|
||||
this._networkRequests = {};
|
||||
@ -289,11 +292,11 @@ WebConsoleFrame.prototype = {
|
||||
_outputTimerInitialized: null,
|
||||
|
||||
/**
|
||||
* Store for tracking repeated CSS nodes.
|
||||
* Store for tracking repeated nodes.
|
||||
* @private
|
||||
* @type object
|
||||
*/
|
||||
_cssNodes: null,
|
||||
_repeatNodes: null,
|
||||
|
||||
/**
|
||||
* Preferences for filtering messages by type.
|
||||
@ -509,6 +512,8 @@ WebConsoleFrame.prototype = {
|
||||
info: Services.prefs.getBoolPref(FILTER_PREFS_PREFIX + "info"),
|
||||
warn: Services.prefs.getBoolPref(FILTER_PREFS_PREFIX + "warn"),
|
||||
log: Services.prefs.getBoolPref(FILTER_PREFS_PREFIX + "log"),
|
||||
secerror: Services.prefs.getBoolPref(FILTER_PREFS_PREFIX + "secerror"),
|
||||
secwarn: Services.prefs.getBoolPref(FILTER_PREFS_PREFIX + "secwarn"),
|
||||
};
|
||||
},
|
||||
|
||||
@ -898,10 +903,11 @@ WebConsoleFrame.prototype = {
|
||||
let uid = repeatNode._uid;
|
||||
let dupeNode = null;
|
||||
|
||||
if (aNode.classList.contains("webconsole-msg-cssparser")) {
|
||||
dupeNode = this._cssNodes[uid];
|
||||
if (aNode.classList.contains("webconsole-msg-cssparser") ||
|
||||
aNode.classList.contains("webconsole-msg-security")) {
|
||||
dupeNode = this._repeatNodes[uid];
|
||||
if (!dupeNode) {
|
||||
this._cssNodes[uid] = aNode;
|
||||
this._repeatNodes[uid] = aNode;
|
||||
}
|
||||
}
|
||||
else if (!aNode.classList.contains("webconsole-msg-network") &&
|
||||
@ -1972,10 +1978,11 @@ WebConsoleFrame.prototype = {
|
||||
aNode._objectActors.clear();
|
||||
}
|
||||
|
||||
if (aNode.classList.contains("webconsole-msg-cssparser")) {
|
||||
if (aNode.classList.contains("webconsole-msg-cssparser") ||
|
||||
aNode.classList.contains("webconsole-msg-security")) {
|
||||
let repeatNode = aNode.getElementsByClassName("webconsole-msg-repeat")[0];
|
||||
if (repeatNode && repeatNode._uid) {
|
||||
delete this._cssNodes[repeatNode._uid];
|
||||
delete this._repeatNodes[repeatNode._uid];
|
||||
}
|
||||
}
|
||||
else if (aNode._connectionId &&
|
||||
@ -2583,7 +2590,7 @@ WebConsoleFrame.prototype = {
|
||||
|
||||
this._destroyer = Promise.defer();
|
||||
|
||||
this._cssNodes = {};
|
||||
this._repeatNodes = {};
|
||||
this._outputQueue = [];
|
||||
this._pruneCategoriesQueue = {};
|
||||
this._networkRequests = {};
|
||||
@ -3598,7 +3605,7 @@ JSTerm.prototype = {
|
||||
hud._outputQueue.forEach(hud._pruneItemFromQueue, hud);
|
||||
hud._outputQueue = [];
|
||||
hud._networkRequests = {};
|
||||
hud._cssNodes = {};
|
||||
hud._repeatNodes = {};
|
||||
|
||||
if (aClearStorage) {
|
||||
this.webConsoleClient.clearMessagesCache();
|
||||
@ -4259,9 +4266,9 @@ var Utils = {
|
||||
*
|
||||
* @param nsIScriptError aScriptError
|
||||
* The script error you want to determine the category for.
|
||||
* @return CATEGORY_JS|CATEGORY_CSS
|
||||
* Depending on the script error CATEGORY_JS or CATEGORY_CSS can be
|
||||
* returned.
|
||||
* @return CATEGORY_JS|CATEGORY_CSS|CATEGORY_SECURITY
|
||||
* Depending on the script error CATEGORY_JS, CATEGORY_CSS, or
|
||||
* CATEGORY_SECURITY can be returned.
|
||||
*/
|
||||
categoryForScriptError: function Utils_categoryForScriptError(aScriptError)
|
||||
{
|
||||
@ -4270,6 +4277,9 @@ var Utils = {
|
||||
case "CSS Loader":
|
||||
return CATEGORY_CSS;
|
||||
|
||||
case "Mixed Content Blocker":
|
||||
return CATEGORY_SECURITY;
|
||||
|
||||
default:
|
||||
return CATEGORY_JS;
|
||||
}
|
||||
|
@ -62,8 +62,8 @@
|
||||
<menuitem id="menu_copyURL" label="©URLCmd.label;"
|
||||
accesskey="©URLCmd.accesskey;" command="consoleCmd_copyURL"
|
||||
selection="network" selectionType="single"/>
|
||||
<menuitem id="menu_copy"/>
|
||||
<menuitem id="menu_selectAll"/>
|
||||
<menuitem id="cMenu_copy"/>
|
||||
<menuitem id="cMenu_selectAll"/>
|
||||
</menupopup>
|
||||
</popupset>
|
||||
|
||||
@ -103,6 +103,16 @@
|
||||
autocheck="false" prefKey="jswarn"/>
|
||||
</menupopup>
|
||||
</toolbarbutton>
|
||||
<toolbarbutton label="&btnPageSecurity.label;" type="menu-button"
|
||||
category="security" class="devtools-toolbarbutton webconsole-filter-button"
|
||||
tooltiptext="&btnPageSecurity.tooltip;">
|
||||
<menupopup>
|
||||
<menuitem label="&btnConsoleErrors;" type="checkbox"
|
||||
autocheck="false" prefKey="secerror"/>
|
||||
<menuitem label="&btnConsoleWarnings;" type="checkbox"
|
||||
autocheck="false" prefKey="secwarn"/>
|
||||
</menupopup>
|
||||
</toolbarbutton>
|
||||
<toolbarbutton label="&btnPageLogging.label;" type="menu-button"
|
||||
category="logging" class="devtools-toolbarbutton webconsole-filter-button"
|
||||
tooltiptext="&btnPageLogging.tooltip;">
|
||||
|
@ -49,6 +49,8 @@
|
||||
<!ENTITY btnPageCSS.tooltip "Log CSS parsing errors">
|
||||
<!ENTITY btnPageJS.label "JS">
|
||||
<!ENTITY btnPageJS.tooltip "Log JavaScript exceptions">
|
||||
<!ENTITY btnPageSecurity.label "Security">
|
||||
<!ENTITY btnPageSecurity.tooltip "Log security errors and warnings">
|
||||
|
||||
<!-- LOCALIZATION NOTE (btnPageLogging): This is used as the text of the
|
||||
- the toolbar. It shows or hides messages that the web developer inserted on
|
||||
|
@ -402,22 +402,41 @@
|
||||
<property name="suppressOnSelect"
|
||||
onget="return this.getAttribute('suppressonselect') == 'true';"
|
||||
onset="this.setAttribute('suppressonselect', val);"/>
|
||||
<property name="crossSlideBoundary"
|
||||
onget="return this.hasAttribute('crossslideboundary')? this.getAttribute('crossslideboundary') : Infinity;"/>
|
||||
|
||||
<!-- Internal methods -->
|
||||
|
||||
<field name="_xslideHandler"/>
|
||||
<constructor>
|
||||
<![CDATA[
|
||||
if (this.controller && this.controller.gridBoundCallback != undefined)
|
||||
this.controller.gridBoundCallback();
|
||||
|
||||
// set up cross-slide gesture handling for multiple-selection grids
|
||||
if (CrossSlide && "multiple" == this.getAttribute("seltype")) {
|
||||
this._xslideHandler = new CrossSlide.Handler(this, {
|
||||
REARRANGESTART: this.crossSlideBoundary
|
||||
});
|
||||
this.addEventListener("touchstart", this._xslideHandler, false);
|
||||
this.addEventListener("touchmove", this._xslideHandler, false);
|
||||
this.addEventListener("touchend", this._xslideHandler, false);
|
||||
}
|
||||
// XXX This event was never actually implemented (bug 223411).
|
||||
var event = document.createEvent("Events");
|
||||
event.initEvent("contentgenerated", true, true);
|
||||
this.dispatchEvent(event);
|
||||
]]>
|
||||
</constructor>
|
||||
|
||||
<method name="_isIndexInBounds">
|
||||
<destructor>
|
||||
<![CDATA[
|
||||
if (this._xslideHandler) {
|
||||
this.removeEventListener("touchstart", this._xslideHandler);
|
||||
this.removeEventListener("touchmove", this._xslideHandler);
|
||||
this.removeEventListener("touchend", this._xslideHandler);
|
||||
this._xslideHandler = null;
|
||||
}
|
||||
]]>
|
||||
</destructor>
|
||||
<method name="_isIndexInBounds">
|
||||
<parameter name="anIndex"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
@ -484,6 +503,56 @@
|
||||
}
|
||||
]]>
|
||||
</handler>
|
||||
<handler event="MozCrossSliding">
|
||||
<![CDATA[
|
||||
// MozCrossSliding is swipe gesture across a tile
|
||||
// The tile should follow the drag to reinforce the gesture
|
||||
// (with inertia/speedbump behavior)
|
||||
let state = event.crossSlidingState;
|
||||
let thresholds = this._xslideHandler.thresholds;
|
||||
let transformValue;
|
||||
switch(state) {
|
||||
case "cancelled":
|
||||
// hopefully nothing else is transform-ing the tile
|
||||
event.target.removeAttribute('crosssliding');
|
||||
event.target.style.removeProperty('transform');
|
||||
break;
|
||||
case "dragging":
|
||||
case "selecting":
|
||||
event.target.setAttribute("crosssliding", true);
|
||||
// just track the mouse in the initial phases of the drag gesture
|
||||
transformValue = (event.direction=='x') ?
|
||||
'translateX('+event.delta+'px)' :
|
||||
'translateY('+event.delta+'px)';
|
||||
event.target.style.transform = transformValue;
|
||||
break;
|
||||
case "selectSpeedBumping":
|
||||
case "speedBumping":
|
||||
event.target.setAttribute('crosssliding', true);
|
||||
// in speed-bump phase, we add inertia to the drag
|
||||
let offset = CrossSlide.speedbump(
|
||||
event.delta,
|
||||
thresholds.SPEEDBUMPSTART,
|
||||
thresholds.SPEEDBUMPEND
|
||||
);
|
||||
transformValue = (event.direction=='x') ?
|
||||
'translateX('+offset+'px)' :
|
||||
'translateY('+offset+'px)';
|
||||
event.target.style.transform = transformValue;
|
||||
break;
|
||||
// "rearranging" case not used or implemented here
|
||||
case "completed":
|
||||
event.target.removeAttribute('crosssliding');
|
||||
event.target.style.removeProperty('transform');
|
||||
break;
|
||||
}
|
||||
]]>
|
||||
</handler>
|
||||
<handler event="MozCrossSlideSelect">
|
||||
<![CDATA[
|
||||
this.toggleItemSelection(event.target);
|
||||
]]>
|
||||
</handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
<binding id="richgrid-item">
|
||||
|
@ -33,6 +33,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "CrossSlide",
|
||||
"resource:///modules/CrossSlide.jsm");
|
||||
|
||||
/*
|
||||
* Services
|
||||
|
@ -335,7 +335,7 @@
|
||||
</hbox>
|
||||
</appbar>
|
||||
|
||||
<vbox id="panel-container" hidden="true" class="window-width window-height meta">
|
||||
<vbox id="panel-container" hidden="true" class="window-width window-height meta" observes="bcast_windowState">
|
||||
<hbox id="panel-header">
|
||||
<toolbarbutton id="panel-close-button" command="cmd_panel"/>
|
||||
|
||||
@ -350,18 +350,18 @@
|
||||
</menulist>
|
||||
</hbox>
|
||||
|
||||
<deck id="panel-items" selectedIndex="0" flex="1">
|
||||
<deck id="panel-items" selectedIndex="0" flex="1" >
|
||||
<scrollbox id="bookmarks-container" flex="1">
|
||||
<richgrid id="bookmarks-list" seltype="single" flex="1"/>
|
||||
<richgrid id="bookmarks-list" class="canSnapTiles" seltype="single" flex="1"/>
|
||||
</scrollbox>
|
||||
<scrollbox id="history-container" flex="1">
|
||||
<richgrid id="history-list" seltype="single" flex="1"/>
|
||||
<richgrid id="history-list" class="canSnapTiles" seltype="single" flex="1"/>
|
||||
</scrollbox>
|
||||
<scrollbox id="downloads-container" flex="1">
|
||||
<richgrid id="downloads-list" seltype="single" flex="1"/>
|
||||
<richgrid id="downloads-list" class="canSnapTiles" seltype="single" flex="1"/>
|
||||
</scrollbox>
|
||||
<scrollbox id="remotetabs-container" flex="1">
|
||||
<richgrid id="remotetabs-list" seltype="single" flex="1"/>
|
||||
<richgrid id="remotetabs-list" class="canSnapTiles" seltype="single" flex="1"/>
|
||||
</scrollbox>
|
||||
<vbox id="console-container" flex="1">
|
||||
<vbox id="console-header" class="panel-list">
|
||||
|
272
browser/metro/modules/CrossSlide.jsm
Normal file
272
browser/metro/modules/CrossSlide.jsm
Normal file
@ -0,0 +1,272 @@
|
||||
/* 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 = ["CrossSlide"];
|
||||
|
||||
// needs DPI adjustment?
|
||||
let CrossSlideThresholds = {
|
||||
SELECTIONSTART: 25,
|
||||
SPEEDBUMPSTART: 30,
|
||||
SPEEDBUMPEND: 50,
|
||||
REARRANGESTART: 80
|
||||
};
|
||||
|
||||
// see: http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.input.crossslidingstate.ASPx
|
||||
let CrossSlidingState = {
|
||||
STARTED: 0,
|
||||
DRAGGING: 1,
|
||||
SELECTING: 2,
|
||||
SELECT_SPEED_BUMPING: 3,
|
||||
SPEED_BUMPING: 4,
|
||||
REARRANGING: 5,
|
||||
COMPLETED: 6
|
||||
};
|
||||
|
||||
let CrossSlidingStateNames = [
|
||||
'started',
|
||||
'dragging',
|
||||
'selecting',
|
||||
'selectSpeedBumping',
|
||||
'speedBumping',
|
||||
'rearranging',
|
||||
'completed'
|
||||
];
|
||||
|
||||
// --------------------------------
|
||||
// module helpers
|
||||
//
|
||||
|
||||
function isSelectable(aElement) {
|
||||
// placeholder logic
|
||||
return aElement.nodeName == 'richgriditem';
|
||||
}
|
||||
|
||||
function withinCone(aLen, aHeight) {
|
||||
// check pt falls within 45deg either side of the cross axis
|
||||
return aLen > aHeight;
|
||||
}
|
||||
|
||||
function getScrollAxisFromElement(aElement) {
|
||||
let elem = aElement,
|
||||
win = elem.ownerDocument.defaultView;
|
||||
let scrollX, scrollY;
|
||||
for (; elem && 1==elem.nodeType; elem = elem.parentNode) {
|
||||
let cs = win.getComputedStyle(elem);
|
||||
scrollX = (cs.overflowX=='scroll' || cs.overflowX=='auto');
|
||||
scrollY = (cs.overflowX=='scroll' || cs.overflowX=='auto');
|
||||
if (scrollX || scrollY) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return scrollX ? 'x' : 'y';
|
||||
}
|
||||
|
||||
function pointFromTouchEvent(aEvent) {
|
||||
let touch = aEvent.touches[0];
|
||||
return { x: touch.clientX, y: touch.clientY };
|
||||
}
|
||||
|
||||
// This damping function has these important properties:
|
||||
// f(0) = 0
|
||||
// f'(0) = 1
|
||||
// limit as x -> Infinity of f(x) = 1
|
||||
function damp(aX) {
|
||||
return 2 / (1 + Math.exp(-2 * aX)) - 1;
|
||||
}
|
||||
function speedbump(aDelta, aStart, aEnd) {
|
||||
let x = Math.abs(aDelta);
|
||||
if (x <= aStart)
|
||||
return aDelta;
|
||||
let sign = aDelta / x;
|
||||
|
||||
let d = aEnd - aStart;
|
||||
let damped = damp((x - aStart) / d);
|
||||
return sign * (aStart + (damped * d));
|
||||
}
|
||||
|
||||
|
||||
this.CrossSlide = {
|
||||
// -----------------------
|
||||
// Gesture constants
|
||||
Thresholds: CrossSlideThresholds,
|
||||
State: CrossSlidingState,
|
||||
StateNames: CrossSlidingStateNames,
|
||||
// -----------------------
|
||||
speedbump: speedbump
|
||||
};
|
||||
|
||||
function CrossSlideHandler(aNode, aThresholds) {
|
||||
this.node = aNode;
|
||||
this.thresholds = Object.create(CrossSlideThresholds);
|
||||
// apply per-instance threshold configuration
|
||||
if (aThresholds) {
|
||||
for(let key in aThresholds)
|
||||
this.thresholds[key] = aThresholds[key];
|
||||
}
|
||||
}
|
||||
|
||||
CrossSlideHandler.prototype = {
|
||||
node: null,
|
||||
drag: null,
|
||||
|
||||
getCrossSlideState: function(aCrossAxisDistance, aScrollAxisDistance) {
|
||||
if (aCrossAxisDistance <= 0) {
|
||||
return CrossSlidingState.STARTED;
|
||||
}
|
||||
if (aCrossAxisDistance < this.thresholds.SELECTIONSTART) {
|
||||
return CrossSlidingState.DRAGGING;
|
||||
}
|
||||
if (aCrossAxisDistance < this.thresholds.SPEEDBUMPSTART) {
|
||||
return CrossSlidingState.SELECTING;
|
||||
}
|
||||
if (aCrossAxisDistance < this.thresholds.SPEEDBUMPEND) {
|
||||
return CrossSlidingState.SELECT_SPEED_BUMPING;
|
||||
}
|
||||
if (aCrossAxisDistance < this.thresholds.REARRANGESTART) {
|
||||
return CrossSlidingState.SPEED_BUMPING;
|
||||
}
|
||||
// out of bounds cross-slide
|
||||
return -1;
|
||||
},
|
||||
|
||||
handleEvent: function handleEvent(aEvent) {
|
||||
switch (aEvent.type) {
|
||||
case "touchstart":
|
||||
this._onTouchStart(aEvent);
|
||||
break;
|
||||
case "touchmove":
|
||||
this._onTouchMove(aEvent);
|
||||
break;
|
||||
case "touchend":
|
||||
this._onTouchEnd(aEvent);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
cancel: function(){
|
||||
this._fireProgressEvent("cancelled", aEvent);
|
||||
this.drag = null;
|
||||
},
|
||||
|
||||
_onTouchStart: function onTouchStart(aEvent){
|
||||
if (aEvent.touches.length > 1)
|
||||
return;
|
||||
let touch = aEvent.touches[0];
|
||||
// cross-slide is a single touch gesture
|
||||
// the top target is the one we need here, touch.target not relevant
|
||||
let target = aEvent.target;
|
||||
|
||||
if (!isSelectable(target))
|
||||
return;
|
||||
|
||||
// we'll handle this event, dont let it bubble further
|
||||
aEvent.stopPropagation();
|
||||
|
||||
let scrollAxis = getScrollAxisFromElement(target);
|
||||
|
||||
this.drag = {
|
||||
scrollAxis: scrollAxis,
|
||||
crossAxis: (scrollAxis=='x') ? 'y' : 'x',
|
||||
origin: pointFromTouchEvent(aEvent),
|
||||
state: -1
|
||||
};
|
||||
},
|
||||
|
||||
_onTouchMove: function(aEvent){
|
||||
if (!this.drag) {
|
||||
return;
|
||||
}
|
||||
// event is handled here, dont let it bubble further
|
||||
aEvent.stopPropagation();
|
||||
|
||||
if (aEvent.touches.length!==1) {
|
||||
// cancel if another touch point gets involved
|
||||
return this.cancel();
|
||||
}
|
||||
|
||||
let startPt = this.drag.origin;
|
||||
let endPt = this.drag.position = pointFromTouchEvent(aEvent);
|
||||
|
||||
let scrollAxis = this.drag.scrollAxis,
|
||||
crossAxis = this.drag.crossAxis;
|
||||
|
||||
// distance from the origin along the axis perpendicular to scrolling
|
||||
let crossAxisDistance = Math.abs(endPt[crossAxis] - startPt[crossAxis]);
|
||||
// distance along the scrolling axis
|
||||
let scrollAxisDistance = Math.abs(endPt[scrollAxis] - startPt[scrollAxis]);
|
||||
|
||||
let currState = this.drag.state;
|
||||
let newState = this.getCrossSlideState(crossAxisDistance, scrollAxisDistance);
|
||||
|
||||
if (-1 == newState) {
|
||||
// out of bounds, cancel the event always
|
||||
return this.cancel();
|
||||
}
|
||||
|
||||
let isWithinCone = withinCone(crossAxisDistance, scrollAxisDistance);
|
||||
if (currState < CrossSlidingState.SELECTING && !isWithinCone) {
|
||||
// ignore, no progress to report
|
||||
return;
|
||||
}
|
||||
if (currState >= CrossSlidingState.SELECTING && !isWithinCone) {
|
||||
// we're committed to a cross-slide gesture,
|
||||
// so going out of bounds at this point means aborting
|
||||
return this.cancel();
|
||||
}
|
||||
|
||||
if (currState > newState) {
|
||||
// moved backwards, ignoring
|
||||
return;
|
||||
}
|
||||
|
||||
this.drag.state = newState;
|
||||
this._fireProgressEvent( CrossSlidingStateNames[newState], aEvent );
|
||||
},
|
||||
_onTouchEnd: function(aEvent){
|
||||
if (!this.drag)
|
||||
return;
|
||||
|
||||
// event is handled, dont let it bubble further
|
||||
aEvent.stopPropagation();
|
||||
|
||||
if (this.drag.state < CrossSlidingState.SELECTING) {
|
||||
return this.cancel();
|
||||
}
|
||||
|
||||
this._fireProgressEvent("completed", aEvent);
|
||||
this._fireSelectEvent(aEvent);
|
||||
this.drag = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Dispatches a custom Event on the drag node.
|
||||
* @param aEvent The source event.
|
||||
* @param aType The event type.
|
||||
*/
|
||||
_fireProgressEvent: function CrossSliding_fireEvent(aState, aEvent) {
|
||||
if (!this.drag)
|
||||
return;
|
||||
let event = this.node.ownerDocument.createEvent("Events");
|
||||
let crossAxis = this.drag.crossAxis;
|
||||
event.initEvent("MozCrossSliding", true, true);
|
||||
event.crossSlidingState = aState;
|
||||
event.position = this.drag.position;
|
||||
event.direction = this.drag.crossAxis;
|
||||
event.delta = this.drag.position[crossAxis] - this.drag.origin[crossAxis];
|
||||
aEvent.target.dispatchEvent(event);
|
||||
},
|
||||
|
||||
/**
|
||||
* Dispatches a custom Event on the given target node.
|
||||
* @param aEvent The source event.
|
||||
*/
|
||||
_fireSelectEvent: function SelectTarget_fireEvent(aEvent) {
|
||||
let event = this.node.ownerDocument.createEvent("Events");
|
||||
event.initEvent("MozCrossSlideSelect", true, true);
|
||||
event.position = this.drag.position;
|
||||
aEvent.target.dispatchEvent(event);
|
||||
}
|
||||
};
|
||||
this.CrossSlide.Handler = CrossSlideHandler;
|
@ -9,9 +9,8 @@ VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
EXTRA_JS_MODULES = \
|
||||
colorUtils.jsm \
|
||||
CrossSlide.jsm \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -894,6 +894,7 @@ setting[type="radio"] > vbox {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
|
||||
/* Browser Content Areas ----------------------------------------------------- */
|
||||
|
||||
/* Hide the browser while the start UI is visible */
|
||||
@ -916,6 +917,10 @@ setting[type="radio"] > vbox {
|
||||
padding: 60px 40px;
|
||||
}
|
||||
|
||||
#panel-container[viewstate="snapped"] .canSnapTiles .richgrid-item-content {
|
||||
-moz-box-orient: horizontal;
|
||||
}
|
||||
|
||||
#panel-close-button {
|
||||
background: transparent;
|
||||
border: 0 none;
|
||||
@ -944,11 +949,19 @@ setting[type="radio"] > vbox {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#panel-container[viewstate="snapped"] #panel-view-switcher {
|
||||
font-size: @metro_font_large@;
|
||||
}
|
||||
|
||||
#panel-items {
|
||||
padding-top: 20px;
|
||||
-moz-padding-start: 88px;
|
||||
}
|
||||
|
||||
#panel-container[viewstate="snapped"] #panel-items {
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
/* Console Section - Panel UI ---------------------------------------------- */
|
||||
|
||||
#console-filter-warnings,
|
||||
|
@ -490,6 +490,10 @@ richgriditem[selected] .richgrid-item-content::after {
|
||||
background-size: 35px 35px;
|
||||
border: @metro_border_xthick@ solid @selected_color@;
|
||||
}
|
||||
/* ease the return to original position when cross-sliding */
|
||||
richgriditem:not([crosssliding]) {
|
||||
transition: transform ease-out 0.2s;
|
||||
}
|
||||
|
||||
richgriditem .richgrid-icon-container {
|
||||
padding-bottom: 2px;
|
||||
|
@ -93,11 +93,13 @@
|
||||
}
|
||||
|
||||
.requests-menu-file {
|
||||
width: 14em;
|
||||
width: 20vw;
|
||||
min-width: 4em;
|
||||
}
|
||||
|
||||
.requests-menu-domain {
|
||||
width: 14em;
|
||||
width: 14vw;
|
||||
min-width: 10em;
|
||||
}
|
||||
|
||||
.requests-menu-type {
|
||||
@ -303,13 +305,44 @@
|
||||
#details-pane {
|
||||
max-width: none;
|
||||
margin: 0 !important;
|
||||
/* To prevent all the margin hacks to hide the sidebar */
|
||||
/* To prevent all the margin hacks to hide the sidebar. */
|
||||
}
|
||||
|
||||
.requests-menu-status-and-method {
|
||||
width: 14vw;
|
||||
}
|
||||
|
||||
.requests-menu-file,
|
||||
.requests-menu-domain {
|
||||
width: 30vw;
|
||||
min-width: 10em;
|
||||
}
|
||||
|
||||
.requests-menu-type {
|
||||
width: 8vw;
|
||||
}
|
||||
|
||||
.requests-menu-size {
|
||||
border-width: 0px !important;
|
||||
width: 16vw;
|
||||
border-width: 0 !important;
|
||||
box-shadow: none !important;
|
||||
/* !important are required here because Timeline is not visible and thus
|
||||
the right border and box-shadow of Size column should be hidden */
|
||||
/* The "Timeline" header is not visible anymore, and thus the
|
||||
right border and box-shadow of "Size" column should be hidden. */
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 701px) {
|
||||
#network-table[type-overflows] .requests-menu-domain {
|
||||
border-width: 0 !important;
|
||||
box-shadow: none !important;
|
||||
/* The "Type" header is not visible anymore, and thus the
|
||||
right border and box-shadow of "Domain" column should be hidden. */
|
||||
}
|
||||
|
||||
#network-table[domain-overflows] .requests-menu-file {
|
||||
border-width: 0 !important;
|
||||
box-shadow: none !important;
|
||||
/* The "Domain" header is not visible anymore, and thus the
|
||||
right border and box-shadow of "File" column should be hidden. */
|
||||
}
|
||||
}
|
||||
|
@ -240,3 +240,12 @@
|
||||
height: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.webconsole-msg-security > .webconsole-msg-icon-container {
|
||||
-moz-border-start: solid red 6px;
|
||||
}
|
||||
|
||||
.webconsole-filter-button[category="security"] > .toolbarbutton-menubutton-button:before {
|
||||
background-image: linear-gradient(#FF3030, #FF7D7D);
|
||||
border-color: #D12C2C;
|
||||
}
|
||||
|
@ -93,11 +93,13 @@
|
||||
}
|
||||
|
||||
.requests-menu-file {
|
||||
width: 16em;
|
||||
width: 20vw;
|
||||
min-width: 4em;
|
||||
}
|
||||
|
||||
.requests-menu-domain {
|
||||
width: 16em;
|
||||
width: 14vw;
|
||||
min-width: 10em;
|
||||
}
|
||||
|
||||
.requests-menu-type {
|
||||
@ -303,13 +305,44 @@
|
||||
#details-pane {
|
||||
max-width: none;
|
||||
margin: 0 !important;
|
||||
/* To prevent all the margin hacks to hide the sidebar */
|
||||
/* To prevent all the margin hacks to hide the sidebar. */
|
||||
}
|
||||
|
||||
.requests-menu-status-and-method {
|
||||
width: 14vw;
|
||||
}
|
||||
|
||||
.requests-menu-file,
|
||||
.requests-menu-domain {
|
||||
width: 30vw;
|
||||
min-width: 10em;
|
||||
}
|
||||
|
||||
.requests-menu-type {
|
||||
width: 8vw;
|
||||
}
|
||||
|
||||
.requests-menu-size {
|
||||
border-width: 0px !important;
|
||||
width: 16vw;
|
||||
border-width: 0 !important;
|
||||
box-shadow: none !important;
|
||||
/* !important are required here because Timeline is not visible and thus
|
||||
the right border and box-shadow of Size column should be hidden */
|
||||
/* The "Timeline" header is not visible anymore, and thus the
|
||||
right border and box-shadow of "Size" column should be hidden. */
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 701px) {
|
||||
#network-table[type-overflows] .requests-menu-domain {
|
||||
border-width: 0 !important;
|
||||
box-shadow: none !important;
|
||||
/* The "Type" header is not visible anymore, and thus the
|
||||
right border and box-shadow of "Domain" column should be hidden. */
|
||||
}
|
||||
|
||||
#network-table[domain-overflows] .requests-menu-file {
|
||||
border-width: 0 !important;
|
||||
box-shadow: none !important;
|
||||
/* The "Domain" header is not visible anymore, and thus the
|
||||
right border and box-shadow of "File" column should be hidden. */
|
||||
}
|
||||
}
|
||||
|
@ -244,3 +244,12 @@
|
||||
height: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.webconsole-msg-security > .webconsole-msg-icon-container {
|
||||
-moz-border-start: solid red 6px;
|
||||
}
|
||||
|
||||
.webconsole-filter-button[category="security"] > .toolbarbutton-menubutton-button:before {
|
||||
background-image: linear-gradient(#FF3030, #FF7D7D);
|
||||
border-color: #D12C2C;
|
||||
}
|
||||
|
@ -93,11 +93,13 @@
|
||||
}
|
||||
|
||||
.requests-menu-file {
|
||||
width: 16em;
|
||||
width: 20vw;
|
||||
min-width: 4em;
|
||||
}
|
||||
|
||||
.requests-menu-domain {
|
||||
width: 16em;
|
||||
width: 14vw;
|
||||
min-width: 10em;
|
||||
}
|
||||
|
||||
.requests-menu-type {
|
||||
@ -303,13 +305,44 @@
|
||||
#details-pane {
|
||||
max-width: none;
|
||||
margin: 0 !important;
|
||||
/* To prevent all the margin hacks to hide the sidebar */
|
||||
/* To prevent all the margin hacks to hide the sidebar. */
|
||||
}
|
||||
|
||||
.requests-menu-status-and-method {
|
||||
width: 14vw;
|
||||
}
|
||||
|
||||
.requests-menu-file,
|
||||
.requests-menu-domain {
|
||||
width: 30vw;
|
||||
min-width: 10em;
|
||||
}
|
||||
|
||||
.requests-menu-type {
|
||||
width: 8vw;
|
||||
}
|
||||
|
||||
.requests-menu-size {
|
||||
border-width: 0px !important;
|
||||
width: 16vw;
|
||||
border-width: 0 !important;
|
||||
box-shadow: none !important;
|
||||
/* !important are required here because Timeline is not visible and thus
|
||||
the right border and box-shadow of Size column should be hidden */
|
||||
/* The "Timeline" header is not visible anymore, and thus the
|
||||
right border and box-shadow of "Size" column should be hidden. */
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 701px) {
|
||||
#network-table[type-overflows] .requests-menu-domain {
|
||||
border-width: 0 !important;
|
||||
box-shadow: none !important;
|
||||
/* The "Type" header is not visible anymore, and thus the
|
||||
right border and box-shadow of "Domain" column should be hidden. */
|
||||
}
|
||||
|
||||
#network-table[domain-overflows] .requests-menu-file {
|
||||
border-width: 0 !important;
|
||||
box-shadow: none !important;
|
||||
/* The "Domain" header is not visible anymore, and thus the
|
||||
right border and box-shadow of "File" column should be hidden. */
|
||||
}
|
||||
}
|
||||
|
@ -249,3 +249,12 @@
|
||||
height: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.webconsole-msg-security > .webconsole-msg-icon-container {
|
||||
-moz-border-start: solid red 6px;
|
||||
}
|
||||
|
||||
.webconsole-filter-button[category="security"] > .toolbarbutton-menubutton-button:before {
|
||||
background-image: linear-gradient(#FF3030, #FF7D7D);
|
||||
border-color: #D12C2C;
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ netscape_security_enablePrivilege(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
return xpc::EnableUniversalXPConnect(cx);
|
||||
}
|
||||
|
||||
static JSFunctionSpec PrivilegeManager_static_methods[] = {
|
||||
static const JSFunctionSpec PrivilegeManager_static_methods[] = {
|
||||
JS_FS("enablePrivilege", netscape_security_enablePrivilege, 1, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
@ -1073,6 +1073,8 @@ conic/conicstatisticsevent.h
|
||||
#endif
|
||||
#if MOZ_NATIVE_LIBEVENT==1
|
||||
event.h
|
||||
#else
|
||||
sys/event.h
|
||||
#endif
|
||||
#ifdef MOZ_ENABLE_LIBPROXY
|
||||
proxy.h
|
||||
|
17
configure.in
17
configure.in
@ -5186,23 +5186,6 @@ fi
|
||||
|
||||
AC_SUBST(MOZ_IPDL_TESTS)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Turns off code necessary for e10s compatibility
|
||||
dnl ========================================================
|
||||
dnl This is a temporary flag to be removed in bug 662601 when
|
||||
dnl it's no longer needed
|
||||
|
||||
MOZ_E10S_COMPAT=
|
||||
|
||||
MOZ_ARG_ENABLE_BOOL(e10s-compat,
|
||||
[ --enable-e10s-compat Turns off code for e10s compat],
|
||||
MOZ_E10S_COMPAT=1,
|
||||
MOZ_E10S_COMPAT=)
|
||||
|
||||
if test -n "$MOZ_E10S_COMPAT"; then
|
||||
AC_DEFINE(MOZ_E10S_COMPAT)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Disable building dbm
|
||||
dnl ========================================================
|
||||
|
22
content/base/crashtests/864448.html
Normal file
22
content/base/crashtests/864448.html
Normal file
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
document.setUserData('key', {}, null);
|
||||
|
||||
// Depending on the pref bidi.direction, one of these will hit the page scrollbar.
|
||||
window.cpRight = document.caretPositionFromPoint(window.innerWidth - 1, 0);
|
||||
window.cpLeft = document.caretPositionFromPoint(0, 0);
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="boom();">
|
||||
<div style="height: 50000px;"></div>
|
||||
</body>
|
||||
</html>
|
@ -134,3 +134,4 @@ load 844404.html
|
||||
load 847127.html
|
||||
load 849601.html
|
||||
load 863950.html
|
||||
load 864448.html
|
||||
|
@ -795,6 +795,7 @@ public:
|
||||
eBRAND_PROPERTIES,
|
||||
eCOMMON_DIALOG_PROPERTIES,
|
||||
eMATHML_PROPERTIES,
|
||||
eSECURITY_PROPERTIES,
|
||||
PropertiesFile_COUNT
|
||||
};
|
||||
static nsresult ReportToConsole(uint32_t aErrorFlags,
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "nsPIDOMWindow.h" // for use in inline functions
|
||||
#include "nsPropertyTable.h" // for member
|
||||
#include "nsTHashtable.h" // for member
|
||||
#include "mozilla/dom/DirectionalityUtils.h"
|
||||
#include "mozilla/dom/DocumentBinding.h"
|
||||
|
||||
class imgIRequest;
|
||||
@ -523,10 +522,6 @@ public:
|
||||
mSandboxFlags = sandboxFlags;
|
||||
}
|
||||
|
||||
inline mozilla::Directionality GetDocumentDirectionality() {
|
||||
return mDirectionality;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access HTTP header data (this may also get set from other
|
||||
* sources, like HTML META tags).
|
||||
@ -641,7 +636,7 @@ protected:
|
||||
public:
|
||||
// Get the root <html> element, or return null if there isn't one (e.g.
|
||||
// if the root isn't <html>)
|
||||
Element* GetHtmlElement();
|
||||
Element* GetHtmlElement() const;
|
||||
// Returns the first child of GetHtmlContent which has the given tag,
|
||||
// or nullptr if that doesn't exist.
|
||||
Element* GetHtmlChildElement(nsIAtom* aTag);
|
||||
@ -2001,7 +1996,7 @@ public:
|
||||
virtual void GetTitle(nsString& aTitle) = 0;
|
||||
virtual void SetTitle(const nsAString& aTitle, mozilla::ErrorResult& rv) = 0;
|
||||
void GetDir(nsAString& aDirection) const;
|
||||
void SetDir(const nsAString& aDirection, mozilla::ErrorResult& rv);
|
||||
void SetDir(const nsAString& aDirection);
|
||||
nsIDOMWindow* GetDefaultView() const
|
||||
{
|
||||
return GetWindow();
|
||||
@ -2150,12 +2145,6 @@ protected:
|
||||
return mContentType;
|
||||
}
|
||||
|
||||
inline void
|
||||
SetDocumentDirectionality(mozilla::Directionality aDir)
|
||||
{
|
||||
mDirectionality = aDir;
|
||||
}
|
||||
|
||||
// All document WrapNode implementations MUST call this method. A
|
||||
// false return value means an exception was thrown.
|
||||
bool PostCreateWrapper(JSContext* aCx, JSObject *aNewObject);
|
||||
@ -2335,9 +2324,6 @@ protected:
|
||||
// are immutable - see nsSandboxFlags.h for the possible flags.
|
||||
uint32_t mSandboxFlags;
|
||||
|
||||
// The root directionality of this document.
|
||||
mozilla::Directionality mDirectionality;
|
||||
|
||||
nsCString mContentLanguage;
|
||||
private:
|
||||
nsCString mContentType;
|
||||
|
@ -600,13 +600,9 @@ RecomputeDirectionality(Element* aElement, bool aNotify)
|
||||
dir = parentDir;
|
||||
}
|
||||
} else {
|
||||
// If there is no parent element, the directionality is the same as the
|
||||
// document direction.
|
||||
Directionality documentDir =
|
||||
aElement->OwnerDoc()->GetDocumentDirectionality();
|
||||
if (documentDir != eDir_NotSet) {
|
||||
dir = documentDir;
|
||||
}
|
||||
// If there is no parent element and no dir attribute, the directionality
|
||||
// is LTR.
|
||||
dir = eDir_LTR;
|
||||
}
|
||||
|
||||
aElement->SetDirectionality(dir, aNotify);
|
||||
|
@ -3224,7 +3224,8 @@ static const char gPropertiesFiles[nsContentUtils::PropertiesFile_COUNT][56] = {
|
||||
"chrome://global/locale/svg/svg.properties",
|
||||
"chrome://branding/locale/brand.properties",
|
||||
"chrome://global/locale/commonDialogs.properties",
|
||||
"chrome://global/locale/mathml/mathml.properties"
|
||||
"chrome://global/locale/mathml/mathml.properties",
|
||||
"chrome://global/locale/security/security.properties"
|
||||
};
|
||||
|
||||
/* static */ nsresult
|
||||
|
@ -58,7 +58,8 @@ nsDOMCaretPosition::WrapObject(JSContext *aCx, JSObject *aScope)
|
||||
return mozilla::dom::CaretPositionBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsDOMCaretPosition, mOffsetNode)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(nsDOMCaretPosition,
|
||||
mOffsetNode, mAnonymousContentNode)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMCaretPosition)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMCaretPosition)
|
||||
|
@ -142,8 +142,6 @@ nsDOMDataChannel::Init(nsPIDOMWindow* aDOMWindow)
|
||||
nsresult rv;
|
||||
nsAutoString urlParam;
|
||||
|
||||
nsDOMEventTargetHelper::Init();
|
||||
|
||||
MOZ_ASSERT(mDataChannel);
|
||||
mDataChannel->SetListener(this, nullptr);
|
||||
|
||||
|
@ -118,20 +118,25 @@ nsDOMFileReader::~nsDOMFileReader()
|
||||
nsLayoutStatics::Release();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This Init method is called from the factory constructor.
|
||||
*/
|
||||
nsresult
|
||||
nsDOMFileReader::Init()
|
||||
{
|
||||
nsDOMEventTargetHelper::Init();
|
||||
|
||||
nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
|
||||
nsCOMPtr<nsIPrincipal> subjectPrincipal;
|
||||
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
if (secMan) {
|
||||
nsresult rv = secMan->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
secMan->GetSystemPrincipal(getter_AddRefs(principal));
|
||||
}
|
||||
NS_ENSURE_STATE(subjectPrincipal);
|
||||
mPrincipal.swap(subjectPrincipal);
|
||||
NS_ENSURE_STATE(principal);
|
||||
mPrincipal.swap(principal);
|
||||
|
||||
// Instead of grabbing some random global from the context stack,
|
||||
// let's use the default one (junk drawer) for now.
|
||||
// We should move away from this Init...
|
||||
BindToOwner(xpc::GetNativeForGlobal(xpc::GetJunkScope()));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,6 @@
|
||||
#include "nsIFormControl.h"
|
||||
|
||||
#include "nsBidiUtils.h"
|
||||
#include "mozilla/dom/DirectionalityUtils.h"
|
||||
|
||||
#include "nsIDOMUserDataHandler.h"
|
||||
#include "nsIDOMXPathEvaluator.h"
|
||||
@ -1323,7 +1322,6 @@ nsIDocument::nsIDocument()
|
||||
mAllowDNSPrefetch(true),
|
||||
mIsBeingUsedAsImage(false),
|
||||
mHasLinksToUpdate(false),
|
||||
mDirectionality(eDir_LTR),
|
||||
mPartID(0)
|
||||
{
|
||||
SetInDocument();
|
||||
@ -5782,7 +5780,7 @@ nsIDocument::GetLocation() const
|
||||
}
|
||||
|
||||
Element*
|
||||
nsIDocument::GetHtmlElement()
|
||||
nsIDocument::GetHtmlElement() const
|
||||
{
|
||||
Element* rootElement = GetRootElement();
|
||||
if (rootElement && rootElement->IsHTML(nsGkAtoms::html))
|
||||
@ -6241,17 +6239,6 @@ nsDocument::GetAnimationController()
|
||||
return mAnimationController;
|
||||
}
|
||||
|
||||
struct DirTable {
|
||||
const char* mName;
|
||||
uint8_t mValue;
|
||||
};
|
||||
|
||||
static const DirTable dirAttributes[] = {
|
||||
{"ltr", IBMBIDI_TEXTDIRECTION_LTR},
|
||||
{"rtl", IBMBIDI_TEXTDIRECTION_RTL},
|
||||
{0}
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the "direction" property of the document.
|
||||
*
|
||||
@ -6267,12 +6254,10 @@ nsDocument::GetDir(nsAString& aDirection)
|
||||
void
|
||||
nsIDocument::GetDir(nsAString& aDirection) const
|
||||
{
|
||||
uint32_t options = GetBidiOptions();
|
||||
for (const DirTable* elt = dirAttributes; elt->mName; elt++) {
|
||||
if (GET_BIDI_OPTION_DIRECTION(options) == elt->mValue) {
|
||||
CopyASCIItoUTF16(elt->mName, aDirection);
|
||||
return;
|
||||
}
|
||||
aDirection.Truncate();
|
||||
Element* rootElement = GetHtmlElement();
|
||||
if (rootElement) {
|
||||
static_cast<nsGenericHTMLElement*>(rootElement)->GetDir(aDirection);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6284,45 +6269,17 @@ nsIDocument::GetDir(nsAString& aDirection) const
|
||||
NS_IMETHODIMP
|
||||
nsDocument::SetDir(const nsAString& aDirection)
|
||||
{
|
||||
ErrorResult rv;
|
||||
nsIDocument::SetDir(aDirection, rv);
|
||||
return rv.ErrorCode();
|
||||
nsIDocument::SetDir(aDirection);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsIDocument::SetDir(const nsAString& aDirection, ErrorResult& rv)
|
||||
nsIDocument::SetDir(const nsAString& aDirection)
|
||||
{
|
||||
uint32_t options = GetBidiOptions();
|
||||
|
||||
for (const DirTable* elt = dirAttributes; elt->mName; elt++) {
|
||||
if (aDirection == NS_ConvertASCIItoUTF16(elt->mName)) {
|
||||
if (GET_BIDI_OPTION_DIRECTION(options) != elt->mValue) {
|
||||
SET_BIDI_OPTION_DIRECTION(options, elt->mValue);
|
||||
nsIPresShell *shell = GetShell();
|
||||
if (shell) {
|
||||
nsPresContext *context = shell->GetPresContext();
|
||||
if (!context) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
context->SetBidi(options, true);
|
||||
} else {
|
||||
// No presentation; just set it on ourselves
|
||||
SetBidiOptions(options);
|
||||
}
|
||||
Directionality dir = elt->mValue == IBMBIDI_TEXTDIRECTION_RTL ?
|
||||
eDir_RTL : eDir_LTR;
|
||||
SetDocumentDirectionality(dir);
|
||||
// Set the directionality of the root element and its descendants, if any
|
||||
Element* rootElement = GetRootElement();
|
||||
if (rootElement) {
|
||||
rootElement->SetDirectionality(dir, true);
|
||||
SetDirectionalityOnDescendants(rootElement, dir);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
Element* rootElement = GetHtmlElement();
|
||||
if (rootElement) {
|
||||
rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::dir,
|
||||
aDirection, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "nsIDocumentLoader.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsLoadGroup.h"
|
||||
#include "nsIScriptError.h"
|
||||
|
||||
#include "prlog.h"
|
||||
|
||||
@ -146,6 +147,24 @@ nsMixedContentBlocker::~nsMixedContentBlocker()
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsMixedContentBlocker, nsIContentPolicy)
|
||||
|
||||
void
|
||||
LogBlockingMixedContent(MixedContentTypes classification,
|
||||
nsIURI* aContentLocation,
|
||||
nsIDocument* aRootDoc)
|
||||
{
|
||||
nsAutoCString locationSpec;
|
||||
aContentLocation->GetSpec(locationSpec);
|
||||
NS_ConvertUTF8toUTF16 locationSpecUTF16(locationSpec);
|
||||
|
||||
const PRUnichar* strings[] = { locationSpecUTF16.get() };
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
|
||||
"Mixed Content Blocker",
|
||||
aRootDoc,
|
||||
nsContentUtils::eSECURITY_PROPERTIES,
|
||||
classification == eMixedDisplay ? "BlockMixedDisplayContent" : "BlockMixedActiveContent",
|
||||
strings, ArrayLength(strings));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMixedContentBlocker::ShouldLoad(uint32_t aContentType,
|
||||
nsIURI* aContentLocation,
|
||||
@ -441,6 +460,7 @@ nsMixedContentBlocker::ShouldLoad(uint32_t aContentType,
|
||||
}
|
||||
} else {
|
||||
*aDecision = nsIContentPolicy::REJECT_REQUEST;
|
||||
LogBlockingMixedContent(classification, aContentLocation, rootDoc);
|
||||
if (!rootDoc->GetHasMixedDisplayContentBlocked() && NS_SUCCEEDED(stateRV)) {
|
||||
eventSink->OnSecurityChange(aRequestingContext, (State | nsIWebProgressListener::STATE_BLOCKED_MIXED_DISPLAY_CONTENT));
|
||||
}
|
||||
@ -481,6 +501,7 @@ nsMixedContentBlocker::ShouldLoad(uint32_t aContentType,
|
||||
} else {
|
||||
//User has not overriden the pref by Disabling protection. Reject the request and update the security state.
|
||||
*aDecision = nsIContentPolicy::REJECT_REQUEST;
|
||||
LogBlockingMixedContent(classification, aContentLocation, rootDoc);
|
||||
// See if the pref will change here. If it will, only then do we need to call OnSecurityChange() to update the UI.
|
||||
if (rootDoc->GetHasMixedActiveContentBlocked()) {
|
||||
return NS_OK;
|
||||
|
@ -363,27 +363,3 @@ nsDOMEventTargetHelper::GetContextForEventHandlers(nsresult* aRv)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMEventTargetHelper::Init(JSContext* aCx)
|
||||
{
|
||||
JSContext* cx = aCx;
|
||||
if (!cx) {
|
||||
nsIJSContextStack* stack = nsContentUtils::ThreadJSContextStack();
|
||||
|
||||
if (!stack)
|
||||
return;
|
||||
|
||||
if (NS_FAILED(stack->Peek(&cx)) || !cx)
|
||||
return;
|
||||
}
|
||||
|
||||
NS_ASSERTION(cx, "Should have returned earlier ...");
|
||||
nsIScriptContext* context = GetScriptContextFromJSContext(cx);
|
||||
if (context) {
|
||||
nsCOMPtr<nsPIDOMWindow> window =
|
||||
do_QueryInterface(context->GetGlobalObject());
|
||||
if (window) {
|
||||
BindToOwner(window->GetCurrentInnerWindow());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,8 +68,6 @@ public:
|
||||
return static_cast<nsDOMEventTargetHelper*>(target);
|
||||
}
|
||||
|
||||
void Init(JSContext* aCx = nullptr);
|
||||
|
||||
bool HasListenersFor(nsIAtom* aTypeWithOn)
|
||||
{
|
||||
return mListenerManager && mListenerManager->HasListenersFor(aTypeWithOn);
|
||||
|
@ -4561,7 +4561,9 @@ nsEventStateManager::CheckForAndDispatchClick(nsPresContext* aPresContext,
|
||||
nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
|
||||
if (presShell) {
|
||||
nsCOMPtr<nsIContent> mouseContent = GetEventTargetContent(aEvent);
|
||||
|
||||
if (!mouseContent && !mCurrentTarget) {
|
||||
return NS_OK;
|
||||
}
|
||||
ret = presShell->HandleEventWithTarget(&event, mCurrentTarget,
|
||||
mouseContent, aStatus);
|
||||
if (NS_SUCCEEDED(ret) && aEvent->clickCount == 2) {
|
||||
|
@ -956,7 +956,7 @@ protected:
|
||||
nsAutoPtr<AudioStream> mAudioStream;
|
||||
|
||||
// Range of time played.
|
||||
TimeRanges mPlayed;
|
||||
nsRefPtr<TimeRanges> mPlayed;
|
||||
|
||||
// Stores the time at the start of the current 'played' range.
|
||||
double mCurrentPlayRangeStart;
|
||||
|
@ -411,6 +411,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTM
|
||||
for (uint32_t i = 0; i < tmp->mOutputStreams.Length(); ++i) {
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutputStreams[i].mStream);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlayed);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLElement)
|
||||
@ -427,6 +428,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLE
|
||||
for (uint32_t i = 0; i < tmp->mOutputStreams.Length(); ++i) {
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOutputStreams[i].mStream);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPlayed);
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLMediaElement)
|
||||
@ -1307,7 +1309,7 @@ HTMLMediaElement::SetCurrentTime(double aCurrentTime, ErrorResult& aRv)
|
||||
LOG(PR_LOG_DEBUG, ("%p Adding \'played\' a range : [%f, %f]", this, mCurrentPlayRangeStart, rangeEndTime));
|
||||
// Multiple seek without playing, or seek while playing.
|
||||
if (mCurrentPlayRangeStart != rangeEndTime) {
|
||||
mPlayed.Add(mCurrentPlayRangeStart, rangeEndTime);
|
||||
mPlayed->Add(mCurrentPlayRangeStart, rangeEndTime);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1408,12 +1410,12 @@ HTMLMediaElement::Played()
|
||||
nsRefPtr<TimeRanges> ranges = new TimeRanges();
|
||||
|
||||
uint32_t timeRangeCount = 0;
|
||||
mPlayed.GetLength(&timeRangeCount);
|
||||
mPlayed->GetLength(&timeRangeCount);
|
||||
for (uint32_t i = 0; i < timeRangeCount; i++) {
|
||||
double begin;
|
||||
double end;
|
||||
mPlayed.Start(i, &begin);
|
||||
mPlayed.End(i, &end);
|
||||
mPlayed->Start(i, &begin);
|
||||
mPlayed->End(i, &end);
|
||||
ranges->Add(begin, end);
|
||||
}
|
||||
|
||||
@ -1888,6 +1890,7 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<nsINodeInfo> aNodeInfo)
|
||||
mDefaultPlaybackRate(1.0),
|
||||
mPlaybackRate(1.0),
|
||||
mPreservesPitch(true),
|
||||
mPlayed(new TimeRanges),
|
||||
mCurrentPlayRangeStart(-1.0),
|
||||
mAllowAudioData(false),
|
||||
mBegun(false),
|
||||
|
@ -377,10 +377,12 @@ ImageDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject)
|
||||
target->AddEventListener(NS_LITERAL_STRING("resize"), this, false);
|
||||
target->AddEventListener(NS_LITERAL_STRING("keypress"), this, false);
|
||||
|
||||
if (!nsContentUtils::IsChildOfSameType(this) &&
|
||||
GetReadyStateEnum() != nsIDocument::READYSTATE_COMPLETE) {
|
||||
LinkStylesheet(NS_LITERAL_STRING("resource://gre/res/TopLevelImageDocument.css"));
|
||||
LinkStylesheet(NS_LITERAL_STRING("chrome://global/skin/media/TopLevelImageDocument.css"));
|
||||
if (GetReadyStateEnum() != nsIDocument::READYSTATE_COMPLETE) {
|
||||
LinkStylesheet(NS_LITERAL_STRING("resource://gre/res/ImageDocument.css"));
|
||||
if (!nsContentUtils::IsChildOfSameType(this)) {
|
||||
LinkStylesheet(NS_LITERAL_STRING("resource://gre/res/TopLevelImageDocument.css"));
|
||||
LinkStylesheet(NS_LITERAL_STRING("chrome://global/skin/media/TopLevelImageDocument.css"));
|
||||
}
|
||||
}
|
||||
BecomeInteractive();
|
||||
}
|
||||
@ -810,29 +812,6 @@ ImageDocument::CreateSyntheticDocument()
|
||||
nsresult rv = MediaDocument::CreateSyntheticDocument();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// We must declare the image as a block element. If we stay as
|
||||
// an inline element, our parent LineBox will be inline too and
|
||||
// ignore the available height during reflow.
|
||||
// This is bad during printing, it means tall image frames won't know
|
||||
// the size of the paper and cannot break into continuations along
|
||||
// multiple pages.
|
||||
Element* head = GetHeadElement();
|
||||
NS_ENSURE_TRUE(head, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsINodeInfo> nodeInfo;
|
||||
if (nsContentUtils::IsChildOfSameType(this)) {
|
||||
nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::style, nullptr,
|
||||
kNameSpaceID_XHTML,
|
||||
nsIDOMNode::ELEMENT_NODE);
|
||||
nsRefPtr<nsGenericHTMLElement> styleContent = NS_NewHTMLStyleElement(nodeInfo.forget());
|
||||
NS_ENSURE_TRUE(styleContent, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
ErrorResult error;
|
||||
styleContent->SetTextContent(NS_LITERAL_STRING("img { display: block; }"),
|
||||
error);
|
||||
head->AppendChildTo(styleContent, false);
|
||||
}
|
||||
|
||||
// Add the image element
|
||||
Element* body = GetBodyElement();
|
||||
if (!body) {
|
||||
@ -840,6 +819,7 @@ ImageDocument::CreateSyntheticDocument()
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsINodeInfo> nodeInfo;
|
||||
nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::img, nullptr,
|
||||
kNameSpaceID_XHTML,
|
||||
nsIDOMNode::ELEMENT_NODE);
|
||||
|
@ -201,6 +201,11 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void CancelAllEvents()
|
||||
{
|
||||
mEvents.Clear();
|
||||
}
|
||||
|
||||
// This method computes the AudioParam value at a given time based on the event timeline
|
||||
template<class TimeType>
|
||||
float GetValueAtTime(TimeType aTime) const
|
||||
|
@ -77,11 +77,6 @@ AnalyserNode::AnalyserNode(AudioContext* aContext)
|
||||
AllocateBuffer();
|
||||
}
|
||||
|
||||
AnalyserNode::~AnalyserNode()
|
||||
{
|
||||
DestroyMediaStream();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
AnalyserNode::WrapObject(JSContext* aCx, JSObject* aScope)
|
||||
{
|
||||
@ -243,12 +238,6 @@ AnalyserNode::ApplyBlackmanWindow(float* aBuffer, uint32_t aSize)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AnalyserNode::DestroyMediaStream()
|
||||
{
|
||||
AudioNode::DestroyMediaStream();
|
||||
}
|
||||
|
||||
bool
|
||||
AnalyserNode::AllocateBuffer()
|
||||
{
|
||||
|
@ -18,7 +18,6 @@ class AnalyserNode : public AudioNode
|
||||
{
|
||||
public:
|
||||
explicit AnalyserNode(AudioContext* aContext);
|
||||
virtual ~AnalyserNode();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
@ -29,8 +28,6 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void DestroyMediaStream() MOZ_OVERRIDE;
|
||||
|
||||
void GetFloatFrequencyData(Float32Array& aArray);
|
||||
void GetByteFrequencyData(Uint8Array& aArray);
|
||||
void GetByteTimeDomainData(Uint8Array& aArray);
|
||||
|
@ -165,8 +165,7 @@ StealJSArrayDataIntoThreadSharedFloatArrayBufferList(JSContext* aJSContext,
|
||||
}
|
||||
|
||||
ThreadSharedFloatArrayBufferList*
|
||||
AudioBuffer::GetThreadSharedChannelsForRate(JSContext* aJSContext, uint32_t* aRate,
|
||||
uint32_t* aLength)
|
||||
AudioBuffer::GetThreadSharedChannelsForRate(JSContext* aJSContext)
|
||||
{
|
||||
if (!mSharedChannels) {
|
||||
// Steal JS data
|
||||
@ -174,8 +173,6 @@ AudioBuffer::GetThreadSharedChannelsForRate(JSContext* aJSContext, uint32_t* aRa
|
||||
StealJSArrayDataIntoThreadSharedFloatArrayBufferList(aJSContext, mJSChannels);
|
||||
}
|
||||
|
||||
*aLength = mLength;
|
||||
*aRate = mSampleRate;
|
||||
return mSharedChannels;
|
||||
}
|
||||
|
||||
|
@ -89,12 +89,9 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a ThreadSharedFloatArrayBufferList containing the sample data
|
||||
* at aRate. Sets *aLength to the number of samples per channel.
|
||||
* Returns a ThreadSharedFloatArrayBufferList containing the sample data.
|
||||
*/
|
||||
ThreadSharedFloatArrayBufferList* GetThreadSharedChannelsForRate(JSContext* aContext,
|
||||
uint32_t* aRate,
|
||||
uint32_t* aLength);
|
||||
ThreadSharedFloatArrayBufferList* GetThreadSharedChannelsForRate(JSContext* aContext);
|
||||
|
||||
// aContents should either come from JS_AllocateArrayBufferContents or
|
||||
// JS_StealArrayBufferContents.
|
||||
|
@ -58,25 +58,10 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// START, OFFSET and DURATION are always set by start() (along with setting
|
||||
// mBuffer to something non-null).
|
||||
// STOP is set by stop().
|
||||
enum Parameters {
|
||||
SAMPLE_RATE,
|
||||
START,
|
||||
STOP,
|
||||
OFFSET,
|
||||
DURATION,
|
||||
LOOP,
|
||||
LOOPSTART,
|
||||
LOOPEND,
|
||||
PLAYBACKRATE,
|
||||
DOPPLERSHIFT
|
||||
};
|
||||
virtual void SetTimelineParameter(uint32_t aIndex, const dom::AudioParamTimeline& aValue)
|
||||
{
|
||||
switch (aIndex) {
|
||||
case PLAYBACKRATE:
|
||||
case AudioBufferSourceNode::PLAYBACKRATE:
|
||||
mPlaybackRateTimeline = aValue;
|
||||
// If we have a simple value that is 1.0 (i.e. intrinsic speed), and our
|
||||
// input buffer is already at the ideal audio rate, and we have a
|
||||
@ -96,8 +81,8 @@ public:
|
||||
virtual void SetStreamTimeParameter(uint32_t aIndex, TrackTicks aParam)
|
||||
{
|
||||
switch (aIndex) {
|
||||
case START: mStart = aParam; break;
|
||||
case STOP: mStop = aParam; break;
|
||||
case AudioBufferSourceNode::START: mStart = aParam; break;
|
||||
case AudioBufferSourceNode::STOP: mStop = aParam; break;
|
||||
default:
|
||||
NS_ERROR("Bad AudioBufferSourceNodeEngine StreamTimeParameter");
|
||||
}
|
||||
@ -105,7 +90,7 @@ public:
|
||||
virtual void SetDoubleParameter(uint32_t aIndex, double aParam)
|
||||
{
|
||||
switch (aIndex) {
|
||||
case DOPPLERSHIFT:
|
||||
case AudioBufferSourceNode::DOPPLERSHIFT:
|
||||
mDopplerShift = aParam;
|
||||
break;
|
||||
default:
|
||||
@ -115,12 +100,12 @@ public:
|
||||
virtual void SetInt32Parameter(uint32_t aIndex, int32_t aParam)
|
||||
{
|
||||
switch (aIndex) {
|
||||
case SAMPLE_RATE: mSampleRate = aParam; break;
|
||||
case OFFSET: mOffset = aParam; break;
|
||||
case DURATION: mDuration = aParam; break;
|
||||
case LOOP: mLoop = !!aParam; break;
|
||||
case LOOPSTART: mLoopStart = aParam; break;
|
||||
case LOOPEND: mLoopEnd = aParam; break;
|
||||
case AudioBufferSourceNode::SAMPLE_RATE: mSampleRate = aParam; break;
|
||||
case AudioBufferSourceNode::OFFSET: mOffset = aParam; break;
|
||||
case AudioBufferSourceNode::DURATION: mDuration = aParam; break;
|
||||
case AudioBufferSourceNode::LOOP: mLoop = !!aParam; break;
|
||||
case AudioBufferSourceNode::LOOPSTART: mLoopStart = aParam; break;
|
||||
case AudioBufferSourceNode::LOOPEND: mLoopEnd = aParam; break;
|
||||
default:
|
||||
NS_ERROR("Bad AudioBufferSourceNodeEngine Int32Parameter");
|
||||
}
|
||||
@ -428,11 +413,9 @@ AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* aContext)
|
||||
|
||||
AudioBufferSourceNode::~AudioBufferSourceNode()
|
||||
{
|
||||
//
|
||||
if (Context()) {
|
||||
Context()->UnregisterAudioBufferSourceNode(this);
|
||||
}
|
||||
DestroyMediaStream();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
@ -457,10 +440,10 @@ AudioBufferSourceNode::Start(JSContext* aCx, double aWhen, double aOffset,
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t rate;
|
||||
uint32_t lengthSamples;
|
||||
float rate = mBuffer->SampleRate();
|
||||
int32_t lengthSamples = mBuffer->Length();
|
||||
nsRefPtr<ThreadSharedFloatArrayBufferList> data =
|
||||
mBuffer->GetThreadSharedChannelsForRate(aCx, &rate, &lengthSamples);
|
||||
mBuffer->GetThreadSharedChannelsForRate(aCx);
|
||||
double length = double(lengthSamples) / rate;
|
||||
double offset = std::max(0.0, aOffset);
|
||||
double endOffset = aDuration.WasPassed() ?
|
||||
@ -470,40 +453,19 @@ AudioBufferSourceNode::Start(JSContext* aCx, double aWhen, double aOffset,
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't compute and set the loop parameters unnecessarily
|
||||
if (mLoop) {
|
||||
double actualLoopStart, actualLoopEnd;
|
||||
if (((mLoopStart != 0.0) || (mLoopEnd != 0.0)) &&
|
||||
mLoopStart >= 0.0 && mLoopEnd > 0.0 &&
|
||||
mLoopStart < mLoopEnd) {
|
||||
actualLoopStart = (mLoopStart > length) ? 0.0 : mLoopStart;
|
||||
actualLoopEnd = std::min(mLoopEnd, length);
|
||||
} else {
|
||||
actualLoopStart = 0.0;
|
||||
actualLoopEnd = length;
|
||||
}
|
||||
int32_t loopStartTicks = NS_lround(actualLoopStart * rate);
|
||||
int32_t loopEndTicks = NS_lround(actualLoopEnd * rate);
|
||||
ns->SetInt32Parameter(AudioBufferSourceNodeEngine::LOOP, 1);
|
||||
ns->SetInt32Parameter(AudioBufferSourceNodeEngine::LOOPSTART, loopStartTicks);
|
||||
ns->SetInt32Parameter(AudioBufferSourceNodeEngine::LOOPEND, loopEndTicks);
|
||||
}
|
||||
|
||||
ns->SetBuffer(data.forget());
|
||||
// Don't set parameter unnecessarily
|
||||
if (aWhen > 0.0) {
|
||||
ns->SetStreamTimeParameter(AudioBufferSourceNodeEngine::START,
|
||||
Context()->DestinationStream(),
|
||||
aWhen);
|
||||
ns->SetStreamTimeParameter(START, Context()->DestinationStream(), aWhen);
|
||||
}
|
||||
int32_t offsetTicks = NS_lround(offset*rate);
|
||||
// Don't set parameter unnecessarily
|
||||
if (offsetTicks > 0) {
|
||||
ns->SetInt32Parameter(AudioBufferSourceNodeEngine::OFFSET, offsetTicks);
|
||||
ns->SetInt32Parameter(OFFSET, offsetTicks);
|
||||
}
|
||||
ns->SetInt32Parameter(AudioBufferSourceNodeEngine::DURATION,
|
||||
ns->SetInt32Parameter(DURATION,
|
||||
NS_lround(endOffset*rate) - offsetTicks);
|
||||
ns->SetInt32Parameter(AudioBufferSourceNodeEngine::SAMPLE_RATE, rate);
|
||||
ns->SetInt32Parameter(SAMPLE_RATE, rate);
|
||||
|
||||
MOZ_ASSERT(!mPlayingRef, "We can only accept a successful start() call once");
|
||||
mPlayingRef.Take(this);
|
||||
@ -523,8 +485,7 @@ AudioBufferSourceNode::Stop(double aWhen, ErrorResult& aRv)
|
||||
return;
|
||||
}
|
||||
|
||||
ns->SetStreamTimeParameter(AudioBufferSourceNodeEngine::STOP,
|
||||
Context()->DestinationStream(),
|
||||
ns->SetStreamTimeParameter(STOP, Context()->DestinationStream(),
|
||||
std::max(0.0, aWhen));
|
||||
}
|
||||
|
||||
@ -542,13 +503,39 @@ void
|
||||
AudioBufferSourceNode::SendPlaybackRateToStream(AudioNode* aNode)
|
||||
{
|
||||
AudioBufferSourceNode* This = static_cast<AudioBufferSourceNode*>(aNode);
|
||||
SendTimelineParameterToStream(This, AudioBufferSourceNodeEngine::PLAYBACKRATE, *This->mPlaybackRate);
|
||||
SendTimelineParameterToStream(This, PLAYBACKRATE, *This->mPlaybackRate);
|
||||
}
|
||||
|
||||
void
|
||||
AudioBufferSourceNode::SendDopplerShiftToStream(double aDopplerShift)
|
||||
{
|
||||
SendDoubleParameterToStream(AudioBufferSourceNodeEngine::DOPPLERSHIFT, aDopplerShift);
|
||||
SendDoubleParameterToStream(DOPPLERSHIFT, aDopplerShift);
|
||||
}
|
||||
|
||||
void
|
||||
AudioBufferSourceNode::SendLoopParametersToStream()
|
||||
{
|
||||
SendInt32ParameterToStream(LOOP, mLoop ? 1 : 0);
|
||||
|
||||
// Don't compute and set the loop parameters unnecessarily
|
||||
if (mLoop && mBuffer) {
|
||||
float rate = mBuffer->SampleRate();
|
||||
double length = (double(mBuffer->Length()) / mBuffer->SampleRate());
|
||||
double actualLoopStart, actualLoopEnd;
|
||||
if (((mLoopStart != 0.0) || (mLoopEnd != 0.0)) &&
|
||||
mLoopStart >= 0.0 && mLoopEnd > 0.0 &&
|
||||
mLoopStart < mLoopEnd) {
|
||||
actualLoopStart = (mLoopStart > length) ? 0.0 : mLoopStart;
|
||||
actualLoopEnd = std::min(mLoopEnd, length);
|
||||
} else {
|
||||
actualLoopStart = 0.0;
|
||||
actualLoopEnd = length;
|
||||
}
|
||||
int32_t loopStartTicks = NS_lround(actualLoopStart * rate);
|
||||
int32_t loopEndTicks = NS_lround(actualLoopEnd * rate);
|
||||
SendInt32ParameterToStream(LOOPSTART, loopStartTicks);
|
||||
SendInt32ParameterToStream(LOOPEND, loopEndTicks);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -93,6 +93,7 @@ public:
|
||||
void SetLoop(bool aLoop)
|
||||
{
|
||||
mLoop = aLoop;
|
||||
SendLoopParametersToStream();
|
||||
}
|
||||
double LoopStart() const
|
||||
{
|
||||
@ -101,6 +102,7 @@ public:
|
||||
void SetLoopStart(double aStart)
|
||||
{
|
||||
mLoopStart = aStart;
|
||||
SendLoopParametersToStream();
|
||||
}
|
||||
double LoopEnd() const
|
||||
{
|
||||
@ -109,13 +111,34 @@ public:
|
||||
void SetLoopEnd(double aEnd)
|
||||
{
|
||||
mLoopEnd = aEnd;
|
||||
SendLoopParametersToStream();
|
||||
}
|
||||
void SendDopplerShiftToStream(double aDopplerShift);
|
||||
|
||||
virtual void NotifyMainThreadStateChanged() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
friend class AudioBufferSourceNodeEngine;
|
||||
// START, OFFSET and DURATION are always set by start() (along with setting
|
||||
// mBuffer to something non-null).
|
||||
// STOP is set by stop().
|
||||
enum EngineParameters {
|
||||
SAMPLE_RATE,
|
||||
START,
|
||||
STOP,
|
||||
OFFSET,
|
||||
DURATION,
|
||||
LOOP,
|
||||
LOOPSTART,
|
||||
LOOPEND,
|
||||
PLAYBACKRATE,
|
||||
DOPPLERSHIFT
|
||||
};
|
||||
|
||||
void SendLoopParametersToStream();
|
||||
static void SendPlaybackRateToStream(AudioNode* aNode);
|
||||
|
||||
private:
|
||||
double mLoopStart;
|
||||
double mLoopEnd;
|
||||
nsRefPtr<AudioBuffer> mBuffer;
|
||||
|
@ -141,6 +141,7 @@ AudioContext::CreateScriptProcessor(uint32_t aBufferSize,
|
||||
nsRefPtr<ScriptProcessorNode> scriptProcessor =
|
||||
new ScriptProcessorNode(this, aBufferSize, aNumberOfInputChannels,
|
||||
aNumberOfOutputChannels);
|
||||
mScriptProcessorNodes.AppendElement(scriptProcessor);
|
||||
return scriptProcessor.forget();
|
||||
}
|
||||
|
||||
@ -245,6 +246,12 @@ AudioContext::UnregisterPannerNode(PannerNode* aNode)
|
||||
mPannerNodes.RemoveElement(aNode);
|
||||
}
|
||||
|
||||
void
|
||||
AudioContext::UnregisterScriptProcessorNode(ScriptProcessorNode* aNode)
|
||||
{
|
||||
mScriptProcessorNodes.RemoveElement(aNode);
|
||||
}
|
||||
|
||||
void
|
||||
AudioContext::UpdatePannerSource()
|
||||
{
|
||||
@ -274,6 +281,25 @@ AudioContext::CurrentTime() const
|
||||
return MediaTimeToSeconds(Destination()->Stream()->GetCurrentTime());
|
||||
}
|
||||
|
||||
void
|
||||
AudioContext::Shutdown()
|
||||
{
|
||||
Suspend();
|
||||
mDecoder.Shutdown();
|
||||
|
||||
// Stop all audio buffer source nodes, to make sure that they release
|
||||
// their self-references.
|
||||
for (uint32_t i = 0; i < mAudioBufferSourceNodes.Length(); ++i) {
|
||||
ErrorResult rv;
|
||||
mAudioBufferSourceNodes[i]->Stop(0.0, rv);
|
||||
}
|
||||
// Stop all script processor nodes, to make sure that they release
|
||||
// their self-references.
|
||||
for (uint32_t i = 0; i < mScriptProcessorNodes.Length(); ++i) {
|
||||
mScriptProcessorNodes[i]->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioContext::Suspend()
|
||||
{
|
||||
|
@ -65,12 +65,7 @@ public:
|
||||
return mWindow;
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
Suspend();
|
||||
mDecoder.Shutdown();
|
||||
}
|
||||
|
||||
void Shutdown();
|
||||
void Suspend();
|
||||
void Resume();
|
||||
|
||||
@ -156,6 +151,7 @@ public:
|
||||
MediaStream* DestinationStream() const;
|
||||
void UnregisterAudioBufferSourceNode(AudioBufferSourceNode* aNode);
|
||||
void UnregisterPannerNode(PannerNode* aNode);
|
||||
void UnregisterScriptProcessorNode(ScriptProcessorNode* aNode);
|
||||
void UpdatePannerSource();
|
||||
|
||||
JSContext* GetJSContext() const;
|
||||
@ -175,6 +171,7 @@ private:
|
||||
// to compute the doppler shift. Those are weak pointers.
|
||||
nsTArray<PannerNode*> mPannerNodes;
|
||||
nsTArray<AudioBufferSourceNode*> mAudioBufferSourceNodes;
|
||||
nsTArray<ScriptProcessorNode*> mScriptProcessorNodes;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -202,12 +202,18 @@ AudioNode::Disconnect(uint32_t aOutput, ErrorResult& aRv)
|
||||
}
|
||||
|
||||
void
|
||||
AudioNode::UnbindFromEngine()
|
||||
AudioNode::DestroyMediaStream()
|
||||
{
|
||||
AudioNodeStream* ns = static_cast<AudioNodeStream*>(mStream.get());
|
||||
MOZ_ASSERT(ns, "How come we don't have a stream here?");
|
||||
MOZ_ASSERT(ns->Engine()->mNode == this, "Invalid node reference");
|
||||
ns->Engine()->mNode = nullptr;
|
||||
if (mStream) {
|
||||
// Remove the node reference on the engine
|
||||
AudioNodeStream* ns = static_cast<AudioNodeStream*>(mStream.get());
|
||||
MOZ_ASSERT(ns, "How come we don't have a stream here?");
|
||||
MOZ_ASSERT(ns->Engine()->mNode == this, "Invalid node reference");
|
||||
ns->Engine()->mNode = nullptr;
|
||||
|
||||
mStream->Destroy();
|
||||
mStream = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -78,16 +78,7 @@ public:
|
||||
virtual ~AudioNode();
|
||||
|
||||
// This should be idempotent (safe to call multiple times).
|
||||
// This should be called in the destructor of every class that overrides
|
||||
// this method.
|
||||
virtual void DestroyMediaStream()
|
||||
{
|
||||
if (mStream) {
|
||||
UnbindFromEngine();
|
||||
mStream->Destroy();
|
||||
mStream = nullptr;
|
||||
}
|
||||
}
|
||||
virtual void DestroyMediaStream();
|
||||
|
||||
// This method should be overridden to return true in nodes
|
||||
// which support being hooked up to the Media Stream graph.
|
||||
@ -114,10 +105,10 @@ public:
|
||||
return mContext;
|
||||
}
|
||||
|
||||
void Connect(AudioNode& aDestination, uint32_t aOutput,
|
||||
uint32_t aInput, ErrorResult& aRv);
|
||||
virtual void Connect(AudioNode& aDestination, uint32_t aOutput,
|
||||
uint32_t aInput, ErrorResult& aRv);
|
||||
|
||||
void Disconnect(uint32_t aOutput, ErrorResult& aRv);
|
||||
virtual void Disconnect(uint32_t aOutput, ErrorResult& aRv);
|
||||
|
||||
// The following two virtual methods must be implemented by each node type
|
||||
// to provide their number of input and output ports. These numbers are
|
||||
@ -153,8 +144,6 @@ private:
|
||||
// This could possibly delete 'this'.
|
||||
void DisconnectFromGraph();
|
||||
|
||||
void UnbindFromEngine();
|
||||
|
||||
protected:
|
||||
static void Callback(AudioNode* aNode) { /* not implemented */ }
|
||||
|
||||
|
@ -109,11 +109,6 @@ BiquadFilterNode::BiquadFilterNode(AudioContext* aContext)
|
||||
engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
|
||||
}
|
||||
|
||||
BiquadFilterNode::~BiquadFilterNode()
|
||||
{
|
||||
DestroyMediaStream();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
BiquadFilterNode::WrapObject(JSContext* aCx, JSObject* aScope)
|
||||
{
|
||||
|
@ -33,7 +33,6 @@ class BiquadFilterNode : public AudioNode
|
||||
{
|
||||
public:
|
||||
explicit BiquadFilterNode(AudioContext* aContext);
|
||||
~BiquadFilterNode();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BiquadFilterNode, AudioNode)
|
||||
|
@ -10,6 +10,11 @@
|
||||
#include "AudioNodeStream.h"
|
||||
#include "AudioDestinationNode.h"
|
||||
#include "WebAudioUtils.h"
|
||||
#include "blink/DynamicsCompressor.h"
|
||||
|
||||
using WebCore::DynamicsCompressor;
|
||||
|
||||
const unsigned DEFAULT_NUMBER_OF_CHANNELS = 2;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -41,9 +46,10 @@ public:
|
||||
, mThreshold(-24.f)
|
||||
, mKnee(30.f)
|
||||
, mRatio(12.f)
|
||||
, mReduction(0.f)
|
||||
, mAttack(0.003f)
|
||||
, mRelease(0.25f)
|
||||
, mCompressor(new DynamicsCompressor(aNode->Context()->SampleRate(),
|
||||
DEFAULT_NUMBER_OF_CHANNELS))
|
||||
{
|
||||
}
|
||||
|
||||
@ -56,7 +62,6 @@ public:
|
||||
THRESHOLD,
|
||||
KNEE,
|
||||
RATIO,
|
||||
REDUCTION,
|
||||
ATTACK,
|
||||
RELEASE
|
||||
};
|
||||
@ -76,10 +81,6 @@ public:
|
||||
mRatio = aValue;
|
||||
WebAudioUtils::ConvertAudioParamToTicks(mRatio, mSource, mDestination);
|
||||
break;
|
||||
case REDUCTION:
|
||||
mReduction = aValue;
|
||||
WebAudioUtils::ConvertAudioParamToTicks(mReduction, mSource, mDestination);
|
||||
break;
|
||||
case ATTACK:
|
||||
mAttack = aValue;
|
||||
WebAudioUtils::ConvertAudioParamToTicks(mAttack, mSource, mDestination);
|
||||
@ -98,8 +99,62 @@ public:
|
||||
AudioChunk* aOutput,
|
||||
bool* aFinished) MOZ_OVERRIDE
|
||||
{
|
||||
// TODO: do the necessary computation here
|
||||
*aOutput = aInput;
|
||||
if (aInput.IsNull()) {
|
||||
// Just output silence
|
||||
*aOutput = aInput;
|
||||
return;
|
||||
}
|
||||
|
||||
TrackTicks pos = aStream->GetCurrentPosition();
|
||||
mCompressor->setParameterValue(DynamicsCompressor::ParamThreshold,
|
||||
mThreshold.GetValueAtTime(pos));
|
||||
mCompressor->setParameterValue(DynamicsCompressor::ParamKnee,
|
||||
mKnee.GetValueAtTime(pos));
|
||||
mCompressor->setParameterValue(DynamicsCompressor::ParamRatio,
|
||||
mRatio.GetValueAtTime(pos));
|
||||
mCompressor->setParameterValue(DynamicsCompressor::ParamAttack,
|
||||
mAttack.GetValueAtTime(pos));
|
||||
mCompressor->setParameterValue(DynamicsCompressor::ParamRelease,
|
||||
mRelease.GetValueAtTime(pos));
|
||||
|
||||
AllocateAudioBlock(DEFAULT_NUMBER_OF_CHANNELS, aOutput);
|
||||
mCompressor->process(&aInput, aOutput, aInput.GetDuration());
|
||||
|
||||
SendReductionParamToMainThread(aStream,
|
||||
mCompressor->parameterValue(DynamicsCompressor::ParamReduction));
|
||||
}
|
||||
|
||||
private:
|
||||
void SendReductionParamToMainThread(AudioNodeStream* aStream, float aReduction)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
class Command : public nsRunnable
|
||||
{
|
||||
public:
|
||||
Command(AudioNodeStream* aStream, float aReduction)
|
||||
: mStream(aStream)
|
||||
, mReduction(aReduction)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP Run()
|
||||
{
|
||||
nsRefPtr<DynamicsCompressorNode> node = static_cast<DynamicsCompressorNode*>(mStream->Engine()->Node());
|
||||
if (node) {
|
||||
AudioParam* reduction = node->Reduction();
|
||||
reduction->CancelAllEvents();
|
||||
reduction->SetValue(mReduction);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<AudioNodeStream> mStream;
|
||||
float mReduction;
|
||||
};
|
||||
|
||||
NS_DispatchToMainThread(new Command(aStream, aReduction));
|
||||
}
|
||||
|
||||
private:
|
||||
@ -108,9 +163,9 @@ private:
|
||||
AudioParamTimeline mThreshold;
|
||||
AudioParamTimeline mKnee;
|
||||
AudioParamTimeline mRatio;
|
||||
AudioParamTimeline mReduction;
|
||||
AudioParamTimeline mAttack;
|
||||
AudioParamTimeline mRelease;
|
||||
nsAutoPtr<DynamicsCompressor> mCompressor;
|
||||
};
|
||||
|
||||
DynamicsCompressorNode::DynamicsCompressorNode(AudioContext* aContext)
|
||||
@ -118,20 +173,16 @@ DynamicsCompressorNode::DynamicsCompressorNode(AudioContext* aContext)
|
||||
, mThreshold(new AudioParam(this, SendThresholdToStream, -24.f))
|
||||
, mKnee(new AudioParam(this, SendKneeToStream, 30.f))
|
||||
, mRatio(new AudioParam(this, SendRatioToStream, 12.f))
|
||||
, mReduction(new AudioParam(this, SendReductionToStream, 0.f))
|
||||
, mReduction(new AudioParam(this, Callback, 0.f))
|
||||
, mAttack(new AudioParam(this, SendAttackToStream, 0.003f))
|
||||
, mRelease(new AudioParam(this, SendReleaseToStream, 0.25f))
|
||||
{
|
||||
DynamicsCompressorNodeEngine* engine = new DynamicsCompressorNodeEngine(this, aContext->Destination());
|
||||
mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM);
|
||||
mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM,
|
||||
DEFAULT_NUMBER_OF_CHANNELS);
|
||||
engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
|
||||
}
|
||||
|
||||
DynamicsCompressorNode::~DynamicsCompressorNode()
|
||||
{
|
||||
DestroyMediaStream();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
DynamicsCompressorNode::WrapObject(JSContext* aCx, JSObject* aScope)
|
||||
{
|
||||
@ -159,13 +210,6 @@ DynamicsCompressorNode::SendRatioToStream(AudioNode* aNode)
|
||||
SendTimelineParameterToStream(This, DynamicsCompressorNodeEngine::RATIO, *This->mRatio);
|
||||
}
|
||||
|
||||
void
|
||||
DynamicsCompressorNode::SendReductionToStream(AudioNode* aNode)
|
||||
{
|
||||
DynamicsCompressorNode* This = static_cast<DynamicsCompressorNode*>(aNode);
|
||||
SendTimelineParameterToStream(This, DynamicsCompressorNodeEngine::REDUCTION, *This->mReduction);
|
||||
}
|
||||
|
||||
void
|
||||
DynamicsCompressorNode::SendAttackToStream(AudioNode* aNode)
|
||||
{
|
||||
|
@ -19,7 +19,6 @@ class DynamicsCompressorNode : public AudioNode
|
||||
{
|
||||
public:
|
||||
explicit DynamicsCompressorNode(AudioContext* aContext);
|
||||
~DynamicsCompressorNode();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DynamicsCompressorNode, AudioNode)
|
||||
@ -66,7 +65,6 @@ private:
|
||||
static void SendThresholdToStream(AudioNode* aNode);
|
||||
static void SendKneeToStream(AudioNode* aNode);
|
||||
static void SendRatioToStream(AudioNode* aNode);
|
||||
static void SendReductionToStream(AudioNode* aNode);
|
||||
static void SendAttackToStream(AudioNode* aNode);
|
||||
static void SendReleaseToStream(AudioNode* aNode);
|
||||
|
||||
|
@ -103,11 +103,6 @@ GainNode::GainNode(AudioContext* aContext)
|
||||
engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
|
||||
}
|
||||
|
||||
GainNode::~GainNode()
|
||||
{
|
||||
DestroyMediaStream();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
GainNode::WrapObject(JSContext* aCx, JSObject* aScope)
|
||||
{
|
||||
|
@ -19,7 +19,6 @@ class GainNode : public AudioNode
|
||||
{
|
||||
public:
|
||||
explicit GainNode(AudioContext* aContext);
|
||||
virtual ~GainNode();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(GainNode, AudioNode)
|
||||
|
@ -184,7 +184,6 @@ PannerNode::~PannerNode()
|
||||
if (Context()) {
|
||||
Context()->UnregisterPannerNode(this);
|
||||
}
|
||||
DestroyMediaStream();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
|
@ -13,13 +13,21 @@
|
||||
#include "AudioProcessingEvent.h"
|
||||
#include "WebAudioUtils.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include <deque>
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ScriptProcessorNode, AudioNode)
|
||||
if (tmp->Context()) {
|
||||
tmp->Context()->UnregisterScriptProcessorNode(tmp);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ScriptProcessorNode, AudioNode)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ScriptProcessorNode)
|
||||
NS_INTERFACE_MAP_END_INHERITING(AudioNode)
|
||||
|
||||
@ -304,10 +312,7 @@ private:
|
||||
// Steal the output buffers
|
||||
nsRefPtr<ThreadSharedFloatArrayBufferList> output;
|
||||
if (event->HasOutputBuffer()) {
|
||||
uint32_t rate, length;
|
||||
output = event->OutputBuffer()->GetThreadSharedChannelsForRate(cx, &rate, &length);
|
||||
unused << rate;
|
||||
unused << length;
|
||||
output = event->OutputBuffer()->GetThreadSharedChannelsForRate(cx);
|
||||
}
|
||||
|
||||
// Append it to our output buffer queue
|
||||
@ -363,7 +368,9 @@ ScriptProcessorNode::ScriptProcessorNode(AudioContext* aContext,
|
||||
|
||||
ScriptProcessorNode::~ScriptProcessorNode()
|
||||
{
|
||||
DestroyMediaStream();
|
||||
if (Context()) {
|
||||
Context()->UnregisterScriptProcessorNode(this);
|
||||
}
|
||||
}
|
||||
|
||||
JSObject*
|
||||
|
@ -30,6 +30,7 @@ public:
|
||||
virtual ~ScriptProcessorNode();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ScriptProcessorNode, AudioNode)
|
||||
|
||||
IMPL_EVENT_HANDLER(audioprocess)
|
||||
|
||||
@ -40,6 +41,23 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void Connect(AudioNode& aDestination, uint32_t aOutput,
|
||||
uint32_t aInput, ErrorResult& aRv) MOZ_OVERRIDE
|
||||
{
|
||||
AudioNode::Connect(aDestination, aOutput, aInput, aRv);
|
||||
if (!aRv.Failed()) {
|
||||
mPlayingRef.Take(this);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Disconnect(uint32_t aOutput, ErrorResult& aRv) MOZ_OVERRIDE
|
||||
{
|
||||
AudioNode::Disconnect(aOutput, aRv);
|
||||
if (!aRv.Failed()) {
|
||||
mPlayingRef.Drop(this);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t BufferSize() const
|
||||
{
|
||||
return mBufferSize;
|
||||
@ -57,10 +75,16 @@ public:
|
||||
|
||||
using nsDOMEventTargetHelper::DispatchTrustedEvent;
|
||||
|
||||
void Stop()
|
||||
{
|
||||
mPlayingRef.Drop(this);
|
||||
}
|
||||
|
||||
private:
|
||||
nsAutoPtr<SharedBuffers> mSharedBuffers;
|
||||
const uint32_t mBufferSize;
|
||||
const uint32_t mNumberOfOutputChannels;
|
||||
SelfReference<ScriptProcessorNode> mPlayingRef; // a reference to self while planing
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -60,6 +60,14 @@ struct WebAudioUtils {
|
||||
return aLinearValue ? 20.0f * std::log10(aLinearValue) : aMinDecibels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a decibel value to a linear value.
|
||||
*/
|
||||
static float ConvertDecibelsToLinear(float aDecibels)
|
||||
{
|
||||
return std::pow(10.0f, 0.05f * aDecibels);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a decibel to a linear value.
|
||||
*/
|
||||
@ -75,6 +83,11 @@ struct WebAudioUtils {
|
||||
}
|
||||
}
|
||||
|
||||
static double DiscreteTimeConstantForSampleRate(double timeConstant, double sampleRate)
|
||||
{
|
||||
return 1.0 - std::exp(-1.0 / (sampleRate * timeConstant));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a stream position into the time coordinate of the destination
|
||||
* stream.
|
||||
|
125
content/media/webaudio/blink/DenormalDisabler.h
Normal file
125
content/media/webaudio/blink/DenormalDisabler.h
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2011, Google Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef DenormalDisabler_h
|
||||
#define DenormalDisabler_h
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath>
|
||||
|
||||
namespace WebCore {
|
||||
|
||||
// Deal with denormals. They can very seriously impact performance on x86.
|
||||
|
||||
// Define HAVE_DENORMAL if we support flushing denormals to zero.
|
||||
#if defined(XP_WIN) && defined(_MSC_VER)
|
||||
#include <float.h>
|
||||
#define HAVE_DENORMAL
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
||||
#define HAVE_DENORMAL
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DENORMAL
|
||||
class DenormalDisabler {
|
||||
public:
|
||||
DenormalDisabler()
|
||||
: m_savedCSR(0)
|
||||
{
|
||||
#if defined(XP_WIN) && defined(_MSC_VER)
|
||||
// Save the current state, and set mode to flush denormals.
|
||||
//
|
||||
// http://stackoverflow.com/questions/637175/possible-bug-in-controlfp-s-may-not-restore-control-word-correctly
|
||||
_controlfp_s(&m_savedCSR, 0, 0);
|
||||
unsigned int unused;
|
||||
_controlfp_s(&unused, _DN_FLUSH, _MCW_DN);
|
||||
#else
|
||||
m_savedCSR = getCSR();
|
||||
setCSR(m_savedCSR | 0x8040);
|
||||
#endif
|
||||
}
|
||||
|
||||
~DenormalDisabler()
|
||||
{
|
||||
#if defined(XP_WIN) && defined(_MSC_VER)
|
||||
unsigned int unused;
|
||||
_controlfp_s(&unused, m_savedCSR, _MCW_DN);
|
||||
#else
|
||||
setCSR(m_savedCSR);
|
||||
#endif
|
||||
}
|
||||
|
||||
// This is a nop if we can flush denormals to zero in hardware.
|
||||
static inline float flushDenormalFloatToZero(float f)
|
||||
{
|
||||
#if defined(XP_WIN) && defined(_MSC_VER) && _M_IX86_FP
|
||||
// For systems using x87 instead of sse, there's no hardware support
|
||||
// to flush denormals automatically. Hence, we need to flush
|
||||
// denormals to zero manually.
|
||||
return (fabs(f) < FLT_MIN) ? 0.0f : f;
|
||||
#else
|
||||
return f;
|
||||
#endif
|
||||
}
|
||||
private:
|
||||
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
||||
inline int getCSR()
|
||||
{
|
||||
int result;
|
||||
asm volatile("stmxcsr %0" : "=m" (result));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setCSR(int a)
|
||||
{
|
||||
int temp = a;
|
||||
asm volatile("ldmxcsr %0" : : "m" (temp));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
unsigned int m_savedCSR;
|
||||
};
|
||||
|
||||
#else
|
||||
// FIXME: add implementations for other architectures and compilers
|
||||
class DenormalDisabler {
|
||||
public:
|
||||
DenormalDisabler() { }
|
||||
|
||||
// Assume the worst case that other architectures and compilers
|
||||
// need to flush denormals to zero manually.
|
||||
static inline float flushDenormalFloatToZero(float f)
|
||||
{
|
||||
return (fabs(f) < FLT_MIN) ? 0.0f : f;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // WebCore
|
||||
|
||||
#undef HAVE_DENORMAL
|
||||
#endif // DenormalDisabler_h
|
282
content/media/webaudio/blink/DynamicsCompressor.cpp
Normal file
282
content/media/webaudio/blink/DynamicsCompressor.cpp
Normal file
@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
|
||||
* its contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "DynamicsCompressor.h"
|
||||
#include "AudioSegment.h"
|
||||
|
||||
#include <cmath>
|
||||
#include "AudioNodeEngine.h"
|
||||
#include "nsDebug.h"
|
||||
|
||||
using mozilla::WEBAUDIO_BLOCK_SIZE;
|
||||
|
||||
namespace WebCore {
|
||||
|
||||
DynamicsCompressor::DynamicsCompressor(float sampleRate, unsigned numberOfChannels)
|
||||
: m_numberOfChannels(numberOfChannels)
|
||||
, m_sampleRate(sampleRate)
|
||||
, m_compressor(sampleRate, numberOfChannels)
|
||||
{
|
||||
// Uninitialized state - for parameter recalculation.
|
||||
m_lastFilterStageRatio = -1;
|
||||
m_lastAnchor = -1;
|
||||
m_lastFilterStageGain = -1;
|
||||
|
||||
setNumberOfChannels(numberOfChannels);
|
||||
initializeParameters();
|
||||
}
|
||||
|
||||
void DynamicsCompressor::setParameterValue(unsigned parameterID, float value)
|
||||
{
|
||||
MOZ_ASSERT(parameterID < ParamLast);
|
||||
if (parameterID < ParamLast)
|
||||
m_parameters[parameterID] = value;
|
||||
}
|
||||
|
||||
void DynamicsCompressor::initializeParameters()
|
||||
{
|
||||
// Initializes compressor to default values.
|
||||
|
||||
m_parameters[ParamThreshold] = -24; // dB
|
||||
m_parameters[ParamKnee] = 30; // dB
|
||||
m_parameters[ParamRatio] = 12; // unit-less
|
||||
m_parameters[ParamAttack] = 0.003f; // seconds
|
||||
m_parameters[ParamRelease] = 0.250f; // seconds
|
||||
m_parameters[ParamPreDelay] = 0.006f; // seconds
|
||||
|
||||
// Release zone values 0 -> 1.
|
||||
m_parameters[ParamReleaseZone1] = 0.09f;
|
||||
m_parameters[ParamReleaseZone2] = 0.16f;
|
||||
m_parameters[ParamReleaseZone3] = 0.42f;
|
||||
m_parameters[ParamReleaseZone4] = 0.98f;
|
||||
|
||||
m_parameters[ParamFilterStageGain] = 4.4f; // dB
|
||||
m_parameters[ParamFilterStageRatio] = 2;
|
||||
m_parameters[ParamFilterAnchor] = 15000 / nyquist();
|
||||
|
||||
m_parameters[ParamPostGain] = 0; // dB
|
||||
m_parameters[ParamReduction] = 0; // dB
|
||||
|
||||
// Linear crossfade (0 -> 1).
|
||||
m_parameters[ParamEffectBlend] = 1;
|
||||
}
|
||||
|
||||
float DynamicsCompressor::parameterValue(unsigned parameterID)
|
||||
{
|
||||
MOZ_ASSERT(parameterID < ParamLast);
|
||||
return m_parameters[parameterID];
|
||||
}
|
||||
|
||||
void DynamicsCompressor::setEmphasisStageParameters(unsigned stageIndex, float gain, float normalizedFrequency /* 0 -> 1 */)
|
||||
{
|
||||
float gk = 1 - gain / 20;
|
||||
float f1 = normalizedFrequency * gk;
|
||||
float f2 = normalizedFrequency / gk;
|
||||
float r1 = expf(-f1 * M_PI);
|
||||
float r2 = expf(-f2 * M_PI);
|
||||
|
||||
MOZ_ASSERT(m_numberOfChannels == m_preFilterPacks.Length());
|
||||
|
||||
for (unsigned i = 0; i < m_numberOfChannels; ++i) {
|
||||
// Set pre-filter zero and pole to create an emphasis filter.
|
||||
ZeroPole& preFilter = m_preFilterPacks[i]->filters[stageIndex];
|
||||
preFilter.setZero(r1);
|
||||
preFilter.setPole(r2);
|
||||
|
||||
// Set post-filter with zero and pole reversed to create the de-emphasis filter.
|
||||
// If there were no compressor kernel in between, they would cancel each other out (allpass filter).
|
||||
ZeroPole& postFilter = m_postFilterPacks[i]->filters[stageIndex];
|
||||
postFilter.setZero(r2);
|
||||
postFilter.setPole(r1);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicsCompressor::setEmphasisParameters(float gain, float anchorFreq, float filterStageRatio)
|
||||
{
|
||||
setEmphasisStageParameters(0, gain, anchorFreq);
|
||||
setEmphasisStageParameters(1, gain, anchorFreq / filterStageRatio);
|
||||
setEmphasisStageParameters(2, gain, anchorFreq / (filterStageRatio * filterStageRatio));
|
||||
setEmphasisStageParameters(3, gain, anchorFreq / (filterStageRatio * filterStageRatio * filterStageRatio));
|
||||
}
|
||||
|
||||
void DynamicsCompressor::process(const AudioChunk* sourceChunk, AudioChunk* destinationChunk, unsigned framesToProcess)
|
||||
{
|
||||
// Though numberOfChannels is retrived from destinationBus, we still name it numberOfChannels instead of numberOfDestinationChannels.
|
||||
// It's because we internally match sourceChannels's size to destinationBus by channel up/down mix. Thus we need numberOfChannels
|
||||
// to do the loop work for both m_sourceChannels and m_destinationChannels.
|
||||
|
||||
unsigned numberOfChannels = destinationChunk->mChannelData.Length();
|
||||
unsigned numberOfSourceChannels = sourceChunk->mChannelData.Length();
|
||||
|
||||
MOZ_ASSERT(numberOfChannels == m_numberOfChannels && numberOfSourceChannels);
|
||||
|
||||
if (numberOfChannels != m_numberOfChannels || !numberOfSourceChannels) {
|
||||
destinationChunk->SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (numberOfChannels) {
|
||||
case 2: // stereo
|
||||
m_sourceChannels[0] = static_cast<const float*>(sourceChunk->mChannelData[0]);
|
||||
|
||||
if (numberOfSourceChannels > 1)
|
||||
m_sourceChannels[1] = static_cast<const float*>(sourceChunk->mChannelData[1]);
|
||||
else
|
||||
// Simply duplicate mono channel input data to right channel for stereo processing.
|
||||
m_sourceChannels[1] = m_sourceChannels[0];
|
||||
|
||||
break;
|
||||
default:
|
||||
// FIXME : support other number of channels.
|
||||
NS_NOTREACHED("Support other number of channels");
|
||||
destinationChunk->SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < numberOfChannels; ++i)
|
||||
m_destinationChannels[i] = const_cast<float*>(static_cast<const float*>(
|
||||
destinationChunk->mChannelData[i]));
|
||||
|
||||
float filterStageGain = parameterValue(ParamFilterStageGain);
|
||||
float filterStageRatio = parameterValue(ParamFilterStageRatio);
|
||||
float anchor = parameterValue(ParamFilterAnchor);
|
||||
|
||||
if (filterStageGain != m_lastFilterStageGain || filterStageRatio != m_lastFilterStageRatio || anchor != m_lastAnchor) {
|
||||
m_lastFilterStageGain = filterStageGain;
|
||||
m_lastFilterStageRatio = filterStageRatio;
|
||||
m_lastAnchor = anchor;
|
||||
|
||||
setEmphasisParameters(filterStageGain, anchor, filterStageRatio);
|
||||
}
|
||||
|
||||
// Apply pre-emphasis filter.
|
||||
// Note that the final three stages are computed in-place in the destination buffer.
|
||||
for (unsigned i = 0; i < numberOfChannels; ++i) {
|
||||
const float* sourceData = m_sourceChannels[i];
|
||||
float* destinationData = m_destinationChannels[i];
|
||||
ZeroPole* preFilters = m_preFilterPacks[i]->filters;
|
||||
|
||||
preFilters[0].process(sourceData, destinationData, framesToProcess);
|
||||
preFilters[1].process(destinationData, destinationData, framesToProcess);
|
||||
preFilters[2].process(destinationData, destinationData, framesToProcess);
|
||||
preFilters[3].process(destinationData, destinationData, framesToProcess);
|
||||
}
|
||||
|
||||
float dbThreshold = parameterValue(ParamThreshold);
|
||||
float dbKnee = parameterValue(ParamKnee);
|
||||
float ratio = parameterValue(ParamRatio);
|
||||
float attackTime = parameterValue(ParamAttack);
|
||||
float releaseTime = parameterValue(ParamRelease);
|
||||
float preDelayTime = parameterValue(ParamPreDelay);
|
||||
|
||||
// This is effectively a master volume on the compressed signal (pre-blending).
|
||||
float dbPostGain = parameterValue(ParamPostGain);
|
||||
|
||||
// Linear blending value from dry to completely processed (0 -> 1)
|
||||
// 0 means the signal is completely unprocessed.
|
||||
// 1 mixes in only the compressed signal.
|
||||
float effectBlend = parameterValue(ParamEffectBlend);
|
||||
|
||||
float releaseZone1 = parameterValue(ParamReleaseZone1);
|
||||
float releaseZone2 = parameterValue(ParamReleaseZone2);
|
||||
float releaseZone3 = parameterValue(ParamReleaseZone3);
|
||||
float releaseZone4 = parameterValue(ParamReleaseZone4);
|
||||
|
||||
// Apply compression to the pre-filtered signal.
|
||||
// The processing is performed in place.
|
||||
m_compressor.process(m_destinationChannels.get(),
|
||||
m_destinationChannels.get(),
|
||||
numberOfChannels,
|
||||
framesToProcess,
|
||||
|
||||
dbThreshold,
|
||||
dbKnee,
|
||||
ratio,
|
||||
attackTime,
|
||||
releaseTime,
|
||||
preDelayTime,
|
||||
dbPostGain,
|
||||
effectBlend,
|
||||
|
||||
releaseZone1,
|
||||
releaseZone2,
|
||||
releaseZone3,
|
||||
releaseZone4
|
||||
);
|
||||
|
||||
// Update the compression amount.
|
||||
setParameterValue(ParamReduction, m_compressor.meteringGain());
|
||||
|
||||
// Apply de-emphasis filter.
|
||||
for (unsigned i = 0; i < numberOfChannels; ++i) {
|
||||
float* destinationData = m_destinationChannels[i];
|
||||
ZeroPole* postFilters = m_postFilterPacks[i]->filters;
|
||||
|
||||
postFilters[0].process(destinationData, destinationData, framesToProcess);
|
||||
postFilters[1].process(destinationData, destinationData, framesToProcess);
|
||||
postFilters[2].process(destinationData, destinationData, framesToProcess);
|
||||
postFilters[3].process(destinationData, destinationData, framesToProcess);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicsCompressor::reset()
|
||||
{
|
||||
m_lastFilterStageRatio = -1; // for recalc
|
||||
m_lastAnchor = -1;
|
||||
m_lastFilterStageGain = -1;
|
||||
|
||||
for (unsigned channel = 0; channel < m_numberOfChannels; ++channel) {
|
||||
for (unsigned stageIndex = 0; stageIndex < 4; ++stageIndex) {
|
||||
m_preFilterPacks[channel]->filters[stageIndex].reset();
|
||||
m_postFilterPacks[channel]->filters[stageIndex].reset();
|
||||
}
|
||||
}
|
||||
|
||||
m_compressor.reset();
|
||||
}
|
||||
|
||||
void DynamicsCompressor::setNumberOfChannels(unsigned numberOfChannels)
|
||||
{
|
||||
if (m_preFilterPacks.Length() == numberOfChannels)
|
||||
return;
|
||||
|
||||
m_preFilterPacks.Clear();
|
||||
m_postFilterPacks.Clear();
|
||||
for (unsigned i = 0; i < numberOfChannels; ++i) {
|
||||
m_preFilterPacks.AppendElement(new ZeroPoleFilterPack4());
|
||||
m_postFilterPacks.AppendElement(new ZeroPoleFilterPack4());
|
||||
}
|
||||
|
||||
m_sourceChannels = new const float* [numberOfChannels];
|
||||
m_destinationChannels = new float* [numberOfChannels];
|
||||
|
||||
m_compressor.setNumberOfChannels(numberOfChannels);
|
||||
m_numberOfChannels = numberOfChannels;
|
||||
}
|
||||
|
||||
} // namespace WebCore
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user