Merge inbound to mozilla-central r=merge a=merge

This commit is contained in:
Dorel Luca 2017-12-07 00:01:19 +02:00
commit ed8dc2034d
369 changed files with 3929 additions and 4518 deletions

View File

@ -1386,7 +1386,7 @@ bool
AttrIterator::Next(nsAString& aAttrName, nsAString& aAttrValue)
{
while (mAttrIdx < mAttrCount) {
const nsAttrName* attr = mContent->GetAttrNameAt(mAttrIdx);
const nsAttrName* attr = mElement->GetAttrNameAt(mAttrIdx);
mAttrIdx++;
if (attr->NamespaceEquals(kNameSpaceID_None)) {
nsAtom* attrAtom = attr->Atom();
@ -1399,17 +1399,17 @@ AttrIterator::Next(nsAString& aAttrName, nsAString& aAttrValue)
continue; // No need to handle exposing as obj attribute here
if ((attrFlags & ATTR_VALTOKEN) &&
!nsAccUtils::HasDefinedARIAToken(mContent, attrAtom))
!nsAccUtils::HasDefinedARIAToken(mElement, attrAtom))
continue; // only expose token based attributes if they are defined
if ((attrFlags & ATTR_BYPASSOBJ_IF_FALSE) &&
mContent->AttrValueIs(kNameSpaceID_None, attrAtom,
mElement->AttrValueIs(kNameSpaceID_None, attrAtom,
nsGkAtoms::_false, eCaseMatters)) {
continue; // only expose token based attribute if value is not 'false'.
}
nsAutoString value;
if (mContent->GetAttr(kNameSpaceID_None, attrAtom, value)) {
if (mElement->GetAttr(kNameSpaceID_None, attrAtom, value)) {
aAttrName.Assign(Substring(attrStr, 5));
aAttrValue.Assign(value);
return true;

View File

@ -14,6 +14,7 @@
#include "nsAtom.h"
#include "nsIContent.h"
#include "mozilla/dom/Element.h"
class nsINode;
@ -288,10 +289,11 @@ bool HasDefinedARIAHidden(nsIContent* aContent);
class AttrIterator
{
public:
explicit AttrIterator(nsIContent* aContent) :
mContent(aContent), mAttrIdx(0)
explicit AttrIterator(nsIContent* aContent)
: mElement(aContent->IsElement() ? aContent->AsElement() : nullptr)
, mAttrIdx(0)
{
mAttrCount = mContent->GetAttrCount();
mAttrCount = mElement ? mElement->GetAttrCount() : 0;
}
bool Next(nsAString& aAttrName, nsAString& aAttrValue);
@ -301,7 +303,7 @@ private:
AttrIterator(const AttrIterator&) = delete;
AttrIterator& operator= (const AttrIterator&) = delete;
nsIContent* mContent;
dom::Element* mElement;
uint32_t mAttrIdx;
uint32_t mAttrCount;
};

View File

@ -114,20 +114,22 @@ MustBeAccessible(nsIContent* aContent, DocAccessible* aDocument)
if (aContent->GetPrimaryFrame()->IsFocusable())
return true;
uint32_t attrCount = aContent->GetAttrCount();
for (uint32_t attrIdx = 0; attrIdx < attrCount; attrIdx++) {
const nsAttrName* attr = aContent->GetAttrNameAt(attrIdx);
if (attr->NamespaceEquals(kNameSpaceID_None)) {
nsAtom* attrAtom = attr->Atom();
nsDependentAtomString attrStr(attrAtom);
if (!StringBeginsWith(attrStr, NS_LITERAL_STRING("aria-")))
continue; // not ARIA
if (aContent->IsElement()) {
uint32_t attrCount = aContent->AsElement()->GetAttrCount();
for (uint32_t attrIdx = 0; attrIdx < attrCount; attrIdx++) {
const nsAttrName* attr = aContent->AsElement()->GetAttrNameAt(attrIdx);
if (attr->NamespaceEquals(kNameSpaceID_None)) {
nsAtom* attrAtom = attr->Atom();
nsDependentAtomString attrStr(attrAtom);
if (!StringBeginsWith(attrStr, NS_LITERAL_STRING("aria-")))
continue; // not ARIA
// A global state or a property and in case of token defined.
uint8_t attrFlags = aria::AttrCharacteristicsFor(attrAtom);
if ((attrFlags & ATTR_GLOBAL) && (!(attrFlags & ATTR_VALTOKEN) ||
nsAccUtils::HasDefinedARIAToken(aContent, attrAtom))) {
return true;
// A global state or a property and in case of token defined.
uint8_t attrFlags = aria::AttrCharacteristicsFor(attrAtom);
if ((attrFlags & ATTR_GLOBAL) && (!(attrFlags & ATTR_VALTOKEN) ||
nsAccUtils::HasDefinedARIAToken(aContent, attrAtom))) {
return true;
}
}
}
}

View File

@ -465,16 +465,18 @@ ARIAGridAccessible::SetARIASelected(Accessible* aAccessible,
if (IsARIARole(nsGkAtoms::table))
return NS_OK;
nsIContent *content = aAccessible->GetContent();
nsIContent* content = aAccessible->GetContent();
NS_ENSURE_STATE(content);
nsresult rv = NS_OK;
if (aIsSelected)
rv = content->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
NS_LITERAL_STRING("true"), aNotify);
else
rv = content->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
NS_LITERAL_STRING("false"), aNotify);
if (content->IsElement()) {
if (aIsSelected)
rv = content->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
NS_LITERAL_STRING("true"), aNotify);
else
rv = content->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
NS_LITERAL_STRING("false"), aNotify);
}
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -704,12 +704,14 @@ Accessible::SetSelected(bool aSelect)
Accessible* select = nsAccUtils::GetSelectableContainer(this, State());
if (select) {
if (select->State() & states::MULTISELECTABLE) {
if (ARIARoleMap()) {
if (mContent->IsElement() && ARIARoleMap()) {
if (aSelect) {
mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
NS_LITERAL_STRING("true"), true);
mContent->AsElement()->SetAttr(kNameSpaceID_None,
nsGkAtoms::aria_selected,
NS_LITERAL_STRING("true"), true);
} else {
mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected, true);
mContent->AsElement()->UnsetAttr(kNameSpaceID_None,
nsGkAtoms::aria_selected, true);
}
}
return;
@ -1416,8 +1418,12 @@ Accessible::SetCurValue(double aValue)
nsAutoString strValue;
strValue.AppendFloat(aValue);
if (!mContent->IsElement())
return true;
return NS_SUCCEEDED(
mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_valuenow, strValue, true));
mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_valuenow,
strValue, true));
}
role
@ -2570,8 +2576,10 @@ Accessible::SetCurrentItem(Accessible* aItem)
if (id) {
nsAutoString idStr;
id->ToString(idStr);
mContent->SetAttr(kNameSpaceID_None,
nsGkAtoms::aria_activedescendant, idStr, true);
mContent->AsElement()->SetAttr(kNameSpaceID_None,
nsGkAtoms::aria_activedescendant,
idStr,
true);
}
}

View File

@ -110,9 +110,13 @@ HTMLSelectListAccessible::CurrentItem()
void
HTMLSelectListAccessible::SetCurrentItem(Accessible* aItem)
{
aItem->GetContent()->SetAttr(kNameSpaceID_None,
nsGkAtoms::selected, NS_LITERAL_STRING("true"),
true);
if (!aItem->GetContent()->IsElement())
return;
aItem->GetContent()->AsElement()->SetAttr(kNameSpaceID_None,
nsGkAtoms::selected,
NS_LITERAL_STRING("true"),
true);
}
bool

View File

@ -13,7 +13,8 @@
#include "mozilla/dom/Element.h"
#include "mozilla/FloatingPoint.h"
using namespace mozilla::a11y;
namespace mozilla {
namespace a11y {
////////////////////////////////////////////////////////////////////////////////
// XULSliderAccessible
@ -40,7 +41,7 @@ XULSliderAccessible::NativeInteractiveState() const
if (NativelyUnavailable())
return states::UNAVAILABLE;
nsIContent* sliderElm = GetSliderElement();
dom::Element* sliderElm = GetSliderElement();
if (sliderElm) {
nsIFrame* frame = sliderElm->GetPrimaryFrame();
if (frame && frame->IsFocusable())
@ -83,7 +84,7 @@ XULSliderAccessible::DoAction(uint8_t aIndex)
if (aIndex != 0)
return false;
nsIContent* sliderElm = GetSliderElement();
dom::Element* sliderElm = GetSliderElement();
if (sliderElm)
DoCommand(sliderElm);
@ -129,17 +130,17 @@ XULSliderAccessible::SetCurValue(double aValue)
// Utils
nsIContent*
dom::Element*
XULSliderAccessible::GetSliderElement() const
{
if (!mSliderNode) {
if (!mSliderElement) {
// XXX: we depend on anonymous content.
mSliderNode = mContent->OwnerDoc()->
mSliderElement = mContent->OwnerDoc()->
GetAnonymousElementByAttribute(mContent, nsGkAtoms::anonid,
NS_LITERAL_STRING("slider"));
}
return mSliderNode;
return mSliderElement;
}
nsresult
@ -163,8 +164,7 @@ XULSliderAccessible::SetSliderAttr(nsAtom* aName, const nsAString& aValue)
if (IsDefunct())
return NS_ERROR_FAILURE;
nsIContent* sliderElm = GetSliderElement();
if (sliderElm)
if (dom::Element* sliderElm = GetSliderElement())
sliderElm->SetAttr(kNameSpaceID_None, aName, aValue, true);
return NS_OK;
@ -212,3 +212,5 @@ XULThumbAccessible::NativeRole()
return roles::INDICATOR;
}
}
}

View File

@ -43,7 +43,7 @@ protected:
/**
* Return anonymous slider element.
*/
nsIContent* GetSliderElement() const;
dom::Element* GetSliderElement() const;
nsresult GetSliderAttr(nsAtom *aName, nsAString& aValue) const;
nsresult SetSliderAttr(nsAtom *aName, const nsAString& aValue);
@ -52,7 +52,7 @@ protected:
bool SetSliderAttr(nsAtom *aName, double aValue);
private:
mutable nsCOMPtr<nsIContent> mSliderNode;
mutable RefPtr<dom::Element> mSliderElement;
};

View File

@ -951,7 +951,7 @@ BrowserPageActions.sendToDevice = {
},
onSubviewPlaced(panelViewNode) {
let bodyNode = panelViewNode.firstChild;
let bodyNode = panelViewNode.querySelector(".panel-subview-body");
for (let node of bodyNode.childNodes) {
BrowserPageActions.takeNodeAttributeFromPanel(node, "title");
BrowserPageActions.takeNodeAttributeFromPanel(node, "shortcut");
@ -970,7 +970,7 @@ BrowserPageActions.sendToDevice = {
let url = browser.currentURI.spec;
let title = browser.contentTitle;
let bodyNode = panelViewNode.firstChild;
let bodyNode = panelViewNode.querySelector(".panel-subview-body");
let panelNode = panelViewNode.closest("panel");
// This is on top because it also clears the device list between state

View File

@ -445,6 +445,17 @@ var SidebarUI = {
});
},
/**
* Sets the webpage favicon in sidebar
*
*/
setWebPageIcon(url) {
let iconURL = "url(page-icon:" + url + ")";
if (this._box.getAttribute("sidebarcommand") == "viewWebPanelsSidebar") {
this._icon.style.setProperty("--sidebar-webpage-icon", iconURL);
}
},
/**
* Hide the sidebar.
*

View File

@ -73,12 +73,10 @@ panelmultiview {
}
panelview {
-moz-binding: url("chrome://browser/content/customizableui/panelUI.xml#panelview");
-moz-box-orient: vertical;
}
panel[hidden] panelmultiview,
panel[hidden] panelview {
panel[hidden] panelmultiview {
-moz-binding: none;
}
@ -86,8 +84,8 @@ panelview:not([current]):not([in-transition]) {
visibility: collapse;
}
panelview[mainview] > .panel-header,
panelview:not([title]) > .panel-header {
/* Hide the header when a subview is reused as a main view. */
panelview[mainview] > .panel-header {
display: none;
}
@ -1407,6 +1405,16 @@ toolbarpaletteitem[place="palette"][hidden] {
visibility: visible;
}
/* Favicon in Open Bookmark in Sidebar */
#sidebar-box[sidebarcommand="viewWebPanelsSidebar"] > #sidebar-header > #sidebar-switcher-target > #sidebar-icon {
list-style-image: var(--sidebar-webpage-icon, url(chrome://mozapps/skin/places/defaultFavicon.svg) );
-moz-context-properties: fill;
fill: currentColor;
width: 16px;
height: 16px;
}
/* WebExtension Sidebars */
#sidebar-box[sidebarcommand$="-sidebar-action"] > #sidebar-header > #sidebar-switcher-target > #sidebar-icon {
list-style-image: var(--webextension-menuitem-image, inherit);

View File

@ -5789,6 +5789,7 @@ function asyncOpenWebPanel(event) {
if (gWebPanelURI && SidebarUI.browser.contentDocument &&
SidebarUI.browser.contentDocument.getElementById("web-panels-browser")) {
SidebarUI.browser.contentWindow.loadWebPanel(gWebPanelURI);
SidebarUI.setWebPageIcon(gWebPanelURI);
}
gWebPanelURI = "";
SidebarUI.browser.removeEventListener("load", asyncOpenWebPanel, true);

View File

@ -278,23 +278,23 @@
key="viewBookmarksSidebarKb"
observes="viewBookmarksSidebar"
oncommand="SidebarUI.show('viewBookmarksSidebar');">
<observes element="viewBookmarksSidebar" attribute="checked"/>
</toolbarbutton>
<observes element="viewBookmarksSidebar" attribute="checked"/>
</toolbarbutton>
<toolbarbutton id="sidebar-switcher-history"
label="&historyButton.label;"
class="subviewbutton subviewbutton-iconic"
key="key_gotoHistory"
observes="viewHistorySidebar"
oncommand="SidebarUI.show('viewHistorySidebar');">
<observes element="viewHistorySidebar" attribute="checked"/>
</toolbarbutton>
<observes element="viewHistorySidebar" attribute="checked"/>
</toolbarbutton>
<toolbarbutton id="sidebar-switcher-tabs"
label="&syncedTabs.sidebar.label;"
class="subviewbutton subviewbutton-iconic"
observes="viewTabsSidebar"
oncommand="SidebarUI.show('viewTabsSidebar');">
<observes element="viewTabsSidebar" attribute="checked"/>
</toolbarbutton>
<observes element="viewTabsSidebar" attribute="checked"/>
</toolbarbutton>
<toolbarseparator/>
<vbox id="sidebar-extensions"></vbox>
<toolbarseparator/>

View File

@ -1,19 +1,11 @@
/*
* Make sure that the origin is shown for ContentPermissionPrompt
* consumers e.g. geolocation.
*/
* Make sure that the correct origin is shown for permission prompts.
*/
add_task(async function test_displayURI() {
await BrowserTestUtils.withNewTab({
gBrowser,
url: "https://test1.example.com/",
}, async function(browser) {
async function check(contentTask) {
await BrowserTestUtils.withNewTab("https://test1.example.com/", async function(browser) {
let popupShownPromise = waitForNotificationPanel();
await ContentTask.spawn(browser, null, async function() {
content.navigator.geolocation.getCurrentPosition(function(pos) {
// Do nothing
});
});
await ContentTask.spawn(browser, null, contentTask);
let panel = await popupShownPromise;
let notification = panel.children[0];
let body = document.getAnonymousElementByAttribute(notification,
@ -21,4 +13,63 @@ add_task(async function test_displayURI() {
"popup-notification-body");
ok(body.innerHTML.includes("example.com"), "Check that at least the eTLD+1 is present in the markup");
});
let channel = NetUtil.newChannel({
uri: getRootDirectory(gTestPath),
loadUsingSystemPrincipal: true,
});
channel = channel.QueryInterface(Ci.nsIFileChannel);
return BrowserTestUtils.withNewTab(channel.file.path, async function(browser) {
let popupShownPromise = waitForNotificationPanel();
await ContentTask.spawn(browser, null, contentTask);
let panel = await popupShownPromise;
let notification = panel.children[0];
let body = document.getAnonymousElementByAttribute(notification,
"class",
"popup-notification-body");
if (notification.id == "geolocation-notification") {
ok(body.innerHTML.includes("local file"), `file:// URIs should be displayed as local file.`);
} else {
ok(body.innerHTML.includes("Unknown origin"), "file:// URIs should be displayed as unknown origin.");
}
});
}
add_task(async function setup() {
await SpecialPowers.pushPrefEnv({set: [
["media.navigator.permission.fake", true],
["media.navigator.permission.force", true],
]});
});
add_task(async function test_displayURI_geo() {
await check(async function() {
content.navigator.geolocation.getCurrentPosition(() => {});
});
});
add_task(async function test_displayURI_camera() {
await check(async function() {
content.navigator.mediaDevices.getUserMedia({video: true, fake: true});
});
});
add_task(async function test_displayURI_geo_blob() {
await check(async function() {
let text = "<script>navigator.geolocation.getCurrentPosition(() => {})</script>";
let blob = new Blob([text], {type: "text/html"});
let url = content.URL.createObjectURL(blob);
content.location.href = url;
});
});
add_task(async function test_displayURI_camera_blob() {
await check(async function() {
let text = "<script>navigator.mediaDevices.getUserMedia({video: true, fake: true})</script>";
let blob = new Blob([text], {type: "text/html"});
let url = content.URL.createObjectURL(blob);
content.location.href = url;
});
});

View File

@ -32,7 +32,8 @@ function requestDevice(aAudio, aVideo, aShare, aBadDevice = false) {
mozMediaSource: aShare,
mediaSource: aShare
};
} else if (useFakeStreams) {
}
if (useFakeStreams) {
opts.fake = true;
}

View File

@ -368,9 +368,49 @@ this.PanelMultiView = class {
this.panelViews.push(viewNode);
}
goBack(target) {
_setHeader(viewNode, titleText) {
// If the header already exists, update or remove it as requested.
let header = viewNode.firstChild;
if (header && header.classList.contains("panel-header")) {
if (titleText) {
header.querySelector("label").setAttribute("value", titleText);
} else {
header.remove();
}
return;
}
// The header doesn't exist, only create it if needed.
if (!titleText) {
return;
}
header = this.document.createElement("box");
header.classList.add("panel-header");
let backButton = this.document.createElement("toolbarbutton");
backButton.className =
"subviewbutton subviewbutton-iconic subviewbutton-back";
backButton.setAttribute("closemenu", "none");
backButton.setAttribute("tabindex", "0");
backButton.setAttribute("tooltip",
this.node.getAttribute("data-subviewbutton-tooltip"));
backButton.addEventListener("command", () => {
// The panelmultiview element may change if the view is reused.
viewNode.panelMultiView.goBack();
backButton.blur();
});
let label = this.document.createElement("label");
label.setAttribute("value", titleText);
header.append(backButton, label);
viewNode.prepend(header);
}
goBack() {
let [current, previous] = this.panelViews.back();
return this.showSubView(current, target, previous);
return this.showSubView(current, null, previous);
}
/**
@ -454,6 +494,10 @@ this.PanelMultiView = class {
this._placeSubView(viewNode);
}
viewNode.panelMultiView = this.node;
this._setHeader(viewNode, viewNode.getAttribute("title") ||
(aAnchor && aAnchor.getAttribute("label")));
let reverse = !!aPreviousView;
let previousViewNode = aPreviousView || this._currentSubView;
// If the panelview to show is the same as the previous one, the 'ViewShowing'
@ -488,10 +532,7 @@ this.PanelMultiView = class {
else
viewNode.removeAttribute("mainview");
// Make sure that new panels always have a title set.
if (aAnchor) {
if (!viewNode.hasAttribute("title"))
viewNode.setAttribute("title", aAnchor.getAttribute("label"));
viewNode.classList.add("PanelUI-subView");
}
if (!isMainView && this._mainViewWidth)
@ -599,8 +640,8 @@ this.PanelMultiView = class {
// aren't enumerable.
let {height, width} = previousRect;
viewRect = Object.assign({height, width}, viewNode.customRectGetter());
let {header} = viewNode;
if (header) {
let header = viewNode.firstChild;
if (header && header.classList.contains("panel-header")) {
viewRect.height += this._dwu.getBoundsWithoutFlushing(header).height;
}
viewNode.setAttribute("in-transition", true);
@ -1023,7 +1064,7 @@ this.PanelMultiView = class {
if ((dir == "ltr" && keyCode == "ArrowLeft") ||
(dir == "rtl" && keyCode == "ArrowRight")) {
if (this._canGoBack(view))
this.goBack(view.backButton);
this.goBack();
break;
}
// If the current button is _not_ one that points to a subview, pressing
@ -1089,8 +1130,6 @@ this.PanelMultiView = class {
*/
_getNavigableElements(view) {
let buttons = Array.from(view.querySelectorAll(".subviewbutton:not([disabled])"));
if (this._canGoBack(view))
buttons.unshift(view.backButton);
let dwu = this._dwu;
return buttons.filter(button => {
let bounds = dwu.getBoundsWithoutFlushing(button);

View File

@ -17,7 +17,7 @@
<resources>
<stylesheet src="chrome://browser/content/customizableui/panelUI.css"/>
</resources>
<content>
<content data-subviewbutton-tooltip="&backCmd.label;">
<xul:box anonid="viewContainer" class="panel-viewcontainer" xbl:inherits="panelopen,transitioning">
<xul:box anonid="viewStack" xbl:inherits="transitioning" class="panel-viewstack">
<children includes="panelview"/>
@ -38,36 +38,4 @@
]]></destructor>
</implementation>
</binding>
<binding id="panelview">
<content>
<xul:box class="panel-header" anonid="header">
<xul:toolbarbutton anonid="back"
class="subviewbutton subviewbutton-iconic subviewbutton-back"
closemenu="none"
tabindex="0"
tooltip="&backCmd.label;"
oncommand="document.getBindingParent(this).panelMultiView.goBack(); this.blur()"/>
<xul:label xbl:inherits="value=title"/>
</xul:box>
<children/>
</content>
<implementation>
<property name="header"
readonly="true"
onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'header');"/>
<property name="backButton"
readonly="true"
onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'back');"/>
<property name="panelMultiView" readonly="true">
<getter><![CDATA[
if (!this.parentNode.localName.endsWith("panelmultiview")) {
return document.getBindingParent(this.parentNode);
}
return this.parentNode;
]]></getter>
</property>
</implementation>
</binding>
</bindings>

View File

@ -29,7 +29,7 @@ add_task(async function() {
is(initialEncoding.getAttribute("label"), "Western", "The western encoding is initially selected");
// change the encoding
let encodings = characterEncodingView.querySelectorAll("toolbarbutton");
let encodings = characterEncodingView.querySelectorAll("toolbarbutton:not(.subviewbutton-back)");
let newEncoding = encodings[0].hasAttribute("checked") ? encodings[1] : encodings[0];
let browserStopPromise = BrowserTestUtils.browserStopped(gBrowser, TEST_PAGE);
newEncoding.click();

View File

@ -148,7 +148,6 @@ const listeners = {
"FormValidation:ShowPopup": ["FormValidationHandler"],
"FormValidation:HidePopup": ["FormValidationHandler"],
"Prompt:Open": ["RemotePrompt"],
"Reader:ArticleGet": ["ReaderParent"],
"Reader:FaviconRequest": ["ReaderParent"],
"Reader:UpdateReaderButton": ["ReaderParent"],
// PLEASE KEEP THIS LIST IN SYNC WITH THE MOBILE LISTENERS IN BrowserCLH.js

View File

@ -216,6 +216,7 @@ function prompt(aContentWindow, aWindowID, aCallID, aConstraints, aDevices, aSec
let request = {
callID: aCallID,
windowID: aWindowID,
origin: aContentWindow.origin,
documentURI: aContentWindow.document.documentURI,
secure: aSecure,
requestTypes,

View File

@ -22,22 +22,6 @@ var ReaderParent = {
// Listeners are added in nsBrowserGlue.js
receiveMessage(message) {
switch (message.name) {
case "Reader:ArticleGet":
this._getArticle(message.data.url, message.target).then((article) => {
// Make sure the target browser is still alive before trying to send data back.
if (message.target.messageManager) {
message.target.messageManager.sendAsyncMessage("Reader:ArticleData", { article });
}
}, e => {
if (e && e.newURL) {
// Make sure the target browser is still alive before trying to send data back.
if (message.target.messageManager) {
message.target.messageManager.sendAsyncMessage("Reader:ArticleData", { newURL: e.newURL });
}
}
});
break;
case "Reader:FaviconRequest": {
if (message.target.messageManager) {
let faviconUrl = PlacesUtils.promiseFaviconLinkUrl(message.data.url);

View File

@ -368,7 +368,13 @@ function prompt(aBrowser, aRequest) {
aBrowser.dispatchEvent(new aBrowser.ownerGlobal
.CustomEvent("PermissionStateChange"));
let uri = Services.io.newURI(aRequest.documentURI);
let uri;
try {
// This fails for principals that serialize to "null", e.g. file URIs.
uri = Services.io.newURI(aRequest.origin);
} catch (e) {
uri = Services.io.newURI(aRequest.documentURI);
}
let host = getHost(uri);
let chromeDoc = aBrowser.ownerDocument;
let stringBundle = chromeDoc.defaultView.gNavigatorBundle;

View File

@ -35,14 +35,6 @@ panelmultiview .toolbaritem-combined-buttons > spacer {
margin-inline-start: 18px;
}
.subviewbutton[checked="true"] {
background-position: top 7px left 4px;
}
.subviewbutton[checked="true"]:-moz-locale-dir(rtl) {
background-position: top 7px right 4px;
}
.subviewbutton:not(:-moz-any([image],[targetURI],.cui-withicon, .bookmark-item)) > .menu-iconic-left {
display: none;
}

View File

@ -1487,18 +1487,18 @@ menuitem[checked="true"].subviewbutton > .menu-iconic-left {
text-align: center;
}
.PanelUI-subView .panel-header > .subviewbutton-back {
.panel-header > .subviewbutton-back {
-moz-context-properties: fill;
fill: var(--arrowpanel-color);
list-style-image: url(chrome://browser/skin/arrow-left.svg);
padding: 8px;
}
.panel-header > .subviewbutton-back:-moz-locale-dir(rtl) {
.subviewbutton-back:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
.panel-header > .subviewbutton-back > .toolbarbutton-text {
.subviewbutton-back > .toolbarbutton-text {
/* !important to override .cui-widget-panel toolbarbutton:not([wrap]) > .toolbarbutton-text
* selector further down. */
display: none !important;

View File

@ -100,22 +100,43 @@
display: none;
}
%ifndef XP_MACOSX
#sidebarMenu-popup > .subviewbutton[checked="true"] {
list-style-image: none;
background: url(chrome://browser/skin/check.svg) no-repeat transparent;
background-size: 11px 11px;
}
%ifdef XP_MACOSX
#sidebarMenu-popup > .subviewbutton[checked="true"] {
background-position: top 7px left 4px;
}
#sidebarMenu-popup > .subviewbutton[checked="true"]:-moz-locale-dir(rtl) {
background-position: top 7px right 4px;
}
%else
#sidebarMenu-popup > .subviewbutton[checked="true"] {
background-position: center left 7px;
}
#sidebarMenu-popup > .subviewbutton[checked="true"]:-moz-locale-dir(rtl) {
background-position: center right 7px;
}
/* Allow room for the checkbox drawn as a background image at the start of the toolbarbutton */
#sidebarMenu-popup .subviewbutton-iconic > .toolbarbutton-icon {
#sidebarMenu-popup > .subviewbutton-iconic > .toolbarbutton-icon {
margin-inline-start: 16px;
}
/* Align items without icons to the start of the icons: */
#sidebarMenu-popup .subviewbutton:not(.subviewbutton-iconic) > .toolbarbutton-text {
#sidebarMenu-popup > .subviewbutton:not(.subviewbutton-iconic) > .toolbarbutton-text {
padding-inline-start: 16px;
}
%endif
#sidebar-box[sidebarcommand="viewWebPanelsSidebar"] > #sidebar-header > #sidebar-switcher-target > #sidebar-icon {
list-style-image: url(chrome://mozapps/skin/places/defaultFavicon.svg);
}
#sidebar-switcher-bookmarks > .toolbarbutton-icon,
#sidebar-box[sidebarcommand="viewBookmarksSidebar"] > #sidebar-header > #sidebar-switcher-target > #sidebar-icon {
list-style-image: url(chrome://browser/skin/bookmark.svg);

Binary file not shown.

Binary file not shown.

View File

@ -292,3 +292,6 @@ https://mochitest.youtube.com:443
# Hosts for stylo blocklist tests
http://stylo-blocklist.com:80 privileged
http://test.stylo-blocklist.com:80 privileged
# Host for U2F localhost tests
https://localhost:443

View File

@ -205,11 +205,11 @@ body {
}
.cm-s-mozilla.CodeMirror-focused .CodeMirror-selected { /* selected text (focused) */
background: rgb(77, 86, 103);
background: var(--theme-selection-background-hover);
}
.cm-s-mozilla .CodeMirror-selected { /* selected text (unfocused) */
background: rgb(77, 86, 103);
background: var(--theme-selection-background-hover);
}
.cm-s-mozilla .CodeMirror-activeline-background { /* selected color with alpha */

View File

@ -1134,7 +1134,6 @@ var SyntaxTreeVisitor = {
* type: "TryStatement";
* block: BlockStatement;
* handler: CatchClause | null;
* guardedHandlers: [ CatchClause ];
* finalizer: BlockStatement | null;
* }
*/
@ -1156,9 +1155,6 @@ var SyntaxTreeVisitor = {
if (node.handler) {
this[node.handler.type](node.handler, node, callbacks);
}
for (let guardedHandler of node.guardedHandlers) {
this[guardedHandler.type](guardedHandler, node, callbacks);
}
if (node.finalizer) {
this[node.finalizer.type](node.finalizer, node, callbacks);
}

View File

@ -10531,6 +10531,9 @@ nsDocShell::InternalLoad(nsIURI* aURI,
(aFlags & INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) != 0;
mURIResultedInDocument = false; // reset the clock...
// Note that there is code that relies on this check to stop us entering the
// `doShortCircuitedLoad` block below for certain load types. (For example,
// reftest-content.js uses LOAD_FLAGS_BYPASS_CACHE for this purpose.)
if (aLoadType == LOAD_NORMAL ||
aLoadType == LOAD_STOP_CONTENT ||
LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||

View File

@ -69,33 +69,6 @@ public:
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
// nsIContent
using nsIContent::SetAttr;
virtual nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName,
nsAtom* aPrefix, const nsAString& aValue,
nsIPrincipal* aSubjectPrincipal,
bool aNotify) override
{
return NS_OK;
}
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsAtom* aAttribute,
bool aNotify) override
{
return NS_OK;
}
virtual const nsAttrName* GetAttrNameAt(uint32_t aIndex) const override
{
return nullptr;
}
virtual BorrowedAttrInfo GetAttrInfoAt(uint32_t aIndex) const override
{
return BorrowedAttrInfo(nullptr, nullptr);
}
virtual uint32_t GetAttrCount() const override
{
return 0;
}
virtual bool IsNodeOfType(uint32_t aFlags) const override;
virtual nsIDOMNode* AsDOMNode() override { return this; }

View File

@ -430,6 +430,11 @@ public:
virtual nsChangeHint GetAttributeChangeHint(const nsAtom* aAttribute,
int32_t aModType) const;
NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker)
{
return NS_OK;
}
inline Directionality GetDirectionality() const {
if (HasFlag(NODE_HAS_DIRECTION_RTL)) {
return eDir_RTL;
@ -697,8 +702,6 @@ public:
already_AddRefed<mozilla::dom::NodeInfo>
GetExistingAttrNameFromQName(const nsAString& aStr) const;
using nsIContent::SetAttr;
/**
* Helper for SetAttr/SetParsedAttr. This method will return true if aNotify
* is true or there are mutation listeners that must be triggered, the
@ -758,9 +761,6 @@ public:
*/
nsresult SetSingleClassFromParser(nsAtom* aSingleClassName);
virtual nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName, nsAtom* aPrefix,
const nsAString& aValue, nsIPrincipal* aSubjectPrincipal,
bool aNotify) override;
// aParsedValue receives the old value of the attribute. That's useful if
// either the input or output value of aParsedValue is StoresOwnData.
nsresult SetParsedAttr(int32_t aNameSpaceID, nsAtom* aName, nsAtom* aPrefix,
@ -777,19 +777,97 @@ public:
inline bool AttrValueIs(int32_t aNameSpaceID, nsAtom* aName,
nsAtom* aValue,
nsCaseTreatment aCaseSensitive) const;
virtual int32_t FindAttrValueIn(int32_t aNameSpaceID,
nsAtom* aName,
AttrValuesArray* aValues,
nsCaseTreatment aCaseSensitive) const override;
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsAtom* aAttribute,
bool aNotify) override;
int32_t FindAttrValueIn(int32_t aNameSpaceID,
nsAtom* aName,
AttrValuesArray* aValues,
nsCaseTreatment aCaseSensitive) const override;
virtual const nsAttrName* GetAttrNameAt(uint32_t aIndex) const final override
/**
* Set attribute values. All attribute values are assumed to have a
* canonical string representation that can be used for these
* methods. The SetAttr method is assumed to perform a translation
* of the canonical form into the underlying content specific
* form.
*
* @param aNameSpaceID the namespace of the attribute
* @param aName the name of the attribute
* @param aValue the value to set
* @param aNotify specifies how whether or not the document should be
* notified of the attribute change.
*/
nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName,
const nsAString& aValue, bool aNotify)
{
return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
}
nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName, nsAtom* aPrefix,
const nsAString& aValue, bool aNotify)
{
return SetAttr(aNameSpaceID, aName, aPrefix, aValue, nullptr, aNotify);
}
nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName, const nsAString& aValue,
nsIPrincipal* aTriggeringPrincipal, bool aNotify)
{
return SetAttr(aNameSpaceID, aName, nullptr, aValue, aTriggeringPrincipal, aNotify);
}
/**
* Set attribute values. All attribute values are assumed to have a
* canonical String representation that can be used for these
* methods. The SetAttr method is assumed to perform a translation
* of the canonical form into the underlying content specific
* form.
*
* @param aNameSpaceID the namespace of the attribute
* @param aName the name of the attribute
* @param aPrefix the prefix of the attribute
* @param aValue the value to set
* @param aMaybeScriptedPrincipal the principal of the scripted caller responsible
* for setting the attribute, or null if no scripted caller can be
* determined. A null value here does not guarantee that there is no
* scripted caller, but a non-null value does guarantee that a scripted
* caller with the given principal is directly responsible for the
* attribute change.
* @param aNotify specifies how whether or not the document should be
* notified of the attribute change.
*/
virtual nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName,
nsAtom* aPrefix, const nsAString& aValue,
nsIPrincipal* aMaybeScriptedPrincipal,
bool aNotify);
/**
* Remove an attribute so that it is no longer explicitly specified.
*
* @param aNameSpaceID the namespace id of the attribute
* @param aAttr the name of the attribute to unset
* @param aNotify specifies whether or not the document should be
* notified of the attribute change
*/
virtual nsresult UnsetAttr(int32_t aNameSpaceID,
nsAtom* aAttribute,
bool aNotify);
/**
* Get the namespace / name / prefix of a given attribute.
*
* @param aIndex the index of the attribute name
* @returns The name at the given index, or null if the index is
* out-of-bounds.
* @note The document returned by NodeInfo()->GetDocument() (if one is
* present) is *not* necessarily the owner document of the element.
* @note The pointer returned by this function is only valid until the
* next call of either GetAttrNameAt or SetAttr on the element.
*/
const nsAttrName* GetAttrNameAt(uint32_t aIndex) const
{
return mAttrsAndChildren.GetSafeAttrNameAt(aIndex);
}
virtual BorrowedAttrInfo GetAttrInfoAt(uint32_t aIndex) const final override
/**
* Gets the attribute info (name and value) for this element at a given index.
*/
BorrowedAttrInfo GetAttrInfoAt(uint32_t aIndex) const
{
if (aIndex >= mAttrsAndChildren.AttrCount()) {
return BorrowedAttrInfo(nullptr, nullptr);
@ -798,7 +876,12 @@ public:
return mAttrsAndChildren.AttrInfoAt(aIndex);
}
virtual uint32_t GetAttrCount() const final override
/**
* Get the number of all specified attributes.
*
* @return the number of attributes
*/
uint32_t GetAttrCount() const
{
return mAttrsAndChildren.AttrCount();
}
@ -1466,7 +1549,7 @@ public:
void SetAttr(nsAtom* aAttr, const nsAString& aValue, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aError)
{
aError = nsIContent::SetAttr(kNameSpaceID_None, aAttr, aValue, &aTriggeringPrincipal, true);
aError = SetAttr(kNameSpaceID_None, aAttr, aValue, &aTriggeringPrincipal, true);
}
/**

View File

@ -391,7 +391,8 @@ nsIContent::LookupNamespaceURIInternal(const nsAString& aNamespacePrefix,
// declaration that declares aNamespacePrefix.
const nsIContent* content = this;
do {
if (content->GetAttr(kNameSpaceID_XMLNS, name, aNamespaceURI))
if (content->IsElement() &&
content->AsElement()->GetAttr(kNameSpaceID_XMLNS, name, aNamespaceURI))
return NS_OK;
} while ((content = content->GetParent()));
return NS_ERROR_FAILURE;
@ -401,11 +402,14 @@ nsAtom*
nsIContent::GetLang() const
{
for (const auto* content = this; content; content = content->GetParent()) {
if (!content->GetAttrCount() || !content->IsElement()) {
if (!content->IsElement()) {
continue;
}
auto* element = content->AsElement();
if (!element->GetAttrCount()) {
continue;
}
// xml:lang has precedence over lang on HTML elements (see
// XHTML1 section C.7).
@ -1179,12 +1183,6 @@ nsIContent::IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse)
return false;
}
NS_IMETHODIMP
FragmentOrElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
{
return NS_OK;
}
bool
FragmentOrElement::IsLink(nsIURI** aURI) const
{
@ -2241,8 +2239,8 @@ FragmentOrElement::CopyInnerTo(FragmentOrElement* aDst,
const nsAttrValue* value = mAttrsAndChildren.AttrAt(i);
nsAutoString valStr;
value->ToString(valStr);
rv = aDst->SetAttr(name->NamespaceID(), name->LocalName(),
name->GetPrefix(), valStr, false);
rv = aDst->AsElement()->SetAttr(name->NamespaceID(), name->LocalName(),
name->GetPrefix(), valStr, false);
NS_ENSURE_SUCCESS(rv, rv);
}

View File

@ -165,8 +165,6 @@ public:
virtual void DestroyContent() override;
virtual void SaveSubtreeState() override;
NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
nsIHTMLCollection* Children();
uint32_t ChildElementCount()
{

View File

@ -63,7 +63,7 @@ NS_NewXULElement(mozilla::dom::Element** aResult,
mozilla::dom::FromParser aFromParser);
void
NS_TrustedNewXULElement(nsIContent** aResult,
NS_TrustedNewXULElement(mozilla::dom::Element** aResult,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
#endif

View File

@ -5058,13 +5058,13 @@ nsContentUtils::CreateContextualFragment(nsINode* aContextNode,
tagName = content->NodeInfo()->QualifiedName();
// see if we need to add xmlns declarations
uint32_t count = content->GetAttrCount();
uint32_t count = content->AsElement()->GetAttrCount();
bool setDefaultNamespace = false;
if (count > 0) {
uint32_t index;
for (index = 0; index < count; index++) {
const BorrowedAttrInfo info = content->GetAttrInfoAt(index);
const BorrowedAttrInfo info = content->AsElement()->GetAttrInfoAt(index);
const nsAttrName* name = info.mName;
if (name->NamespaceEquals(kNameSpaceID_XMLNS)) {
info.mValue->ToString(uriStr);

View File

@ -421,10 +421,10 @@ nsIdentifierMapEntry::GetImageIdElement()
}
void
nsIdentifierMapEntry::AppendAllIdContent(nsCOMArray<nsIContent>* aElements)
nsIdentifierMapEntry::AppendAllIdContent(nsCOMArray<Element>* aElements)
{
for (size_t i = 0; i < mIdContentList.Length(); ++i) {
aElements->AppendObject(mIdContentList[i]);
for (Element* element : mIdContentList) {
aElements->AppendObject(element);
}
}
@ -3776,7 +3776,11 @@ nsDocument::ElementsFromPointHelper(float aX, float aY,
// If this helper is called via ElementsFromPoint, we need to make sure
// our frame is an element. Otherwise return whatever the top frame is
// even if it isn't the top-painted element.
if (!(aFlags & nsIDocument::IS_ELEMENT_FROM_POINT)) {
// SVG 'text' element's SVGTextFrame doesn't respond to hit-testing, so
// if 'node' is a child of such an element then we need to manually defer
// to the parent here.
if (!(aFlags & nsIDocument::IS_ELEMENT_FROM_POINT) &&
!nsSVGUtils::IsInSVGTextSubtree(outFrames[i])) {
continue;
}
node = node->GetParent();

View File

@ -637,40 +637,6 @@ nsGenericDOMDataNode::GetChildren(uint32_t aFilter)
return nullptr;
}
nsresult
nsGenericDOMDataNode::SetAttr(int32_t aNameSpaceID, nsAtom* aAttr,
nsAtom* aPrefix, const nsAString& aValue,
nsIPrincipal* aContentPrincipal,
bool aNotify)
{
return NS_OK;
}
nsresult
nsGenericDOMDataNode::UnsetAttr(int32_t aNameSpaceID, nsAtom* aAttr,
bool aNotify)
{
return NS_OK;
}
const nsAttrName*
nsGenericDOMDataNode::GetAttrNameAt(uint32_t aIndex) const
{
return nullptr;
}
BorrowedAttrInfo
nsGenericDOMDataNode::GetAttrInfoAt(uint32_t aIndex) const
{
return BorrowedAttrInfo(nullptr, nullptr);
}
uint32_t
nsGenericDOMDataNode::GetAttrCount() const
{
return 0;
}
uint32_t
nsGenericDOMDataNode::GetChildCount() const
{
@ -683,6 +649,7 @@ nsGenericDOMDataNode::GetChildAt(uint32_t aIndex) const
return nullptr;
}
int32_t
nsGenericDOMDataNode::IndexOf(const nsINode* aPossibleChild) const
{
@ -1123,26 +1090,6 @@ nsGenericDOMDataNode::GetCurrentValueAtom()
return NS_Atomize(val);
}
NS_IMETHODIMP
nsGenericDOMDataNode::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
{
return NS_OK;
}
NS_IMETHODIMP_(bool)
nsGenericDOMDataNode::IsAttributeMapped(const nsAtom* aAttribute) const
{
return false;
}
nsChangeHint
nsGenericDOMDataNode::GetAttributeChangeHint(const nsAtom* aAttribute,
int32_t aModType) const
{
NS_NOTREACHED("Shouldn't be calling this!");
return nsChangeHint(0);
}
void
nsGenericDOMDataNode::AddSizeOfExcludingThis(nsWindowSizes& aSizes,
size_t* aNodeSize) const

View File

@ -133,17 +133,6 @@ public:
virtual already_AddRefed<nsINodeList> GetChildren(uint32_t aFilter) override;
using nsIContent::SetAttr;
virtual nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aAttribute,
nsAtom* aPrefix, const nsAString& aValue,
nsIPrincipal* aSubjectPrincipal,
bool aNotify) override;
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsAtom* aAttribute,
bool aNotify) override;
virtual const nsAttrName* GetAttrNameAt(uint32_t aIndex) const override;
virtual mozilla::dom::BorrowedAttrInfo GetAttrInfoAt(uint32_t aIndex) const override;
virtual uint32_t GetAttrCount() const override;
virtual const nsTextFragment *GetText() override;
virtual uint32_t TextLength() const override;
virtual nsresult SetText(const char16_t* aBuffer, uint32_t aLength,
@ -184,11 +173,6 @@ public:
virtual bool IsNodeOfType(uint32_t aFlags) const override;
virtual bool IsLink(nsIURI** aURI) const override;
NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const;
virtual nsChangeHint GetAttributeChangeHint(const nsAtom* aAttribute,
int32_t aModType) const;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
bool aPreallocateChildren) const override
{

View File

@ -64,15 +64,15 @@ nsHTMLContentSerializer::AppendDocumentStart(nsIDocument *aDocument,
}
bool
nsHTMLContentSerializer::SerializeHTMLAttributes(nsIContent* aContent,
nsIContent *aOriginalElement,
nsHTMLContentSerializer::SerializeHTMLAttributes(Element* aElement,
Element* aOriginalElement,
nsAString& aTagPrefix,
const nsAString& aTagNamespaceURI,
nsAtom* aTagName,
int32_t aNamespace,
nsAString& aStr)
{
int32_t count = aContent->GetAttrCount();
int32_t count = aElement->GetAttrCount();
if (!count)
return true;
@ -81,7 +81,7 @@ nsHTMLContentSerializer::SerializeHTMLAttributes(nsIContent* aContent,
NS_NAMED_LITERAL_STRING(_mozStr, "_moz");
for (int32_t index = 0; index < count; index++) {
const nsAttrName* name = aContent->GetAttrNameAt(index);
const nsAttrName* name = aElement->GetAttrNameAt(index);
int32_t namespaceID = name->NamespaceID();
nsAtom* attrName = name->LocalName();
@ -91,7 +91,7 @@ nsHTMLContentSerializer::SerializeHTMLAttributes(nsIContent* aContent,
StringBeginsWith(attrNameStr, NS_LITERAL_STRING("-moz"))) {
continue;
}
aContent->GetAttr(namespaceID, attrName, valueStr);
aElement->GetAttr(namespaceID, attrName, valueStr);
//
// Filter out special case of <br type="_moz"> or <br _moz*>,
@ -109,7 +109,7 @@ nsHTMLContentSerializer::SerializeHTMLAttributes(nsIContent* aContent,
// This is handled separately in SerializeLIValueAttribute()
continue;
}
bool isJS = IsJavaScript(aContent, attrName, namespaceID, valueStr);
bool isJS = IsJavaScript(aElement, attrName, namespaceID, valueStr);
if (((attrName == nsGkAtoms::href &&
(namespaceID == kNameSpaceID_None ||
@ -120,7 +120,7 @@ nsHTMLContentSerializer::SerializeHTMLAttributes(nsIContent* aContent,
// Would be nice to handle OBJECT tags, but that gets more complicated
// since we have to search the tag list for CODEBASE as well. For now,
// just leave them relative.
nsCOMPtr<nsIURI> uri = aContent->GetBaseURI();
nsCOMPtr<nsIURI> uri = aElement->GetBaseURI();
if (uri) {
nsAutoString absURI;
rv = NS_MakeAbsoluteURI(absURI, valueStr, uri);
@ -137,7 +137,7 @@ nsHTMLContentSerializer::SerializeHTMLAttributes(nsIContent* aContent,
// If we're serializing a <meta http-equiv="content-type">,
// use the proper value, rather than what's in the document.
nsAutoString header;
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
if (header.LowerCaseEqualsLiteral("content-type")) {
valueStr = NS_LITERAL_STRING("text/html; charset=") +
NS_ConvertASCIItoUTF16(mCharset);
@ -173,22 +173,20 @@ nsHTMLContentSerializer::AppendElementStart(Element* aElement,
{
NS_ENSURE_ARG(aElement);
nsIContent* content = aElement;
bool forceFormat = false;
nsresult rv = NS_OK;
if (!CheckElementStart(content, forceFormat, aStr, rv)) {
if (!CheckElementStart(aElement, forceFormat, aStr, rv)) {
// When we go to AppendElementEnd for this element, we're going to
// MaybeLeaveFromPreContent(). So make sure to MaybeEnterInPreContent()
// now, so our PreLevel() doesn't get confused.
MaybeEnterInPreContent(content);
MaybeEnterInPreContent(aElement);
return rv;
}
NS_ENSURE_SUCCESS(rv, rv);
nsAtom *name = content->NodeInfo()->NameAtom();
int32_t ns = content->GetNameSpaceID();
nsAtom *name = aElement->NodeInfo()->NameAtom();
int32_t ns = aElement->GetNameSpaceID();
bool lineBreakBeforeOpen = LineBreakBeforeOpen(ns, name);
@ -224,7 +222,7 @@ nsHTMLContentSerializer::AppendElementStart(Element* aElement,
NS_ENSURE_TRUE(AppendToString(nsDependentAtomString(name), aStr), NS_ERROR_OUT_OF_MEMORY);
MaybeEnterInPreContent(content);
MaybeEnterInPreContent(aElement);
// for block elements, we increase the indentation
if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel())
@ -264,7 +262,7 @@ nsHTMLContentSerializer::AppendElementStart(Element* aElement,
// Even LI passed above have to go through this
// for serializing attributes other than "value".
nsAutoString dummyPrefix;
NS_ENSURE_TRUE(SerializeHTMLAttributes(content,
NS_ENSURE_TRUE(SerializeHTMLAttributes(aElement,
aOriginalElement,
dummyPrefix,
EmptyString(),
@ -287,21 +285,18 @@ nsHTMLContentSerializer::AppendElementStart(Element* aElement,
NS_ENSURE_TRUE(AppendNewLineToString(aStr), NS_ERROR_OUT_OF_MEMORY);
}
NS_ENSURE_TRUE(AfterElementStart(content, aOriginalElement, aStr), NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_TRUE(AfterElementStart(aElement, aOriginalElement, aStr), NS_ERROR_OUT_OF_MEMORY);
return NS_OK;
}
NS_IMETHODIMP
nsHTMLContentSerializer::AppendElementEnd(Element* aElement,
nsAString& aStr)
nsHTMLContentSerializer::AppendElementEnd(Element* aElement, nsAString& aStr)
{
NS_ENSURE_ARG(aElement);
nsIContent* content = aElement;
nsAtom *name = content->NodeInfo()->NameAtom();
int32_t ns = content->GetNameSpaceID();
nsAtom *name = aElement->NodeInfo()->NameAtom();
int32_t ns = aElement->GetNameSpaceID();
if (ns == kNameSpaceID_XHTML &&
(name == nsGkAtoms::script ||
@ -312,7 +307,7 @@ nsHTMLContentSerializer::AppendElementEnd(Element* aElement,
}
bool forceFormat = !(mFlags & nsIDocumentEncoder::OutputIgnoreMozDirty) &&
content->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdirty);
aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdirty);
if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
DecrIndentation(name);
@ -344,7 +339,7 @@ nsHTMLContentSerializer::AppendElementEnd(Element* aElement,
if (!isContainer) {
// Keep this in sync with the cleanup at the end of this method.
MOZ_ASSERT(name != nsGkAtoms::body);
MaybeLeaveFromPreContent(content);
MaybeLeaveFromPreContent(aElement);
return NS_OK;
}
}
@ -376,7 +371,7 @@ nsHTMLContentSerializer::AppendElementEnd(Element* aElement,
NS_ENSURE_TRUE(AppendToString(kGreaterThan, aStr), NS_ERROR_OUT_OF_MEMORY);
// Keep this cleanup in sync with the IsContainer() early return above.
MaybeLeaveFromPreContent(content);
MaybeLeaveFromPreContent(aElement);
if ((mDoFormat || forceFormat)&& !mDoRaw && !PreLevel()
&& LineBreakAfterClose(ns, name)) {

View File

@ -17,7 +17,6 @@
#include "nsXHTMLContentSerializer.h"
#include "nsString.h"
class nsIContent;
class nsAtom;
class nsHTMLContentSerializer final : public nsXHTMLContentSerializer {
@ -37,8 +36,8 @@ class nsHTMLContentSerializer final : public nsXHTMLContentSerializer {
protected:
MOZ_MUST_USE
virtual bool SerializeHTMLAttributes(nsIContent* aContent,
nsIContent *aOriginalElement,
virtual bool SerializeHTMLAttributes(mozilla::dom::Element* aContent,
mozilla::dom::Element* aOriginalElement,
nsAString& aTagPrefix,
const nsAString& aTagNamespaceURI,
nsAtom* aTagName,

View File

@ -15,7 +15,6 @@
// Forward declarations
class nsAtom;
class nsIURI;
class nsRuleWalker;
class nsAttrValue;
class nsAttrName;
class nsTextFragment;
@ -356,60 +355,6 @@ public:
mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentafter;
}
/**
* Set attribute values. All attribute values are assumed to have a
* canonical string representation that can be used for these
* methods. The SetAttr method is assumed to perform a translation
* of the canonical form into the underlying content specific
* form.
*
* @param aNameSpaceID the namespace of the attribute
* @param aName the name of the attribute
* @param aValue the value to set
* @param aNotify specifies how whether or not the document should be
* notified of the attribute change.
*/
nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName,
const nsAString& aValue, bool aNotify)
{
return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
}
nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName, nsAtom* aPrefix,
const nsAString& aValue, bool aNotify)
{
return SetAttr(aNameSpaceID, aName, aPrefix, aValue, nullptr, aNotify);
}
nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName, const nsAString& aValue,
nsIPrincipal* aTriggeringPrincipal, bool aNotify)
{
return SetAttr(aNameSpaceID, aName, nullptr, aValue, aTriggeringPrincipal, aNotify);
}
/**
* Set attribute values. All attribute values are assumed to have a
* canonical String representation that can be used for these
* methods. The SetAttr method is assumed to perform a translation
* of the canonical form into the underlying content specific
* form.
*
* @param aNameSpaceID the namespace of the attribute
* @param aName the name of the attribute
* @param aPrefix the prefix of the attribute
* @param aValue the value to set
* @param aMaybeScriptedPrincipal the principal of the scripted caller responsible
* for setting the attribute, or null if no scripted caller can be
* determined. A null value here does not guarantee that there is no
* scripted caller, but a non-null value does guarantee that a scripted
* caller with the given principal is directly responsible for the
* attribute change.
* @param aNotify specifies how whether or not the document should be
* notified of the attribute change.
*/
virtual nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName,
nsAtom* aPrefix, const nsAString& aValue,
nsIPrincipal* aMaybeScriptedPrincipal,
bool aNotify) = 0;
/**
* Get the current value of the attribute. This returns a form that is
* suitable for passing back into SetAttr.
@ -419,6 +364,8 @@ public:
* @param aResult the value (may legitimately be the empty string) [OUT]
* @returns true if the attribute was set (even when set to empty string)
* false when not set.
*
* FIXME(emilio): Move to Element.
*/
bool GetAttr(int32_t aNameSpaceID, nsAtom* aName,
nsAString& aResult) const;
@ -492,43 +439,6 @@ public:
return ATTR_MISSING;
}
/**
* Remove an attribute so that it is no longer explicitly specified.
*
* @param aNameSpaceID the namespace id of the attribute
* @param aAttr the name of the attribute to unset
* @param aNotify specifies whether or not the document should be
* notified of the attribute change
*/
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsAtom* aAttr,
bool aNotify) = 0;
/**
* Get the namespace / name / prefix of a given attribute.
*
* @param aIndex the index of the attribute name
* @returns The name at the given index, or null if the index is
* out-of-bounds.
* @note The document returned by NodeInfo()->GetDocument() (if one is
* present) is *not* necessarily the owner document of the element.
* @note The pointer returned by this function is only valid until the
* next call of either GetAttrNameAt or SetAttr on the element.
*/
virtual const nsAttrName* GetAttrNameAt(uint32_t aIndex) const = 0;
/**
* Gets the attribute info (name and value) for this content at a given index.
*/
virtual mozilla::dom::BorrowedAttrInfo GetAttrInfoAt(uint32_t aIndex) const = 0;
/**
* Get the number of all specified attributes.
*
* @return the number of attributes
*/
virtual uint32_t GetAttrCount() const = 0;
/**
* Get direct access (but read only) to the text in the text content.
* NOTE: For elements this is *not* the concatenation of all text children,
@ -925,12 +835,6 @@ public:
return nullptr;
}
/**
* Walk aRuleWalker over the content style rules (presentational
* hint rules) for this content node.
*/
NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) = 0;
/**
* Should be called when the node can become editable or when it can stop
* being editable (for example when its contentEditable attribute changes,

View File

@ -778,17 +778,22 @@ nsINode::LookupPrefix(const nsAString& aNamespaceURI, nsAString& aPrefix)
// return the prefix (i.e. the attribute localName).
for (nsIContent* content = element; content;
content = content->GetParent()) {
uint32_t attrCount = content->GetAttrCount();
if (!content->IsElement()) {
continue;
}
Element* element = content->AsElement();
uint32_t attrCount = element->GetAttrCount();
for (uint32_t i = 0; i < attrCount; ++i) {
const nsAttrName* name = content->GetAttrNameAt(i);
const nsAttrName* name = element->GetAttrNameAt(i);
if (name->NamespaceEquals(kNameSpaceID_XMLNS) &&
content->AttrValueIs(kNameSpaceID_XMLNS, name->LocalName(),
element->AttrValueIs(kNameSpaceID_XMLNS, name->LocalName(),
aNamespaceURI, eCaseMatters)) {
// If the localName is "xmlns", the prefix we output should be
// null.
nsAtom *localName = name->LocalName();
nsAtom* localName = name->LocalName();
if (localName != nsGkAtoms::xmlns) {
localName->ToString(aPrefix);

View File

@ -152,7 +152,7 @@ public:
/**
* Append all the elements with this id to aElements
*/
void AppendAllIdContent(nsCOMArray<nsIContent>* aElements);
void AppendAllIdContent(nsCOMArray<Element>* aElements);
/**
* This can fire ID change callbacks.
* @return true if the content could be added, false if we failed due

View File

@ -924,14 +924,14 @@ nsObjectLoadingContent::BuildParametersArray()
return NS_OK;
}
nsCOMPtr<nsIContent> content =
nsCOMPtr<Element> element =
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
for (uint32_t i = 0; i != content->GetAttrCount(); i += 1) {
for (uint32_t i = 0; i != element->GetAttrCount(); i += 1) {
MozPluginParameter param;
const nsAttrName* attrName = content->GetAttrNameAt(i);
const nsAttrName* attrName = element->GetAttrNameAt(i);
nsAtom* atom = attrName->LocalName();
content->GetAttr(attrName->NamespaceID(), atom, param.mValue);
element->GetAttr(attrName->NamespaceID(), atom, param.mValue);
atom->ToString(param.mName);
mCachedAttributes.AppendElement(param);
}
@ -958,10 +958,10 @@ nsObjectLoadingContent::BuildParametersArray()
// Nav 4.x would simply replace the "data" with "src". Because some plugins correctly
// look for "data", lets instead copy the "data" attribute and add another entry
// to the bottom of the array if there isn't already a "src" specified.
if (content->IsHTMLElement(nsGkAtoms::object) &&
!content->HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
if (element->IsHTMLElement(nsGkAtoms::object) &&
!element->HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
MozPluginParameter param;
content->GetAttr(kNameSpaceID_None, nsGkAtoms::data, param.mValue);
element->GetAttr(kNameSpaceID_None, nsGkAtoms::data, param.mValue);
if (!param.mValue.IsEmpty()) {
param.mName = NS_LITERAL_STRING("SRC");
mCachedAttributes.AppendElement(param);

View File

@ -1401,10 +1401,12 @@ nsTreeSanitizer::SanitizeChildren(nsINode* aRoot)
int32_t ns = nodeInfo->NamespaceID();
if (MustPrune(ns, localName, elt)) {
RemoveAllAttributes(node);
RemoveAllAttributes(elt);
nsIContent* descendant = node;
while ((descendant = descendant->GetNextNode(node))) {
RemoveAllAttributes(descendant);
if (descendant->IsElement()) {
RemoveAllAttributes(descendant->AsElement());
}
}
nsIContent* next = node->GetNextNonChildNode(aRoot);
node->RemoveFromParent();
@ -1450,7 +1452,7 @@ nsTreeSanitizer::SanitizeChildren(nsINode* aRoot)
continue;
}
if (MustFlatten(ns, localName)) {
RemoveAllAttributes(node);
RemoveAllAttributes(elt);
nsCOMPtr<nsIContent> next = node->GetNextNode(aRoot);
nsCOMPtr<nsIContent> parent = node->GetParent();
nsCOMPtr<nsIContent> child; // Must keep the child alive during move
@ -1505,7 +1507,7 @@ nsTreeSanitizer::SanitizeChildren(nsINode* aRoot)
}
void
nsTreeSanitizer::RemoveAllAttributes(nsIContent* aElement)
nsTreeSanitizer::RemoveAllAttributes(Element* aElement)
{
const nsAttrName* attrName;
while ((attrName = aElement->GetAttrNameAt(0))) {

View File

@ -146,8 +146,8 @@ class MOZ_STACK_CLASS nsTreeSanitizer {
* @return true if the attribute was removed and false otherwise
*/
bool SanitizeURL(mozilla::dom::Element* aElement,
int32_t aNamespace,
nsAtom* aLocalName);
int32_t aNamespace,
nsAtom* aLocalName);
/**
* Checks a style rule for the presence of the 'binding' CSS property and
@ -178,7 +178,7 @@ class MOZ_STACK_CLASS nsTreeSanitizer {
/**
* Removes all attributes from an element node.
*/
void RemoveAllAttributes(nsIContent* aElement);
void RemoveAllAttributes(mozilla::dom::Element* aElement);
/**
* The whitelist of HTML elements.

View File

@ -156,8 +156,8 @@ nsXHTMLContentSerializer::AppendText(nsIContent* aText,
}
bool
nsXHTMLContentSerializer::SerializeAttributes(nsIContent* aContent,
nsIContent *aOriginalElement,
nsXHTMLContentSerializer::SerializeAttributes(Element* aElement,
Element* aOriginalElement,
nsAString& aTagPrefix,
const nsAString& aTagNamespaceURI,
nsAtom* aTagName,
@ -171,7 +171,7 @@ nsXHTMLContentSerializer::SerializeAttributes(nsIContent* aContent,
nsAutoString xmlnsStr;
xmlnsStr.AssignLiteral(kXMLNS);
int32_t contentNamespaceID = aContent->GetNameSpaceID();
int32_t contentNamespaceID = aElement->GetNameSpaceID();
// this method is not called by nsHTMLContentSerializer
// so we don't have to check HTML element, just XHTML
@ -185,7 +185,7 @@ nsXHTMLContentSerializer::SerializeAttributes(nsIContent* aContent,
// Store its start attribute value in olState->startVal.
nsAutoString start;
int32_t startAttrVal = 0;
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::start, start);
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::start, start);
if (!start.IsEmpty()) {
nsresult rv = NS_OK;
startAttrVal = start.ToInteger(&rv);
@ -204,7 +204,7 @@ nsXHTMLContentSerializer::SerializeAttributes(nsIContent* aContent,
mIsFirstChildOfOL = IsFirstChildOfOL(aOriginalElement);
if (mIsFirstChildOfOL) {
// If OL is parent of this LI, serialize attributes in different manner.
NS_ENSURE_TRUE(SerializeLIValueAttribute(aContent, aStr), false);
NS_ENSURE_TRUE(SerializeLIValueAttribute(aElement, aStr), false);
}
}
}
@ -228,7 +228,7 @@ nsXHTMLContentSerializer::SerializeAttributes(nsIContent* aContent,
NS_NAMED_LITERAL_STRING(_mozStr, "_moz");
count = aContent->GetAttrCount();
count = aElement->GetAttrCount();
// Now serialize each of the attributes
// XXX Unfortunately we need a namespace manager to get
@ -239,7 +239,7 @@ nsXHTMLContentSerializer::SerializeAttributes(nsIContent* aContent,
continue;
}
mozilla::dom::BorrowedAttrInfo info = aContent->GetAttrInfoAt(index);
mozilla::dom::BorrowedAttrInfo info = aElement->GetAttrInfoAt(index);
const nsAttrName* name = info.mName;
int32_t namespaceID = name->NamespaceID();
@ -287,7 +287,7 @@ nsXHTMLContentSerializer::SerializeAttributes(nsIContent* aContent,
continue;
}
isJS = IsJavaScript(aContent, attrName, namespaceID, valueStr);
isJS = IsJavaScript(aElement, attrName, namespaceID, valueStr);
if (namespaceID == kNameSpaceID_None &&
((attrName == nsGkAtoms::href) ||
@ -298,7 +298,7 @@ nsXHTMLContentSerializer::SerializeAttributes(nsIContent* aContent,
// but that gets more complicated since we have to
// search the tag list for CODEBASE as well.
// For now, just leave them relative.
nsCOMPtr<nsIURI> uri = aContent->GetBaseURI();
nsCOMPtr<nsIURI> uri = aElement->GetBaseURI();
if (uri) {
nsAutoString absURI;
rv = NS_MakeAbsoluteURI(absURI, valueStr, uri);
@ -314,7 +314,7 @@ nsXHTMLContentSerializer::SerializeAttributes(nsIContent* aContent,
// If we're serializing a <meta http-equiv="content-type">,
// use the proper value, rather than what's in the document.
nsAutoString header;
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
if (header.LowerCaseEqualsLiteral("content-type")) {
valueStr = NS_LITERAL_STRING("text/html; charset=") +
NS_ConvertASCIItoUTF16(mCharset);
@ -327,7 +327,7 @@ nsXHTMLContentSerializer::SerializeAttributes(nsIContent* aContent,
}
}
else {
isJS = IsJavaScript(aContent, attrName, namespaceID, valueStr);
isJS = IsJavaScript(aElement, attrName, namespaceID, valueStr);
}
NS_ENSURE_TRUE(SerializeAttr(prefixStr, nameStr, valueStr, aStr, !isJS), false);
@ -414,8 +414,8 @@ nsXHTMLContentSerializer::AppendDocumentStart(nsIDocument *aDocument,
}
bool
nsXHTMLContentSerializer::CheckElementStart(nsIContent * aContent,
bool & aForceFormat,
nsXHTMLContentSerializer::CheckElementStart(Element* aElement,
bool& aForceFormat,
nsAString& aStr,
nsresult& aResult)
{
@ -425,16 +425,16 @@ nsXHTMLContentSerializer::CheckElementStart(nsIContent * aContent,
// indicate that this element should be pretty printed
// even if we're not in pretty printing mode
aForceFormat = !(mFlags & nsIDocumentEncoder::OutputIgnoreMozDirty) &&
aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdirty);
aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdirty);
if (aContent->IsHTMLElement(nsGkAtoms::br) &&
if (aElement->IsHTMLElement(nsGkAtoms::br) &&
(mFlags & nsIDocumentEncoder::OutputNoFormattingInPre) &&
PreLevel() > 0) {
aResult = AppendNewLineToString(aStr) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
return false;
}
if (aContent->IsHTMLElement(nsGkAtoms::body)) {
if (aElement->IsHTMLElement(nsGkAtoms::body)) {
++mInBody;
}
@ -834,7 +834,7 @@ nsXHTMLContentSerializer::IsFirstChildOfOL(nsIContent* aElement)
}
bool
nsXHTMLContentSerializer::HasNoChildren(nsIContent * aContent) {
nsXHTMLContentSerializer::HasNoChildren(nsIContent* aContent) {
for (nsIContent* child = aContent->GetFirstChild();
child;

View File

@ -48,10 +48,10 @@ class nsXHTMLContentSerializer : public nsXMLContentSerializer {
protected:
virtual bool CheckElementStart(nsIContent * aContent,
bool & aForceFormat,
nsAString& aStr,
nsresult& aResult) override;
virtual bool CheckElementStart(mozilla::dom::Element* aElement,
bool& aForceFormat,
nsAString& aStr,
nsresult& aResult) override;
MOZ_MUST_USE
virtual bool AfterElementStart(nsIContent* aContent,
@ -77,14 +77,14 @@ class nsXHTMLContentSerializer : public nsXMLContentSerializer {
virtual void MaybeLeaveFromPreContent(nsIContent* aNode) override;
MOZ_MUST_USE
virtual bool SerializeAttributes(nsIContent* aContent,
nsIContent *aOriginalElement,
nsAString& aTagPrefix,
const nsAString& aTagNamespaceURI,
nsAtom* aTagName,
nsAString& aStr,
uint32_t aSkipAttr,
bool aAddNSAttr) override;
virtual bool SerializeAttributes(mozilla::dom::Element* aContent,
mozilla::dom::Element* aOriginalElement,
nsAString& aTagPrefix,
const nsAString& aTagNamespaceURI,
nsAtom* aTagName,
nsAString& aStr,
uint32_t aSkipAttr,
bool aAddNSAttr) override;
bool IsFirstChildOfOL(nsIContent* aElement);

View File

@ -712,20 +712,20 @@ nsXMLContentSerializer::SerializeAttr(const nsAString& aPrefix,
}
uint32_t
nsXMLContentSerializer::ScanNamespaceDeclarations(nsIContent* aContent,
nsIContent *aOriginalElement,
nsXMLContentSerializer::ScanNamespaceDeclarations(Element* aElement,
Element* aOriginalElement,
const nsAString& aTagNamespaceURI)
{
uint32_t index, count;
nsAutoString uriStr, valueStr;
count = aContent->GetAttrCount();
count = aElement->GetAttrCount();
// First scan for namespace declarations, pushing each on the stack
uint32_t skipAttr = count;
for (index = 0; index < count; index++) {
const BorrowedAttrInfo info = aContent->GetAttrInfoAt(index);
const BorrowedAttrInfo info = aElement->GetAttrInfoAt(index);
const nsAttrName* name = info.mName;
int32_t namespaceID = name->NamespaceID();
@ -799,8 +799,8 @@ nsXMLContentSerializer::IsJavaScript(nsIContent * aContent, nsAtom* aAttrNameAto
bool
nsXMLContentSerializer::SerializeAttributes(nsIContent* aContent,
nsIContent *aOriginalElement,
nsXMLContentSerializer::SerializeAttributes(Element* aElement,
Element* aOriginalElement,
nsAString& aTagPrefix,
const nsAString& aTagNamespaceURI,
nsAtom* aTagName,
@ -828,7 +828,7 @@ nsXMLContentSerializer::SerializeAttributes(nsIContent* aContent,
PushNameSpaceDecl(aTagPrefix, aTagNamespaceURI, aOriginalElement);
}
count = aContent->GetAttrCount();
count = aElement->GetAttrCount();
// Now serialize each of the attributes
// XXX Unfortunately we need a namespace manager to get
@ -838,7 +838,7 @@ nsXMLContentSerializer::SerializeAttributes(nsIContent* aContent,
continue;
}
const nsAttrName* name = aContent->GetAttrNameAt(index);
const nsAttrName* name = aElement->GetAttrNameAt(index);
int32_t namespaceID = name->NamespaceID();
nsAtom* attrName = name->LocalName();
nsAtom* attrPrefix = name->GetPrefix();
@ -863,10 +863,10 @@ nsXMLContentSerializer::SerializeAttributes(nsIContent* aContent,
addNSAttr = ConfirmPrefix(prefixStr, uriStr, aOriginalElement, true);
}
aContent->GetAttr(namespaceID, attrName, valueStr);
aElement->GetAttr(namespaceID, attrName, valueStr);
nsDependentAtomString nameStr(attrName);
bool isJS = IsJavaScript(aContent, attrName, namespaceID, valueStr);
bool isJS = IsJavaScript(aElement, attrName, namespaceID, valueStr);
NS_ENSURE_TRUE(SerializeAttr(prefixStr, nameStr, valueStr, aStr, !isJS), false);
@ -888,15 +888,13 @@ nsXMLContentSerializer::AppendElementStart(Element* aElement,
{
NS_ENSURE_ARG(aElement);
nsIContent* content = aElement;
bool forceFormat = false;
nsresult rv = NS_OK;
if (!CheckElementStart(content, forceFormat, aStr, rv)) {
if (!CheckElementStart(aElement, forceFormat, aStr, rv)) {
// When we go to AppendElementEnd for this element, we're going to
// MaybeLeaveFromPreContent(). So make sure to MaybeEnterInPreContent()
// now, so our PreLevel() doesn't get confused.
MaybeEnterInPreContent(content);
MaybeEnterInPreContent(aElement);
return rv;
}
@ -907,11 +905,12 @@ nsXMLContentSerializer::AppendElementStart(Element* aElement,
aElement->NodeInfo()->GetName(tagLocalName);
aElement->NodeInfo()->GetNamespaceURI(tagNamespaceURI);
uint32_t skipAttr = ScanNamespaceDeclarations(content,
aOriginalElement, tagNamespaceURI);
uint32_t skipAttr =
ScanNamespaceDeclarations(aElement, aOriginalElement, tagNamespaceURI);
nsAtom *name = content->NodeInfo()->NameAtom();
bool lineBreakBeforeOpen = LineBreakBeforeOpen(content->GetNameSpaceID(), name);
nsAtom *name = aElement->NodeInfo()->NameAtom();
bool lineBreakBeforeOpen =
LineBreakBeforeOpen(aElement->GetNameSpaceID(), name);
if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
if (mColPos && lineBreakBeforeOpen) {
@ -952,25 +951,26 @@ nsXMLContentSerializer::AppendElementStart(Element* aElement,
}
NS_ENSURE_TRUE(AppendToString(tagLocalName, aStr), NS_ERROR_OUT_OF_MEMORY);
MaybeEnterInPreContent(content);
MaybeEnterInPreContent(aElement);
if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
NS_ENSURE_TRUE(IncrIndentation(name), NS_ERROR_OUT_OF_MEMORY);
}
NS_ENSURE_TRUE(SerializeAttributes(content, aOriginalElement, tagPrefix, tagNamespaceURI,
name, aStr, skipAttr, addNSAttr),
NS_ENSURE_TRUE(SerializeAttributes(aElement, aOriginalElement, tagPrefix,
tagNamespaceURI, name, aStr, skipAttr,
addNSAttr),
NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_TRUE(AppendEndOfElementStart(aElement, aOriginalElement, aStr),
NS_ERROR_OUT_OF_MEMORY);
if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()
&& LineBreakAfterOpen(content->GetNameSpaceID(), name)) {
&& LineBreakAfterOpen(aElement->GetNameSpaceID(), name)) {
NS_ENSURE_TRUE(AppendNewLineToString(aStr), NS_ERROR_OUT_OF_MEMORY);
}
NS_ENSURE_TRUE(AfterElementStart(content, aOriginalElement, aStr), NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_TRUE(AfterElementStart(aElement, aOriginalElement, aStr), NS_ERROR_OUT_OF_MEMORY);
return NS_OK;
}
@ -1145,8 +1145,8 @@ nsXMLContentSerializer::AppendDocumentStart(nsIDocument *aDocument,
}
bool
nsXMLContentSerializer::CheckElementStart(nsIContent * aContent,
bool & aForceFormat,
nsXMLContentSerializer::CheckElementStart(Element*,
bool& aForceFormat,
nsAString& aStr,
nsresult& aResult)
{

View File

@ -209,13 +209,13 @@ class nsXMLContentSerializer : public nsIContentSerializer {
*/
void GenerateNewPrefix(nsAString& aPrefix);
uint32_t ScanNamespaceDeclarations(nsIContent* aContent,
nsIContent *aOriginalElement,
uint32_t ScanNamespaceDeclarations(mozilla::dom::Element* aContent,
mozilla::dom::Element* aOriginalElement,
const nsAString& aTagNamespaceURI);
MOZ_MUST_USE
virtual bool SerializeAttributes(nsIContent* aContent,
nsIContent *aOriginalElement,
virtual bool SerializeAttributes(mozilla::dom::Element* aContent,
mozilla::dom::Element* aOriginalElement,
nsAString& aTagPrefix,
const nsAString& aTagNamespaceURI,
nsAtom* aTagName,
@ -243,10 +243,10 @@ class nsXMLContentSerializer : public nsIContentSerializer {
* by setting aForceFormat to true.
* @return boolean true if the element can be output
*/
virtual bool CheckElementStart(nsIContent * aContent,
bool & aForceFormat,
nsAString& aStr,
nsresult& aResult);
virtual bool CheckElementStart(Element* aElement,
bool & aForceFormat,
nsAString& aStr,
nsresult& aResult);
/**
* This method is responsible for appending the '>' at the end of the start

View File

@ -494,7 +494,8 @@ public:
NS_IMETHOD
GetName(nsAString& aName) override
{
aName.AssignLiteral("ReleasingTimerHolder");
aName.AssignLiteral("ReleasingTimerHolder for blobURL: ");
aName.Append(NS_ConvertUTF8toUTF16(mURI));
return NS_OK;
}

View File

@ -4591,11 +4591,18 @@ ContentParent::CommonCreateWindow(PBrowserParent* aThisTab,
if (frameLoader) {
frameLoader->GetTabParent(getter_AddRefs(aNewTabParent));
}
} else if (NS_SUCCEEDED(aResult) && !frameLoaderOwner) {
// Fall through to the normal window opening code path when there is no
// window which we can open a new tab in.
openLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
} else {
*aWindowIsNew = false;
}
return IPC_OK();
// If we didn't retarget our window open into a new window, we should return now.
if (openLocation != nsIBrowserDOMWindow::OPEN_NEWWINDOW) {
return IPC_OK();
}
}
nsCOMPtr<nsPIWindowWatcher> pwwatch =

View File

@ -187,7 +187,9 @@ struct AudioChunk {
}
return true;
}
bool IsNull() const { return mBuffer == nullptr; }
bool IsNull() const {
return mBuffer == nullptr;
}
void SetNull(StreamTime aDuration)
{
mBuffer = nullptr;
@ -333,13 +335,15 @@ public:
void ResampleChunks(SpeexResamplerState* aResampler,
uint32_t aInRate,
uint32_t aOutRate);
void AppendFrames(already_AddRefed<ThreadSharedObject> aBuffer,
const nsTArray<const float*>& aChannelData,
int32_t aDuration, const PrincipalHandle& aPrincipalHandle)
{
AudioChunk* chunk = AppendChunk(aDuration);
chunk->mBuffer = aBuffer;
MOZ_ASSERT(chunk->mBuffer || aChannelData.IsEmpty(), "Appending invalid data ?");
for (uint32_t channel = 0; channel < aChannelData.Length(); ++channel) {
chunk->mChannelData.AppendElement(aChannelData[channel]);
}
@ -355,6 +359,9 @@ public:
{
AudioChunk* chunk = AppendChunk(aDuration);
chunk->mBuffer = aBuffer;
MOZ_ASSERT(chunk->mBuffer || aChannelData.IsEmpty(), "Appending invalid data ?");
for (uint32_t channel = 0; channel < aChannelData.Length(); ++channel) {
chunk->mChannelData.AppendElement(aChannelData[channel]);
}
@ -363,6 +370,7 @@ public:
chunk->mTimeStamp = TimeStamp::Now();
#endif
chunk->mPrincipalHandle = aPrincipalHandle;
}
// Consumes aChunk, and returns a pointer to the persistent copy of aChunk
// in the segment.
@ -371,6 +379,9 @@ public:
AudioChunk* chunk = AppendChunk(aChunk->mDuration);
chunk->mBuffer = aChunk->mBuffer.forget();
chunk->mChannelData.SwapElements(aChunk->mChannelData);
MOZ_ASSERT(chunk->mBuffer || aChunk->mChannelData.IsEmpty(), "Appending invalid data ?");
chunk->mVolume = aChunk->mVolume;
chunk->mBufferFormat = aChunk->mBufferFormat;
#ifdef MOZILLA_INTERNAL_API

View File

@ -16,17 +16,17 @@ inline TrackTicks RateConvertTicksRoundDown(TrackRate aOutRate,
TrackRate aInRate,
TrackTicks aTicks)
{
NS_ASSERTION(0 < aOutRate && aOutRate <= TRACK_RATE_MAX, "Bad out rate");
NS_ASSERTION(0 < aInRate && aInRate <= TRACK_RATE_MAX, "Bad in rate");
NS_ASSERTION(0 <= aTicks && aTicks <= TRACK_TICKS_MAX, "Bad ticks");
MOZ_ASSERT(0 < aOutRate && aOutRate <= TRACK_RATE_MAX, "Bad out rate");
MOZ_ASSERT(0 < aInRate && aInRate <= TRACK_RATE_MAX, "Bad in rate");
MOZ_ASSERT(0 <= aTicks && aTicks <= TRACK_TICKS_MAX, "Bad ticks");
return (aTicks * aOutRate) / aInRate;
}
inline TrackTicks RateConvertTicksRoundUp(TrackRate aOutRate,
TrackRate aInRate, TrackTicks aTicks)
{
NS_ASSERTION(0 < aOutRate && aOutRate <= TRACK_RATE_MAX, "Bad out rate");
NS_ASSERTION(0 < aInRate && aInRate <= TRACK_RATE_MAX, "Bad in rate");
NS_ASSERTION(0 <= aTicks && aTicks <= TRACK_TICKS_MAX, "Bad ticks");
MOZ_ASSERT(0 < aOutRate && aOutRate <= TRACK_RATE_MAX, "Bad out rate");
MOZ_ASSERT(0 < aInRate && aInRate <= TRACK_RATE_MAX, "Bad in rate");
MOZ_ASSERT(0 <= aTicks && aTicks <= TRACK_TICKS_MAX, "Bad ticks");
return (aTicks * aOutRate + aInRate - 1) / aInRate;
}

View File

@ -16,7 +16,7 @@ createHTML({
var audioContext;
var gUMAudioElement;
var analyser;
runTest(() => getUserMedia({audio: true})
runTest(() => getUserMedia({audio: { echoCancellation: false }})
.then(stream => {
gUMAudioElement = createMediaElement("audio", "gUMAudio");
gUMAudioElement.srcObject = stream;

View File

@ -423,11 +423,12 @@
pc.addTransceiver("foo");
ok(false, 'addTransceiver("foo") throws');
}
catch (e if e instanceof TypeError) {
ok(true, 'addTransceiver("foo") throws a TypeError');
}
catch (e) {
ok(false, 'addTransceiver("foo") throws a TypeError');
if (e instanceof TypeError) {
ok(true, 'addTransceiver("foo") throws a TypeError');
} else {
ok(false, 'addTransceiver("foo") throws a TypeError');
}
}
hasProps(pc.getTransceivers(), []);

View File

@ -17,13 +17,13 @@ class SingleRwFifo;
namespace mozilla {
typedef struct FarEndAudioChunk_ {
uint16_t mSamples;
size_t mSamples;
bool mOverrun;
int16_t mData[1]; // variable-length
AudioDataValue mData[1]; // variable-length
} FarEndAudioChunk;
// This class is used to packetize and send the mixed audio from an MSG, in
// int16, to the AEC module of WebRTC.org.
// float, to the AEC module of WebRTC.org.
class AudioOutputObserver
{
public:

View File

@ -53,8 +53,6 @@ public:
static const int DEFAULT_169_VIDEO_WIDTH = 1280;
static const int DEFAULT_169_VIDEO_HEIGHT = 720;
static const int DEFAULT_SAMPLE_RATE = 32000;
// This allows using whatever rate the graph is using for the
// MediaStreamTrack. This is useful for microphone data, we know it's already
// at the correct rate for insertion in the MSG.

View File

@ -26,7 +26,6 @@
#include "YuvStamper.h"
#endif
#define AUDIO_RATE mozilla::MediaEngine::DEFAULT_SAMPLE_RATE
#define DEFAULT_AUDIO_TIMER_MS 10
namespace mozilla {
@ -332,6 +331,7 @@ NS_IMPL_ISUPPORTS0(MediaEngineDefaultAudioSource)
MediaEngineDefaultAudioSource::MediaEngineDefaultAudioSource()
: MediaEngineAudioSource(kReleased)
, mLastNotify(0)
, mFreq(1000)
{}
MediaEngineDefaultAudioSource::~MediaEngineDefaultAudioSource()
@ -382,10 +382,8 @@ MediaEngineDefaultAudioSource::Allocate(const dom::MediaTrackConstraints &aConst
return NS_ERROR_FAILURE;
}
mFreq = aPrefs.mFreq ? aPrefs.mFreq : 1000;
mState = kAllocated;
// generate sine wave (default 1KHz)
mSineGenerator = new SineWaveGenerator(AUDIO_RATE,
static_cast<uint32_t>(aPrefs.mFreq ? aPrefs.mFreq : 1000));
*aOutHandle = nullptr;
return NS_OK;
}
@ -409,9 +407,15 @@ MediaEngineDefaultAudioSource::Start(SourceMediaStream* aStream, TrackID aID,
return NS_ERROR_FAILURE;
}
if (!mSineGenerator) {
// generate sine wave (default 1KHz)
mSineGenerator = new SineWaveGenerator(aStream->GraphRate(), mFreq);
}
// AddTrack will take ownership of segment
AudioSegment* segment = new AudioSegment();
aStream->AddAudioTrack(aID, AUDIO_RATE, 0, segment, SourceMediaStream::ADDTRACK_QUEUED);
aStream->AddAudioTrack(aID, aStream->GraphRate(), 0, segment, SourceMediaStream::ADDTRACK_QUEUED);
// Remember TrackID so we can finish later
mTrackID = aID;
@ -467,7 +471,7 @@ MediaEngineDefaultAudioSource::NotifyPull(MediaStreamGraph* aGraph,
MOZ_ASSERT(aID == mTrackID);
AudioSegment segment;
// avoid accumulating rounding errors
TrackTicks desired = aSource->TimeToTicksRoundUp(AUDIO_RATE, aDesiredTime);
TrackTicks desired = aSource->TimeToTicksRoundUp(aGraph->GraphRate(), aDesiredTime);
TrackTicks delta = desired - mLastNotify;
mLastNotify += delta;
AppendToSegment(segment, delta, aPrincipalHandle);

View File

@ -188,8 +188,9 @@ protected:
TrackID mTrackID;
TrackTicks mLastNotify; // Accessed in ::Start(), then on NotifyPull (from MSG thread)
uint32_t mFreq; // ditto
// Created on Allocate, then accessed from NotifyPull (MSG thread)
// Created on Start, then accessed from NotifyPull (MSG thread)
nsAutoPtr<SineWaveGenerator> mSineGenerator;
};

View File

@ -107,7 +107,6 @@ void AudioInputCubeb::UpdateDeviceList()
MediaEngineWebRTC::MediaEngineWebRTC(MediaEnginePrefs &aPrefs)
: mMutex("mozilla::MediaEngineWebRTC"),
mVoiceEngine(nullptr),
mAudioInput(nullptr),
mFullDuplex(aPrefs.mFullDuplex),
mDelayAgnostic(aPrefs.mDelayAgnostic),
@ -280,43 +279,11 @@ MediaEngineWebRTC::EnumerateAudioDevices(dom::MediaSourceEnum aMediaSource,
return;
}
#ifdef MOZ_WIDGET_ANDROID
JavaVM* jvm = mozilla::jni::GetVM();
jobject context = mozilla::AndroidBridge::Bridge()->GetGlobalContextRef();
if (webrtc::VoiceEngine::SetAndroidObjects(jvm, (void*)context) != 0) {
LOG(("VoiceEngine:SetAndroidObjects Failed"));
return;
}
#endif
if (!mVoiceEngine) {
mVoiceEngine = webrtc::VoiceEngine::Create();
if (!mVoiceEngine) {
if (!mAudioInput) {
if (!SupportsDuplex()) {
return;
}
}
ptrVoEBase = webrtc::VoEBase::GetInterface(mVoiceEngine);
if (!ptrVoEBase) {
return;
}
// Always re-init the voice engine, since if we close the last use we
// DeInitEngine() and Terminate(), which shuts down Process() - but means
// we have to Init() again before using it. Init() when already inited is
// just a no-op, so call always.
if (ptrVoEBase->Init() < 0) {
return;
}
if (!mAudioInput) {
if (SupportsDuplex()) {
// The platform_supports_full_duplex.
mAudioInput = new mozilla::AudioInputCubeb(mVoiceEngine);
} else {
mAudioInput = new mozilla::AudioInputWebRTC(mVoiceEngine);
}
mAudioInput = new mozilla::AudioInputCubeb();
}
int nDevices = 0;
@ -344,7 +311,6 @@ MediaEngineWebRTC::EnumerateAudioDevices(dom::MediaSourceEnum aMediaSource,
if (uniqueId[0] == '\0') {
// Mac and Linux don't set uniqueId!
MOZ_ASSERT(sizeof(deviceName) == sizeof(uniqueId)); // total paranoia
strcpy(uniqueId, deviceName); // safe given assert and initialization/error-check
}
@ -354,16 +320,7 @@ MediaEngineWebRTC::EnumerateAudioDevices(dom::MediaSourceEnum aMediaSource,
// We've already seen this device, just append.
aASources->AppendElement(aSource.get());
} else {
AudioInput* audioinput = mAudioInput;
if (SupportsDuplex()) {
// The platform_supports_full_duplex.
// For cubeb, it has state (the selected ID)
// XXX just use the uniqueID for cubeb and support it everywhere, and get rid of this
// XXX Small window where the device list/index could change!
audioinput = new mozilla::AudioInputCubeb(mVoiceEngine, i);
}
aSource = new MediaEngineWebRTCMicrophoneSource(mVoiceEngine, audioinput,
aSource = new MediaEngineWebRTCMicrophoneSource(new mozilla::AudioInputCubeb(i),
i, deviceName, uniqueId,
mDelayAgnostic, mExtendedFilter);
mAudioSources.Put(uuid, aSource); // Hashtable takes ownership.
@ -401,13 +358,6 @@ MediaEngineWebRTC::Shutdown()
mVideoSources.Clear();
mAudioSources.Clear();
if (mVoiceEngine) {
mVoiceEngine->SetTraceCallback(nullptr);
webrtc::VoiceEngine::Delete(mVoiceEngine);
}
mVoiceEngine = nullptr;
mozilla::camera::Shutdown();
AudioInputCubeb::CleanupGlobalData();
}

View File

@ -141,7 +141,7 @@ protected:
class AudioInput
{
public:
explicit AudioInput(webrtc::VoiceEngine* aVoiceEngine) : mVoiceEngine(aVoiceEngine) {};
AudioInput() = default;
// Threadsafe because it's referenced from an MicrophoneSource, which can
// had references to it on other threads.
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioInput)
@ -160,15 +160,13 @@ public:
protected:
// Protected destructor, to discourage deletion outside of Release():
virtual ~AudioInput() {}
webrtc::VoiceEngine* mVoiceEngine;
};
class AudioInputCubeb final : public AudioInput
{
public:
explicit AudioInputCubeb(webrtc::VoiceEngine* aVoiceEngine, int aIndex = 0) :
AudioInput(aVoiceEngine), mSelectedDevice(aIndex), mInUseCount(0)
explicit AudioInputCubeb(int aIndex = 0) :
AudioInput(), mSelectedDevice(aIndex), mInUseCount(0)
{
if (!mDeviceIndexes) {
mDeviceIndexes = new nsTArray<int>;
@ -314,14 +312,7 @@ public:
MOZ_ASSERT(mDevices.count > 0);
#endif
if (mInUseCount == 0) {
ScopedCustomReleasePtr<webrtc::VoEExternalMedia> ptrVoEXMedia;
ptrVoEXMedia = webrtc::VoEExternalMedia::GetInterface(mVoiceEngine);
if (ptrVoEXMedia) {
ptrVoEXMedia->SetExternalRecordingStatus(true);
}
mAnyInUse = true;
}
mAnyInUse = true;
mInUseCount++;
// Always tell the stream we're using it for input
aStream->OpenAudioInput(mSelectedDevice, aListener);
@ -369,77 +360,6 @@ private:
static uint32_t sUserChannelCount;
};
class AudioInputWebRTC final : public AudioInput
{
public:
explicit AudioInputWebRTC(webrtc::VoiceEngine* aVoiceEngine) : AudioInput(aVoiceEngine) {}
int GetNumOfRecordingDevices(int& aDevices)
{
ScopedCustomReleasePtr<webrtc::VoEBase> ptrVoEBase;
ptrVoEBase = webrtc::VoEBase::GetInterface(mVoiceEngine);
if (!ptrVoEBase) {
return 1;
}
aDevices = ptrVoEBase->audio_device_module()->RecordingDevices();
return 0;
}
int GetRecordingDeviceName(int aIndex, char (&aStrNameUTF8)[128],
char aStrGuidUTF8[128])
{
ScopedCustomReleasePtr<webrtc::VoEBase> ptrVoEBase;
ptrVoEBase = webrtc::VoEBase::GetInterface(mVoiceEngine);
if (!ptrVoEBase) {
return 1;
}
return ptrVoEBase->audio_device_module()->RecordingDeviceName(aIndex,
aStrNameUTF8,
aStrGuidUTF8);
}
int GetRecordingDeviceStatus(bool& aIsAvailable)
{
ScopedCustomReleasePtr<webrtc::VoEBase> ptrVoEBase;
ptrVoEBase = webrtc::VoEBase::GetInterface(mVoiceEngine);
if (!ptrVoEBase) {
return 1;
}
return ptrVoEBase->audio_device_module()->RecordingIsAvailable(&aIsAvailable);
}
void GetChannelCount(uint32_t& aChannels)
{
aChannels = 1; // default to mono
}
int GetMaxAvailableChannels(uint32_t& aChannels)
{
aChannels = 1;
return 0;
}
void SetUserChannelCount(uint32_t aChannels)
{}
void StartRecording(SourceMediaStream *aStream, AudioDataListener *aListener) {}
void StopRecording(SourceMediaStream *aStream) {}
int SetRecordingDevice(int aIndex)
{
ScopedCustomReleasePtr<webrtc::VoEBase> ptrVoEBase;
ptrVoEBase = webrtc::VoEBase::GetInterface(mVoiceEngine);
if (!ptrVoEBase) {
return 1;
}
return ptrVoEBase->audio_device_module()->SetRecordingDevice(aIndex);
}
protected:
// Protected destructor, to discourage deletion outside of Release():
~AudioInputWebRTC() {}
};
class WebRTCAudioDataListener : public AudioDataListener
{
protected:
@ -490,13 +410,11 @@ private:
RefPtr<MediaEngineAudioSource> mAudioSource;
};
class MediaEngineWebRTCMicrophoneSource : public MediaEngineAudioSource,
public webrtc::VoEMediaProcess
class MediaEngineWebRTCMicrophoneSource : public MediaEngineAudioSource
{
typedef MediaEngineAudioSource Super;
public:
MediaEngineWebRTCMicrophoneSource(webrtc::VoiceEngine* aVoiceEnginePtr,
mozilla::AudioInput* aAudioInput,
MediaEngineWebRTCMicrophoneSource(mozilla::AudioInput* aAudioInput,
int aIndex,
const char* name,
const char* uuid,
@ -550,11 +468,6 @@ public:
const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
const nsString& aDeviceId) const override;
// VoEMediaProcess.
virtual void Process(int channel, webrtc::ProcessingTypes type,
int16_t audio10ms[], size_t length,
int samplingFreq, bool isStereo) override;
void Shutdown() override;
NS_DECL_THREADSAFE_ISUPPORTS
@ -571,20 +484,16 @@ private:
const nsString& aDeviceId,
const char** aOutBadConstraint) override;
void UpdateAECSettingsIfNeeded(bool aEnable, webrtc::EcModes aMode);
void UpdateAGCSettingsIfNeeded(bool aEnable, webrtc::AgcModes aMode);
void UpdateNSSettingsIfNeeded(bool aEnable, webrtc::NsModes aMode);
void SetLastPrefs(const MediaEnginePrefs& aPrefs);
// These allocate/configure and release the channel
bool AllocChannel();
void FreeChannel();
// These start/stop VoEBase and associated interfaces
bool InitEngine();
void DeInitEngine();
// This is true when all processing is disabled, we can skip
// packetization, resampling and other processing passes.
bool PassThrough() {
return mSkipProcessing;
}
template<typename T>
void InsertInGraph(const T* aBuffer,
size_t aFrames,
@ -596,22 +505,27 @@ private:
TrackRate aRate,
uint32_t aChannels);
webrtc::VoiceEngine* mVoiceEngine;
// This is true when all processing is disabled, we can skip
// packetization, resampling and other processing passes.
bool PassThrough() {
return mSkipProcessing;
}
void SetPassThrough(bool aPassThrough) {
mSkipProcessing = aPassThrough;
}
RefPtr<mozilla::AudioInput> mAudioInput;
RefPtr<WebRTCAudioDataListener> mListener;
RefPtr<AudioOutputObserver> mAudioOutputObserver;
// Note: shared across all microphone sources - we don't want to Terminate()
// the VoEBase until there are no active captures
// Note: shared across all microphone sources
static int sChannelsOpen;
static ScopedCustomReleasePtr<webrtc::VoEBase> mVoEBase;
static ScopedCustomReleasePtr<webrtc::VoEExternalMedia> mVoERender;
static ScopedCustomReleasePtr<webrtc::VoENetwork> mVoENetwork;
static ScopedCustomReleasePtr<webrtc::VoEAudioProcessing> mVoEProcessing;
const UniquePtr<webrtc::AudioProcessing> mAudioProcessing;
const RefPtr<AudioOutputObserver> mAudioOutputObserver;
// accessed from the GraphDriver thread except for deletion
nsAutoPtr<AudioPacketizer<AudioDataValue, int16_t>> mPacketizer;
nsAutoPtr<AudioPacketizer<AudioDataValue, float>> mPacketizer;
ScopedCustomReleasePtr<webrtc::VoEExternalMedia> mVoERenderListener;
// mMonitor protects mSources[] and mPrinicpalIds[] access/changes, and
@ -623,7 +537,6 @@ private:
nsTArray<PrincipalHandle> mPrincipalHandles; // Maps to mSources.
int mCapIndex;
int mChannel;
bool mDelayAgnostic;
bool mExtendedFilter;
MOZ_INIT_OUTSIDE_CTOR TrackID mTrackID;
@ -636,18 +549,18 @@ private:
uint64_t mTotalFrames;
uint64_t mLastLogFrames;
NullTransport *mNullTransport;
nsTArray<int16_t> mInputBuffer;
// mSkipProcessing is true if none of the processing passes are enabled,
// because of prefs or constraints. This allows simply copying the audio into
// the MSG, skipping resampling and the whole webrtc.org code.
// This is read and written to only on the MSG thread.
bool mSkipProcessing;
// To only update microphone when needed, we keep track of previous settings.
MediaEnginePrefs mLastPrefs;
AlignedShortBuffer mInputDownmixBuffer;
AlignedFloatBuffer mInputBuffer;
AlignedFloatBuffer mDeinterleavedBuffer;
AlignedAudioBuffer mInputDownmixBuffer;
};
class MediaEngineWebRTC : public MediaEngine
@ -676,7 +589,6 @@ private:
// gUM runnables can e.g. Enumerate from multiple threads
Mutex mMutex;
webrtc::VoiceEngine* mVoiceEngine;
RefPtr<mozilla::AudioInput> mAudioInput;
bool mFullDuplex;
bool mDelayAgnostic;

View File

@ -10,19 +10,18 @@
#include "mtransport/runnable_utils.h"
#include "nsAutoPtr.h"
#include "AudioConverter.h"
#include "MediaStreamGraphImpl.h"
// scoped_ptr.h uses FF
#ifdef FF
#undef FF
#endif
#include "webrtc/modules/audio_device/opensl/single_rw_fifo.h"
#include "webrtc/voice_engine/voice_engine_defines.h"
#include "webrtc/modules/audio_processing/include/audio_processing.h"
#include "webrtc/common_audio/include/audio_util.h"
#define CHANNELS 1
#define ENCODING "L16"
#define DEFAULT_PORT 5555
#define SAMPLE_RATE(freq) ((freq)*2*8) // bps, 16-bit samples
#define SAMPLE_LENGTH(freq) (((freq)*10)/1000)
using namespace webrtc;
// These are restrictions from the webrtc.org code
#define MAX_CHANNELS 2
@ -53,10 +52,6 @@ NS_IMPL_ISUPPORTS0(MediaEngineWebRTCMicrophoneSource)
NS_IMPL_ISUPPORTS0(MediaEngineWebRTCAudioCaptureSource)
int MediaEngineWebRTCMicrophoneSource::sChannelsOpen = 0;
ScopedCustomReleasePtr<webrtc::VoEBase> MediaEngineWebRTCMicrophoneSource::mVoEBase;
ScopedCustomReleasePtr<webrtc::VoEExternalMedia> MediaEngineWebRTCMicrophoneSource::mVoERender;
ScopedCustomReleasePtr<webrtc::VoENetwork> MediaEngineWebRTCMicrophoneSource::mVoENetwork;
ScopedCustomReleasePtr<webrtc::VoEAudioProcessing> MediaEngineWebRTCMicrophoneSource::mVoEProcessing;
AudioOutputObserver::AudioOutputObserver()
: mPlayoutFreq(0)
@ -67,7 +62,7 @@ AudioOutputObserver::AudioOutputObserver()
, mDownmixBuffer(MAX_SAMPLING_FREQ * MAX_CHANNELS / 100)
{
// Buffers of 10ms chunks
mPlayoutFifo = new webrtc::SingleRwFifo(MAX_AEC_FIFO_DEPTH/10);
mPlayoutFifo = new SingleRwFifo(MAX_AEC_FIFO_DEPTH/10);
}
AudioOutputObserver::~AudioOutputObserver()
@ -143,7 +138,7 @@ AudioOutputObserver::InsertFarEnd(const AudioDataValue *aBuffer, uint32_t aFrame
while (aFrames) {
if (!mSaved) {
mSaved = (FarEndAudioChunk *) moz_xmalloc(sizeof(FarEndAudioChunk) +
(mChunkSize * channels - 1)*sizeof(int16_t));
(mChunkSize * channels - 1)*sizeof(AudioDataValue));
mSaved->mSamples = mChunkSize;
mSaved->mOverrun = aOverran;
aOverran = false;
@ -153,7 +148,7 @@ AudioOutputObserver::InsertFarEnd(const AudioDataValue *aBuffer, uint32_t aFrame
to_copy = aFrames;
}
int16_t* dest = &(mSaved->mData[mSamplesSaved * channels]);
AudioDataValue* dest = &(mSaved->mData[mSamplesSaved * channels]);
if (aChannels > MAX_CHANNELS) {
AudioConverter converter(AudioConfig(aChannels, 0), AudioConfig(channels, 0));
converter.Process(mDownmixBuffer, aBuffer, to_copy);
@ -164,7 +159,7 @@ AudioOutputObserver::InsertFarEnd(const AudioDataValue *aBuffer, uint32_t aFrame
#ifdef LOG_FAREND_INSERTION
if (fp) {
fwrite(&(mSaved->mData[mSamplesSaved * aChannels]), to_copy * aChannels, sizeof(int16_t), fp);
fwrite(&(mSaved->mData[mSamplesSaved * aChannels]), to_copy * aChannels, sizeof(AudioDataValue), fp);
}
#endif
aFrames -= to_copy;
@ -187,7 +182,6 @@ AudioOutputObserver::InsertFarEnd(const AudioDataValue *aBuffer, uint32_t aFrame
}
MediaEngineWebRTCMicrophoneSource::MediaEngineWebRTCMicrophoneSource(
webrtc::VoiceEngine* aVoiceEnginePtr,
mozilla::AudioInput* aAudioInput,
int aIndex,
const char* name,
@ -195,23 +189,21 @@ MediaEngineWebRTCMicrophoneSource::MediaEngineWebRTCMicrophoneSource(
bool aDelayAgnostic,
bool aExtendedFilter)
: MediaEngineAudioSource(kReleased)
, mVoiceEngine(aVoiceEnginePtr)
, mAudioInput(aAudioInput)
, mAudioProcessing(AudioProcessing::Create())
, mAudioOutputObserver(new AudioOutputObserver())
, mMonitor("WebRTCMic.Monitor")
, mCapIndex(aIndex)
, mChannel(-1)
, mDelayAgnostic(aDelayAgnostic)
, mExtendedFilter(aExtendedFilter)
, mTrackID(TRACK_NONE)
, mStarted(false)
, mSampleFrequency(MediaEngine::DEFAULT_SAMPLE_RATE)
, mSampleFrequency(MediaEngine::USE_GRAPH_RATE)
, mTotalFrames(0)
, mLastLogFrames(0)
, mNullTransport(nullptr)
, mSkipProcessing(false)
, mInputDownmixBuffer(MAX_SAMPLING_FREQ * MAX_CHANNELS / 100)
{
MOZ_ASSERT(aVoiceEnginePtr);
MOZ_ASSERT(aAudioInput);
mDeviceName.Assign(NS_ConvertUTF8toUTF16(name));
mDeviceUUID.Assign(uuid);
@ -275,6 +267,140 @@ bool operator == (const MediaEnginePrefs& a, const MediaEnginePrefs& b)
return !memcmp(&a, &b, sizeof(MediaEnginePrefs));
};
// This does an early return in case of error.
#define HANDLE_APM_ERROR(fn) \
do { \
int rv = fn; \
if (rv != AudioProcessing::kNoError) { \
MOZ_ASSERT_UNREACHABLE("APM error in " #fn); \
return; \
} \
} while(0);
void MediaEngineWebRTCMicrophoneSource::UpdateAECSettingsIfNeeded(bool aEnable, EcModes aMode)
{
using webrtc::EcModes;
EchoCancellation::SuppressionLevel level;
switch(aMode) {
case EcModes::kEcUnchanged:
level = mAudioProcessing->echo_cancellation()->suppression_level();
break;
case EcModes::kEcConference:
level = EchoCancellation::kHighSuppression;
break;
case EcModes::kEcDefault:
level = EchoCancellation::kModerateSuppression;
break;
case EcModes::kEcAec:
level = EchoCancellation::kModerateSuppression;
break;
case EcModes::kEcAecm:
// No suppression level to set for the mobile echo canceller
break;
default:
MOZ_LOG(GetMediaManagerLog(), LogLevel::Error, ("Bad EcMode value"));
MOZ_ASSERT_UNREACHABLE("Bad pref set in all.js or in about:config"
" for the echo cancelation mode.");
// fall back to something sensible in release
level = EchoCancellation::kModerateSuppression;
break;
}
// AECm and AEC are mutually exclusive.
if (aMode == EcModes::kEcAecm) {
HANDLE_APM_ERROR(mAudioProcessing->echo_cancellation()->Enable(false));
HANDLE_APM_ERROR(mAudioProcessing->echo_control_mobile()->Enable(aEnable));
} else {
HANDLE_APM_ERROR(mAudioProcessing->echo_control_mobile()->Enable(false));
HANDLE_APM_ERROR(mAudioProcessing->echo_cancellation()->Enable(aEnable));
HANDLE_APM_ERROR(mAudioProcessing->echo_cancellation()->set_suppression_level(level));
}
}
void
MediaEngineWebRTCMicrophoneSource::UpdateAGCSettingsIfNeeded(bool aEnable, AgcModes aMode)
{
#if defined(WEBRTC_IOS) || defined(ATA) || defined(WEBRTC_ANDROID)
if (aMode == kAgcAdaptiveAnalog) {
MOZ_LOG(GetMediaManagerLog(),
LogLevel::Error,
("Invalid AGC mode kAgcAdaptiveAnalog on mobile"));
MOZ_ASSERT_UNREACHABLE("Bad pref set in all.js or in about:config"
" for the auto gain, on mobile.");
aMode = kAgcDefault;
}
#endif
GainControl::Mode mode = kDefaultAgcMode;
switch (aMode) {
case AgcModes::kAgcDefault:
mode = kDefaultAgcMode;
break;
case AgcModes::kAgcUnchanged:
mode = mAudioProcessing->gain_control()->mode();
break;
case AgcModes::kAgcFixedDigital:
mode = GainControl::Mode::kFixedDigital;
break;
case AgcModes::kAgcAdaptiveAnalog:
mode = GainControl::Mode::kAdaptiveAnalog;
break;
case AgcModes::kAgcAdaptiveDigital:
mode = GainControl::Mode::kAdaptiveDigital;
break;
default:
MOZ_ASSERT_UNREACHABLE("Bad pref set in all.js or in about:config"
" for the auto gain.");
// This is a good fallback, it works regardless of the platform.
mode = GainControl::Mode::kAdaptiveDigital;
break;
}
HANDLE_APM_ERROR(mAudioProcessing->gain_control()->set_mode(mode));
HANDLE_APM_ERROR(mAudioProcessing->gain_control()->Enable(aEnable));
}
void
MediaEngineWebRTCMicrophoneSource::UpdateNSSettingsIfNeeded(bool aEnable, NsModes aMode)
{
NoiseSuppression::Level nsLevel;
switch (aMode) {
case NsModes::kNsDefault:
nsLevel = kDefaultNsMode;
break;
case NsModes::kNsUnchanged:
nsLevel = mAudioProcessing->noise_suppression()->level();
break;
case NsModes::kNsConference:
nsLevel = NoiseSuppression::kHigh;
break;
case NsModes::kNsLowSuppression:
nsLevel = NoiseSuppression::kLow;
break;
case NsModes::kNsModerateSuppression:
nsLevel = NoiseSuppression::kModerate;
break;
case NsModes::kNsHighSuppression:
nsLevel = NoiseSuppression::kHigh;
break;
case NsModes::kNsVeryHighSuppression:
nsLevel = NoiseSuppression::kVeryHigh;
break;
default:
MOZ_ASSERT_UNREACHABLE("Bad pref set in all.js or in about:config"
" for the noise suppression.");
// Pick something sensible as a faillback in release.
nsLevel = NoiseSuppression::kModerate;
}
HANDLE_APM_ERROR(mAudioProcessing->noise_suppression()->set_level(nsLevel));
HANDLE_APM_ERROR(mAudioProcessing->noise_suppression()->Enable(aEnable));
}
#undef HANDLE_APM_ERROR
nsresult
MediaEngineWebRTCMicrophoneSource::UpdateSingleSource(
const AllocationHandle* aHandle,
@ -318,12 +444,7 @@ MediaEngineWebRTCMicrophoneSource::UpdateSingleSource(
switch (mState) {
case kReleased:
MOZ_ASSERT(aHandle);
if (sChannelsOpen == 0) {
if (!InitEngine()) {
LOG(("Audio engine is not initalized"));
return NS_ERROR_FAILURE;
}
} else {
if (sChannelsOpen != 0) {
// Until we fix (or wallpaper) support for multiple mic input
// (Bug 1238038) fail allocation for a second device
return NS_ERROR_FAILURE;
@ -355,19 +476,19 @@ MediaEngineWebRTCMicrophoneSource::UpdateSingleSource(
if (prefs.mChannels != mLastPrefs.mChannels) {
MOZ_ASSERT(mSources.Length() > 0);
// If the channel count changed, tell the MSG to open a new driver with
// the correct channel count.
auto& source = mSources.LastElement();
mAudioInput->SetUserChannelCount(prefs.mChannels);
// Get validated number of channel
uint32_t channelCount = 0;
mAudioInput->GetChannelCount(channelCount);
MOZ_ASSERT(channelCount > 0 && mLastPrefs.mChannels > 0);
// Check if new validated channels is the same as previous
if (static_cast<uint32_t>(mLastPrefs.mChannels) != channelCount &&
if (mLastPrefs.mChannels != prefs.mChannels &&
!source->OpenNewAudioCallbackDriver(mListener)) {
MOZ_LOG(GetMediaManagerLog(), LogLevel::Error, ("Could not open a new AudioCallbackDriver for input"));
return NS_ERROR_FAILURE;
}
// Update settings
prefs.mChannels = channelCount;
}
if (MOZ_LOG_TEST(GetMediaManagerLog(), LogLevel::Debug)) {
@ -386,49 +507,23 @@ MediaEngineWebRTCMicrophoneSource::UpdateSingleSource(
}
if (sChannelsOpen > 0) {
int error;
UpdateAGCSettingsIfNeeded(prefs.mAgcOn, static_cast<AgcModes>(prefs.mAgc));
UpdateNSSettingsIfNeeded(prefs.mNoiseOn, static_cast<NsModes>(prefs.mNoise));
UpdateAECSettingsIfNeeded(prefs.mAecOn, static_cast<EcModes>(prefs.mAec));
error = mVoEProcessing->SetEcStatus(prefs.mAecOn, (webrtc::EcModes)prefs.mAec);
if (error) {
LOG(("%s Error setting Echo Status: %d ",__FUNCTION__, error));
// Overhead of capturing all the time is very low (<0.1% of an audio only call)
if (prefs.mAecOn) {
error = mVoEProcessing->SetEcMetricsStatus(true);
if (error) {
LOG(("%s Error setting Echo Metrics: %d ",__FUNCTION__, error));
}
}
}
error = mVoEProcessing->SetAgcStatus(prefs.mAgcOn, (webrtc::AgcModes)prefs.mAgc);
if (error) {
LOG(("%s Error setting AGC Status: %d ",__FUNCTION__, error));
}
error = mVoEProcessing->SetNsStatus(prefs.mNoiseOn, (webrtc::NsModes)prefs.mNoise);
if (error) {
LOG(("%s Error setting NoiseSuppression Status: %d ",__FUNCTION__, error));
}
}
// we don't allow switching from non-fast-path to fast-path on the fly yet
if (mState != kStarted) {
mSkipProcessing = !(prefs.mAecOn || prefs.mAgcOn || prefs.mNoiseOn);
if (mSkipProcessing) {
mSampleFrequency = MediaEngine::USE_GRAPH_RATE;
} else {
// make sure we route a copy of the mixed audio output of this MSG to the
// AEC
if (!mAudioOutputObserver) {
mAudioOutputObserver = new AudioOutputObserver();
}
}
webrtc::Config config;
config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(mExtendedFilter));
config.Set<webrtc::DelayAgnostic>(new webrtc::DelayAgnostic(mDelayAgnostic));
mAudioProcessing->SetExtraOptions(config);
}
SetLastPrefs(prefs);
return NS_OK;
}
#undef HANDLE_APM_ERROR
void
MediaEngineWebRTCMicrophoneSource::SetLastPrefs(
const MediaEnginePrefs& aPrefs)
MediaEngineWebRTCMicrophoneSource::SetLastPrefs(const MediaEnginePrefs& aPrefs)
{
mLastPrefs = aPrefs;
@ -439,11 +534,35 @@ MediaEngineWebRTCMicrophoneSource::SetLastPrefs(
that->mSettings->mAutoGainControl.Value() = aPrefs.mAgcOn;
that->mSettings->mNoiseSuppression.Value() = aPrefs.mNoiseOn;
that->mSettings->mChannelCount.Value() = aPrefs.mChannels;
class Message : public ControlMessage {
public:
Message(MediaEngineWebRTCMicrophoneSource* aSource,
bool aPassThrough)
: ControlMessage(nullptr)
, mMicrophoneSource(aSource)
, mPassThrough(aPassThrough)
{}
void Run() override
{
mMicrophoneSource->SetPassThrough(mPassThrough);
}
protected:
RefPtr<MediaEngineWebRTCMicrophoneSource> mMicrophoneSource;
bool mPassThrough;
};
bool passThrough = !(aPrefs.mAecOn || aPrefs.mAgcOn || aPrefs.mNoiseOn);
if (!that->mSources.IsEmpty()) {
that->mSources[0]->GraphImpl()->AppendMessage(MakeUnique<Message>(that, passThrough));
}
return NS_OK;
}));
}
nsresult
MediaEngineWebRTCMicrophoneSource::Deallocate(AllocationHandle* aHandle)
{
@ -493,7 +612,7 @@ MediaEngineWebRTCMicrophoneSource::Start(SourceMediaStream *aStream,
if (mSampleFrequency == MediaEngine::USE_GRAPH_RATE) {
mSampleFrequency = aStream->GraphRate();
}
aStream->AddAudioTrack(aID, mSampleFrequency, 0, segment, SourceMediaStream::ADDTRACK_QUEUED);
aStream->AddAudioTrack(aID, aStream->GraphRate(), 0, segment, SourceMediaStream::ADDTRACK_QUEUED);
// XXX Make this based on the pref.
aStream->RegisterForAudioMixing();
@ -514,24 +633,10 @@ MediaEngineWebRTCMicrophoneSource::Start(SourceMediaStream *aStream,
// Make sure logger starts before capture
AsyncLatencyLogger::Get(true);
if (mAudioOutputObserver) {
mAudioOutputObserver->Clear();
}
mAudioOutputObserver->Clear();
if (mVoEBase->StartReceive(mChannel)) {
return NS_ERROR_FAILURE;
}
// Must be *before* StartSend() so it will notice we selected external input (full_duplex)
mAudioInput->StartRecording(aStream, mListener);
if (mVoEBase->StartSend(mChannel)) {
return NS_ERROR_FAILURE;
}
// Attach external media processor, so this::Process will be called.
mVoERender->RegisterExternalMediaProcessing(mChannel, webrtc::kRecordingPerChannel, *this);
return NS_OK;
}
@ -560,9 +665,6 @@ MediaEngineWebRTCMicrophoneSource::Stop(SourceMediaStream *aSource, TrackID aID)
if (mState != kStarted) {
return NS_ERROR_FAILURE;
}
if (!mVoEBase) {
return NS_ERROR_FAILURE;
}
mState = kStopped;
}
@ -574,14 +676,6 @@ MediaEngineWebRTCMicrophoneSource::Stop(SourceMediaStream *aSource, TrackID aID)
mAudioInput->StopRecording(aSource);
mVoERender->DeRegisterExternalMediaProcessing(mChannel, webrtc::kRecordingPerChannel);
if (mVoEBase->StopSend(mChannel)) {
return NS_ERROR_FAILURE;
}
if (mVoEBase->StopReceive(mChannel)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
@ -603,12 +697,13 @@ MediaEngineWebRTCMicrophoneSource::NotifyOutputData(MediaStreamGraph* aGraph,
TrackRate aRate,
uint32_t aChannels)
{
if (mAudioOutputObserver) {
if (!PassThrough()) {
mAudioOutputObserver->InsertFarEnd(aBuffer, aFrames, false,
aRate, aChannels);
aRate, aChannels);
}
}
// Only called if we're not in passthrough mode
void
MediaEngineWebRTCMicrophoneSource::PacketizeAndProcess(MediaStreamGraph* aGraph,
const AudioDataValue* aBuffer,
@ -616,15 +711,131 @@ MediaEngineWebRTCMicrophoneSource::PacketizeAndProcess(MediaStreamGraph* aGraph,
TrackRate aRate,
uint32_t aChannels)
{
// This will call Process() with data coming out of the AEC/NS/AGC/etc chain
MOZ_ASSERT(!PassThrough(), "This should be bypassed when in PassThrough mode.");
size_t offset = 0;
if (!mPacketizer ||
mPacketizer->PacketSize() != aRate/100u ||
mPacketizer->Channels() != aChannels) {
// It's ok to drop the audio still in the packetizer here.
mPacketizer =
new AudioPacketizer<AudioDataValue, int16_t>(aRate/100, aChannels);
new AudioPacketizer<AudioDataValue, float>(aRate/100, aChannels);
}
// On initial capture, throw away all far-end data except the most recent sample
// since it's already irrelevant and we want to keep avoid confusing the AEC far-end
// input code with "old" audio.
if (!mStarted) {
mStarted = true;
while (mAudioOutputObserver->Size() > 1) {
free(mAudioOutputObserver->Pop()); // only call if size() > 0
}
}
// Feed the far-end audio data (speakers) to the feedback input of the AEC.
while (mAudioOutputObserver->Size() > 0) {
// Bug 1414837: This will call `free()`, and we should remove it.
// Pop gives ownership.
nsAutoPtr<FarEndAudioChunk> buffer(mAudioOutputObserver->Pop()); // only call if size() > 0
if (!buffer) {
continue;
}
AudioDataValue* packetDataPointer = buffer->mData;
AutoTArray<AudioDataValue*, MAX_CHANNELS> deinterleavedPacketDataChannelPointers;
AudioDataValue* interleavedFarend = nullptr;
uint32_t channelCountFarend = 0;
uint32_t framesPerPacketFarend = 0;
// Downmix from aChannels to MAX_CHANNELS if needed
if (mAudioOutputObserver->PlayoutChannels() > MAX_CHANNELS) {
AudioConverter converter(AudioConfig(aChannels, 0, AudioConfig::FORMAT_DEFAULT),
AudioConfig(MAX_CHANNELS, 0, AudioConfig::FORMAT_DEFAULT));
framesPerPacketFarend =
buffer->mSamples;
framesPerPacketFarend =
converter.Process(mInputDownmixBuffer,
packetDataPointer,
framesPerPacketFarend);
interleavedFarend = mInputDownmixBuffer.Data();
channelCountFarend = MAX_CHANNELS;
deinterleavedPacketDataChannelPointers.SetLength(MAX_CHANNELS);
} else {
uint32_t outputChannels = mAudioOutputObserver->PlayoutChannels();
interleavedFarend = packetDataPointer;
channelCountFarend = outputChannels;
framesPerPacketFarend = buffer->mSamples;
deinterleavedPacketDataChannelPointers.SetLength(outputChannels);
}
MOZ_ASSERT(interleavedFarend &&
(channelCountFarend == 1 || channelCountFarend == 2) &&
framesPerPacketFarend);
offset = 0;
for (size_t i = 0; i < deinterleavedPacketDataChannelPointers.Length(); ++i) {
deinterleavedPacketDataChannelPointers[i] = packetDataPointer + offset;
offset += framesPerPacketFarend;
}
// deinterleave back into the FarEndAudioChunk buffer to save an alloc.
// There is enough room because either there is the same number of
// channels/frames or we've just downmixed.
Deinterleave(interleavedFarend,
framesPerPacketFarend,
channelCountFarend,
deinterleavedPacketDataChannelPointers.Elements());
// Having the same config for input and output means we potentially save
// some CPU. We won't need the output here, the API forces us to set a
// valid pointer with enough space.
StreamConfig inputConfig(mAudioOutputObserver->PlayoutFrequency(),
channelCountFarend,
false /* we don't use typing detection*/);
StreamConfig outputConfig = inputConfig;
// Prepare a channel pointers array, with enough storage for the
// frames.
//
// If this is a platform that uses s16 for audio input and output,
// convert to floats, the APM API we use only accepts floats.
float* inputData = nullptr;
#ifdef MOZ_SAMPLE_TYPE_S16
// Convert to floats, use mInputBuffer for this.
size_t sampleCount = framesPerPacketFarend * channelCountFarend;
if (mInputBuffer.Length() < sampleCount) {
mInputBuffer.SetLength(sampleCount);
}
ConvertAudioSamples(buffer->mData, mInputBuffer.Data(), sampleCount);
inputData = mInputBuffer.Data();
#else // MOZ_SAMPLE_TYPE_F32
inputData = buffer->mData;
#endif
AutoTArray<float*, MAX_CHANNELS> channelsPointers;
channelsPointers.SetLength(channelCountFarend);
offset = 0;
for (size_t i = 0; i < channelsPointers.Length(); ++i) {
channelsPointers[i] = inputData + offset;
offset += framesPerPacketFarend;
}
// Passing the same pointers here saves a copy inside this function.
int err =
mAudioProcessing->ProcessReverseStream(channelsPointers.Elements(),
inputConfig,
outputConfig,
channelsPointers.Elements());
if (err) {
MOZ_LOG(GetMediaManagerLog(), LogLevel::Error,
("error in audio ProcessReverseStream(): %d", err));
return;
}
}
// Packetize our input data into 10ms chunks, deinterleave into planar channel
// buffers, process, and append to the right MediaStreamTrack.
mPacketizer->Input(aBuffer, static_cast<uint32_t>(aFrames));
while (mPacketizer->PacketsAvailable()) {
@ -632,19 +843,73 @@ MediaEngineWebRTCMicrophoneSource::PacketizeAndProcess(MediaStreamGraph* aGraph,
mPacketizer->Channels();
if (mInputBuffer.Length() < samplesPerPacket) {
mInputBuffer.SetLength(samplesPerPacket);
mDeinterleavedBuffer.SetLength(samplesPerPacket);
}
int16_t* packet = mInputBuffer.Elements();
float* packet = mInputBuffer.Data();
mPacketizer->Output(packet);
if (aChannels > MAX_CHANNELS) {
AudioConverter converter(AudioConfig(aChannels, 0, AudioConfig::FORMAT_S16),
AudioConfig(MAX_CHANNELS, 0, AudioConfig::FORMAT_S16));
converter.Process(mInputDownmixBuffer, packet, mPacketizer->PacketSize());
mVoERender->ExternalRecordingInsertData(mInputDownmixBuffer.Data(),
mPacketizer->PacketSize() * MAX_CHANNELS,
aRate, 0);
} else {
mVoERender->ExternalRecordingInsertData(packet, samplesPerPacket, aRate, 0);
// Deinterleave the input data
// Prepare an array pointing to deinterleaved channels.
AutoTArray<float*, 8> deinterleavedPacketizedInputDataChannelPointers;
deinterleavedPacketizedInputDataChannelPointers.SetLength(aChannels);
offset = 0;
for (size_t i = 0; i < deinterleavedPacketizedInputDataChannelPointers.Length(); ++i) {
deinterleavedPacketizedInputDataChannelPointers[i] = mDeinterleavedBuffer.Data() + offset;
offset += aFrames;
}
// Deinterleave to mInputBuffer, pointed to by inputBufferChannelPointers.
Deinterleave(packet, mPacketizer->PacketSize(), aChannels,
deinterleavedPacketizedInputDataChannelPointers.Elements());
StreamConfig inputConfig(aRate,
aChannels,
false /* we don't use typing detection*/);
StreamConfig outputConfig = inputConfig;
// Bug 1404965: Get the right delay here, it saves some work down the line.
mAudioProcessing->set_stream_delay_ms(0);
// Bug 1414837: find a way to not allocate here.
RefPtr<SharedBuffer> buffer =
SharedBuffer::Create(mPacketizer->PacketSize() * aChannels * sizeof(float));
AudioSegment segment;
// Prepare channel pointers to the SharedBuffer created above.
AutoTArray<float*, 8> processedOutputChannelPointers;
AutoTArray<const float*, 8> processedOutputChannelPointersConst;
processedOutputChannelPointers.SetLength(aChannels);
processedOutputChannelPointersConst.SetLength(aChannels);
offset = 0;
for (size_t i = 0; i < processedOutputChannelPointers.Length(); ++i) {
processedOutputChannelPointers[i] = static_cast<float*>(buffer->Data()) + offset;
processedOutputChannelPointersConst[i] = static_cast<float*>(buffer->Data()) + offset;
offset += aFrames;
}
mAudioProcessing->ProcessStream(deinterleavedPacketizedInputDataChannelPointers.Elements(),
inputConfig,
outputConfig,
processedOutputChannelPointers.Elements());
MonitorAutoLock lock(mMonitor);
if (mState != kStarted)
return;
for (size_t i = 0; i < mSources.Length(); ++i) {
if (!mSources[i]) { // why ?!
continue;
}
// We already have planar audio data of the right format. Insert into the
// MSG.
MOZ_ASSERT(processedOutputChannelPointers.Length() == aChannels);
RefPtr<SharedBuffer> other = buffer;
segment.AppendFrames(other.forget(),
processedOutputChannelPointersConst,
mPacketizer->PacketSize(),
mPrincipalHandles[i]);
mSources[i]->AppendToTrack(mTrackID, &segment);
}
}
}
@ -671,7 +936,7 @@ MediaEngineWebRTCMicrophoneSource::InsertInGraph(const T* aBuffer,
}
size_t len = mSources.Length();
for (size_t i = 0; i < len; i++) {
for (size_t i = 0; i < len; ++i) {
if (!mSources[i]) {
continue;
}
@ -687,7 +952,7 @@ MediaEngineWebRTCMicrophoneSource::InsertInGraph(const T* aBuffer,
MOZ_ASSERT(aChannels >= 1 && aChannels <= 8,
"Support up to 8 channels");
nsAutoPtr<AudioSegment> segment(new AudioSegment());
AudioSegment segment;
RefPtr<SharedBuffer> buffer =
SharedBuffer::Create(aFrames * aChannels * sizeof(T));
AutoTArray<const T*, 8> channels;
@ -713,11 +978,11 @@ MediaEngineWebRTCMicrophoneSource::InsertInGraph(const T* aBuffer,
}
MOZ_ASSERT(aChannels == channels.Length());
segment->AppendFrames(buffer.forget(), channels, aFrames,
segment.AppendFrames(buffer.forget(), channels, aFrames,
mPrincipalHandles[i]);
segment->GetStartTime(insertTime);
segment.GetStartTime(insertTime);
mSources[i]->AppendToTrack(mTrackID, segment);
mSources[i]->AppendToTrack(mTrackID, &segment);
}
}
@ -741,164 +1006,54 @@ MediaEngineWebRTCMicrophoneSource::NotifyInputData(MediaStreamGraph* aGraph,
#define ResetProcessingIfNeeded(_processing) \
do { \
webrtc::_processing##Modes mode; \
int rv = mVoEProcessing->Get##_processing##Status(enabled, mode); \
if (rv) { \
NS_WARNING("Could not get the status of the " \
#_processing " on device change."); \
return; \
} \
bool enabled = mAudioProcessing->_processing()->is_enabled(); \
\
if (enabled) { \
rv = mVoEProcessing->Set##_processing##Status(!enabled); \
int rv = mAudioProcessing->_processing()->Enable(!enabled); \
if (rv) { \
NS_WARNING("Could not reset the status of the " \
#_processing " on device change."); \
return; \
} \
rv = mAudioProcessing->_processing()->Enable(enabled); \
if (rv) { \
NS_WARNING("Could not reset the status of the " \
#_processing " on device change."); \
return; \
} \
\
rv = mVoEProcessing->Set##_processing##Status(enabled); \
if (rv) { \
NS_WARNING("Could not reset the status of the " \
#_processing " on device change."); \
return; \
} \
} \
} while(0)
void
MediaEngineWebRTCMicrophoneSource::DeviceChanged() {
// Reset some processing
bool enabled;
ResetProcessingIfNeeded(Agc);
ResetProcessingIfNeeded(Ec);
ResetProcessingIfNeeded(Ns);
ResetProcessingIfNeeded(gain_control);
ResetProcessingIfNeeded(echo_cancellation);
ResetProcessingIfNeeded(noise_suppression);
}
bool
MediaEngineWebRTCMicrophoneSource::InitEngine()
{
MOZ_ASSERT(!mVoEBase);
mVoEBase = webrtc::VoEBase::GetInterface(mVoiceEngine);
mVoEBase->Init();
webrtc::Config config;
config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(mExtendedFilter));
config.Set<webrtc::DelayAgnostic>(new webrtc::DelayAgnostic(mDelayAgnostic));
mVoEBase->audio_processing()->SetExtraOptions(config);
mVoERender = webrtc::VoEExternalMedia::GetInterface(mVoiceEngine);
if (mVoERender) {
mVoENetwork = webrtc::VoENetwork::GetInterface(mVoiceEngine);
if (mVoENetwork) {
mVoEProcessing = webrtc::VoEAudioProcessing::GetInterface(mVoiceEngine);
if (mVoEProcessing) {
mNullTransport = new NullTransport();
return true;
}
}
}
DeInitEngine();
return false;
}
// This shuts down the engine when no channel is open
void
MediaEngineWebRTCMicrophoneSource::DeInitEngine()
{
if (mVoEBase) {
mVoEBase->Terminate();
delete mNullTransport;
mNullTransport = nullptr;
mVoEProcessing = nullptr;
mVoENetwork = nullptr;
mVoERender = nullptr;
mVoEBase = nullptr;
}
}
// This shuts down the engine when no channel is open.
// mState records if a channel is allocated (slightly redundantly to mChannel)
void
MediaEngineWebRTCMicrophoneSource::FreeChannel()
{
if (mState != kReleased) {
if (mChannel != -1) {
MOZ_ASSERT(mVoENetwork && mVoEBase);
if (mVoENetwork) {
mVoENetwork->DeRegisterExternalTransport(mChannel);
}
if (mVoEBase) {
mVoEBase->DeleteChannel(mChannel);
}
mChannel = -1;
}
mState = kReleased;
MOZ_ASSERT(sChannelsOpen > 0);
if (--sChannelsOpen == 0) {
DeInitEngine();
}
--sChannelsOpen;
}
}
bool
MediaEngineWebRTCMicrophoneSource::AllocChannel()
{
MOZ_ASSERT(mVoEBase);
mSampleFrequency = MediaEngine::USE_GRAPH_RATE;
LOG(("%s: sampling rate %u", __FUNCTION__, mSampleFrequency));
mChannel = mVoEBase->CreateChannel();
if (mChannel >= 0) {
if (!mVoENetwork->RegisterExternalTransport(mChannel, *mNullTransport)) {
mSampleFrequency = MediaEngine::DEFAULT_SAMPLE_RATE;
LOG(("%s: sampling rate %u", __FUNCTION__, mSampleFrequency));
// Check for availability.
if (!mAudioInput->SetRecordingDevice(mCapIndex)) {
// Because of the permission mechanism of B2G, we need to skip the status
// check here.
bool avail = false;
mAudioInput->GetRecordingDeviceStatus(avail);
if (!avail) {
if (sChannelsOpen == 0) {
DeInitEngine();
}
return false;
}
// Set "codec" to PCM, 32kHz on device's channels
ScopedCustomReleasePtr<webrtc::VoECodec> ptrVoECodec(webrtc::VoECodec::GetInterface(mVoiceEngine));
if (ptrVoECodec) {
webrtc::CodecInst codec;
strcpy(codec.plname, ENCODING);
codec.channels = CHANNELS;
uint32_t maxChannels = 0;
if (mAudioInput->GetMaxAvailableChannels(maxChannels) == 0) {
MOZ_ASSERT(maxChannels);
codec.channels = std::min<uint32_t>(maxChannels, MAX_CHANNELS);
}
MOZ_ASSERT(mSampleFrequency == 16000 || mSampleFrequency == 32000);
codec.rate = SAMPLE_RATE(mSampleFrequency);
codec.plfreq = mSampleFrequency;
codec.pacsize = SAMPLE_LENGTH(mSampleFrequency);
codec.pltype = 0; // Default payload type
if (!ptrVoECodec->SetSendCodec(mChannel, codec)) {
mState = kAllocated;
sChannelsOpen++;
return true;
}
}
}
}
}
mVoEBase->DeleteChannel(mChannel);
mChannel = -1;
if (sChannelsOpen == 0) {
DeInitEngine();
}
return false;
mState = kAllocated;
sChannelsOpen++;
return true;
}
void
@ -936,46 +1091,6 @@ MediaEngineWebRTCMicrophoneSource::Shutdown()
Deallocate(mRegisteredHandles[0].get());
}
MOZ_ASSERT(mState == kReleased);
mAudioInput = nullptr;
}
typedef int16_t sample;
void
MediaEngineWebRTCMicrophoneSource::Process(int channel,
webrtc::ProcessingTypes type,
sample *audio10ms, size_t length,
int samplingFreq, bool isStereo)
{
MOZ_ASSERT(!PassThrough(), "This should be bypassed when in PassThrough mode.");
// On initial capture, throw away all far-end data except the most recent sample
// since it's already irrelevant and we want to keep avoid confusing the AEC far-end
// input code with "old" audio.
if (!mStarted) {
mStarted = true;
while (mAudioOutputObserver->Size() > 1) {
free(mAudioOutputObserver->Pop()); // only call if size() > 0
}
}
while (mAudioOutputObserver->Size() > 0) {
FarEndAudioChunk *buffer = mAudioOutputObserver->Pop(); // only call if size() > 0
if (buffer) {
int length = buffer->mSamples;
int res = mVoERender->ExternalPlayoutData(buffer->mData,
mAudioOutputObserver->PlayoutFrequency(),
mAudioOutputObserver->PlayoutChannels(),
length);
free(buffer);
if (res == -1) {
return;
}
}
}
uint32_t channels = isStereo ? 2 : 1;
InsertInGraph<int16_t>(audio10ms, length, channels);
}
void

View File

@ -39,11 +39,12 @@ if CONFIG['MOZ_WEBRTC']:
'MediaEngineWebRTC.cpp',
]
LOCAL_INCLUDES += [
'..',
'/dom/base',
'/media/libyuv/libyuv/include',
'/media/webrtc/signaling/src/common',
'/media/webrtc/signaling/src/common/browser_logging',
'/media/webrtc/trunk',
'/media/webrtc/trunk'
]
XPIDL_SOURCES += [

View File

@ -141,6 +141,17 @@ PerformanceMainThread::AddEntry(nsIHttpChannel* channel,
originalURI->GetSpec(name);
NS_ConvertUTF8toUTF16 entryName(name);
bool reportTiming = true;
timedChannel->GetReportResourceTiming(&reportTiming);
if (!reportTiming) {
#ifdef DEBUG_jwatt
NS_WARNING(
nsPrintfCString("Not reporting CORS resource: %s", name.get()).get());
#endif
return;
}
// The nsITimedChannel argument will be used to gather all the timings.
// The nsIHttpChannel argument will be used to check if any cross-origin
// redirects occurred.

View File

@ -52,6 +52,23 @@ PerformanceTiming::PerformanceTiming(Performance* aPerformance,
mReportCrossOriginRedirect = mTimingAllowed && redirectsPassCheck;
}
mSecureConnection = false;
nsCOMPtr<nsIURI> uri;
if (aHttpChannel) {
aHttpChannel->GetURI(getter_AddRefs(uri));
} else {
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
if (httpChannel) {
httpChannel->GetURI(getter_AddRefs(uri));
}
}
if (uri) {
nsresult rv = uri->SchemeIs("https", &mSecureConnection);
if (NS_FAILED(rv)) {
mSecureConnection = false;
}
}
InitializeTimingInfo(aChannel);
// Non-null aHttpChannel implies that this PerformanceTiming object is being
@ -118,7 +135,8 @@ PerformanceTiming::InitializeTimingInfo(nsITimedChannel* aChannel)
mConnectStart = *clampTime;
}
if (!mSecureConnectionStart.IsNull() && mSecureConnectionStart < *clampTime) {
if (mSecureConnection && !mSecureConnectionStart.IsNull() &&
mSecureConnectionStart < *clampTime) {
mSecureConnectionStart = *clampTime;
}
@ -369,8 +387,11 @@ PerformanceTiming::SecureConnectionStartHighRes()
nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime;
}
return mSecureConnectionStart.IsNull() ? mZeroTime
: TimeStampToDOMHighRes(mSecureConnectionStart);
return !mSecureConnection
? 0 // We use 0 here, because mZeroTime is sometimes set to the navigation
// start time.
: (mSecureConnectionStart.IsNull() ? mZeroTime
: TimeStampToDOMHighRes(mSecureConnectionStart));
}
DOMTimeMilliSec

View File

@ -305,6 +305,8 @@ private:
// redirectEnd attributes. It is false if there were no redirects, or if
// any of the responses didn't pass the timing-allow-check
bool mReportCrossOriginRedirect;
bool mSecureConnection;
};
} // namespace dom

View File

@ -266,7 +266,7 @@ var steps = [
performance.measure("test", n);
ok(true, "Measure created from reserved name as starting time: " + n);
} catch (e) {
ok(["redirectStart", "redirectEnd", "unloadEventStart", "unloadEventEnd", "loadEventEnd"].indexOf(n) >= 0,
ok(["redirectStart", "redirectEnd", "unloadEventStart", "unloadEventEnd", "loadEventEnd", "secureConnectionStart"].indexOf(n) >= 0,
"Measure created from reserved name as starting time: " + n + " and threw expected error");
}
};

View File

@ -56,7 +56,7 @@ public:
virtual void GetLinkTarget(nsAString& aTarget) override;
virtual already_AddRefed<nsIURI> GetHrefURI() const override;
virtual EventStates IntrinsicState() const override;
using nsIContent::SetAttr;
using Element::SetAttr;
virtual nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName,
nsAtom* aPrefix, const nsAString& aValue,
nsIPrincipal* aSubjectPrincipal,

View File

@ -44,7 +44,7 @@ public:
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep = true,
bool aNullParent = true) override;
using nsIContent::SetAttr;
using Element::SetAttr;
virtual nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName,
nsAtom* aPrefix, const nsAString& aValue,
nsIPrincipal* aSubjectPrincipal,

View File

View File

@ -0,0 +1,2 @@
@import 'cssC.css';
@import url('http://example.org/tests/dom/tests/mochitest/general/cssC.css');

View File

View File

@ -0,0 +1 @@
@import url('http://example.org/tests/dom/tests/mochitest/general/cross.css');

View File

@ -0,0 +1,191 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="http://mochi.test:8888/tests/SimpleTest/test.css"/>
<!--
This document has the origin http://mochi.test:8888.
The resource timing of any all sub-resources should be reported, except for
any sub-resources of any cross-origin resources that are loaded.
Note that the resource timing of the original cross-origin resource should
itself be reported. The goal here is to not reveal which sub-resources are
loaded by any cross-origin resources (the fact that any given cross-origin
resource itself is loaded is known to the original origin).
In the comments below, the following annotations apply:
[r] - this resource should be reported by performance.getEntries()
[!] - this resource should be excluded from performance.getEntries()
-->
<!-- 1. [r] http://mochi.test:8888 , generateCss.sjs?A
[r] http://mochi.test:8888 , generateCss.sjs?B
-->
<link rel="stylesheet" type="text/css" href="generateCss.sjs?A"/>
<!-- 2. [r] http://example.com , generateCss.sjs?C
[!] http://example.com , generateCss.sjs?D
-->
<link rel="stylesheet" type="text/css" href="http://example.com/tests/dom/tests/mochitest/general/generateCss.sjs?C"/>
<!-- 3. [r] http://example.com , generateCss.sjs?E
[!] http://mochi.test:8888 , generateCss.sjs?F
-->
<link rel="stylesheet" type="text/css" href="http://example.com/tests/dom/tests/mochitest/general/generateCss.sjs?E"/>
<!-- 4. [r] http://mochi.test:8888 , generateCss.sjs?G
[r] http://mochi.test:8888 , generateCss.sjs?H
[r] http://example.com , generateCss.sjs?I
[!] http://example.com , generateCss.sjs?J
[r] http://example.org , generateCss.sjs?K
[!] http://example.org , generateCss.sjs?L
[!] http://example.org , generateCss.sjs?M
-->
<link rel="stylesheet" type="text/css" href="generateCss.sjs?G"/>
<!-- 5. background-image: -moz-image-rect()
[r] http://example.net , generateCss.sjs?N
[!] http://example.net , blue.png
-->
<link rel="stylesheet" type="text/css" href="http://example.net/tests/dom/tests/mochitest/general/generateCss.sjs?N"/>
<!-- 6. background-image: url()
[r] http://example.net , generateCss.sjs?O
[!] http://example.net , red.png
-->
<link rel="stylesheet" type="text/css" href="http://example.net/tests/dom/tests/mochitest/general/generateCss.sjs?O"/>
<!-- 7. @font-face
[r] http://example.net , generateCss.sjs?P
[!] http://example.net , Ahem.tff
-->
<link rel="stylesheet" type="text/css" href="http://example.net/tests/dom/tests/mochitest/general/generateCss.sjs?P"/>
<!-- 8. cursor: url()
[r] http://example.net , generateCss.sjs?Q
[!] http://example.net , over.png
-->
<link rel="stylesheet" type="text/css" href="http://example.net/tests/dom/tests/mochitest/general/generateCss.sjs?Q"/>
<!-- 9. mask: url(res.svg#mask)
TODO: I don't think this is working properly. Must fix.
[r] http://example.net , generateCss.sjs?R
[!] http://example.net , file_use_counter_svg_fill_pattern_data.svg
-->
<link rel="stylesheet" type="text/css" href="http://example.net/tests/dom/tests/mochitest/general/generateCss.sjs?R"/>
<!-- TODO: add test that we _do_ include subresources if the cross-origin sheet was fetched via CORS -->
<script type="application/javascript">
function ok(cond, message) {
window.opener.ok(cond, message)
}
function is(received, expected, message) {
window.opener.is(received, expected, message);
}
function isnot(received, notExpected, message) {
window.opener.isnot(received, notExpected, message);
}
var allResources = {
"http://mochi.test:8888/tests/SimpleTest/test.css" : "link",
// 1
"http://mochi.test:8888/tests/dom/tests/mochitest/general/generateCss.sjs?A" : "link",
"http://mochi.test:8888/tests/dom/tests/mochitest/general/generateCss.sjs?B" : "css",
// 2
"http://example.com/tests/dom/tests/mochitest/general/generateCss.sjs?C" : "link",
// 3
"http://example.com/tests/dom/tests/mochitest/general/generateCss.sjs?E" : "link",
// 4
"http://mochi.test:8888/tests/dom/tests/mochitest/general/generateCss.sjs?G" : "link",
"http://mochi.test:8888/tests/dom/tests/mochitest/general/generateCss.sjs?H" : "css",
"http://example.com/tests/dom/tests/mochitest/general/generateCss.sjs?I" : "css",
"http://example.org/tests/dom/tests/mochitest/general/generateCss.sjs?K" : "css",
// 5
"http://example.net/tests/dom/tests/mochitest/general/generateCss.sjs?N" : "link",
// 6
"http://example.net/tests/dom/tests/mochitest/general/generateCss.sjs?O" : "link",
// 7
"http://example.net/tests/dom/tests/mochitest/general/generateCss.sjs?P" : "link",
// 8
"http://example.net/tests/dom/tests/mochitest/general/generateCss.sjs?Q" : "link",
// 9
"http://example.net/tests/dom/tests/mochitest/general/generateCss.sjs?R" : "link",
};
window.onload = function() {
let entries = performance.getEntries();
// The entries.slice() to drop first 'document' item.
for (let entry of entries.slice(1)) {
//dump(entry.name + " || "+ entry.initiatorType+ "\n");
if (!(entry.name in allResources)) {
if (entry.name.substr(-4) == ".ttf") {
// TODO: fix hiding of font files
continue;
}
ok(false, "Did not expect timing for resource: " + entry.name);
continue;
}
let resType = allResources[entry.name];
is(entry.initiatorType, resType,
"Expected matching initiatorType for: " + entry.name);
delete allResources[entry.name];
}
for (let res in allResources) {
ok(false, "Expect timing for resource: " + res);
}
window.opener.finishTests();
}
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1180145"
title="Resource timing NO-CORS CSS">
Bug #1180145 - Resource Timing NO-CORS CSS
</a>
<p id="display"></p>
<div id="content">
</div>
<div class="c1"> BLUE </div>
<div class="c2"> RED </div>
<div class="c3"> Font </div>
<div class="c4"> CURSOR </div>
<div class="c5"> <img id="image" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="> </div>
<div class="c6"> </div>
</body>
</html>

View File

@ -0,0 +1,42 @@
function handleRequest(request, response) {
response.setHeader("Content-Type", "text/css", false);
response.write(gResponses[request.queryString]);
}
let gResponses = {
// 1
"A": "@import 'generateCss.sjs?B';",
"B": "",
// 2
"C": "@import 'generateCss.sjs?D';",
"D": "",
// 3
"E": "@import 'generateCss.sjs?F';",
"F": "",
// 4
"G": "@import 'generateCss.sjs?H'; @import 'http://example.org/tests/dom/tests/mochitest/general/generateCss.sjs?K';",
"H": "@import 'http://example.com/tests/dom/tests/mochitest/general/generateCss.sjs?I';",
"I": "@import 'generateCss.sjs?J",
"J": "",
"K": "@import 'generateCss.sjs?L';",
"L": "@import 'generateCss.sjs?M",
"M": "",
// 5
"N": ".c1 { background-image: -moz-image-rect(url('/image/test/mochitest/blue.png'), 0, 0, 200, 200);}",
// 6
"O": ".c2 { background-image: url('/image/test/mochitest/red.png');}",
// 7
"P": "@font-face { font-family: Ahem; src: url('/tests/dom/base/test/Ahem.ttf'); } .c3 { font-family: Ahem; font-size: 20px; }",
// 8
"Q": ".c4 { cursor: url('/image/test/mochitest/over.png') 2 2, auto; } ",
// 9
"R": "#image { mask: url('/tests/dom/base/test/file_use_counter_svg_fill_pattern_data.svg'); }",
};

View File

@ -0,0 +1,3 @@
@import 'emptyCssFile2.css';
@import url('http://example.org/tests/dom/tests/mochitest/general/emptyCssFile2.css');

View File

@ -9,6 +9,8 @@ support-files =
file_interfaces.xml
file_moving_nodeList.html
file_moving_xhr.html
file_resource_timing_nocors.html
generateCss.sjs
historyframes.html
start_historyframe.html
url1_historyframe.html
@ -56,7 +58,9 @@ support-files =
!/image/test/mochitest/damon.jpg
!/image/test/mochitest/over.png
!/image/test/mochitest/red.png
!/dom/base/test/Ahem.ttf
!/dom/base/test/file_empty.html
!/dom/base/test/file_use_counter_svg_fill_pattern_data.svg
file_focusrings.html
[test_497898.html]
@ -135,5 +139,6 @@ skip-if = toolkit == 'android' # bug 1230232 - Mouse doesn't select in the same
[test_WebKitCSSMatrix.html]
[test_windowedhistoryframes.html]
[test_windowProperties.html]
[test_resource_timing_nocors.html]
[test_resizeby.html]
skip-if = toolkit == 'android' # Window sizes cannot be controled on android.

View File

@ -66,6 +66,13 @@ function isnot(received, notExpected, message) {
var bufferFullCounter = 0;
const expectedBufferFullEvents = 1;
var allResources = {
"http://mochi.test:8888/tests/SimpleTest/test.css": "link",
"http://mochi.test:8888/tests/image/test/mochitest/blue.png" : "img",
"http://mochi.test:8888/tests/image/test/mochitest/red.png" : "object",
"http://mochi.test:8888/tests/image/test/mochitest/big.png" : "embed",
"http://mochi.test:8888/tests/dom/tests/mochitest/general/resource_timing_iframe.html" : "iframe"};
window.onload = function() {
ok(!!window.performance, "Performance object should exist");
ok(!!window.performance.getEntries, "Performance.getEntries() should exist");
@ -76,8 +83,7 @@ window.onload = function() {
bufferFullCounter += 1;
}
// Here, we should have 5 entries (1 css, 3 png, 1 html) since the image was loaded.
is(window.performance.getEntriesByType("resource").length, 5, "Performance.getEntriesByType() returned wrong number of entries.");
is(window.performance.getEntriesByType("resource").length, Object.keys(allResources).length, "Performance.getEntriesByType() returned wrong number of entries.");
checkStringify(window.performance.getEntriesByType("resource")[0]);
@ -106,11 +112,11 @@ window.onload = function() {
checkEntries(window.performance.getEntriesByType("resource"));
window.performance.setResourceTimingBufferSize(1);
is(window.performance.getEntriesByType("resource").length, 5, "No entries should be " +
is(window.performance.getEntriesByType("resource").length, Object.keys(allResources).length, "No entries should be " +
"removed when setResourceTimingBufferSize is called.");
window.performance.setResourceTimingBufferSize(4);
is(window.performance.getEntriesByType("resource").length, 5, "No entries should be " +
is(window.performance.getEntriesByType("resource").length, Object.keys(allResources).length, "No entries should be " +
"removed when setResourceTimingBufferSize is called.");
window.performance.setResourceTimingBufferSize(1);
@ -183,13 +189,6 @@ function checkEntries(anEntryList) {
// Check that the entries have the expected initiator type. We can't check
// the order (the order might depend on the platform the tests are running).
allResources = {
"http://mochi.test:8888/tests/SimpleTest/test.css" : "link",
"http://mochi.test:8888/tests/image/test/mochitest/blue.png" : "img",
"http://mochi.test:8888/tests/image/test/mochitest/red.png" : "object",
"http://mochi.test:8888/tests/image/test/mochitest/big.png" : "embed",
"http://mochi.test:8888/tests/dom/tests/mochitest/general/resource_timing_iframe.html" : "iframe"};
for (resourceName in allResources) {
// Check that we have a resource with the specific name.
namedEntries = window.performance.getEntriesByName(resourceName);

View File

@ -0,0 +1,88 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="http://mochi.test:8888/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="http://mochi.test:8888/tests/dom/tests/mochitest/general/linkA.css"/>
<link rel="stylesheet" type="text/css" href="http://example.com/tests/dom/tests/mochitest/general/linkB.css"/>
<link rel="stylesheet" type="text/css" href="http://example.net/tests/dom/tests/mochitest/general/linkC.css"/>
<!--
Resources fetched by a cross-origin stylesheet loaded with a no-cors mode should not be reported.
Resources marked with a ^ should be reported in performance.getEntries()
(mochi.test:8888 | linkA.css)^ -> (mochi.test:8888 | cssA.css)^
-> (mochi.test:8888 | cssB.css)^ -> (mochi.test:8888 | cssC.css)^
-> (example.org | cssC.css)^
(example.com | linkB.css)^ -> (example.com | cssA.css)
-> (mochi.test:8888 | cssA.css)
-> (test2.examp.org | cssB.css) -> (test2.examp.org | cssC.css)
-> (example.org | cssC.css)
-> (example.net | cssC.css)
(example.net | linkC.css)^ -> (example.net | cssA.css)
[WITH Allow-* HEADERS]
-->
<script type="application/javascript">
function ok(cond, message) {
window.opener.ok(cond, message)
}
function is(received, expected, message) {
window.opener.is(received, expected, message);
}
function isnot(received, notExpected, message) {
window.opener.isnot(received, notExpected, message);
}
var allResources = {
"http://mochi.test:8888/tests/SimpleTest/test.css" : "link",
"http://mochi.test:8888/tests/dom/tests/mochitest/general/linkA.css" : "link",
"http://example.com/tests/dom/tests/mochitest/general/linkB.css" : "link",
"http://example.net/tests/dom/tests/mochitest/general/linkC.css" : "link",
"http://mochi.test:8888/tests/dom/tests/mochitest/general/cssA.css" : "css",
"http://mochi.test:8888/tests/dom/tests/mochitest/general/cssB.css" : "css",
"http://mochi.test:8888/tests/dom/tests/mochitest/general/cssC.css" : "css",
"http://example.org/tests/dom/tests/mochitest/general/cssC.css" : "css",
};
window.onload = function() {
let entries = performance.getEntries();
for (let entry of entries) {
let type = allResources[entry.name];
if (!type) {
ok(false, "Did not expect to find resource: "+entry.name);
continue;
}
is(entry.initiatorType, type, "Expected initiatorType does not match");
}
is(entries.length, Object.keys(allResources).length, "Found wrong number of resources");
window.opener.finishTests();
}
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1180145"
title="Resource timing NO-CORS CSS">
Bug #1180145 - Resource Timing NO-CORS CSS
</a>
<p id="display"></p>
<div id="content">
</div>
</body>
</html>

View File

@ -238,7 +238,7 @@ const gTests = {
let mql = window.matchMedia(`(resolution: ${dppx}dppx)`);
mql.addListener(function listener() {
ok("MediaQueryList's listener invoked.")
ok(true, "MediaQueryList's listener invoked.")
mql.removeListener(listener);
resolve();
});
@ -247,7 +247,7 @@ const gTests = {
let mql = frameWindow.matchMedia(`(resolution: ${dppx}dppx)`);
mql.addListener(function listener() {
ok("frame's MediaQueryList's listener invoked.")
ok(true, "frame's MediaQueryList's listener invoked.")
mql.removeListener(listener);
resolve();
});
@ -270,7 +270,7 @@ const gTests = {
let mql = window.matchMedia(`(resolution: ${dppx}dppx)`);
mql.addListener(function listener() {
ok("MediaQueryList's listener for dppx invoked.");
ok(true, "MediaQueryList's listener for dppx invoked.");
mql.removeListener(listener);
overridden = true;
resolve();
@ -289,14 +289,14 @@ const gTests = {
})
];
setOverrideDPPX(dppx);
setFullZoom(zoom);
promises[0]
.then(() => setOverrideDPPX(0))
.then(promises[1])
.then(() => setFullZoom(originalZoom))
.then(done, e => {throw e});
setOverrideDPPX(dppx);
setFullZoom(zoom);
},
"test OverrideDPPX is kept on document navigation": (done) => {
assertValuesAreInitial();

View File

@ -0,0 +1,37 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1180145
-->
<head>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<pre id="test">
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.enable_resource_timing", true]]}, start);
var subwindow = null;
function start() {
subwindow = window.open("file_resource_timing_nocors.html");
}
function finishTests() {
subwindow.close();
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

View File

@ -5,7 +5,6 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/U2F.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/WebCryptoCommon.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "mozilla/ipc/BackgroundChild.h"
@ -33,7 +32,6 @@ namespace dom {
static mozilla::LazyLogModule gU2FLog("u2fmanager");
NS_NAMED_LITERAL_STRING(kVisibilityChange, "visibilitychange");
NS_NAMED_LITERAL_STRING(kFinishEnrollment, "navigator.id.finishEnrollment");
NS_NAMED_LITERAL_STRING(kGetAssertion, "navigator.id.getAssertion");
@ -160,6 +158,23 @@ EvaluateAppID(nsPIDOMWindowInner* aParent, const nsString& aOrigin,
return ErrorCode::BAD_REQUEST;
}
nsAutoCString appIdHost;
if (NS_FAILED(appIdUri->GetAsciiHost(appIdHost))) {
return ErrorCode::BAD_REQUEST;
}
// Allow localhost.
if (appIdHost.EqualsLiteral("localhost")) {
nsAutoCString facetHost;
if (NS_FAILED(facetUri->GetAsciiHost(facetHost))) {
return ErrorCode::BAD_REQUEST;
}
if (facetHost.EqualsLiteral("localhost")) {
return ErrorCode::OK;
}
}
// Run the HTML5 algorithm to relax the same-origin policy, copied from W3C
// Web Authentication. See Bug 1244959 comment #8 for context on why we are
// doing this instead of implementing the external-fetch FacetID logic.
@ -184,10 +199,6 @@ EvaluateAppID(nsPIDOMWindowInner* aParent, const nsString& aOrigin,
if (NS_FAILED(tldService->GetBaseDomain(facetUri, 0, lowestFacetHost))) {
return ErrorCode::BAD_REQUEST;
}
nsAutoCString appIdHost;
if (NS_FAILED(appIdUri->GetAsciiHost(appIdHost))) {
return ErrorCode::BAD_REQUEST;
}
MOZ_LOG(gU2FLog, LogLevel::Debug,
("AppId %s Facet %s", appIdHost.get(), lowestFacetHost.get()));
@ -278,12 +289,6 @@ ExecuteCallback(T& aResp, Maybe<nsMainThreadPtrHandle<C>>& aCb)
* U2F JavaScript API Implementation
**********************************************************************/
U2F::U2F(nsPIDOMWindowInner* aParent)
: mParent(aParent)
{
MOZ_ASSERT(NS_IsMainThread());
}
U2F::~U2F()
{
MOZ_ASSERT(NS_IsMainThread());
@ -671,104 +676,5 @@ U2F::RequestAborted(const uint64_t& aTransactionId, const nsresult& aError)
}
}
/***********************************************************************
* Event Handling
**********************************************************************/
void
U2F::ListenForVisibilityEvents()
{
nsCOMPtr<nsIDocument> doc = mParent->GetExtantDoc();
if (NS_WARN_IF(!doc)) {
return;
}
nsresult rv = doc->AddSystemEventListener(kVisibilityChange, this,
/* use capture */ true,
/* wants untrusted */ false);
Unused << NS_WARN_IF(NS_FAILED(rv));
}
void
U2F::StopListeningForVisibilityEvents()
{
nsCOMPtr<nsIDocument> doc = mParent->GetExtantDoc();
if (NS_WARN_IF(!doc)) {
return;
}
nsresult rv = doc->RemoveSystemEventListener(kVisibilityChange, this,
/* use capture */ true);
Unused << NS_WARN_IF(NS_FAILED(rv));
}
NS_IMETHODIMP
U2F::HandleEvent(nsIDOMEvent* aEvent)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aEvent);
nsAutoString type;
aEvent->GetType(type);
if (!type.Equals(kVisibilityChange)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDocument> doc =
do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget());
if (NS_WARN_IF(!doc)) {
return NS_ERROR_FAILURE;
}
if (doc->Hidden()) {
MOZ_LOG(gU2FLog, LogLevel::Debug,
("Visibility change: U2F window is hidden, cancelling job."));
CancelTransaction(NS_ERROR_ABORT);
}
return NS_OK;
}
/***********************************************************************
* IPC Protocol Implementation
**********************************************************************/
bool
U2F::MaybeCreateBackgroundActor()
{
MOZ_ASSERT(NS_IsMainThread());
if (mChild) {
return true;
}
PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread();
if (NS_WARN_IF(!actorChild)) {
return false;
}
RefPtr<WebAuthnTransactionChild> mgr(new WebAuthnTransactionChild(this));
PWebAuthnTransactionChild* constructedMgr =
actorChild->SendPWebAuthnTransactionConstructor(mgr);
if (NS_WARN_IF(!constructedMgr)) {
return false;
}
MOZ_ASSERT(constructedMgr == mgr);
mChild = mgr.forget();
return true;
}
void
U2F::ActorDestroyed()
{
MOZ_ASSERT(NS_IsMainThread());
mChild = nullptr;
}
} // namespace dom
} // namespace mozilla

View File

@ -18,14 +18,10 @@
#include "nsProxyRelease.h"
#include "nsWrapperCache.h"
#include "U2FAuthenticator.h"
#include "nsIDOMEventListener.h"
class nsISerialEventTarget;
namespace mozilla {
namespace dom {
class WebAuthnTransactionChild;
class U2FRegisterCallback;
class U2FSignCallback;
@ -59,17 +55,16 @@ private:
}
};
class U2F final : public nsIDOMEventListener
, public WebAuthnManagerBase
class U2F final : public WebAuthnManagerBase
, public nsWrapperCache
{
public:
NS_DECL_NSIDOMEVENTLISTENER
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(U2F)
explicit U2F(nsPIDOMWindowInner* aParent);
explicit U2F(nsPIDOMWindowInner* aParent)
: WebAuthnManagerBase(aParent)
{ }
nsPIDOMWindowInner*
GetParentObject() const
@ -114,35 +109,25 @@ public:
RequestAborted(const uint64_t& aTransactionId,
const nsresult& aError) override;
void ActorDestroyed() override;
protected:
// Cancels the current transaction (by sending a Cancel message to the
// parent) and rejects it by calling RejectTransaction().
void CancelTransaction(const nsresult& aError) override;
private:
~U2F();
// Visibility event handling.
void ListenForVisibilityEvents();
void StopListeningForVisibilityEvents();
// Clears all information we have about the current transaction.
void ClearTransaction();
// Rejects the current transaction and calls ClearTransaction().
void RejectTransaction(const nsresult& aError);
// Cancels the current transaction (by sending a Cancel message to the
// parent) and rejects it by calling RejectTransaction().
void CancelTransaction(const nsresult& aError);
bool MaybeCreateBackgroundActor();
nsString mOrigin;
nsCOMPtr<nsPIDOMWindowInner> mParent;
// U2F API callbacks.
Maybe<nsMainThreadPtrHandle<U2FRegisterCallback>> mRegisterCallback;
Maybe<nsMainThreadPtrHandle<U2FSignCallback>> mSignCallback;
// IPC Channel to the parent process.
RefPtr<WebAuthnTransactionChild> mChild;
// The current transaction, if any.
Maybe<U2FTransaction> mTransaction;
};

View File

@ -1,6 +1,8 @@
[DEFAULT]
support-files =
head.js
tab_u2f_result.html
skip-if = !e10s
[browser_abort_visibility.js]
[browser_appid_localhost.js]

View File

@ -6,22 +6,6 @@
const TEST_URL = "https://example.com/browser/dom/u2f/tests/browser/tab_u2f_result.html";
function bytesToBase64(u8a){
let CHUNK_SZ = 0x8000;
let c = [];
for (let i = 0; i < u8a.length; i += CHUNK_SZ) {
c.push(String.fromCharCode.apply(null, u8a.subarray(i, i + CHUNK_SZ)));
}
return window.btoa(c.join(""));
}
function bytesToBase64UrlSafe(buf) {
return bytesToBase64(buf)
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=/g, "");
}
async function assertStatus(tab, expected) {
let actual = await ContentTask.spawn(tab.linkedBrowser, null, async function () {
return content.document.getElementById("status").value;

View File

@ -0,0 +1,78 @@
/* 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";
const TEST_URL = "https://localhost/";
function promiseU2FRegister(tab, app_id) {
let challenge = crypto.getRandomValues(new Uint8Array(16));
challenge = bytesToBase64UrlSafe(challenge);
return ContentTask.spawn(tab.linkedBrowser, [app_id, challenge], async function ([app_id, challenge]) {
return new Promise(resolve => {
let version = "U2F_V2";
content.u2f.register(app_id, [{version, challenge}], [], resolve);
});
});
}
add_task(async function () {
// Enable the soft token.
Services.prefs.setBoolPref("security.webauth.u2f", true);
Services.prefs.setBoolPref("security.webauth.webauthn_enable_softtoken", true);
Services.prefs.setBoolPref("security.webauth.webauthn_enable_usbtoken", false);
// Open a new tab.
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
// Check that we have the right origin, and U2F is available.
let ready = await ContentTask.spawn(tab.linkedBrowser, null, async () => {
return content.location.origin == "https://localhost" && content.u2f;
});
ok(ready, "Origin is https://localhost. U2F is available.");
// Test: Null AppID
await promiseU2FRegister(tab, null).then(res => {
is(res.errorCode, 0, "Null AppID should work.");
});
// Test: Empty AppID
await promiseU2FRegister(tab, "").then(res => {
is(res.errorCode, 0, "Empty AppID should work.");
});
// Test: Correct TLD, incorrect scheme
await promiseU2FRegister(tab, "http://localhost/appId").then(res => {
isnot(res.errorCode, 0, "Incorrect scheme.");
});
// Test: Incorrect TLD
await promiseU2FRegister(tab, "https://localhost.ssl/appId").then(res => {
isnot(res.errorCode, 0, "Incorrect TLD.");
});
// Test: Incorrect TLD
await promiseU2FRegister(tab, "https://sub.localhost/appId").then(res => {
isnot(res.errorCode, 0, "Incorrect TLD.");
});
// Test: Correct TLD
await promiseU2FRegister(tab, "https://localhost/appId").then(res => {
is(res.errorCode, 0, "https://localhost/appId should work.");
});
// Test: Correct TLD
await promiseU2FRegister(tab, "https://localhost:443/appId").then(res => {
is(res.errorCode, 0, "https://localhost:443/appId should work.");
});
// Close tab.
await BrowserTestUtils.removeTab(tab);
// Cleanup.
Services.prefs.clearUserPref("security.webauth.u2f");
Services.prefs.clearUserPref("security.webauth.webauthn_enable_softtoken");
Services.prefs.clearUserPref("security.webauth.webauthn_enable_usbtoken");
});

View File

@ -0,0 +1,21 @@
/* 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";
function bytesToBase64(u8a){
let CHUNK_SZ = 0x8000;
let c = [];
for (let i = 0; i < u8a.length; i += CHUNK_SZ) {
c.push(String.fromCharCode.apply(null, u8a.subarray(i, i + CHUNK_SZ)));
}
return window.btoa(c.join(""));
}
function bytesToBase64UrlSafe(buf) {
return bytesToBase64(buf)
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=/g, "");
}

View File

@ -42,8 +42,6 @@ namespace {
static mozilla::LazyLogModule gWebAuthnManagerLog("webauthnmanager");
}
NS_NAMED_LITERAL_STRING(kVisibilityChange, "visibilitychange");
NS_IMPL_ISUPPORTS(WebAuthnManager, nsIDOMEventListener);
/***********************************************************************
@ -145,44 +143,10 @@ RelaxSameOrigin(nsPIDOMWindowInner* aParent,
return NS_OK;
}
void
WebAuthnManager::ListenForVisibilityEvents()
{
nsCOMPtr<nsIDocument> doc = mParent->GetExtantDoc();
if (NS_WARN_IF(!doc)) {
return;
}
nsresult rv = doc->AddSystemEventListener(kVisibilityChange, this,
/* use capture */ true,
/* wants untrusted */ false);
Unused << NS_WARN_IF(NS_FAILED(rv));
}
void
WebAuthnManager::StopListeningForVisibilityEvents()
{
nsCOMPtr<nsIDocument> doc = mParent->GetExtantDoc();
if (NS_WARN_IF(!doc)) {
return;
}
nsresult rv = doc->RemoveSystemEventListener(kVisibilityChange, this,
/* use capture */ true);
Unused << NS_WARN_IF(NS_FAILED(rv));
}
/***********************************************************************
* WebAuthnManager Implementation
**********************************************************************/
WebAuthnManager::WebAuthnManager(nsPIDOMWindowInner* aParent)
: mParent(aParent)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aParent);
}
void
WebAuthnManager::ClearTransaction()
{
@ -229,34 +193,6 @@ WebAuthnManager::~WebAuthnManager()
}
}
bool
WebAuthnManager::MaybeCreateBackgroundActor()
{
MOZ_ASSERT(NS_IsMainThread());
if (mChild) {
return true;
}
PBackgroundChild* actor = BackgroundChild::GetOrCreateForCurrentThread();
if (NS_WARN_IF(!actor)) {
return false;
}
RefPtr<WebAuthnTransactionChild> mgr(new WebAuthnTransactionChild(this));
PWebAuthnTransactionChild* constructedMgr =
actor->SendPWebAuthnTransactionConstructor(mgr);
if (NS_WARN_IF(!constructedMgr)) {
return false;
}
MOZ_ASSERT(constructedMgr == mgr);
mChild = mgr.forget();
return true;
}
already_AddRefed<Promise>
WebAuthnManager::MakeCredential(const MakePublicKeyCredentialOptions& aOptions,
const Optional<OwningNonNull<AbortSignal>>& aSignal)
@ -888,46 +824,11 @@ WebAuthnManager::RequestAborted(const uint64_t& aTransactionId,
}
}
NS_IMETHODIMP
WebAuthnManager::HandleEvent(nsIDOMEvent* aEvent)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aEvent);
nsAutoString type;
aEvent->GetType(type);
if (!type.Equals(kVisibilityChange)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDocument> doc =
do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget());
if (NS_WARN_IF(!doc)) {
return NS_ERROR_FAILURE;
}
if (doc->Hidden()) {
MOZ_LOG(gWebAuthnManagerLog, LogLevel::Debug,
("Visibility change: WebAuthn window is hidden, cancelling job."));
CancelTransaction(NS_ERROR_ABORT);
}
return NS_OK;
}
void
WebAuthnManager::Abort()
{
CancelTransaction(NS_ERROR_DOM_ABORT_ERR);
}
void
WebAuthnManager::ActorDestroyed()
{
MOZ_ASSERT(NS_IsMainThread());
mChild = nullptr;
}
}
}

View File

@ -8,10 +8,8 @@
#define mozilla_dom_WebAuthnManager_h
#include "mozilla/MozPromise.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/PWebAuthnTransaction.h"
#include "mozilla/dom/WebAuthnManagerBase.h"
#include "nsIDOMEventListener.h"
/*
* Content process manager for the WebAuthn protocol. Created on calls to the
@ -53,14 +51,6 @@ public:
namespace mozilla {
namespace dom {
struct Account;
class ArrayBufferViewOrArrayBuffer;
struct AssertionOptions;
class OwningArrayBufferViewOrArrayBuffer;
struct MakePublicKeyCredentialOptions;
class Promise;
class WebAuthnTransactionChild;
class WebAuthnTransaction
{
public:
@ -103,14 +93,14 @@ private:
};
class WebAuthnManager final : public WebAuthnManagerBase
, public nsIDOMEventListener
, public AbortFollower
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENTLISTENER
explicit WebAuthnManager(nsPIDOMWindowInner* aParent);
explicit WebAuthnManager(nsPIDOMWindowInner* aParent)
: WebAuthnManagerBase(aParent)
{ }
already_AddRefed<Promise>
MakeCredential(const MakePublicKeyCredentialOptions& aOptions,
@ -138,34 +128,22 @@ public:
RequestAborted(const uint64_t& aTransactionId,
const nsresult& aError) override;
void ActorDestroyed() override;
// AbortFollower
void Abort() override;
protected:
// Cancels the current transaction (by sending a Cancel message to the
// parent) and rejects it by calling RejectTransaction().
void CancelTransaction(const nsresult& aError) override;
private:
virtual ~WebAuthnManager();
// Visibility event handling.
void ListenForVisibilityEvents();
void StopListeningForVisibilityEvents();
// Clears all information we have about the current transaction.
void ClearTransaction();
// Rejects the current transaction and calls ClearTransaction().
void RejectTransaction(const nsresult& aError);
// Cancels the current transaction (by sending a Cancel message to the
// parent) and rejects it by calling RejectTransaction().
void CancelTransaction(const nsresult& aError);
bool MaybeCreateBackgroundActor();
// The parent window.
nsCOMPtr<nsPIDOMWindowInner> mParent;
// IPC Channel to the parent process.
RefPtr<WebAuthnTransactionChild> mChild;
// The current transaction, if any.
Maybe<WebAuthnTransaction> mTransaction;

View File

@ -0,0 +1,128 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "mozilla/dom/WebAuthnManagerBase.h"
#include "mozilla/dom/WebAuthnTransactionChild.h"
#include "mozilla/dom/Event.h"
namespace mozilla {
namespace dom {
NS_NAMED_LITERAL_STRING(kVisibilityChange, "visibilitychange");
WebAuthnManagerBase::WebAuthnManagerBase(nsPIDOMWindowInner* aParent)
: mParent(aParent)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aParent);
}
WebAuthnManagerBase::~WebAuthnManagerBase()
{
MOZ_ASSERT(NS_IsMainThread());
}
/***********************************************************************
* IPC Protocol Implementation
**********************************************************************/
bool
WebAuthnManagerBase::MaybeCreateBackgroundActor()
{
MOZ_ASSERT(NS_IsMainThread());
if (mChild) {
return true;
}
PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread();
if (NS_WARN_IF(!actorChild)) {
return false;
}
RefPtr<WebAuthnTransactionChild> mgr(new WebAuthnTransactionChild(this));
PWebAuthnTransactionChild* constructedMgr =
actorChild->SendPWebAuthnTransactionConstructor(mgr);
if (NS_WARN_IF(!constructedMgr)) {
return false;
}
MOZ_ASSERT(constructedMgr == mgr);
mChild = mgr.forget();
return true;
}
void
WebAuthnManagerBase::ActorDestroyed()
{
MOZ_ASSERT(NS_IsMainThread());
mChild = nullptr;
}
/***********************************************************************
* Event Handling
**********************************************************************/
void
WebAuthnManagerBase::ListenForVisibilityEvents()
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIDocument> doc = mParent->GetExtantDoc();
if (NS_WARN_IF(!doc)) {
return;
}
nsresult rv = doc->AddSystemEventListener(kVisibilityChange, this,
/* use capture */ true,
/* wants untrusted */ false);
Unused << NS_WARN_IF(NS_FAILED(rv));
}
void
WebAuthnManagerBase::StopListeningForVisibilityEvents()
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIDocument> doc = mParent->GetExtantDoc();
if (NS_WARN_IF(!doc)) {
return;
}
nsresult rv = doc->RemoveSystemEventListener(kVisibilityChange, this,
/* use capture */ true);
Unused << NS_WARN_IF(NS_FAILED(rv));
}
NS_IMETHODIMP
WebAuthnManagerBase::HandleEvent(nsIDOMEvent* aEvent)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aEvent);
nsAutoString type;
aEvent->GetType(type);
if (!type.Equals(kVisibilityChange)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDocument> doc =
do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget());
if (NS_WARN_IF(!doc)) {
return NS_ERROR_FAILURE;
}
if (doc->Hidden()) {
CancelTransaction(NS_ERROR_ABORT);
}
return NS_OK;
}
}
}

View File

@ -7,6 +7,8 @@
#ifndef mozilla_dom_WebAuthnManagerBase_h
#define mozilla_dom_WebAuthnManagerBase_h
#include "nsIDOMEventListener.h"
/*
* A base class used by WebAuthn and U2F implementations, providing shared
* functionality and requiring an interface used by the IPC child actors.
@ -15,9 +17,15 @@
namespace mozilla {
namespace dom {
class WebAuthnManagerBase
class WebAuthnTransactionChild;
class WebAuthnManagerBase : public nsIDOMEventListener
{
public:
NS_DECL_NSIDOMEVENTLISTENER
explicit WebAuthnManagerBase(nsPIDOMWindowInner* aParent);
virtual void
FinishMakeCredential(const uint64_t& aTransactionId,
nsTArray<uint8_t>& aRegBuffer) = 0;
@ -31,7 +39,25 @@ public:
RequestAborted(const uint64_t& aTransactionId,
const nsresult& aError) = 0;
virtual void ActorDestroyed() = 0;
void ActorDestroyed();
protected:
~WebAuthnManagerBase();
// Needed by HandleEvent() to cancel transactions.
virtual void CancelTransaction(const nsresult& aError) = 0;
// Visibility event handling.
void ListenForVisibilityEvents();
void StopListeningForVisibilityEvents();
bool MaybeCreateBackgroundActor();
// The parent window.
nsCOMPtr<nsPIDOMWindowInner> mParent;
// IPC Channel to the parent process.
RefPtr<WebAuthnTransactionChild> mChild;
};
}

View File

@ -40,6 +40,7 @@ UNIFIED_SOURCES += [
'U2FTokenManager.cpp',
'WebAuthnCBORUtil.cpp',
'WebAuthnManager.cpp',
'WebAuthnManagerBase.cpp',
'WebAuthnTransactionChild.cpp',
'WebAuthnTransactionParent.cpp',
'WebAuthnUtil.cpp',

View File

@ -262,7 +262,7 @@ nsXBLBinding::UnbindAnonymousContent(nsIDocument* aDocument,
}
void
nsXBLBinding::SetBoundElement(nsIContent* aElement)
nsXBLBinding::SetBoundElement(Element* aElement)
{
mBoundElement = aElement;
if (mNextBinding)
@ -301,7 +301,7 @@ nsXBLBinding::GenerateAnonymousContent()
"Someone forgot a script blocker");
// Fetch the content element for this binding.
nsIContent* content =
Element* content =
mPrototypeBinding->GetImmediateChild(nsGkAtoms::content);
if (!content) {
@ -417,8 +417,12 @@ nsXBLBinding::GenerateAnonymousContent()
}
// Conserve space by wiping the attributes off the clone.
//
// FIXME(emilio): It'd be nice to make `mContent` a `RefPtr<Element>`, but
// as of right now it can also be a ShadowRoot (we don't enter in this
// codepath though). Move Shadow DOM outside XBL and then fix that.
if (mContent)
mContent->UnsetAttr(namespaceID, name, false);
mContent->AsElement()->UnsetAttr(namespaceID, name, false);
}
}

View File

@ -64,8 +64,8 @@ public:
nsXBLBinding* GetBaseBinding() const { return mNextBinding; }
void SetBaseBinding(nsXBLBinding *aBinding);
nsIContent* GetBoundElement() { return mBoundElement; }
void SetBoundElement(nsIContent *aElement);
mozilla::dom::Element* GetBoundElement() { return mBoundElement; }
void SetBoundElement(mozilla::dom::Element* aElement);
/*
* Does a lookup for a method or attribute provided by one of the bindings'
@ -173,7 +173,7 @@ protected:
nsCOMPtr<nsIContent> mContent; // Strong. Our anonymous content stays around with us.
RefPtr<nsXBLBinding> mNextBinding; // Strong. The derived binding owns the base class bindings.
nsIContent* mBoundElement; // [WEAK] We have a reference, but we don't own it.
mozilla::dom::Element* mBoundElement; // [WEAK] We have a reference, but we don't own it.
// The <xbl:children> elements that we found in our <xbl:content> when we
// processed this binding. The default insertion point has no includes

View File

@ -535,7 +535,8 @@ nsXBLContentSink::OnOpenContainer(const char16_t **aAtts,
nsresult
nsXBLContentSink::ConstructBinding(uint32_t aLineNumber)
{
nsCOMPtr<nsIContent> binding = GetCurrentContent();
// This is only called from HandleStartElement, so it'd better be an element.
RefPtr<Element> binding = GetCurrentContent()->AsElement();
binding->GetAttr(kNameSpaceID_None, nsGkAtoms::id, mCurrentBindingID);
NS_ConvertUTF16toUTF8 cid(mCurrentBindingID);
@ -880,13 +881,12 @@ nsXBLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
}
nsresult
nsXBLContentSink::AddAttributes(const char16_t** aAtts,
nsIContent* aContent)
nsXBLContentSink::AddAttributes(const char16_t** aAtts, Element* aElement)
{
if (aContent->IsXULElement())
if (aElement->IsXULElement())
return NS_OK; // Nothing to do, since the proto already has the attrs.
return nsXMLContentSink::AddAttributes(aAtts, aContent);
return nsXMLContentSink::AddAttributes(aAtts, aElement);
}
#ifdef MOZ_XUL

View File

@ -92,8 +92,7 @@ protected:
nsIContent** aResult, bool* aAppendContent,
mozilla::dom::FromParser aFromParser) override;
nsresult AddAttributes(const char16_t** aAtts,
nsIContent* aContent) override;
nsresult AddAttributes(const char16_t** aAtts, Element* aElement) override;
#ifdef MOZ_XUL
nsresult AddAttributesToXULPrototype(const char16_t **aAtts,

View File

@ -62,8 +62,8 @@ using namespace mozilla::dom;
class nsXBLAttributeEntry {
public:
nsXBLAttributeEntry(nsAtom* aSrcAtom, nsAtom* aDstAtom,
int32_t aDstNameSpace, nsIContent* aContent)
: mElement(aContent),
int32_t aDstNameSpace, Element* aElement)
: mElement(aElement),
mSrcAttribute(aSrcAtom),
mDstAttribute(aDstAtom),
mDstNameSpace(aDstNameSpace),
@ -77,13 +77,13 @@ public:
nsAtom* GetDstAttribute() { return mDstAttribute; }
int32_t GetDstNameSpace() { return mDstNameSpace; }
nsIContent* GetElement() { return mElement; }
Element* GetElement() { return mElement; }
nsXBLAttributeEntry* GetNext() { return mNext; }
void SetNext(nsXBLAttributeEntry* aEntry) { mNext = aEntry; }
protected:
nsIContent* mElement;
Element* mElement;
RefPtr<nsAtom> mSrcAttribute;
RefPtr<nsAtom> mDstAttribute;
@ -113,7 +113,7 @@ nsXBLPrototypeBinding::nsXBLPrototypeBinding()
nsresult
nsXBLPrototypeBinding::Init(const nsACString& aID,
nsXBLDocumentInfo* aInfo,
nsIContent* aElement,
Element* aElement,
bool aFirstBinding)
{
nsresult rv = aInfo->DocumentURI()->Clone(getter_AddRefs(mBindingURI));
@ -180,8 +180,7 @@ nsXBLPrototypeBinding::Trace(const TraceCallbacks& aCallbacks, void *aClosure) c
void
nsXBLPrototypeBinding::Initialize()
{
nsIContent* content = GetImmediateChild(nsGkAtoms::content);
if (content) {
if (Element* content = GetImmediateChild(nsGkAtoms::content)) {
ConstructAttributeTable(content);
}
}
@ -207,7 +206,7 @@ nsXBLPrototypeBinding::SetBasePrototype(nsXBLPrototypeBinding* aBinding)
}
void
nsXBLPrototypeBinding::SetBindingElement(nsIContent* aElement)
nsXBLPrototypeBinding::SetBindingElement(Element* aElement)
{
mBinding = aElement;
if (mBinding->AttrValueIs(kNameSpaceID_None, nsGkAtoms::inheritstyle,
@ -323,7 +322,7 @@ void
nsXBLPrototypeBinding::AttributeChanged(nsAtom* aAttribute,
int32_t aNameSpaceID,
bool aRemoveFlag,
nsIContent* aChangedElement,
Element* aChangedElement,
nsIContent* aAnonymousContent,
bool aNotify)
{
@ -339,13 +338,12 @@ nsXBLPrototypeBinding::AttributeChanged(nsAtom* aAttribute,
return;
// Iterate over the elements in the array.
nsCOMPtr<nsIContent> content = GetImmediateChild(nsGkAtoms::content);
RefPtr<Element> content = GetImmediateChild(nsGkAtoms::content);
while (xblAttr) {
nsIContent* element = xblAttr->GetElement();
Element* element = xblAttr->GetElement();
nsCOMPtr<nsIContent> realElement = LocateInstance(aChangedElement, content,
aAnonymousContent,
element);
RefPtr<Element> realElement =
LocateInstance(aChangedElement, content, aAnonymousContent, element);
if (realElement) {
// Hold a strong reference here so that the atom doesn't go away during
@ -436,14 +434,14 @@ nsXBLPrototypeBinding::ImplementsInterface(REFNSIID aIID) const
// Internal helpers ///////////////////////////////////////////////////////////////////////
nsIContent*
Element*
nsXBLPrototypeBinding::GetImmediateChild(nsAtom* aTag)
{
for (nsIContent* child = mBinding->GetFirstChild();
child;
child = child->GetNextSibling()) {
if (child->NodeInfo()->Equals(aTag, kNameSpaceID_XBL)) {
return child;
return child->AsElement();
}
}
@ -461,18 +459,18 @@ nsXBLPrototypeBinding::InitClass(const nsString& aClassName,
aClassName, this, aClassObject, aNew);
}
nsIContent*
nsXBLPrototypeBinding::LocateInstance(nsIContent* aBoundElement,
Element*
nsXBLPrototypeBinding::LocateInstance(Element* aBoundElement,
nsIContent* aTemplRoot,
nsIContent* aCopyRoot,
nsIContent* aTemplChild)
Element* aTemplChild)
{
// XXX We will get in trouble if the binding instantiation deviates from the template
// in the prototype.
if (aTemplChild == aTemplRoot || !aTemplChild)
return nullptr;
nsIContent* templParent = aTemplChild->GetParent();
Element* templParent = aTemplChild->GetParentElement();
// We may be disconnected from our parent during cycle collection.
if (!templParent)
@ -485,11 +483,17 @@ nsXBLPrototypeBinding::LocateInstance(nsIContent* aBoundElement,
if (!copyParent)
return nullptr;
return copyParent->GetChildAt(templParent->IndexOf(aTemplChild));
nsIContent* child = copyParent->GetChildAt(templParent->IndexOf(aTemplChild));
if (child && child->IsElement()) {
return child->AsElement();
}
return nullptr;
}
void
nsXBLPrototypeBinding::SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent)
nsXBLPrototypeBinding::SetInitialAttributes(
Element* aBoundElement,
nsIContent* aAnonymousContent)
{
if (!mAttributeTable) {
return;
@ -528,9 +532,9 @@ nsXBLPrototypeBinding::SetInitialAttributes(nsIContent* aBoundElement, nsIConten
while (curr) {
nsAtom* dst = curr->GetDstAttribute();
int32_t dstNs = curr->GetDstNameSpace();
nsIContent* element = curr->GetElement();
Element* element = curr->GetElement();
nsIContent* realElement =
Element* realElement =
LocateInstance(aBoundElement, content,
aAnonymousContent, element);
@ -595,7 +599,7 @@ nsXBLPrototypeBinding::EnsureAttributeTable()
void
nsXBLPrototypeBinding::AddToAttributeTable(int32_t aSourceNamespaceID, nsAtom* aSourceTag,
int32_t aDestNamespaceID, nsAtom* aDestTag,
nsIContent* aContent)
Element* aElement)
{
InnerAttributeTable* attributesNS = mAttributeTable->Get(aSourceNamespaceID);
if (!attributesNS) {
@ -604,7 +608,7 @@ nsXBLPrototypeBinding::AddToAttributeTable(int32_t aSourceNamespaceID, nsAtom* a
}
nsXBLAttributeEntry* xblAttr =
new nsXBLAttributeEntry(aSourceTag, aDestTag, aDestNamespaceID, aContent);
new nsXBLAttributeEntry(aSourceTag, aDestTag, aDestNamespaceID, aElement);
nsXBLAttributeEntry* entry = attributesNS->Get(aSourceTag);
if (!entry) {
@ -617,7 +621,7 @@ nsXBLPrototypeBinding::AddToAttributeTable(int32_t aSourceNamespaceID, nsAtom* a
}
void
nsXBLPrototypeBinding::ConstructAttributeTable(nsIContent* aElement)
nsXBLPrototypeBinding::ConstructAttributeTable(Element* aElement)
{
// Don't add entries for <children> elements, since those will get
// removed from the DOM when we construct the insertion point table.
@ -692,7 +696,9 @@ nsXBLPrototypeBinding::ConstructAttributeTable(nsIContent* aElement)
for (nsIContent* child = aElement->GetFirstChild();
child;
child = child->GetNextSibling()) {
ConstructAttributeTable(child);
if (child->IsElement()) {
ConstructAttributeTable(child->AsElement());
}
}
}
@ -1195,12 +1201,11 @@ nsXBLPrototypeBinding::ReadContentNode(nsIObjectInputStream* aStream,
if (namespaceID == XBLBinding_Serialize_NoContent)
return NS_OK;
nsCOMPtr<nsIContent> content;
// If this is a text type, just read the string and return.
if (namespaceID == XBLBinding_Serialize_TextNode ||
namespaceID == XBLBinding_Serialize_CDATANode ||
namespaceID == XBLBinding_Serialize_CommentNode) {
nsCOMPtr<nsIContent> content;
switch (namespaceID) {
case XBLBinding_Serialize_TextNode:
content = new nsTextNode(aNim);
@ -1244,6 +1249,7 @@ nsXBLPrototypeBinding::ReadContentNode(nsIObjectInputStream* aStream,
rv = aStream->Read32(&attrCount);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<Element> element;
// Create XUL prototype elements, or regular elements for other namespaces.
// This needs to match the code in nsXBLContentSink::CreateElement.
#ifdef MOZ_XUL
@ -1293,17 +1299,12 @@ nsXBLPrototypeBinding::ReadContentNode(nsIObjectInputStream* aStream,
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<Element> result;
nsresult rv =
nsXULElement::Create(prototype, aDocument, false, false, getter_AddRefs(result));
nsXULElement::Create(prototype, aDocument, false, false, getter_AddRefs(element));
NS_ENSURE_SUCCESS(rv, rv);
content = result;
}
else {
} else {
#endif
nsCOMPtr<Element> element;
NS_NewElement(getter_AddRefs(element), nodeInfo.forget(), NOT_FROM_PARSER);
content = element;
for (uint32_t i = 0; i < attrCount; i++) {
rv = ReadNamespace(aStream, namespaceID);
@ -1322,7 +1323,7 @@ nsXBLPrototypeBinding::ReadContentNode(nsIObjectInputStream* aStream,
prefixAtom = NS_Atomize(prefix);
RefPtr<nsAtom> nameAtom = NS_Atomize(name);
content->SetAttr(namespaceID, nameAtom, prefixAtom, val, false);
element->SetAttr(namespaceID, nameAtom, prefixAtom, val, false);
}
#ifdef MOZ_XUL
@ -1348,7 +1349,7 @@ nsXBLPrototypeBinding::ReadContentNode(nsIObjectInputStream* aStream,
RefPtr<nsAtom> destAtom = NS_Atomize(destAttribute);
EnsureAttributeTable();
AddToAttributeTable(srcNamespaceID, srcAtom, destNamespaceID, destAtom, content);
AddToAttributeTable(srcNamespaceID, srcAtom, destNamespaceID, destAtom, element);
rv = ReadNamespace(aStream, srcNamespaceID);
NS_ENSURE_SUCCESS(rv, rv);
@ -1365,11 +1366,11 @@ nsXBLPrototypeBinding::ReadContentNode(nsIObjectInputStream* aStream,
// Child may be null if this was a comment for example and can just be ignored.
if (child) {
content->AppendChildTo(child, false);
element->AppendChildTo(child, false);
}
}
content.swap(*aContent);
element.forget(aContent);
return NS_OK;
}
@ -1405,21 +1406,22 @@ nsXBLPrototypeBinding::WriteContentNode(nsIObjectOutputStream* aStream,
}
// Otherwise, this is an element.
Element* element = aNode->AsElement();
// Write the namespace id followed by the tag name
rv = WriteNamespace(aStream, aNode->GetNameSpaceID());
rv = WriteNamespace(aStream, element->GetNameSpaceID());
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString prefixStr;
aNode->NodeInfo()->GetPrefix(prefixStr);
element->NodeInfo()->GetPrefix(prefixStr);
rv = aStream->WriteWStringZ(prefixStr.get());
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->WriteWStringZ(nsDependentAtomString(aNode->NodeInfo()->NameAtom()).get());
rv = aStream->WriteWStringZ(nsDependentAtomString(element->NodeInfo()->NameAtom()).get());
NS_ENSURE_SUCCESS(rv, rv);
// Write attributes
uint32_t count = aNode->GetAttrCount();
uint32_t count = element->GetAttrCount();
rv = aStream->Write32(count);
NS_ENSURE_SUCCESS(rv, rv);
@ -1428,7 +1430,7 @@ nsXBLPrototypeBinding::WriteContentNode(nsIObjectOutputStream* aStream,
// Write out the namespace id, the namespace prefix, the local tag name,
// and the value, in that order.
const BorrowedAttrInfo attrInfo = aNode->GetAttrInfoAt(i);
const BorrowedAttrInfo attrInfo = element->GetAttrInfoAt(i);
const nsAttrName* name = attrInfo.mName;
// XXXndeakin don't write out xbl:inherits?
@ -1462,7 +1464,7 @@ nsXBLPrototypeBinding::WriteContentNode(nsIObjectOutputStream* aStream,
nsXBLAttributeEntry* entry = iter2.UserData();
do {
if (entry->GetElement() == aNode) {
if (entry->GetElement() == element) {
WriteNamespace(aStream, srcNamespace);
aStream->WriteWStringZ(
nsDependentAtomString(entry->GetSrcAttribute()).get());
@ -1480,12 +1482,12 @@ nsXBLPrototypeBinding::WriteContentNode(nsIObjectOutputStream* aStream,
NS_ENSURE_SUCCESS(rv, rv);
// Finally, write out the child nodes.
count = aNode->GetChildCount();
count = element->GetChildCount();
rv = aStream->Write32(count);
NS_ENSURE_SUCCESS(rv, rv);
for (i = 0; i < count; i++) {
rv = WriteContentNode(aStream, aNode->GetChildAt(i));
rv = WriteContentNode(aStream, element->GetChildAt(i));
NS_ENSURE_SUCCESS(rv, rv);
}

Some files were not shown because too many files have changed in this diff Show More