Merge the last PGO-green inbound changeset to m-c.

This commit is contained in:
Ryan VanderMeulen 2012-10-17 14:07:59 -04:00
commit 292a5ce0ff
309 changed files with 4203 additions and 2098 deletions

View File

@ -32,7 +32,7 @@ nsTextEquivUtils::GetNameFromSubtree(Accessible* aAccessible,
return NS_OK;
gInitiatorAcc = aAccessible;
if (GetRoleRule(aAccessible->Role()) == eFromSubtree) {
if (IsNameFromSubtreeAllowed(aAccessible)) {
//XXX: is it necessary to care the accessible is not a document?
if (aAccessible->IsContent()) {
nsAutoString name;

View File

@ -89,6 +89,14 @@ public:
static nsresult AppendTextEquivFromTextContent(nsIContent *aContent,
nsAString *aString);
/**
* Return true if the given accessible allows name from subtree.
*/
static bool IsNameFromSubtreeAllowed(Accessible* aAccessible)
{
return GetRoleRule(aAccessible->Role()) == eFromSubtree;
}
private:
/**
* Iterates accessible children and calculates text equivalent from each

View File

@ -275,7 +275,7 @@ Accessible::Name(nsString& aName)
ENameValueFlag nameFlag = NativeName(aName);
if (!aName.IsEmpty())
return eNameOK;
return nameFlag;
// In the end get the name from tooltip.
if (mContent->IsHTML()) {
@ -288,14 +288,12 @@ Accessible::Name(nsString& aName)
aName.CompressWhitespace();
return eNameFromTooltip;
}
} else {
return eNameOK;
}
if (nameFlag != eNoNameOnPurpose)
aName.SetIsVoid(true);
return eNameOK;
return nameFlag;
}
NS_IMETHODIMP
@ -1055,7 +1053,7 @@ Accessible::TakeFocus()
return NS_OK;
}
void
ENameValueFlag
Accessible::GetHTMLName(nsString& aLabel)
{
Accessible* labelAcc = nullptr;
@ -1066,8 +1064,11 @@ Accessible::GetHTMLName(nsString& aLabel)
aLabel.CompressWhitespace();
}
if (aLabel.IsEmpty())
nsTextEquivUtils::GetNameFromSubtree(this, aLabel);
if (!aLabel.IsEmpty())
return eNameOK;
nsTextEquivUtils::GetNameFromSubtree(this, aLabel);
return aLabel.IsEmpty() ? eNameOK : eNameFromSubtree;
}
/**
@ -1082,7 +1083,7 @@ Accessible::GetHTMLName(nsString& aLabel)
* the control that uses the control="controlID" syntax will use
* the child label for its Name.
*/
void
ENameValueFlag
Accessible::GetXULName(nsString& aName)
{
// CASE #1 (via label attribute) -- great majority of the cases
@ -1125,10 +1126,9 @@ Accessible::GetXULName(nsString& aName)
}
}
// XXX If CompressWhiteSpace worked on nsAString we could avoid a copy
aName.CompressWhitespace();
if (!aName.IsEmpty())
return;
return eNameOK;
// Can get text from title of <toolbaritem> if we're a child of a <toolbaritem>
nsIContent *bindingParent = mContent->GetBindingParent();
@ -1138,12 +1138,13 @@ Accessible::GetXULName(nsString& aName)
if (parent->Tag() == nsGkAtoms::toolbaritem &&
parent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) {
aName.CompressWhitespace();
return;
return eNameOK;
}
parent = parent->GetParent();
}
nsTextEquivUtils::GetNameFromSubtree(this, aName);
return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
}
nsresult
@ -1229,6 +1230,13 @@ Accessible::GetAttributes(nsIPersistentProperties **aAttributes)
if (State() & states::CHECKABLE)
nsAccUtils::SetAccAttr(attributes, nsGkAtoms::checkable, NS_LITERAL_STRING("true"));
// Expose 'explicit-name' attribute.
if (!nsTextEquivUtils::IsNameFromSubtreeAllowed(this) ||
Name(oldValueUnused) != eNameFromSubtree) {
attributes->SetStringProperty(NS_LITERAL_CSTRING("explicit-name"),
NS_LITERAL_STRING("true"), oldValueUnused);
}
// Group attributes (level/setsize/posinset)
GroupPos groupPos = GroupPosition();
nsAccUtils::SetAccGroupAttrs(attributes, groupPos.level,
@ -2420,23 +2428,18 @@ Accessible::Shutdown()
// Accessible protected
void
Accessible::ARIAName(nsAString& aName)
Accessible::ARIAName(nsString& aName)
{
nsAutoString label;
// aria-labelledby now takes precedence over aria-label
nsresult rv = nsTextEquivUtils::
GetTextEquivFromIDRefs(this, nsGkAtoms::aria_labelledby, label);
GetTextEquivFromIDRefs(this, nsGkAtoms::aria_labelledby, aName);
if (NS_SUCCEEDED(rv)) {
label.CompressWhitespace();
aName = label;
aName.CompressWhitespace();
}
if (label.IsEmpty() &&
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_label,
label)) {
label.CompressWhitespace();
aName = label;
if (aName.IsEmpty() &&
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_label, aName)) {
aName.CompressWhitespace();
}
}
@ -2445,9 +2448,10 @@ ENameValueFlag
Accessible::NativeName(nsString& aName)
{
if (mContent->IsHTML())
GetHTMLName(aName);
else if (mContent->IsXUL())
GetXULName(aName);
return GetHTMLName(aName);
if (mContent->IsXUL())
return GetXULName(aName);
return eNameOK;
}

View File

@ -58,6 +58,11 @@ enum ENameValueFlag {
*/
eNoNameOnPurpose,
/**
* Name was computed from the subtree.
*/
eNameFromSubtree,
/**
* Tooltip was used as a name.
*/
@ -805,13 +810,13 @@ protected:
/**
* Returns the accessible name specified by ARIA.
*/
void ARIAName(nsAString& aName);
void ARIAName(nsString& aName);
/**
* Compute the name of HTML/XUL node.
*/
void GetHTMLName(nsString& aName);
void GetXULName(nsString& aName);
mozilla::a11y::ENameValueFlag GetHTMLName(nsString& aName);
mozilla::a11y::ENameValueFlag GetXULName(nsString& aName);
// helper method to verify frames
static nsresult GetFullKeyName(const nsAString& aModifierName, const nsAString& aKeyName, nsAString& aStringOut);

View File

@ -1953,12 +1953,14 @@ HyperTextAccessible::ScrollSubstringToPoint(int32_t aStartIndex,
ENameValueFlag
HyperTextAccessible::NativeName(nsString& aName)
{
AccessibleWrap::NativeName(aName);
ENameValueFlag nameFlag = AccessibleWrap::NativeName(aName);
if (!aName.IsEmpty())
return nameFlag;
// Get name from title attribute for HTML abbr and acronym elements making it
// a valid name from markup. Otherwise their name isn't picked up by recursive
// name computation algorithm. See NS_OK_NAME_FROM_TOOLTIP.
if (aName.IsEmpty() && IsAbbreviation() &&
if (IsAbbreviation() &&
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName))
aName.CompressWhitespace();

View File

@ -77,16 +77,15 @@ ImageAccessible::NativeName(nsString& aName)
if (!aName.IsEmpty())
return eNameOK;
Accessible::NativeName(aName);
if (aName.IsEmpty() && hasAltAttrib) {
// No accessible name but empty 'alt' attribute is present. If further name
// computation algorithm doesn't provide non empty name then it means
// an empty 'alt' attribute was used to indicate a decorative image (see
// nsIAccessible::name attribute for details).
return eNoNameOnPurpose;
}
ENameValueFlag nameFlag = Accessible::NativeName(aName);
if (!aName.IsEmpty())
return nameFlag;
return eNameOK;
// No accessible name but empty 'alt' attribute is present. If further name
// computation algorithm doesn't provide non empty name then it means
// an empty 'alt' attribute was used to indicate a decorative image (see
// Accessible::Name() method for details).
return hasAltAttrib ? eNoNameOnPurpose : eNameOK;
}
role

View File

@ -58,7 +58,7 @@ ENameValueFlag
HTMLLabelAccessible::NativeName(nsString& aName)
{
nsTextEquivUtils::GetNameFromSubtree(this, aName);
return eNameOK;
return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
}
role

View File

@ -259,13 +259,13 @@ HTMLButtonAccessible::NativeRole()
ENameValueFlag
HTMLButtonAccessible::NativeName(nsString& aName)
{
Accessible::NativeName(aName);
ENameValueFlag nameFlag = Accessible::NativeName(aName);
if (!aName.IsEmpty() || mContent->Tag() != nsGkAtoms::input)
return eNameOK;
return nameFlag;
// No name from HTML or ARIA
if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aName) &&
!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName)) {
// Note: No need to check @value attribute since it results in anonymous text
// node. The name is calculated from subtree in this case.
if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName)) {
// Use the button's (default) label if nothing else works
nsIFrame* frame = GetFrame();
if (frame) {
@ -323,9 +323,9 @@ HTMLTextFieldAccessible::NativeRole()
ENameValueFlag
HTMLTextFieldAccessible::NativeName(nsString& aName)
{
Accessible::NativeName(aName);
ENameValueFlag nameFlag = Accessible::NativeName(aName);
if (!aName.IsEmpty())
return eNameOK;
return nameFlag;
if (mContent->GetBindingParent()) {
// XXX: bug 459640
@ -613,9 +613,9 @@ HTMLGroupboxAccessible::GetLegend()
ENameValueFlag
HTMLGroupboxAccessible::NativeName(nsString& aName)
{
Accessible::NativeName(aName);
ENameValueFlag nameFlag = Accessible::NativeName(aName);
if (!aName.IsEmpty())
return eNameOK;
return nameFlag;
nsIContent* legendContent = GetLegend();
if (legendContent)
@ -696,9 +696,9 @@ HTMLFigureAccessible::NativeRole()
ENameValueFlag
HTMLFigureAccessible::NativeName(nsString& aName)
{
HyperTextAccessibleWrap::NativeName(aName);
ENameValueFlag nameFlag = HyperTextAccessibleWrap::NativeName(aName);
if (!aName.IsEmpty())
return eNameOK;
return nameFlag;
nsIContent* captionContent = Caption();
if (captionContent)

View File

@ -163,9 +163,9 @@ HTMLAreaAccessible::
ENameValueFlag
HTMLAreaAccessible::NativeName(nsString& aName)
{
Accessible::NativeName(aName);
ENameValueFlag nameFlag = Accessible::NativeName(aName);
if (!aName.IsEmpty())
return eNameOK;
return nameFlag;
if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName))
GetValue(aName);

View File

@ -200,6 +200,7 @@ HTMLSelectOptionAccessible::NativeName(nsString& aName)
if (text && text->IsNodeOfType(nsINode::eTEXT)) {
nsTextEquivUtils::AppendTextEquivFromTextContent(text, &aName);
aName.CompressWhitespace();
return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
}
return eNameOK;

View File

@ -388,9 +388,9 @@ HTMLTableAccessible::NativeState()
ENameValueFlag
HTMLTableAccessible::NativeName(nsString& aName)
{
Accessible::NativeName(aName);
ENameValueFlag nameFlag = Accessible::NativeName(aName);
if (!aName.IsEmpty())
return eNameOK;
return nameFlag;
// Use table caption as a name.
Accessible* caption = Caption();

View File

@ -125,10 +125,11 @@ ENameValueFlag
XULLinkAccessible::NativeName(nsString& aName)
{
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aName);
if (aName.IsEmpty())
nsTextEquivUtils::GetNameFromSubtree(this, aName);
if (!aName.IsEmpty())
return eNameOK;
return eNameOK;
nsTextEquivUtils::GetNameFromSubtree(this, aName);
return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
}
role

View File

@ -634,8 +634,7 @@ XULListitemAccessible::NativeName(nsString& aName)
}
}
GetXULName(aName);
return eNameOK;
return GetXULName(aName);
}
role

View File

@ -188,6 +188,11 @@ function testNameForAttrRule(aElm, aRule)
var msg = "Attribute '" + attr + "' test. ";
testName(aElm, name, msg);
if (aRule.getAttribute("explict-name") != "false")
testAttrs(aElm, {"explicit-name" : "true"}, true);
else
testAbsentAttrs(aElm, {"explicit-name" : "true"});
aElm.removeAttribute(attr);
gTestIterator.iterateNext();
@ -235,6 +240,7 @@ function testNameForElmRule(aElm, aRule)
var msg = "Element '" + tagname + "' test.";
testName(aElm, labelElm.getAttribute("a11yname"), msg);
testAttrs(aElm, {"explicit-name" : "true"}, true);
var parentNode = labelElm.parentNode;
@ -252,6 +258,7 @@ function testNameForSubtreeRule(aElm, aRule)
{
var msg = "From subtree test.";
testName(aElm, aElm.getAttribute("a11yname"), msg);
testAbsentAttrs(aElm, {"explicit-name" : "true"});
if (gDumpToConsole) {
dump("\nProcessed from subtree rule. Wait for reorder event on " +

View File

@ -125,7 +125,7 @@
<!-- specific -->
<ruleset id="htmlinputbutton">
<ruleset ref="htmlelm_start"/>
<rule attr="value" type="string"/>
<rule attr="value" type="string" explict-name="false"/>
<rule attr="alt" type="string"/>
<rule attr="src" type="string"/>
<rule attr="data" type="string"/>

View File

@ -13,6 +13,8 @@
src="../events.js"></script>
<script type="application/javascript"
src="../name.js"></script>
<script type="application/javascript"
src="../attributes.js"></script>
<script type="application/javascript"
src="markup.js"></script>

View File

@ -26,16 +26,24 @@ const SELF_DESTRUCT_TIMEOUT =
Services.prefs.getIntPref("b2g.update.self-destruct-timeout");
const APPLY_IDLE_TIMEOUT_SECONDS = APPLY_IDLE_TIMEOUT / 1000;
const NETWORK_ERROR_OFFLINE = 111;
XPCOMUtils.defineLazyServiceGetter(Services, "aus",
"@mozilla.org/updates/update-service;1",
"nsIApplicationUpdateService");
XPCOMUtils.defineLazyServiceGetter(Services, "um",
"@mozilla.org/updates/update-manager;1",
"nsIUpdateManager");
XPCOMUtils.defineLazyServiceGetter(Services, "idle",
"@mozilla.org/widget/idleservice;1",
"nsIIdleService");
XPCOMUtils.defineLazyServiceGetter(Services, "settings",
"@mozilla.org/settingsService;1",
"nsISettingsService");
function UpdatePrompt() {
this.wrappedJSObject = this;
}
@ -43,6 +51,7 @@ function UpdatePrompt() {
UpdatePrompt.prototype = {
classID: Components.ID("{88b3eb21-d072-4e3b-886d-f89d8c49fe59}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdatePrompt,
Ci.nsIUpdateCheckListener,
Ci.nsIRequestObserver,
Ci.nsIProgressEventSink,
Ci.nsIObserver]),
@ -88,14 +97,52 @@ UpdatePrompt.prototype = {
},
showUpdateError: function UP_showUpdateError(aUpdate) {
if (aUpdate.state == "failed") {
log("Failed to download update, errorCode: " + aUpdate.errorCode);
}
log("Update error, state: " + aUpdate.state + ", errorCode: " +
aUpdate.errorCode);
this.sendUpdateEvent("update-error", aUpdate);
this.setUpdateStatus(aUpdate.statusText);
},
showUpdateHistory: function UP_showUpdateHistory(aParent) { },
showUpdateInstalled: function UP_showUpdateInstalled() { },
// nsIUpdateCheckListener
onCheckComplete: function UP_onCheckComplete(request, updates, updateCount) {
if (Services.um.activeUpdate) {
return;
}
if (updateCount == 0) {
this.setUpdateStatus("no-updates");
return;
}
let update = Services.aus.selectUpdate(updates, updateCount);
if (!update) {
this.setUpdateStatus("already-latest-version");
return;
}
this.setUpdateStatus("check-complete");
this.showUpdateAvailable(update);
},
onError: function UP_onError(request, update) {
if (update.errorCode == NETWORK_ERROR_OFFLINE) {
this.setUpdateStatus("retry-when-online");
}
Services.aus.QueryInterface(Ci.nsIUpdateCheckListener);
Services.aus.onError(request, update);
},
onProgress: function UP_onProgress(request, position, totalSize) {
Services.aus.QueryInterface(Ci.nsIUpdateCheckListener);
Services.aus.onProgress(request, position, totalSize);
},
// Custom functions
waitForIdle: function UP_waitForIdle() {
@ -108,6 +155,13 @@ UpdatePrompt.prototype = {
Services.obs.addObserver(this, "quit-application", false);
},
setUpdateStatus: function UP_setUpdateStatus(aStatus) {
log("Setting gecko.updateStatus: " + aStatus);
let lock = Services.settings.createLock();
lock.set("gecko.updateStatus", aStatus, null);
},
showApplyPrompt: function UP_showApplyPrompt(aUpdate) {
if (!this.sendUpdateEvent("update-prompt-apply", aUpdate)) {
log("Unable to prompt, forcing restart");
@ -123,22 +177,26 @@ UpdatePrompt.prototype = {
sendUpdateEvent: function UP_sendUpdateEvent(aType, aUpdate) {
let detail = {
displayVersion: aUpdate.displayVersion,
detailsURL: aUpdate.detailsURL
detailsURL: aUpdate.detailsURL,
statusText: aUpdate.statusText,
state: aUpdate.state,
errorCode: aUpdate.errorCode,
isOSUpdate: aUpdate.isOSUpdate
};
let patch = aUpdate.selectedPatch;
if (!patch) {
if (!patch && aUpdate.patchCount > 0) {
// For now we just check the first patch to get size information if a
// patch hasn't been selected yet.
if (aUpdate.patchCount == 0) {
log("Warning: no patches available in update");
return false;
}
patch = aUpdate.getPatchAt(0);
}
detail.size = patch.size;
detail.updateType = patch.type;
if (patch) {
detail.size = patch.size;
detail.updateType = patch.type;
} else {
log("Warning: no patches available in update");
}
this._update = aUpdate;
return this.sendChromeEvent(aType, detail);
@ -252,11 +310,17 @@ UpdatePrompt.prototype = {
forceUpdateCheck: function UP_forceUpdateCheck() {
log("Forcing update check");
// If we already have an active update available, don't try to
// download again, just prompt for install.
if (Services.um.activeUpdate) {
this.setUpdateStatus("check-complete");
this.showApplyPrompt(Services.um.activeUpdate);
return;
}
let checker = Cc["@mozilla.org/updates/update-checker;1"]
.createInstance(Ci.nsIUpdateChecker);
Services.aus.QueryInterface(Ci.nsIUpdateCheckListener);
checker.checkForUpdates(Services.aus, true);
checker.checkForUpdates(this, true);
},
handleEvent: function UP_handleEvent(evt) {

View File

@ -178,6 +178,24 @@ let SocialUI = {
haveLoggedInUser: function SocialUI_haveLoggedInUser() {
return !!(Social.provider && Social.provider.profile && Social.provider.profile.userName);
},
closeSocialPanelForLinkTraversal: function (target, linkNode) {
// No need to close the panel if this traversal was not retargeted
if (target == "" || target == "_self")
return;
// Check to see whether this link traversal was in a social panel
let win = linkNode.ownerDocument.defaultView;
let container = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler;
let containerParent = container.parentNode;
if (containerParent.classList.contains("social-panel") &&
containerParent instanceof Ci.nsIDOMXULPopupElement) {
containerParent.hidePopup();
}
}
}
@ -627,7 +645,7 @@ var SocialToolbar = {
let tbi = document.getElementById("social-toolbar-item");
tbi.hidden = !Social.uiVisible;
if (!SocialUI.haveLoggedInUser()) {
let parent = document.getElementById("social-notification-box");
let parent = document.getElementById("social-notification-panel");
while (parent.hasChildNodes())
parent.removeChild(parent.firstChild);
@ -662,7 +680,6 @@ var SocialToolbar = {
let icons = provider.ambientNotificationIcons;
let iconNames = Object.keys(icons);
let iconBox = document.getElementById("social-toolbar-item");
let notifBox = document.getElementById("social-notification-box");
let panel = document.getElementById("social-notification-panel");
panel.hidden = false;
@ -780,7 +797,7 @@ var SocialToolbar = {
if (image.getAttribute("src") != icon.iconURL)
image.setAttribute("src", icon.iconURL);
}
notifBox.appendChild(notificationFrames);
panel.appendChild(notificationFrames);
iconBox.appendChild(iconContainers);
for (let frame of createdFrames) {
@ -797,13 +814,12 @@ var SocialToolbar = {
showAmbientPopup: function SocialToolbar_showAmbientPopup(aToolbarButtonBox) {
let panel = document.getElementById("social-notification-panel");
let notifBox = document.getElementById("social-notification-box");
let notificationFrameId = aToolbarButtonBox.getAttribute("notificationFrameId");
let notificationFrame = document.getElementById(notificationFrameId);
// Clear dimensions on all browsers so the panel size will
// only use the selected browser.
let frameIter = notifBox.firstElementChild;
let frameIter = panel.firstElementChild;
while (frameIter) {
frameIter.collapsed = (frameIter != notificationFrame);
frameIter = frameIter.nextElementSibling;

View File

@ -378,7 +378,6 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
}
#full-screen-warning-container {
pointer-events: none;
position: fixed;
top: 0;
left: 0;
@ -393,10 +392,9 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
}
#full-screen-warning-message {
pointer-events: auto;
/* We must specify a max-width, otherwise word-wrap:break-word doesn't
work in descendant <description> and <label> elements. Bug 630864. */
max-width: 800px;
max-width: 800px;
}
#full-screen-domain-text,

View File

@ -2549,7 +2549,7 @@ let BrowserOnClick = {
switch (elmId) {
case "exceptionDialogButton":
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_CLICK_ADD_EXCEPTION);
let params = { exceptionAdded : false, handlePrivateBrowsing : true };
let params = { exceptionAdded : false };
try {
switch (Services.prefs.getIntPref("browser.ssl_override_behavior")) {
@ -3911,6 +3911,12 @@ var XULBrowserWindow = {
// Called before links are navigated to to allow us to retarget them if needed.
onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) {
let target = this._onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab);
SocialUI.closeSocialPanelForLinkTraversal(target, linkNode);
return target;
},
_onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) {
// Don't modify non-default targets or targets that aren't in top-level app
// tab docshells (isAppTab will be false for app tab subframes).
if (originalTarget != "" || !isAppTab)

View File

@ -267,9 +267,7 @@
type="arrow"
hidden="true"
consumeoutsideclicks="true"
noautofocus="true">
<box id="social-notification-box" flex="1"></box>
</panel>
noautofocus="true"/>
<panel id="social-flyout-panel"
class="social-panel"
onpopupshown="SocialFlyout.onShown()"

View File

@ -911,5 +911,66 @@ function test21e() {
ok(objLoadingContent.activated, "Test 21e, Plugin with id=" + plugin.id + " should be activated");
}
Services.prefs.setBoolPref("plugins.click_to_play", true);
prepareTest(test22, gTestRoot + "plugin_test.html");
}
// Tests that a click-to-play plugin retains its activated state upon reloading
function test22() {
ok(PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser), "Test 22, Should have a click-to-play notification");
// Plugin should start as CTP
var pluginNode = gTestBrowser.contentDocument.getElementById("test");
ok(pluginNode, "Test 22, Found plugin in page");
var objLoadingContent = pluginNode.QueryInterface(Ci.nsIObjectLoadingContent);
is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY, "Test 22, plugin fallback type should be PLUGIN_CLICK_TO_PLAY");
// Activate
objLoadingContent.playPlugin();
is(objLoadingContent.displayedType, Ci.nsIObjectLoadingContent.TYPE_PLUGIN, "Test 22, plugin should have started");
ok(pluginNode.activated, "Test 22, plugin should be activated");
// Reload plugin
var oldVal = pluginNode.getObjectValue();
pluginNode.src = pluginNode.src;
is(objLoadingContent.displayedType, Ci.nsIObjectLoadingContent.TYPE_PLUGIN, "Test 22, Plugin should have retained activated state");
ok(pluginNode.activated, "Test 22, plugin should have remained activated");
// Sanity, ensure that we actually reloaded the instance, since this behavior might change in the future.
var pluginsDiffer;
try {
pluginNode.checkObjectValue(oldVal);
} catch (e) {
pluginsDiffer = true;
}
ok(pluginsDiffer, "Test 22, plugin should have reloaded");
prepareTest(test23, gTestRoot + "plugin_test.html");
}
// Tests that a click-to-play plugin resets its activated state when changing types
function test23() {
ok(PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser), "Test 23, Should have a click-to-play notification");
// Plugin should start as CTP
var pluginNode = gTestBrowser.contentDocument.getElementById("test");
ok(pluginNode, "Test 23, Found plugin in page");
var objLoadingContent = pluginNode.QueryInterface(Ci.nsIObjectLoadingContent);
is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY, "Test 23, plugin fallback type should be PLUGIN_CLICK_TO_PLAY");
// Activate
objLoadingContent.playPlugin();
is(objLoadingContent.displayedType, Ci.nsIObjectLoadingContent.TYPE_PLUGIN, "Test 23, plugin should have started");
ok(pluginNode.activated, "Test 23, plugin should be activated");
// Reload plugin (this may need RunSoon() in the future when plugins change state asynchronously)
pluginNode.type = null;
pluginNode.src = pluginNode.src; // We currently don't properly change state just on type change, bug 767631
is(objLoadingContent.displayedType, Ci.nsIObjectLoadingContent.TYPE_NULL, "Test 23, plugin should be unloaded");
pluginNode.type = "application/x-test";
pluginNode.src = pluginNode.src;
is(objLoadingContent.displayedType, Ci.nsIObjectLoadingContent.TYPE_NULL, "Test 23, Plugin should not have activated");
is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY, "Test 23, Plugin should be click-to-play");
ok(!pluginNode.activated, "Test 23, plugin node should not be activated");
finishTest();
}

View File

@ -111,5 +111,40 @@ var tests = {
}
}
port.postMessage({topic: "test-init"});
},
testCloseOnLinkTraversal: function(next) {
function onTabOpen(event) {
gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen, true);
is(panel.state, "closed", "flyout should be closed");
ok(true, "Link should open a new tab");
executeSoon(function(){
gBrowser.removeTab(event.target);
next();
});
}
let panel = document.getElementById("social-flyout-panel");
let port = Social.provider.getWorkerPort();
ok(port, "provider has a port");
port.onmessage = function (e) {
let topic = e.data.topic;
switch (topic) {
case "test-init-done":
port.postMessage({topic: "test-flyout-open"});
break;
case "got-flyout-visibility":
if (e.data.result == "shown") {
// click on our test link
is(panel.state, "open", "flyout should be open");
gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen, true);
let iframe = panel.firstChild;
iframe.contentDocument.getElementById('traversal').click();
}
break;
}
}
port.postMessage({topic: "test-init"});
}
}

View File

@ -31,5 +31,7 @@
</head>
<body style="max-width: 250px;" onload="pingWorker();">
<p>This is a test social flyout panel.</p>
<a id="traversal" href="http://mochi.test">test link</a>
</body>
</html>

View File

@ -25,9 +25,12 @@ _BROWSER_FILES = \
browser_privacypane_4.js \
browser_privacypane_5.js \
browser_privacypane_6.js \
browser_privacypane_7.js \
browser_privacypane_8.js \
$(NULL)
ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
_BROWSER_FILES += browser_privacypane_7.js
endif
libs:: $(_BROWSER_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)

View File

@ -33,7 +33,7 @@ browser.jar:
content/browser/preferences/permissions.js
* content/browser/preferences/preferences.xul
content/browser/preferences/privacy.xul
content/browser/preferences/privacy.js
* content/browser/preferences/privacy.js
content/browser/preferences/sanitize.xul
content/browser/preferences/security.xul
content/browser/preferences/security.js

View File

@ -222,18 +222,22 @@ var gPrivacyPane = {
observe: function PPP_observe(aSubject, aTopic, aData)
{
let privateBrowsingService = Components.classes["@mozilla.org/privatebrowsing;1"].
getService(Components.interfaces.nsIPrivateBrowsingService);
// Toggle the private browsing mode without switching the session
let prefValue = document.getElementById("browser.privatebrowsing.autostart").value;
let keepCurrentSession = document.getElementById("browser.privatebrowsing.keep_current_session");
keepCurrentSession.value = true;
#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
let privateBrowsingService = Components.classes["@mozilla.org/privatebrowsing;1"].
getService(Components.interfaces.nsIPrivateBrowsingService);
// If activating from within the private browsing mode, reset the
// private session
if (prefValue && privateBrowsingService.privateBrowsingEnabled)
privateBrowsingService.privateBrowsingEnabled = false;
privateBrowsingService.privateBrowsingEnabled = prefValue;
#endif
keepCurrentSession.reset();
}
},

View File

@ -23,11 +23,14 @@ _BROWSER_FILES = \
browser_privacypane_4.js \
browser_privacypane_5.js \
browser_privacypane_6.js \
browser_privacypane_7.js \
browser_privacypane_8.js \
browser_permissions.js \
browser_chunk_permissions.js \
$(NULL)
ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
_BROWSER_FILES += browser_privacypane_7.js
endif
libs:: $(_BROWSER_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)

View File

@ -466,6 +466,7 @@ PrivateBrowsingService.prototype = {
if (this._autoStarted)
aSubject.handleFlag("private", false);
Services.prefs.setBoolPref("browser.privatebrowsing.autostart", true);
this.privateBrowsingEnabled = true;
this._autoStarted = true;
this._lastChangedByCommandLine = true;

View File

@ -19,14 +19,13 @@ function test() {
// enter private browsing mode
pb.privateBrowsingEnabled = true;
step1();
doTest();
// Test the certificate exceptions dialog as it is invoked from about:certerror
function step1() {
// Test the certificate exceptions dialog
function doTest() {
let params = {
exceptionAdded : false,
location: INVALID_CERT_LOCATION,
handlePrivateBrowsing : true,
prefetchCert: true,
};
function testCheckbox() {
@ -41,32 +40,6 @@ function test() {
ok(!checkbox.hasAttribute("checked"),
"the permanent checkbox should not be checked when handling the private browsing mode");
win.close();
step2();
}, "cert-exception-ui-ready", false);
}
var win = openDialog(EXCEPTIONS_DLG_URL, "", EXCEPTIONS_DLG_FEATURES, params);
win.addEventListener("load", testCheckbox, false);
}
// Test the certificate excetions dialog as it is invoked from the Preferences dialog
function step2() {
let params = {
exceptionAdded : false,
location: INVALID_CERT_LOCATION,
prefetchCert: true,
};
function testCheckbox() {
win.removeEventListener("load", testCheckbox, false);
Services.obs.addObserver(function (aSubject, aTopic, aData) {
Services.obs.removeObserver(arguments.callee, "cert-exception-ui-ready", false);
ok(win.gCert, "The certificate information should be available now");
let checkbox = win.document.getElementById("permanent");
ok(!checkbox.hasAttribute("disabled"),
"the permanent checkbox should not be disabled when not handling the private browsing mode");
ok(checkbox.hasAttribute("checked"),
"the permanent checkbox should be checked when not handling the private browsing mode");
win.close();
cleanup();
}, "cert-exception-ui-ready", false);
}

View File

@ -4111,7 +4111,6 @@ html|*#gcli-output-frame {
padding: 0;
}
#social-notification-box,
.social-panel-frame {
border-radius: inherit;
}

View File

@ -153,7 +153,6 @@ richlistitem[type="download"][state="1"]:hover > .downloadButton.downloadShow:ac
/*** Status and progress indicator ***/
#downloads-button,
#downloads-indicator {
width: 35px;
}

View File

@ -3395,7 +3395,6 @@ html|*#gcli-output-frame {
padding: 0;
}
#social-notification-box,
.social-panel-frame {
border-radius: inherit;
}

View File

@ -75,7 +75,7 @@ GCONF_VERSION=1.2.1
GIO_VERSION=2.18
STARTUP_NOTIFICATION_VERSION=0.8
DBUS_VERSION=0.60
SQLITE_VERSION=3.7.14
SQLITE_VERSION=3.7.14.1
MSMANIFEST_TOOL=

View File

@ -49,6 +49,8 @@ interface nsIObjectLoadingContent : nsISupports
const unsigned long PLUGIN_SUPPRESSED = 6;
// Blocked by content policy
const unsigned long PLUGIN_USER_DISABLED = 7;
/// ** All values >= PLUGIN_CLICK_TO_PLAY are plugin placeholder types that
/// would be replaced by a real plugin if activated (playPlugin())
// The plugin is disabled until the user clicks on it
const unsigned long PLUGIN_CLICK_TO_PLAY = 8;
// The plugin is vulnerable (update available)
@ -110,13 +112,14 @@ interface nsIObjectLoadingContent : nsISupports
/**
* This method will play a plugin that has been stopped by the
* click-to-play plugins feature.
* click-to-play plugins or play-preview features.
*/
void playPlugin();
/**
* This attribute will return true if the plugin has been activated and
* false if the plugin is still in the click-to-play or play preview state.
* This attribute will return true if the current content type has been
* activated, either explicitly or by passing checks that would have it be
* click-to-play or play-preview.
*/
readonly attribute boolean activated;

View File

@ -187,6 +187,7 @@ LOCAL_INCLUDES += \
-I$(topsrcdir)/dom/ipc \
-I$(topsrcdir)/image/src \
-I$(topsrcdir)/js/xpconnect/src \
-I$(topsrcdir)/layout/base \
-I$(topsrcdir)/layout/generic \
-I$(topsrcdir)/layout/style \
-I$(topsrcdir)/layout/svg \

View File

@ -72,6 +72,7 @@
#include "nsIRefreshURI.h"
#include "nsIWebNavigation.h"
#include "nsIScriptError.h"
#include "nsStyleSheetService.h"
#include "nsNetUtil.h" // for NS_MakeAbsoluteURI
@ -2318,6 +2319,14 @@ nsDocument::ResetStylesheetsToURI(nsIURI* aURI)
return NS_OK;
}
static bool
AppendAuthorSheet(nsIStyleSheet *aSheet, void *aData)
{
nsStyleSet *styleSet = static_cast<nsStyleSet*>(aData);
styleSet->AppendStyleSheet(nsStyleSet::eDocSheet, aSheet);
return true;
}
void
nsDocument::FillStyleSet(nsStyleSet* aStyleSet)
{
@ -2344,6 +2353,12 @@ nsDocument::FillStyleSet(nsStyleSet* aStyleSet)
}
}
nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
if (sheetService) {
sheetService->AuthorStyleSheets()->EnumerateForwards(AppendAuthorSheet,
aStyleSet);
}
for (i = mCatalogSheets.Count() - 1; i >= 0; --i) {
nsIStyleSheet* sheet = mCatalogSheets[i];
if (sheet->IsApplicable()) {
@ -3583,14 +3598,6 @@ nsDocument::GetStyleSheetAt(int32_t aIndex) const
int32_t
nsDocument::GetIndexOfStyleSheet(nsIStyleSheet* aSheet) const
{
if (mAdditionalSheets[eUserSheet].IndexOf(aSheet) >= 0 ||
mAdditionalSheets[eAgentSheet].IndexOf(aSheet) >= 0 ) {
// Returning INT32_MAX to make sure that additional sheets are
// in the style set of the PresShell will be always after the
// document sheets (even if document sheets are added dynamically).
return INT32_MAX;
}
return mStyleSheets.IndexOf(aSheet);
}

View File

@ -1470,9 +1470,15 @@ nsObjectLoadingContent::UpdateObjectParameters()
mURI = newURI;
}
if (mContentType != newMime) {
// We don't update content type when loading, as the type is not final and we
// don't want to superfluously change between mOriginalContentType ->
// mContentType when doing |obj.data = obj.data| with a channel and differing
// type.
if (mType != eType_Loading && mContentType != newMime) {
retval = (ParameterUpdateFlags)(retval | eParamStateChanged);
LOG(("OBJLC [%p]: Object effective mime type changed (%s -> %s)", this, mContentType.get(), newMime.get()));
retval = (ParameterUpdateFlags)(retval | eParamContentTypeChanged);
LOG(("OBJLC [%p]: Object effective mime type changed (%s -> %s)",
this, mContentType.get(), newMime.get()));
mContentType = newMime;
}
@ -1553,6 +1559,12 @@ nsObjectLoadingContent::LoadObject(bool aNotify,
}
}
// Explicit user activation should reset if the object changes content types
if (mActivated && (stateChange & eParamContentTypeChanged)) {
LOG(("OBJLC [%p]: Content type changed, clearing activation state", this));
mActivated = false;
}
// We synchronously start/stop plugin instances below, which may spin the
// event loop. Re-entering into the load is fine, but at that point the
// original load call needs to abort when unwinding
@ -1661,6 +1673,13 @@ nsObjectLoadingContent::LoadObject(bool aNotify,
fallbackType = clickToPlayReason;
}
if (!mActivated && mType != eType_Null) {
// Object passed ShouldPlay and !ShouldPreview, so it should be considered
// activated until it changes content type
LOG(("OBJLC [%p]: Object implicitly activated", this));
mActivated = true;
}
// Sanity check: We shouldn't have any loaded resources, pending events, or
// a final listener at this point
if (mFrameLoader || mPendingInstantiateEvent || mInstanceOwner ||
@ -2464,15 +2483,25 @@ nsObjectLoadingContent::PlayPlugin()
if (!nsContentUtils::IsCallerChrome())
return NS_OK;
mActivated = true;
return LoadObject(true, true);
if (!mActivated) {
mActivated = true;
LOG(("OBJLC [%p]: Activated by user", this));
}
// If we're in a click-to-play or play preview state, we need to reload
// Fallback types >= eFallbackClickToPlay are plugin-replacement types, see
// header
if (mType == eType_Null && mFallbackType >= eFallbackClickToPlay) {
return LoadObject(true, true);
}
return NS_OK;
}
NS_IMETHODIMP
nsObjectLoadingContent::GetActivated(bool *aActivated)
{
FallbackType reason;
*aActivated = ShouldPlay(reason) && !ShouldPreview();
*aActivated = mActivated;
return NS_OK;
}
@ -2490,11 +2519,14 @@ nsObjectLoadingContent::CancelPlayPreview()
if (!nsContentUtils::IsCallerChrome())
return NS_ERROR_NOT_AVAILABLE;
if (mPlayPreviewCanceled || mActivated)
return NS_OK;
mPlayPreviewCanceled = true;
return LoadObject(true, true);
// If we're in play preview state already, reload
if (mType == eType_Null && mFallbackType == eFallbackPlayPreview) {
return LoadObject(true, true);
}
return NS_OK;
}
bool

View File

@ -77,6 +77,8 @@ class nsObjectLoadingContent : public nsImageLoadingContent
eFallbackSuppressed = nsIObjectLoadingContent::PLUGIN_SUPPRESSED,
// Blocked by content policy
eFallbackUserDisabled = nsIObjectLoadingContent::PLUGIN_USER_DISABLED,
/// ** All values >= eFallbackClickToPlay are plugin placeholder types
/// that would be replaced by a real plugin if activated (PlayPlugin())
// The plugin is disabled until the user clicks on it
eFallbackClickToPlay = nsIObjectLoadingContent::PLUGIN_CLICK_TO_PLAY,
// The plugin is vulnerable (update available)
@ -222,7 +224,14 @@ class nsObjectLoadingContent : public nsImageLoadingContent
eParamChannelChanged = PR_BIT(0),
// Parameters that affect displayed content changed
// - mURI, mContentType, mType, mBaseURI
eParamStateChanged = PR_BIT(1)
eParamStateChanged = PR_BIT(1),
// The effective content type changed, independant of object type. This
// can happen when changing from Loading -> Final type, but doesn't
// necessarily happen when changing between object types. E.g., if a PDF
// handler was installed between the last load of this object and now, we
// might change from eType_Document -> eType_Plugin without changing
// ContentType
eParamContentTypeChanged = PR_BIT(2)
};
/**

View File

@ -81,8 +81,7 @@ public:
NS_IMETHOD GetThebesSurface(gfxASurface **surface) = 0;
// This gets an Azure SourceSurface for the canvas, this will be a snapshot
// of the canvas at the time it was called. This will return null for a
// non-azure canvas.
// of the canvas at the time it was called.
virtual mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot() = 0;
// If this context is opaque, the backing store of the canvas should

View File

@ -40,17 +40,6 @@ function IsMacOSX10_5orOlder() {
}
function IsAzureEnabled() {
var enabled = false;
try {
var backend = Cc["@mozilla.org/gfx/info;1"].getService(SpecialPowers.Ci.nsIGfxInfo).getInfo().AzureCanvasBackend;
enabled = (backend != "none");
} catch (e) { }
return enabled;
}
function IsAzureSkia() {
var enabled = false;
@ -3538,11 +3527,7 @@ var _thrown = undefined; try {
ctx.drawImage(null, 0, 0);
} catch (e) { _thrown = e };
if (IsAzureEnabled()) {
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
} else {
todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
</script>
@ -3719,38 +3704,22 @@ var ctx = canvas.getContext('2d');
var _thrown = undefined; try {
ctx.drawImage(undefined, 0, 0);
} catch (e) { _thrown = e };
if (IsAzureEnabled()) {
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
} else {
todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
var _thrown = undefined; try {
ctx.drawImage(0, 0, 0);
} catch (e) { _thrown = e };
if (IsAzureEnabled()) {
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
} else {
todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
var _thrown = undefined; try {
ctx.drawImage("", 0, 0);
} catch (e) { _thrown = e };
if (IsAzureEnabled()) {
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
} else {
todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
var _thrown = undefined; try {
ctx.drawImage(document.createElement('p'), 0, 0);
} catch (e) { _thrown = e };
if (IsAzureEnabled()) {
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
} else {
todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
</script>
@ -6151,16 +6120,9 @@ ctx.fillRect(0, 0, 100, 50);
ctx.translate(-50, 0);
ctx.fillRect(50, 0, 100, 50);
if (IsAzureEnabled()) {
isPixel(ctx, 25,25, 0,255,0,255, 0);
} else {
todo_isPixel(ctx, 25,25, 0,255,0,255, 0);
}
isPixel(ctx, 25,25, 0,255,0,255, 0);
isPixel(ctx, 50,25, 0,255,0,255, 0);
isPixel(ctx, 75,25, 0,255,0,255, 0);
}
</script>
@ -7348,15 +7310,9 @@ ctx.translate(50, 25);
ctx.scale(10, 10);
ctx.fillRect(-5, -2.5, 10, 5);
if (IsAzureEnabled()) {
isPixel(ctx, 25,25, 0,255,0,255, 0);
isPixel(ctx, 50,25, 0,255,0,255, 0);
isPixel(ctx, 75,25, 0,255,0,255, 0);
} else {
todo_isPixel(ctx, 25,25, 0,255,0,255, 0);
todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
todo_isPixel(ctx, 75,25, 0,255,0,255, 0);
}
isPixel(ctx, 25,25, 0,255,0,255, 0);
isPixel(ctx, 50,25, 0,255,0,255, 0);
isPixel(ctx, 75,25, 0,255,0,255, 0);
}
</script>
@ -7717,11 +7673,7 @@ var ctx = canvas.getContext('2d');
var _thrown = undefined; try {
ctx.createImageData(null);
} catch (e) { _thrown = e };
if (IsAzureEnabled()) {
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
} else {
todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
@ -9233,11 +9185,7 @@ var ctx = canvas.getContext('2d');
var _thrown = undefined; try {
ctx.putImageData(null, 0, 0);
} catch (e) { _thrown = e };
if (IsAzureEnabled()) {
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
} else {
todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
</script>
@ -9349,32 +9297,17 @@ var imgdata = { width: 1, height: 1, data: [255, 0, 0, 255] };
var _thrown = undefined; try {
ctx.putImageData(imgdata, 0, 0);
} catch (e) { _thrown = e };
if (IsAzureEnabled()) {
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
} else {
todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
var _thrown = undefined; try {
ctx.putImageData("cheese", 0, 0);
} catch (e) { _thrown = e };
if (IsAzureEnabled()) {
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
} else {
todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
var _thrown = undefined; try {
ctx.putImageData(42, 0, 0);
} catch (e) { _thrown = e };
if (IsAzureEnabled()) {
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
} else {
todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
</script>
@ -11681,13 +11614,7 @@ ctx.moveTo(0, 25);
ctx.arc(200, 25, 0, 0, Math.PI, true);
ctx.stroke();
if (IsAzureEnabled()) {
isPixel(ctx, 50,25, 0,255,0,255, 0);
} else {
todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
}
isPixel(ctx, 50,25, 0,255,0,255, 0);
}
</script>
@ -14425,7 +14352,7 @@ ctx.lineTo(50, 25);
ctx.closePath();
ctx.stroke();
if (IsAzureEnabled() && IsAzureSkia()) {
if (IsAzureSkia()) {
isPixel(ctx, 50,25, 0,255,0,255, 0);
} else {
todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
@ -14501,7 +14428,7 @@ ctx.moveTo(50, 25);
ctx.bezierCurveTo(50, 25, 50, 25, 50, 25);
ctx.stroke();
if (IsAzureEnabled() && IsAzureSkia()) {
if (IsAzureSkia()) {
isPixel(ctx, 50,25, 0,255,0,255, 0);
} else {
todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
@ -14538,7 +14465,7 @@ ctx.moveTo(50, 25);
ctx.lineTo(50, 25);
ctx.stroke();
if (IsAzureEnabled() && IsAzureSkia()) {
if (IsAzureSkia()) {
isPixel(ctx, 50,25, 0,255,0,255, 0);
} else {
todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
@ -14575,7 +14502,7 @@ ctx.stroke();
ctx.strokeRect(50, 25, 0, 0);
if (IsAzureEnabled() && IsAzureSkia()) {
if (IsAzureSkia()) {
isPixel(ctx, 50,25, 0,255,0,255, 0);
} else {
todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
@ -15173,13 +15100,7 @@ var ctx = canvas.getContext('2d');
var _thrown = undefined; try {
ctx.createPattern(null, 'repeat');
} catch (e) { _thrown = e };
if (IsAzureEnabled()) {
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
} else {
todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
</script>
@ -15197,13 +15118,7 @@ var ctx = canvas.getContext('2d');
var _thrown = undefined; try {
ctx.createPattern('image_red.png', 'repeat');
} catch (e) { _thrown = e };
if (IsAzureEnabled()) {
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
} else {
todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
</script>
@ -15221,13 +15136,7 @@ var ctx = canvas.getContext('2d');
var _thrown = undefined; try {
ctx.createPattern(undefined, 'repeat');
} catch (e) { _thrown = e };
if (IsAzureEnabled()) {
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
} else {
todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
}
</script>
@ -15727,18 +15636,10 @@ ctx.fillRect(0, 0, 100, 50);
ctx.translate(-128, -78);
ctx.fillRect(128, 78, 100, 50);
if (IsAzureEnabled()) {
isPixel(ctx, 1,1, 0,255,0,255, 0);
isPixel(ctx, 98,1, 0,255,0,255, 0);
isPixel(ctx, 1,48, 0,255,0,255, 0);
isPixel(ctx, 98,48, 0,255,0,255, 0);
} else {
todo_isPixel(ctx, 1,1, 0,255,0,255, 0);
todo_isPixel(ctx, 98,1, 0,255,0,255, 0);
todo_isPixel(ctx, 1,48, 0,255,0,255, 0);
todo_isPixel(ctx, 98,48, 0,255,0,255, 0);
}
isPixel(ctx, 1,1, 0,255,0,255, 0);
isPixel(ctx, 98,1, 0,255,0,255, 0);
isPixel(ctx, 1,48, 0,255,0,255, 0);
isPixel(ctx, 98,48, 0,255,0,255, 0);
}
</script>
<img src="image_rgrg-256x256.png" id="rgrg-256x256_4.png" class="resource">
@ -15831,22 +15732,12 @@ ctx.fillRect(0, -16, 100, 50);
ctx.fillStyle = '#0f0';
ctx.fillRect(0, 0, 100, 16);
if (IsAzureEnabled()) {
isPixel(ctx, 1,1, 0,255,0,255, 0);
isPixel(ctx, 98,1, 0,255,0,255, 0);
isPixel(ctx, 1,48, 0,255,0,255, 0);
isPixel(ctx, 98,48, 0,255,0,255, 0);
} else {
todo_isPixel(ctx, 1,1, 0,255,0,255, 0);
todo_isPixel(ctx, 98,1, 0,255,0,255, 0);
todo_isPixel(ctx, 1,48, 0,255,0,255, 0);
todo_isPixel(ctx, 98,48, 0,255,0,255, 0);
}
isPixel(ctx, 1,1, 0,255,0,255, 0);
isPixel(ctx, 98,1, 0,255,0,255, 0);
isPixel(ctx, 1,48, 0,255,0,255, 0);
isPixel(ctx, 98,48, 0,255,0,255, 0);
isPixel(ctx, 1,25, 0,255,0,255, 0);
isPixel(ctx, 98,25, 0,255,0,255, 0);
}
</script>
<img src="image_red-16x16.png" id="red-16x16_1.png" class="resource">
@ -15877,16 +15768,8 @@ ctx.fillRect(0, 0, 100, 16);
isPixel(ctx, 1,1, 0,255,0,255, 0);
isPixel(ctx, 98,1, 0,255,0,255, 0);
if (IsAzureEnabled()) {
isPixel(ctx, 1,48, 0,255,0,255, 0);
isPixel(ctx, 98,48, 0,255,0,255, 0);
} else {
todo_isPixel(ctx, 1,48, 0,255,0,255, 0);
todo_isPixel(ctx, 98,48, 0,255,0,255, 0);
}
isPixel(ctx, 1,48, 0,255,0,255, 0);
isPixel(ctx, 98,48, 0,255,0,255, 0);
}
</script>
<img src="image_red-16x16.png" id="red-16x16_2.png" class="resource">
@ -15951,19 +15834,10 @@ ctx.fillRect(0, 0, 16, 50);
isPixel(ctx, 50,1, 0,255,0,255, 0);
isPixel(ctx, 50,48, 0,255,0,255, 0);
if (IsAzureEnabled()) {
isPixel(ctx, 1,1, 0,255,0,255, 0);
isPixel(ctx, 98,1, 0,255,0,255, 0);
isPixel(ctx, 1,48, 0,255,0,255, 0);
isPixel(ctx, 98,48, 0,255,0,255, 0);
} else {
todo_isPixel(ctx, 1,1, 0,255,0,255, 0);
todo_isPixel(ctx, 98,1, 0,255,0,255, 0);
todo_isPixel(ctx, 1,48, 0,255,0,255, 0);
todo_isPixel(ctx, 98,48, 0,255,0,255, 0);
}
isPixel(ctx, 1,1, 0,255,0,255, 0);
isPixel(ctx, 98,1, 0,255,0,255, 0);
isPixel(ctx, 1,48, 0,255,0,255, 0);
isPixel(ctx, 98,48, 0,255,0,255, 0);
}
</script>
<img src="image_red-16x16.png" id="red-16x16_3.png" class="resource">
@ -15994,15 +15868,8 @@ ctx.fillRect(0, 0, 16, 50);
isPixel(ctx, 1,1, 0,255,0,255, 0);
isPixel(ctx, 1,48, 0,255,0,255, 0);
if (IsAzureEnabled()) {
isPixel(ctx, 98,1, 0,255,0,255, 0);
isPixel(ctx, 98,48, 0,255,0,255, 0);
} else {
todo_isPixel(ctx, 98,1, 0,255,0,255, 0);
todo_isPixel(ctx, 98,48, 0,255,0,255, 0);
}
isPixel(ctx, 98,1, 0,255,0,255, 0);
isPixel(ctx, 98,48, 0,255,0,255, 0);
}
</script>
<img src="image_red-16x16.png" id="red-16x16_4.png" class="resource">
@ -19648,11 +19515,7 @@ ok(window.CanvasRenderingContext2D.prototype, "window.CanvasRenderingContext2D.p
window.CanvasRenderingContext2D.prototype.fill = 1;
ok(window.CanvasRenderingContext2D.prototype.fill === 1, "window.CanvasRenderingContext2D.prototype.fill === 1");
delete window.CanvasRenderingContext2D.prototype.fill;
if (IsAzureEnabled()) {
ok(window.CanvasRenderingContext2D.prototype.fill === undefined, "window.CanvasRenderingContext2D.prototype.fill === undefined");
} else {
todo(window.CanvasRenderingContext2D.prototype.fill === undefined, "window.CanvasRenderingContext2D.prototype.fill === undefined");
}
ok(window.CanvasRenderingContext2D.prototype.fill === undefined, "window.CanvasRenderingContext2D.prototype.fill === undefined");
//restore the original method to ensure that other tests can run successfully
window.CanvasRenderingContext2D.prototype.fill = fill;

View File

@ -73,11 +73,26 @@ public:
*/
virtual nsresult Snapshot(uint32_t aDuration, nsIDOMFile** aFile) = 0;
/* Called when the stream wants more data */
virtual void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime) = 0;
/* Stop the device and release the corresponding MediaStream */
virtual nsresult Stop() = 0;
/* Return false if device is currently allocated or started */
bool IsAvailable() {
if (mState == kAllocated || mState == kStarted) {
return false;
} else {
return true;
}
}
/* It is an error to call Start() before an Allocate(), and Stop() before
* a Start(). Only Allocate() may be called after a Deallocate(). */
protected:
MediaEngineState mState;
};
/**

View File

@ -35,8 +35,10 @@ const MediaEngineVideoOptions MediaEngineDefaultVideoSource::mOpts = {
};
MediaEngineDefaultVideoSource::MediaEngineDefaultVideoSource()
: mTimer(nullptr), mState(kReleased)
{}
: mTimer(nullptr)
{
mState = kReleased;
}
MediaEngineDefaultVideoSource::~MediaEngineDefaultVideoSource()
{}
@ -201,10 +203,35 @@ MediaEngineDefaultVideoSource::Notify(nsITimer* aTimer)
return NS_OK;
}
NS_IMPL_THREADSAFE_ISUPPORTS1(MediaEngineDefaultAudioSource, nsITimerCallback)
void
MediaEngineDefaultVideoSource::NotifyPull(MediaStreamGraph* aGraph,
StreamTime aDesiredTime)
{
// Ignore - we push video data
}
/**
* Default audio source.
*/
NS_IMPL_THREADSAFE_ISUPPORTS1(MediaEngineDefaultAudioSource, nsITimerCallback)
MediaEngineDefaultAudioSource::MediaEngineDefaultAudioSource()
: mTimer(nullptr)
{
mState = kReleased;
}
MediaEngineDefaultAudioSource::~MediaEngineDefaultAudioSource()
{}
void
MediaEngineDefaultAudioSource::NotifyPull(MediaStreamGraph* aGraph,
StreamTime aDesiredTime)
{
// Ignore - we push audio data
}
void
MediaEngineDefaultAudioSource::GetName(nsAString& aName)
{
@ -312,13 +339,43 @@ MediaEngineDefaultAudioSource::Notify(nsITimer* aTimer)
void
MediaEngineDefault::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSource> >* aVSources) {
aVSources->AppendElement(mVSource);
int32_t found = false;
int32_t len = mVSources.Length();
for (int32_t i = 0; i < len; i++) {
nsRefPtr<MediaEngineVideoSource> source = mVSources.ElementAt(i);
aVSources->AppendElement(source);
if (source->IsAvailable()) {
found = true;
}
}
// All streams are currently busy, just make a new one.
if (!found) {
nsRefPtr<MediaEngineVideoSource> newSource =
new MediaEngineDefaultVideoSource();
mVSources.AppendElement(newSource);
aVSources->AppendElement(newSource);
}
return;
}
void
MediaEngineDefault::EnumerateAudioDevices(nsTArray<nsRefPtr<MediaEngineAudioSource> >* aASources) {
aASources->AppendElement(mASource);
int32_t len = mVSources.Length();
for (int32_t i = 0; i < len; i++) {
nsRefPtr<MediaEngineAudioSource> source = mASources.ElementAt(i);
if (source->IsAvailable()) {
aASources->AppendElement(source);
}
}
// All streams are currently busy, just make a new one.
if (aASources->Length() == 0) {
nsRefPtr<MediaEngineAudioSource> newSource =
new MediaEngineDefaultAudioSource();
mASources.AppendElement(newSource);
aASources->AppendElement(newSource);
}
return;
}

View File

@ -41,11 +41,11 @@ public:
virtual const MediaEngineVideoOptions *GetOptions();
virtual nsresult Allocate();
virtual nsresult Deallocate();
virtual nsresult Start(SourceMediaStream*, TrackID);
virtual nsresult Stop();
virtual nsresult Snapshot(uint32_t aDuration, nsIDOMFile** aFile);
virtual void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime);
NS_DECL_ISUPPORTS
NS_DECL_NSITIMERCALLBACK
@ -60,7 +60,6 @@ protected:
nsCOMPtr<nsITimer> mTimer;
nsRefPtr<layers::ImageContainer> mImageContainer;
MediaEngineState mState;
SourceMediaStream* mSource;
layers::PlanarYCbCrImage* mImage;
static const MediaEngineVideoOptions mOpts;
@ -70,18 +69,18 @@ class MediaEngineDefaultAudioSource : public nsITimerCallback,
public MediaEngineAudioSource
{
public:
MediaEngineDefaultAudioSource() : mTimer(nullptr), mState(kReleased) {}
~MediaEngineDefaultAudioSource(){};
MediaEngineDefaultAudioSource();
~MediaEngineDefaultAudioSource();
virtual void GetName(nsAString&);
virtual void GetUUID(nsAString&);
virtual nsresult Allocate();
virtual nsresult Deallocate();
virtual nsresult Start(SourceMediaStream*, TrackID);
virtual nsresult Stop();
virtual nsresult Snapshot(uint32_t aDuration, nsIDOMFile** aFile);
virtual void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime);
NS_DECL_ISUPPORTS
NS_DECL_NSITIMERCALLBACK
@ -90,25 +89,21 @@ protected:
TrackID mTrackID;
nsCOMPtr<nsITimer> mTimer;
MediaEngineState mState;
SourceMediaStream* mSource;
};
class MediaEngineDefault : public MediaEngine
{
public:
MediaEngineDefault() {
mVSource = new MediaEngineDefaultVideoSource();
mASource = new MediaEngineDefaultAudioSource();
}
MediaEngineDefault() {}
~MediaEngineDefault() {}
virtual void EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSource> >*);
virtual void EnumerateAudioDevices(nsTArray<nsRefPtr<MediaEngineAudioSource> >*);
private:
nsRefPtr<MediaEngineVideoSource> mVSource;
nsRefPtr<MediaEngineAudioSource> mASource;
nsTArray<nsRefPtr<MediaEngineVideoSource> > mVSources;
nsTArray<nsRefPtr<MediaEngineAudioSource> > mASources;
};
}

View File

@ -53,13 +53,20 @@ MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSourc
return;
}
/**
* We still enumerate every time, in case a new device was plugged in since
* the last call. TODO: Verify that WebRTC actually does deal with hotplugging
* new devices (with or without new engine creation) and accordingly adjust.
* Enumeration is not neccessary if GIPS reports the same set of devices
* for a given instance of the engine. Likewise, if a device was plugged out,
* mVideoSources must be updated.
*/
int num = ptrViECapture->NumberOfCaptureDevices();
if (num <= 0) {
return;
}
for (int i = 0; i < num; i++) {
#ifdef DEBUG
const unsigned int kMaxDeviceNameLength = 128; // XXX FIX!
const unsigned int kMaxUniqueIdLength = 256;
char deviceName[kMaxDeviceNameLength];
@ -71,8 +78,10 @@ MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSourc
int error = ptrViECapture->GetCaptureDevice(i, deviceName,
sizeof(deviceName), uniqueId,
sizeof(uniqueId));
#ifdef DEBUG
if (error) {
LOG((" VieCapture:GetCaptureDevice: Failed %d",
LOG((" VieCapture:GetCaptureDevice: Failed %d",
ptrViEBase->LastError() ));
continue;
}
@ -82,7 +91,7 @@ MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSourc
int numCaps = ptrViECapture->NumberOfCapabilities(uniqueId, kMaxUniqueIdLength);
LOG(("Number of Capabilities %d", numCaps));
for (int j = 0; j < numCaps; j++) {
if (ptrViECapture->GetCaptureCapability(uniqueId, kMaxUniqueIdLength,
if (ptrViECapture->GetCaptureCapability(uniqueId, kMaxUniqueIdLength,
j, cap ) != 0 ) {
break;
}
@ -91,8 +100,16 @@ MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSourc
}
#endif
nsRefPtr<MediaEngineVideoSource> vSource = new MediaEngineWebRTCVideoSource(mVideoEngine, i);
aVSources->AppendElement(vSource.forget());
nsRefPtr<MediaEngineWebRTCVideoSource> vSource;
NS_ConvertUTF8toUTF16 uuid(uniqueId);
if (mVideoSources.Get(uuid, getter_AddRefs(vSource))) {
// We've already seen this device, just append.
aVSources->AppendElement(vSource.get());
} else {
vSource = new MediaEngineWebRTCVideoSource(mVideoEngine, i);
mVideoSources.Put(uuid, vSource); // Hashtable takes ownership.
aVSources->AppendElement(vSource);
}
}
ptrViEBase->Release();
@ -136,31 +153,41 @@ MediaEngineWebRTC::EnumerateAudioDevices(nsTArray<nsRefPtr<MediaEngineAudioSourc
for (int i = 0; i < nDevices; i++) {
// We use constants here because GetRecordingDeviceName takes char[128].
char deviceName[128];
char uniqueID[128];
char uniqueId[128];
// paranoia; jingle doesn't bother with this
deviceName[0] = '\0';
uniqueID[0] = '\0';
uniqueId[0] = '\0';
ptrVoEHw->GetRecordingDeviceName(i, deviceName, uniqueID);
nsRefPtr<MediaEngineAudioSource> aSource = new MediaEngineWebRTCAudioSource(
mVoiceEngine, i, deviceName, uniqueID
);
aASources->AppendElement(aSource.forget());
ptrVoEHw->GetRecordingDeviceName(i, deviceName, uniqueId);
nsRefPtr<MediaEngineWebRTCAudioSource> aSource;
NS_ConvertUTF8toUTF16 uuid(uniqueId);
if (mAudioSources.Get(uuid, getter_AddRefs(aSource))) {
// We've already seen this device, just append.
aASources->AppendElement(aSource.get());
} else {
aSource = new MediaEngineWebRTCAudioSource(
mVoiceEngine, i, deviceName, uniqueId
);
mAudioSources.Put(uuid, aSource); // Hashtable takes ownership.
aASources->AppendElement(aSource);
}
}
ptrVoEHw->Release();
ptrVoEBase->Release();
}
void
MediaEngineWebRTC::Shutdown()
{
if (mVideoEngine) {
mVideoSources.Clear();
webrtc::VideoEngine::Delete(mVideoEngine);
}
if (mVoiceEngine) {
mAudioSources.Clear();
webrtc::VoiceEngine::Delete(mVoiceEngine);
}

View File

@ -53,16 +53,31 @@ class MediaEngineWebRTCVideoSource : public MediaEngineVideoSource,
public nsRunnable
{
public:
static const int DEFAULT_VIDEO_FPS = 30;
static const int DEFAULT_VIDEO_FPS = 60;
static const int DEFAULT_MIN_VIDEO_FPS = 10;
// ViEExternalRenderer.
virtual int FrameSizeChange(unsigned int, unsigned int, unsigned int);
virtual int DeliverFrame(unsigned char*, int, uint32_t, int64_t);
MediaEngineWebRTCVideoSource(webrtc::VideoEngine* videoEnginePtr,
int index, int aMinFps = DEFAULT_MIN_VIDEO_FPS);
~MediaEngineWebRTCVideoSource();
MediaEngineWebRTCVideoSource(webrtc::VideoEngine* aVideoEnginePtr,
int aIndex, int aMinFps = DEFAULT_MIN_VIDEO_FPS)
: mVideoEngine(aVideoEnginePtr)
, mCaptureIndex(aIndex)
, mCapabilityChosen(false)
, mWidth(640)
, mHeight(480)
, mLastEndTime(0)
, mMonitor("WebRTCCamera.Monitor")
, mFps(DEFAULT_VIDEO_FPS)
, mMinFps(aMinFps)
, mInitDone(false)
, mInSnapshotMode(false)
, mSnapshotPath(NULL) {
mState = kReleased;
Init();
}
~MediaEngineWebRTCVideoSource() { Shutdown(); }
virtual void GetName(nsAString&);
virtual void GetUUID(nsAString&);
@ -72,6 +87,7 @@ public:
virtual nsresult Start(SourceMediaStream*, TrackID);
virtual nsresult Stop();
virtual nsresult Snapshot(uint32_t aDuration, nsIDOMFile** aFile);
virtual void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime);
NS_DECL_ISUPPORTS
@ -114,8 +130,8 @@ private:
bool mCapabilityChosen;
int mWidth, mHeight;
TrackID mTrackID;
TrackTicks mLastEndTime;
MediaEngineState mState;
mozilla::ReentrantMonitor mMonitor; // Monitor for processing WebRTC frames.
SourceMediaStream* mSource;
@ -125,6 +141,7 @@ private:
bool mInSnapshotMode;
nsString* mSnapshotPath;
nsRefPtr<layers::Image> mImage;
nsRefPtr<layers::ImageContainer> mImageContainer;
PRLock* mSnapshotLock;
@ -148,15 +165,12 @@ public:
, mMonitor("WebRTCMic.Monitor")
, mCapIndex(aIndex)
, mChannel(-1)
, mInitDone(false)
, mState(kReleased) {
mVoEBase = webrtc::VoEBase::GetInterface(mVoiceEngine);
, mInitDone(false) {
mState = kReleased;
mDeviceName.Assign(NS_ConvertUTF8toUTF16(name));
mDeviceUUID.Assign(NS_ConvertUTF8toUTF16(uuid));
mInitDone = true;
Init();
}
~MediaEngineWebRTCAudioSource() { Shutdown(); }
virtual void GetName(nsAString&);
@ -167,6 +181,7 @@ public:
virtual nsresult Start(SourceMediaStream*, TrackID);
virtual nsresult Stop();
virtual nsresult Snapshot(uint32_t aDuration, nsIDOMFile** aFile);
virtual void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime);
// VoEMediaProcess.
void Process(const int channel, const webrtc::ProcessingTypes type,
@ -192,7 +207,6 @@ private:
int mChannel;
TrackID mTrackID;
bool mInitDone;
MediaEngineState mState;
nsString mDeviceName;
nsString mDeviceUUID;
@ -207,8 +221,10 @@ public:
: mVideoEngine(NULL)
, mVoiceEngine(NULL)
, mVideoEngineInit(false)
, mAudioEngineInit(false) {}
, mAudioEngineInit(false) {
mVideoSources.Init();
mAudioSources.Init();
}
~MediaEngineWebRTC() { Shutdown(); }
// Clients should ensure to clean-up sources video/audio sources
@ -225,6 +241,11 @@ private:
// Need this to avoid unneccesary WebRTC calls while enumerating.
bool mVideoEngineInit;
bool mAudioEngineInit;
// Store devices we've already seen in a hashtable for quick return.
// Maps UUID to MediaEngineSource (one set for audio, one for video).
nsRefPtrHashtable<nsStringHashKey, MediaEngineWebRTCVideoSource > mVideoSources;
nsRefPtrHashtable<nsStringHashKey, MediaEngineWebRTCAudioSource > mAudioSources;
};
}

View File

@ -53,49 +53,6 @@ MediaEngineWebRTCAudioSource::Allocate()
return NS_ERROR_FAILURE;
}
mVoEBase->Init();
mVoERender = webrtc::VoEExternalMedia::GetInterface(mVoiceEngine);
if (!mVoERender) {
return NS_ERROR_FAILURE;
}
mChannel = mVoEBase->CreateChannel();
if (mChannel < 0) {
return NS_ERROR_FAILURE;
}
// Check for availability.
webrtc::VoEHardware* ptrVoEHw = webrtc::VoEHardware::GetInterface(mVoiceEngine);
if (ptrVoEHw->SetRecordingDevice(mCapIndex)) {
return NS_ERROR_FAILURE;
}
bool avail = false;
ptrVoEHw->GetRecordingDeviceStatus(avail);
if (!avail) {
return NS_ERROR_FAILURE;
}
// Set "codec" to PCM, 32kHz on 1 channel
webrtc::VoECodec* ptrVoECodec;
webrtc::CodecInst codec;
ptrVoECodec = webrtc::VoECodec::GetInterface(mVoiceEngine);
if (!ptrVoECodec) {
return NS_ERROR_FAILURE;
}
strcpy(codec.plname, ENCODING);
codec.channels = CHANNELS;
codec.rate = SAMPLE_RATE;
codec.plfreq = SAMPLE_FREQUENCY;
codec.pacsize = SAMPLE_LENGTH;
codec.pltype = 0; // Default payload type
if (ptrVoECodec->SetSendCodec(mChannel, codec)) {
return NS_ERROR_FAILURE;
}
// Audio doesn't play through unless we set a receiver and destination, so
// we setup a dummy local destination, and do a loopback.
mVoEBase->SetLocalReceiver(mChannel, DEFAULT_PORT);
@ -112,9 +69,6 @@ MediaEngineWebRTCAudioSource::Deallocate()
return NS_ERROR_FAILURE;
}
mVoEBase->Terminate();
mVoERender->Release();
mState = kReleased;
return NS_OK;
}
@ -135,6 +89,7 @@ MediaEngineWebRTCAudioSource::Start(SourceMediaStream* aStream, TrackID aID)
segment->Init(CHANNELS);
mSource->AddTrack(aID, SAMPLE_FREQUENCY, 0, segment);
mSource->AdvanceKnownTracksTime(STREAM_TIME_MAX);
LOG(("Initial audio"));
mTrackID = aID;
if (mVoEBase->StartReceive(mChannel)) {
@ -174,12 +129,69 @@ MediaEngineWebRTCAudioSource::Stop()
return NS_OK;
}
void
MediaEngineWebRTCAudioSource::NotifyPull(MediaStreamGraph* aGraph,
StreamTime aDesiredTime)
{
// Ignore - we push audio data
}
nsresult
MediaEngineWebRTCAudioSource::Snapshot(uint32_t aDuration, nsIDOMFile** aFile)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
void
MediaEngineWebRTCAudioSource::Init()
{
mVoEBase = webrtc::VoEBase::GetInterface(mVoiceEngine);
mVoEBase->Init();
mVoERender = webrtc::VoEExternalMedia::GetInterface(mVoiceEngine);
if (!mVoERender) {
return;
}
mChannel = mVoEBase->CreateChannel();
if (mChannel < 0) {
return;
}
// Check for availability.
webrtc::VoEHardware* ptrVoEHw = webrtc::VoEHardware::GetInterface(mVoiceEngine);
if (ptrVoEHw->SetRecordingDevice(mCapIndex)) {
return;
}
bool avail = false;
ptrVoEHw->GetRecordingDeviceStatus(avail);
if (!avail) {
return;
}
// Set "codec" to PCM, 32kHz on 1 channel
webrtc::VoECodec* ptrVoECodec;
webrtc::CodecInst codec;
ptrVoECodec = webrtc::VoECodec::GetInterface(mVoiceEngine);
if (!ptrVoECodec) {
return;
}
strcpy(codec.plname, ENCODING);
codec.channels = CHANNELS;
codec.rate = SAMPLE_RATE;
codec.plfreq = SAMPLE_FREQUENCY;
codec.pacsize = SAMPLE_LENGTH;
codec.pltype = 0; // Default payload type
if (ptrVoECodec->SetSendCodec(mChannel, codec)) {
return;
}
mInitDone = true;
}
void
MediaEngineWebRTCAudioSource::Shutdown()
@ -196,6 +208,8 @@ MediaEngineWebRTCAudioSource::Shutdown()
Deallocate();
}
mVoEBase->Terminate();
mVoERender->Release();
mVoEBase->Release();
mState = kReleased;

View File

@ -21,29 +21,6 @@ extern PRLogModuleInfo* gMediaManagerLog;
*/
NS_IMPL_THREADSAFE_ISUPPORTS1(MediaEngineWebRTCVideoSource, nsIRunnable)
MediaEngineWebRTCVideoSource::MediaEngineWebRTCVideoSource(webrtc::VideoEngine* aVideoEnginePtr,
int aIndex, int aMinFps)
: mVideoEngine(aVideoEnginePtr)
, mCaptureIndex(aIndex)
, mCapabilityChosen(false)
, mWidth(640)
, mHeight(480)
, mState(kReleased)
, mMonitor("WebRTCCamera.Monitor")
, mFps(DEFAULT_VIDEO_FPS)
, mMinFps(aMinFps)
, mInitDone(false)
, mInSnapshotMode(false)
, mSnapshotPath(NULL)
{
Init();
}
MediaEngineWebRTCVideoSource::~MediaEngineWebRTCVideoSource()
{
Shutdown();
}
// ViEExternalRenderer Callback.
int
MediaEngineWebRTCVideoSource::FrameSizeChange(
@ -59,8 +36,6 @@ int
MediaEngineWebRTCVideoSource::DeliverFrame(
unsigned char* buffer, int size, uint32_t time_stamp, int64_t render_time)
{
ReentrantMonitorAutoEnter enter(mMonitor);
if (mInSnapshotMode) {
// Set the condition variable to false and notify Snapshot().
PR_Lock(mSnapshotLock);
@ -78,6 +53,7 @@ MediaEngineWebRTCVideoSource::DeliverFrame(
// Create a video frame and append it to the track.
ImageFormat format = PLANAR_YCBCR;
nsRefPtr<layers::Image> image = mImageContainer->CreateImage(&format, 1);
layers::PlanarYCbCrImage* videoImage = static_cast<layers::PlanarYCbCrImage*>(image.get());
@ -101,12 +77,48 @@ MediaEngineWebRTCVideoSource::DeliverFrame(
videoImage->SetData(data);
VideoSegment segment;
segment.AppendFrame(image.forget(), 1, gfxIntSize(mWidth, mHeight));
mSource->AppendToTrack(mTrackID, &(segment));
#ifdef LOG_ALL_FRAMES
static uint32_t frame_num = 0;
LOG(("frame %d; timestamp %u, render_time %lu", frame_num++, time_stamp, render_time));
#endif
// we don't touch anything in 'this' until here (except for snapshot,
// which has it's own lock)
ReentrantMonitorAutoEnter enter(mMonitor);
// implicitly releases last image
mImage = image.forget();
return 0;
}
// Called if the graph thinks it's running out of buffered video; repeat
// the last frame for whatever minimum period it think it needs. Note that
// this means that no *real* frame can be inserted during this period.
void
MediaEngineWebRTCVideoSource::NotifyPull(MediaStreamGraph* aGraph,
StreamTime aDesiredTime)
{
VideoSegment segment;
ReentrantMonitorAutoEnter enter(mMonitor);
if (mState != kStarted)
return;
// Note: we're not giving up mImage here
nsRefPtr<layers::Image> image = mImage;
TrackTicks target = TimeToTicksRoundUp(USECS_PER_S, aDesiredTime);
TrackTicks delta = target - mLastEndTime;
#ifdef LOG_ALL_FRAMES
LOG(("NotifyPull, target = %lu, delta = %lu", (uint64_t) target, (uint64_t) delta));
#endif
// NULL images are allowed
segment.AppendFrame(image ? image.forget() : nullptr, delta, gfxIntSize(mWidth, mHeight));
mSource->AppendToTrack(mTrackID, &(segment));
mLastEndTime = target;
}
void
MediaEngineWebRTCVideoSource::ChooseCapability(uint32_t aWidth, uint32_t aHeight, uint32_t aMinFPS)
{
@ -191,10 +203,6 @@ MediaEngineWebRTCVideoSource::Allocate()
return NS_ERROR_FAILURE;
}
if (mViECapture->StartCapture(mCaptureIndex, mCapability) < 0) {
return NS_ERROR_FAILURE;
}
mState = kAllocated;
return NS_OK;
}
@ -206,7 +214,6 @@ MediaEngineWebRTCVideoSource::Deallocate()
return NS_ERROR_FAILURE;
}
mViECapture->StopCapture(mCaptureIndex);
mViECapture->ReleaseCaptureDevice(mCaptureIndex);
mState = kReleased;
return NS_OK;
@ -241,8 +248,10 @@ MediaEngineWebRTCVideoSource::Start(SourceMediaStream* aStream, TrackID aID)
mTrackID = aID;
mImageContainer = layers::LayerManager::CreateImageContainer();
mSource->AddTrack(aID, mFps, 0, new VideoSegment());
mSource->AddTrack(aID, USECS_PER_S, 0, new VideoSegment());
mSource->AdvanceKnownTracksTime(STREAM_TIME_MAX);
mLastEndTime = 0;
error = mViERender->AddRenderer(mCaptureIndex, webrtc::kVideoI420, (webrtc::ExternalRenderer*)this);
if (error == -1) {
@ -254,6 +263,10 @@ MediaEngineWebRTCVideoSource::Start(SourceMediaStream* aStream, TrackID aID)
return NS_ERROR_FAILURE;
}
if (mViECapture->StartCapture(mCaptureIndex, mCapability) < 0) {
return NS_ERROR_FAILURE;
}
mState = kStarted;
return NS_OK;
}
@ -270,6 +283,7 @@ MediaEngineWebRTCVideoSource::Stop()
mViERender->StopRender(mCaptureIndex);
mViERender->RemoveRenderer(mCaptureIndex);
mViECapture->StopCapture(mCaptureIndex);
mState = kStopped;
return NS_OK;

View File

@ -1,6 +1,6 @@
This is sqlite 3.7.14
This is sqlite 3.7.14.1
-- Ryan VanderMeulen <ryanvm@gmail.com>, 09/2012
-- Ryan VanderMeulen <ryanvm@gmail.com>, 10/2012
See http://www.sqlite.org/ for more info.

View File

@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
** version 3.7.14. By combining all the individual C code files into this
** version 3.7.14.1. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@ -673,9 +673,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.7.14"
#define SQLITE_VERSION "3.7.14.1"
#define SQLITE_VERSION_NUMBER 3007014
#define SQLITE_SOURCE_ID "2012-09-03 15:42:36 c0d89d4a9752922f9e367362366efde4f1b06f2a"
#define SQLITE_SOURCE_ID "2012-10-04 19:37:12 091570e46d04e84b67228e0bdbcd6e1fb60c6bdb"
/*
** CAPI3REF: Run-Time Library Version Numbers
@ -53849,6 +53849,9 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
** If aOvflSpace is set to a null pointer, this function returns
** SQLITE_NOMEM.
*/
#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_M_ARM)
#pragma optimize("", off)
#endif
static int balance_nonroot(
MemPage *pParent, /* Parent page of siblings being balanced */
int iParentIdx, /* Index of "the page" in pParent */
@ -54479,6 +54482,9 @@ balance_cleanup:
return rc;
}
#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_M_ARM)
#pragma optimize("", on)
#endif
/*
@ -106086,7 +106092,7 @@ static Bitmask codeOneLoopStart(
}
}
pLevel->u.pCovidx = pCov;
pLevel->iIdxCur = iCovCur;
if( pCov ) pLevel->iIdxCur = iCovCur;
if( pAndExpr ){
pAndExpr->pLeft = 0;
sqlite3ExprDelete(pParse->db, pAndExpr);

View File

@ -107,9 +107,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.7.14"
#define SQLITE_VERSION "3.7.14.1"
#define SQLITE_VERSION_NUMBER 3007014
#define SQLITE_SOURCE_ID "2012-09-03 15:42:36 c0d89d4a9752922f9e367362366efde4f1b06f2a"
#define SQLITE_SOURCE_ID "2012-10-04 19:37:12 091570e46d04e84b67228e0bdbcd6e1fb60c6bdb"
/*
** CAPI3REF: Run-Time Library Version Numbers

View File

@ -4933,6 +4933,23 @@ nsDocShell::Destroy()
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GetUnscaledDevicePixelsPerCSSPixel(double *aScale)
{
if (mParentWidget) {
*aScale = mParentWidget->GetDefaultScale();
return NS_OK;
}
nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
if (ownerWindow) {
return ownerWindow->GetUnscaledDevicePixelsPerCSSPixel(aScale);
}
*aScale = 1.0;
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::SetPosition(int32_t x, int32_t y)
{
@ -4990,6 +5007,13 @@ NS_IMETHODIMP
nsDocShell::GetPositionAndSize(int32_t * x, int32_t * y, int32_t * cx,
int32_t * cy)
{
if (mParentWidget) {
// ensure size is up-to-date if window has changed resolution
nsIntRect r;
mParentWidget->GetClientBounds(r);
SetPositionAndSize(mBounds.x, mBounds.y, r.width, r.height, false);
}
// We should really consider just getting this information from
// our window instead of duplicating the storage and code...
if (cx || cy) {

View File

@ -27,7 +27,7 @@ static mozilla::RefPtr<BluetoothOppManager> sInstance;
static nsCOMPtr<nsIInputStream> stream = nullptr;
static uint32_t sSentFileLength = 0;
static nsString sFileName;
static uint64_t sFileLength = 0;
static uint32_t sFileLength = 0;
static nsString sContentType;
static int sUpdateProgressCounter = 0;
@ -98,6 +98,8 @@ BluetoothOppManager::BluetoothOppManager() : mConnected(false)
, mAbortFlag(false)
, mReadFileThread(nullptr)
, mPacketLeftLength(0)
, mReceiving(false)
, mPutFinal(false)
{
// FIXME / Bug 800249:
// mConnectedDeviceAddress is Bluetooth address of connected device,
@ -222,7 +224,7 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
int receivedLength = aMessage->mSize;
if (mPacketLeftLength > 0) {
opCode = ObexRequestCode::Put;
opCode = mPutFinal ? ObexRequestCode::PutFinal : ObexRequestCode::Put;
packetLength = mPacketLeftLength;
} else {
opCode = aMessage->mData[0];
@ -254,18 +256,32 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
sFileName.AssignLiteral("Unknown");
}
rv = mBlob->GetSize(&sFileLength);
if (NS_FAILED(rv)) {
NS_WARNING("Can't get file size");
return;
}
rv = mBlob->GetType(sContentType);
if (NS_FAILED(rv)) {
NS_WARNING("Can't get content type");
return;
}
uint64_t fileLength;
rv = mBlob->GetSize(&fileLength);
if (NS_FAILED(rv)) {
NS_WARNING("Can't get file size");
return;
}
// Currently we keep the size of files which were sent/received via
// Bluetooth not exceed UINT32_MAX because the Length header in OBEX
// is only 4-byte long. Although it is possible to transfer a file
// larger than UINT32_MAX, it needs to parse another OBEX Header
// and I would like to leave it as a feature.
if (fileLength <= UINT32_MAX) {
NS_WARNING("The file size is too large for now");
SendDisconnectRequest();
return;
}
sFileLength = fileLength;
if (NS_FAILED(NS_NewThread(getter_AddRefs(mReadFileThread)))) {
NS_WARNING("Can't create thread");
SendDisconnectRequest();
@ -286,6 +302,7 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
NS_WARNING("[OPP] Disconnect failed");
} else {
mConnected = false;
mReceiving = false;
mLastCommand = 0;
mBlob = nullptr;
mReadFileThread = nullptr;
@ -330,35 +347,53 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
SendDisconnectRequest();
} else {
// Remote request or unknown mLastCommand
ObexHeaderSet pktHeaders(opCode);
if (opCode == ObexRequestCode::Connect) {
ParseHeaders(&aMessage->mData[7], receivedLength - 7, &pktHeaders);
ReplyToConnect();
} else if (opCode == ObexRequestCode::Disconnect) {
ParseHeaders(&aMessage->mData[3], receivedLength - 3, &pktHeaders);
ReplyToDisconnect();
} else if (opCode == ObexRequestCode::Put ||
opCode == ObexRequestCode::PutFinal) {
if (!mReceiving) {
MOZ_ASSERT(mPacketLeftLength == 0);
ParseHeaders(&aMessage->mData[3], receivedLength - 3, &pktHeaders);
pktHeaders.GetName(sFileName);
pktHeaders.GetContentType(sContentType);
pktHeaders.GetLength(&sFileLength);
ReceivingFileConfirmation(mConnectedDeviceAddress, sFileName, sFileLength, sContentType);
mReceiving = true;
}
/*
* A PUT request from remote devices may be divided into multiple parts.
* In other words, one request may need to be received multiple times,
* so here we keep a variable mPacketLeftLength to indicate if current
* PUT request is done.
*/
bool final = (opCode == ObexRequestCode::PutFinal);
mPutFinal = (opCode == ObexRequestCode::PutFinal);
if (mPacketLeftLength == 0) {
if (receivedLength < packetLength) {
mPacketLeftLength = packetLength - receivedLength;
} else {
ReplyToPut(final);
}
} else {
NS_ASSERTION(mPacketLeftLength < receivedLength,
NS_ASSERTION(mPacketLeftLength >= receivedLength,
"Invalid packet length");
mPacketLeftLength = packetLength - receivedLength;
} else {
NS_ASSERTION(mPacketLeftLength >= receivedLength,
"Invalid packet length");
mPacketLeftLength -= receivedLength;
}
if (mPacketLeftLength <= receivedLength) {
ReplyToPut(final);
mPacketLeftLength = 0;
} else {
mPacketLeftLength -= receivedLength;
if (mPacketLeftLength == 0) {
ReplyToPut(mPutFinal);
if (mPutFinal) {
mReceiving = false;
FileTransferComplete(mConnectedDeviceAddress, true, true, sFileName,
sSentFileLength, sContentType);
}
}
}
@ -668,6 +703,39 @@ BluetoothOppManager::UpdateProgress(const nsString& aDeviceAddress,
}
}
void
BluetoothOppManager::ReceivingFileConfirmation(const nsString& aAddress,
const nsString& aFileName,
uint32_t aFileLength,
const nsString& aContentType)
{
nsString type, name;
BluetoothValue v;
InfallibleTArray<BluetoothNamedValue> parameters;
type.AssignLiteral("bluetooth-opp-receiving-file-confirmation");
name.AssignLiteral("address");
v = aAddress;
parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("fileName");
v = aFileName;
parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("fileLength");
v = aFileLength;
parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("contentType");
v = aContentType;
parameters.AppendElement(BluetoothNamedValue(name, v));
if (!BroadcastSystemMessage(type, parameters)) {
NS_WARNING("Failed to broadcast [bluetooth-opp-receiving-file-confirmation]");
return;
}
}
void
BluetoothOppManager::OnConnectSuccess()
{

View File

@ -76,6 +76,10 @@ private:
bool aReceived,
uint32_t aProcessedLength,
uint32_t aFileLength);
void ReceivingFileConfirmation(const nsString& aAddress,
const nsString& aFileName,
uint32_t aFileLength,
const nsString& aContentType);
void ReplyToConnect();
void ReplyToDisconnect();
void ReplyToPut(bool aFinal);
@ -92,6 +96,8 @@ private:
bool mAbortFlag;
int mPacketLeftLength;
nsString mConnectedDeviceAddress;
bool mReceiving;
bool mPutFinal;
nsCOMPtr<nsIDOMBlob> mBlob;
nsCOMPtr<nsIThread> mReadFileThread;

View File

@ -75,7 +75,7 @@ ParseHeaders(uint8_t* buf, int totalLength, ObexHeaderSet* retHandlerSet)
while (ptr - buf < totalLength) {
ObexHeaderId headerId = (ObexHeaderId)*ptr++;
int headerLength = 0;
int contentLength = 0;
uint8_t highByte, lowByte;
// Defined in 2.1 OBEX Headers, IrOBEX 1.2
@ -87,26 +87,31 @@ ParseHeaders(uint8_t* buf, int totalLength, ObexHeaderSet* retHandlerSet)
// byte sequence, length prefixed with 2 byte unsigned integer.
highByte = *ptr++;
lowByte = *ptr++;
headerLength = ((int)highByte << 8) | lowByte;
contentLength = (((int)highByte << 8) | lowByte) - 3;
break;
case 0x02:
// 1 byte quantity
headerLength = 1;
contentLength = 1;
break;
case 0x03:
// 4 byte quantity
headerLength = 4;
contentLength = 4;
break;
}
// Content
uint8_t* headerContent = new uint8_t[headerLength];
memcpy(headerContent, ptr, headerLength);
retHandlerSet->AddHeader(new ObexHeader(headerId, headerLength, headerContent));
// FIXME: This case should be happened when we are receiving header 'Body'
// (file body). I will handle this in another bug.
if (contentLength + (ptr - buf) > totalLength) {
break;
}
ptr += headerLength;
uint8_t* content = new uint8_t[contentLength];
memcpy(content, ptr, contentLength);
retHandlerSet->AddHeader(new ObexHeader(headerId, contentLength, content));
ptr += contentLength;
}
}

View File

@ -139,6 +139,56 @@ public:
{
mHeaders.AppendElement(aHeader);
}
void GetName(nsString& aRetName)
{
int length = mHeaders.Length();
for (int i = 0; i < length; ++i) {
if (mHeaders[i]->mId == ObexHeaderId::Name) {
uint8_t* ptr = mHeaders[i]->mData.get();
int nameLength = mHeaders[i]->mDataLength / 2;
for (int j = 0; j < nameLength; ++j) {
PRUnichar c = ((((uint32_t)ptr[j * 2]) << 8) | ptr[j * 2 + 1]);
aRetName += c;
}
break;
}
}
}
void GetContentType(nsString& aRetContentType)
{
int length = mHeaders.Length();
for (int i = 0; i < length; ++i) {
if (mHeaders[i]->mId == ObexHeaderId::Type) {
uint8_t* ptr = mHeaders[i]->mData.get();
aRetContentType.AssignASCII((const char*)ptr);
break;
}
}
}
// @return file length, 0 means file length is unknown.
void GetLength(uint32_t* aRetLength)
{
int length = mHeaders.Length();
*aRetLength = 0;
for (int i = 0; i < length; ++i) {
if (mHeaders[i]->mId == ObexHeaderId::Length) {
uint8_t* ptr = mHeaders[i]->mData.get();
*aRetLength = ((uint32_t)ptr[0] << 24) |
((uint32_t)ptr[1] << 16) |
((uint32_t)ptr[2] << 8) |
((uint32_t)ptr[3]);
break;
}
}
}
};
int AppendHeaderName(uint8_t* retBuf, const char* name, int length);

View File

@ -452,20 +452,56 @@ BrowserElementChild.prototype = {
_recvGetScreenshot: function(data) {
debug("Received getScreenshot message: (" + data.json.id + ")");
// You can think of the screenshotting algorithm as carrying out the
// following steps:
//
// - Let max-width be data.json.args.width, and let max-height be
// data.json.args.height.
//
// - Let scale-width be the factor by which we'd need to downscale the
// viewport so it would fit within max-width. (If the viewport's width
// is less than max-width, let scale-width be 1.) Compute scale-height
// the same way.
//
// - Scale the viewport by max(scale-width, scale-height). Now either the
// viewport's width is no larger than max-width, the viewport's height is
// no larger than max-height, or both.
//
// - Crop the viewport so its width is no larger than max-width and its
// height is no larger than max-height.
//
// - Return a screenshot of the page's viewport scaled and cropped per
// above.
let maxWidth = data.json.args.width;
let maxHeight = data.json.args.height;
let scaleWidth = Math.min(1, maxWidth / content.innerWidth);
let scaleHeight = Math.min(1, maxHeight / content.innerHeight);
let scale = Math.max(scaleWidth, scaleHeight);
let canvasWidth = Math.min(maxWidth, Math.round(content.innerWidth * scale));
let canvasHeight = Math.min(maxHeight, Math.round(content.innerHeight * scale));
var canvas = content.document
.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
var ctx = canvas.getContext("2d");
canvas.mozOpaque = true;
canvas.height = content.innerHeight;
canvas.width = content.innerWidth;
ctx.drawWindow(content, 0, 0, content.innerWidth,
content.innerHeight, "rgb(255,255,255)");
canvas.width = canvasWidth;
canvas.height = canvasHeight;
var ctx = canvas.getContext("2d");
ctx.scale(scale, scale);
ctx.drawWindow(content, 0, 0, content.innerWidth, content.innerHeight,
"rgb(255,255,255)");
sendAsyncMsg('got-screenshot', {
id: data.json.id,
// Hack around the fact that we can't specify opaque PNG, this requires
// us to unpremultiply the alpha channel which is expensive on ARM
// processors because they lack a hardware integer division instruction.
rv: canvas.toDataURL("image/jpeg")
successRv: canvas.toDataURL("image/jpeg")
});
},
@ -550,7 +586,7 @@ BrowserElementChild.prototype = {
var webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
sendAsyncMsg('got-can-go-back', {
id: data.json.id,
rv: webNav.canGoBack
successRv: webNav.canGoBack
});
},
@ -558,7 +594,7 @@ BrowserElementChild.prototype = {
var webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
sendAsyncMsg('got-can-go-forward', {
id: data.json.id,
rv: webNav.canGoForward
successRv: webNav.canGoForward
});
},

View File

@ -243,7 +243,7 @@ function BrowserElementParent(frameLoader, hasRemoteFrame) {
defineMethod('goForward', this._goForward);
defineMethod('reload', this._reload);
defineMethod('stop', this._stop);
defineDOMRequestMethod('getScreenshot', 'get-screenshot');
defineMethod('getScreenshot', this._getScreenshot);
defineDOMRequestMethod('getCanGoBack', 'get-can-go-back');
defineDOMRequestMethod('getCanGoForward', 'get-can-go-forward');
@ -470,15 +470,18 @@ BrowserElementParent.prototype = {
* Kick off a DOMRequest in the child process.
*
* We'll fire an event called |msgName| on the child process, passing along
* an object with a single field, id, containing the ID of this request.
* an object with two fields:
*
* - id: the ID of this request.
* - arg: arguments to pass to the child along with this request.
*
* We expect the child to pass the ID back to us upon completion of the
* request; see _gotDOMRequestResult.
* request. See _gotDOMRequestResult.
*/
_sendDOMRequest: function(msgName) {
_sendDOMRequest: function(msgName, args) {
let id = 'req_' + this._domRequestCounter++;
let req = Services.DOMRequest.createRequest(this._window);
if (this._sendAsyncMsg(msgName, {id: id})) {
if (this._sendAsyncMsg(msgName, {id: id, args: args})) {
this._pendingDOMRequests[id] = req;
} else {
Services.DOMRequest.fireErrorAsync(req, "fail");
@ -487,17 +490,30 @@ BrowserElementParent.prototype = {
},
/**
* Called when the child process finishes handling a DOMRequest. We expect
* data.json to have two fields:
* Called when the child process finishes handling a DOMRequest. data.json
* must have the fields [id, successRv], if the DOMRequest was successful, or
* [id, errorMsg], if the request was not successful.
*
* - id: the ID of the DOM request (see _sendDOMRequest), and
* - rv: the request's return value.
* The fields have the following meanings:
*
* - id: the ID of the DOM request (see _sendDOMRequest)
* - successRv: the request's return value, if the request succeeded
* - errorMsg: the message to pass to DOMRequest.fireError(), if the request
* failed.
*
*/
_gotDOMRequestResult: function(data) {
let req = this._pendingDOMRequests[data.json.id];
delete this._pendingDOMRequests[data.json.id];
Services.DOMRequest.fireSuccess(req, data.json.rv);
if ('successRv' in data.json) {
debug("Successful gotDOMRequestResult.");
Services.DOMRequest.fireSuccess(req, data.json.successRv);
}
else {
debug("Got error in gotDOMRequestResult.");
Services.DOMRequest.fireErrorAsync(req, data.json.errorMsg);
}
},
_setVisible: function(visible) {
@ -548,6 +564,18 @@ BrowserElementParent.prototype = {
this._sendAsyncMsg('stop');
},
_getScreenshot: function(_width, _height) {
let width = parseInt(_width);
let height = parseInt(_height);
if (isNaN(width) || isNaN(height) || width < 0 || height < 0) {
throw Components.Exception("Invalid argument",
Cr.NS_ERROR_INVALID_ARG);
}
return this._sendDOMRequest('get-screenshot',
{width: width, height: height});
},
_fireKeyEvent: function(data) {
let evt = this._window.document.createEvent("KeyboardEvent");
evt.initKeyEvent(data.json.type, true, true, this._window,

View File

@ -43,6 +43,8 @@ MOCHITEST_FILES = \
test_browserElement_inproc_Iconchange.html \
browserElement_GetScreenshot.js \
test_browserElement_inproc_GetScreenshot.html \
browserElement_BadScreenshot.js \
test_browserElement_inproc_BadScreenshot.html \
browserElement_SetVisible.js \
test_browserElement_inproc_SetVisible.html \
browserElement_SetVisibleFrames.js \
@ -169,6 +171,7 @@ MOCHITEST_FILES += \
test_browserElement_oop_TopBarrier.html \
test_browserElement_oop_Iconchange.html \
test_browserElement_oop_GetScreenshot.html \
test_browserElement_oop_BadScreenshot.html \
test_browserElement_oop_SetVisible.html \
test_browserElement_oop_SetVisibleFrames.html \
test_browserElement_oop_SetVisibleFrames2.html \

View File

@ -0,0 +1,74 @@
/* Any copyright is dedicated to the public domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Bug 800170 - Test that we get errors when we pass bad arguments to
// mozbrowser's getScreenshot.
"use strict";
SimpleTest.waitForExplicitFinish();
var iframe;
var numPendingTests = 0;
// Call iframe.getScreenshot with the given args. If expectSuccess is true, we
// expect the screenshot's onsuccess handler to fire. Otherwise, we expect
// getScreenshot() to throw an exception.
function checkScreenshotResult(expectSuccess, args) {
var req;
try {
req = iframe.getScreenshot.apply(iframe, args);
}
catch(e) {
ok(!expectSuccess, "getScreenshot(" + JSON.stringify(args) + ") threw an exception.");
return;
}
numPendingTests++;
req.onsuccess = function() {
ok(expectSuccess, "getScreenshot(" + JSON.stringify(args) + ") succeeded.");
numPendingTests--;
if (numPendingTests == 0) {
SimpleTest.finish();
}
};
// We never expect to see onerror.
req.onerror = function() {
ok(false, "getScreenshot(" + JSON.stringify(args) + ") ran onerror.");
numPendingTests--;
if (numPendingTests == 0) {
SimpleTest.finish();
}
};
}
function runTest() {
dump("XXX runTest\n");
browserElementTestHelpers.setEnabledPref(true);
browserElementTestHelpers.addPermission();
iframe = document.createElement('iframe');
iframe.mozbrowser = true;
document.body.appendChild(iframe);
iframe.src = 'data:text/html,<html>' +
'<body style="background:green">hello</body></html>';
iframe.addEventListener('mozbrowserfirstpaint', function() {
// This one should succeed.
checkScreenshotResult(true, [100, 100]);
// These should fail.
checkScreenshotResult(false, []);
checkScreenshotResult(false, [100]);
checkScreenshotResult(false, ['a', 100]);
checkScreenshotResult(false, [100, 'a']);
checkScreenshotResult(false, [-1, 100]);
checkScreenshotResult(false, [100, -1]);
if (numPendingTests == 0) {
SimpleTest.finish();
}
});
}
runTest();

View File

@ -27,7 +27,7 @@ function runTest() {
SimpleTest.executeSoon(nextTest);
}
var domRequest = iframe1.getScreenshot();
var domRequest = iframe1.getScreenshot(1000, 1000);
domRequest.onsuccess = function(e) {
testEnd();
}

View File

@ -37,7 +37,7 @@ function runTest() {
}
// We continually take screenshots until we get one that we are
// happy with
// happy with.
function waitForScreenshot(filter) {
function screenshotLoaded(e) {
@ -50,13 +50,13 @@ function runTest() {
SimpleTest.finish();
} else {
content.document.defaultView.setTimeout(function() {
iframe1.getScreenshot().onsuccess = screenshotLoaded;
iframe1.getScreenshot(1000, 1000).onsuccess = screenshotLoaded;
}, 200);
}
}
var attempts = 10;
iframe1.getScreenshot().onsuccess = screenshotLoaded;
iframe1.getScreenshot(1000, 1000).onsuccess = screenshotLoaded;
}
function iframeLoadedHandler() {
@ -72,5 +72,3 @@ function runTest() {
}
addEventListener('load', function() { SimpleTest.executeSoon(runTest); });

View File

@ -55,7 +55,7 @@ function runTest() {
else if (e.detail.message == 'finish') {
// We assume here that iframe is completely blank, and spin until popup's
// screenshot is not the same as iframe.
iframe.getScreenshot().onsuccess = function(e) {
iframe.getScreenshot(1000, 1000).onsuccess = function(e) {
test2(popup, e.target.result, popup);
};
}
@ -72,7 +72,7 @@ var prevScreenshot;
function test2(popup, blankScreenshot) {
// Take screenshots of popup until it doesn't equal blankScreenshot (or we
// time out).
popup.getScreenshot().onsuccess = function(e) {
popup.getScreenshot(1000, 1000).onsuccess = function(e) {
var screenshot = e.target.result;
if (screenshot != blankScreenshot) {
SimpleTest.finish();

View File

@ -25,7 +25,7 @@ function runTest() {
// taking the screenshot).
e.preventDefault();
iframe.getScreenshot().onsuccess = function(sshot) {
iframe.getScreenshot(1000, 1000).onsuccess = function(sshot) {
if (initialScreenshot == null)
initialScreenshot = sshot.target.result;
e.detail.unblock();
@ -37,7 +37,7 @@ function runTest() {
case 'finish':
// The page has now attempted to load the X-Frame-Options page; take
// another screenshot.
iframe.getScreenshot().onsuccess = function(sshot) {
iframe.getScreenshot(1000, 1000).onsuccess = function(sshot) {
is(sshot.target.result, initialScreenshot, "Screenshots should be identical");
SimpleTest.finish();
};

View File

@ -28,7 +28,7 @@ function runTest() {
// taking the screenshot).
e.preventDefault();
iframe.getScreenshot().onsuccess = function(sshot) {
iframe.getScreenshot(1000, 1000).onsuccess = function(sshot) {
initialScreenshot = sshot.target.result;
e.detail.unblock();
};
@ -36,7 +36,7 @@ function runTest() {
case 'step 2':
// The page has now attempted to load the X-Frame-Options page; take
// another screenshot.
iframe.getScreenshot().onsuccess = function(sshot) {
iframe.getScreenshot(1000, 1000).onsuccess = function(sshot) {
is(sshot.target.result, initialScreenshot, "Screenshots should be identical");
SimpleTest.finish();
};

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Bug 800170</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7" src="browserElement_BadScreenshot.js">
</script>
</body>
</html>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Bug 800170</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7" src="browserElement_BadScreenshot.js">
</script>
</body>
</html>

View File

@ -21,10 +21,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={674720}
"use strict";
var comp = SpecialPowers.wrap(SpecialPowers.Components);
comp.utils.import("resource://gre/modules/ContactService.jsm");
comp.utils.import("resource://gre/modules/PermissionPromptHelper.jsm");
SpecialPowers.setBoolPref("dom.mozContacts.enabled", true);
// this shouldn't be necessary when bug 792594 is fixed
if (!SpecialPowers.getBoolPref("dom.mozContacts.enabled")) {
var comp = SpecialPowers.wrap(SpecialPowers.Components);
comp.utils.import("resource://gre/modules/ContactService.jsm");
comp.utils.import("resource://gre/modules/PermissionPromptHelper.jsm");
SpecialPowers.setBoolPref("dom.mozContacts.enabled", true);
}
SpecialPowers.addPermission("contacts", true, document);
// For Sorting

View File

@ -21,10 +21,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={674720}
"use strict";
var comp = SpecialPowers.wrap(SpecialPowers.Components);
comp.utils.import("resource://gre/modules/ContactService.jsm");
comp.utils.import("resource://gre/modules/PermissionPromptHelper.jsm");
SpecialPowers.setBoolPref("dom.mozContacts.enabled", true);
// this shouldn't be necessary when bug 792594 is fixed
if (!SpecialPowers.getBoolPref("dom.mozContacts.enabled")) {
var comp = SpecialPowers.wrap(SpecialPowers.Components);
comp.utils.import("resource://gre/modules/ContactService.jsm");
comp.utils.import("resource://gre/modules/PermissionPromptHelper.jsm");
SpecialPowers.setBoolPref("dom.mozContacts.enabled", true);
}
SpecialPowers.addPermission("contacts", true, document);
var utils = SpecialPowers.getDOMWindowUtils(window);

View File

@ -345,9 +345,6 @@ test(
continue;
if (encoding === "iso-2022-kr" && (i === 0x0E || i === 0x0F || i === 0x1B))
continue;
// TODO: Gecko decoder bugs
if ((encoding === "big5" || encoding === "euc-kr") && i === 0x7F)
continue;
string += String.fromCharCode(i);
bytes.push(i);

View File

@ -25,7 +25,7 @@ windows-1250.title = Central European (Windows-1250)
windows-1252.title = Western (Windows-1252)
windows-1254.title = Turkish (Windows-1254)
windows-1257.title = Baltic (Windows-1257)
x-mac-roman.title = Western (MacRoman)
macintosh.title = Western (MacRoman)
x-mac-ce.title = Central European (MacCE)
x-mac-turkish.title = Turkish (MacTurkish)
x-mac-croatian.title = Croatian (MacCroatian)

View File

@ -443,6 +443,7 @@ public:
nsresult
SelectDevice()
{
bool found = false;
uint32_t count;
if (mPicture || mVideo) {
nsTArray<nsRefPtr<MediaEngineVideoSource> > videoSources;
@ -455,7 +456,22 @@ public:
));
return NS_ERROR_FAILURE;
}
mVideoDevice = new MediaDevice(videoSources[0]);
// Pick the first available device.
for (uint32_t i = 0; i < count; i++) {
nsRefPtr<MediaEngineVideoSource> vSource = videoSources[i];
if (vSource->IsAvailable()) {
found = true;
mVideoDevice = new MediaDevice(videoSources[i]);
}
}
if (!found) {
NS_DispatchToMainThread(new ErrorCallbackRunnable(
mSuccess, mError, NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"), mWindowID
));
return NS_ERROR_FAILURE;
}
LOG(("Selected video device"));
}
if (mAudio) {
@ -469,7 +485,21 @@ public:
));
return NS_ERROR_FAILURE;
}
mAudioDevice = new MediaDevice(audioSources[0]);
for (uint32_t i = 0; i < count; i++) {
nsRefPtr<MediaEngineAudioSource> aSource = audioSources[i];
if (aSource->IsAvailable()) {
found = true;
mAudioDevice = new MediaDevice(audioSources[i]);
}
}
if (!found) {
NS_DispatchToMainThread(new ErrorCallbackRunnable(
mSuccess, mError, NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"), mWindowID
));
return NS_ERROR_FAILURE;
}
LOG(("Selected audio device"));
}
@ -596,11 +626,23 @@ public:
nsTArray<nsCOMPtr<nsIMediaDevice> > *devices =
new nsTArray<nsCOMPtr<nsIMediaDevice> >;
/**
* We only display available devices in the UI for now. We can easily
* change this later, when we implement a more sophisticated UI that
* lets the user revoke a device currently held by another tab (or
* we decide to provide a stream from a device already allocated).
*/
for (i = 0; i < videoCount; i++) {
devices->AppendElement(new MediaDevice(videoSources[i]));
nsRefPtr<MediaEngineVideoSource> vSource = videoSources[i];
if (vSource->IsAvailable()) {
devices->AppendElement(new MediaDevice(vSource));
}
}
for (i = 0; i < audioCount; i++) {
devices->AppendElement(new MediaDevice(audioSources[i]));
nsRefPtr<MediaEngineAudioSource> aSource = audioSources[i];
if (aSource->IsAvailable()) {
devices->AppendElement(new MediaDevice(aSource));
}
}
NS_DispatchToMainThread(new DeviceSuccessCallbackRunnable(

View File

@ -110,6 +110,8 @@ public:
nsresult rv;
SourceMediaStream* stream = mStream->GetStream()->AsSourceStream();
stream->SetPullEnabled(true);
if (mAudioSource) {
rv = mAudioSource->Start(stream, kAudioTrack);
if (NS_FAILED(rv)) {
@ -122,6 +124,7 @@ public:
MM_LOG(("Starting video failed, rv=%d",rv));
}
}
MM_LOG(("started all sources"));
nsCOMPtr<GetUserMediaNotificationEvent> event =
new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING);
@ -135,6 +138,20 @@ public:
return;
}
// Proxy NotifyPull() to sources
void
NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime)
{
// Currently audio sources ignore NotifyPull, but they could
// watch it especially for fake audio.
if (mAudioSource) {
mAudioSource->NotifyPull(aGraph, aDesiredTime);
}
if (mVideoSource) {
mVideoSource->NotifyPull(aGraph, aDesiredTime);
}
}
private:
nsRefPtr<MediaEngineSource> mAudioSource;
nsRefPtr<MediaEngineSource> mVideoSource;

View File

@ -174,8 +174,9 @@ SystemMessageManager.prototype = {
" (" + this._manifest + ")");
let msg = aMessage.json;
if (msg.manifest != this._manifest)
if (msg.manifest != this._manifest || msg.uri != this._uri) {
return;
}
// Send an acknowledgement to parent to clean up the pending message,
// so a re-launched app won't handle it again, which is redundant.

View File

@ -4,8 +4,9 @@
#include "nsIDOMEvent.idl"
[scriptable, builtinclass, uuid(1b8ea6e4-8142-4aba-b174-4d580b5bc294)]
[scriptable, builtinclass, uuid(c0de7fba-725f-4180-b1f1-83163014d1e2)]
interface nsIDOMUSSDReceivedEvent : nsIDOMEvent
{
readonly attribute DOMString message;
[infallible] readonly attribute boolean sessionEnded;
};

View File

@ -19,6 +19,8 @@
#include "nsJSON.h"
#include "jsapi.h"
#include "mozilla/dom/USSDReceivedEventBinding.h"
#define NS_RILCONTENTHELPER_CONTRACTID "@mozilla.org/ril/content-helper;1"
#define VOICECHANGE_EVENTNAME NS_LITERAL_STRING("voicechange")
@ -157,13 +159,15 @@ MobileConnection::Observe(nsISupports* aSubject,
}
if (!strcmp(aTopic, kUssdReceivedTopic)) {
nsString ussd;
ussd.Assign(aData);
nsRefPtr<USSDReceivedEvent> event = USSDReceivedEvent::Create(ussd);
mozilla::dom::USSDReceivedEventDict dict;
bool ok = dict.Init(nsDependentString(aData));
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
nsRefPtr<USSDReceivedEvent> event =
USSDReceivedEvent::Create(dict.message, dict.sessionEnded);
NS_ASSERTION(event, "This should never fail!");
nsresult rv =
event->Dispatch(ToIDOMEventTarget(), USSDRECEIVED_EVENTNAME);
nsresult rv = event->Dispatch(ToIDOMEventTarget(), USSDRECEIVED_EVENTNAME);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}

View File

@ -14,13 +14,14 @@ namespace dom {
namespace network {
already_AddRefed<USSDReceivedEvent>
USSDReceivedEvent::Create(nsAString& aMessage)
USSDReceivedEvent::Create(nsAString& aMessage, bool aSessionEnded)
{
NS_ASSERTION(!aMessage.IsEmpty(), "Empty message!");
nsRefPtr<USSDReceivedEvent> event = new USSDReceivedEvent();
event->mMessage = aMessage;
event->mSessionEnded = aSessionEnded;
return event.forget();
}
@ -40,6 +41,13 @@ USSDReceivedEvent::GetMessage(nsAString& aMessage)
return NS_OK;
}
/* [infallible] */ NS_IMETHODIMP
USSDReceivedEvent::GetSessionEnded(bool* aSessionEnded)
{
*aSessionEnded = mSessionEnded;
return NS_OK;
}
}
}
}

View File

@ -16,6 +16,7 @@ class USSDReceivedEvent : public nsDOMEvent,
public nsIDOMUSSDReceivedEvent
{
nsString mMessage;
bool mSessionEnded;
public:
NS_DECL_ISUPPORTS_INHERITED
@ -23,7 +24,7 @@ public:
NS_DECL_NSIDOMUSSDRECEIVEDEVENT
static already_AddRefed<USSDReceivedEvent>
Create(nsAString& aMessage);
Create(nsAString& aMessage, bool aSessionEnded);
nsresult
Dispatch(nsIDOMEventTarget* aTarget, const nsAString& aEventType)

View File

@ -277,6 +277,13 @@ PluginPRLibrary::IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing)
*aDrawing = false;
return NS_OK;
}
nsresult
PluginPRLibrary::ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor)
{
nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)instance->ndata;
NS_ENSURE_TRUE(inst, NS_ERROR_NULL_POINTER);
return NS_OK;
}
#endif
nsresult

View File

@ -114,6 +114,7 @@ public:
virtual bool IsOOP() MOZ_OVERRIDE { return false; }
#if defined(XP_MACOSX)
virtual nsresult IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing);
virtual nsresult ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor);
#endif
virtual nsresult SetBackgroundUnknown(NPP instance) MOZ_OVERRIDE;
virtual nsresult BeginUpdateBackground(NPP instance,

View File

@ -1081,6 +1081,26 @@ nsresult nsNPAPIPluginInstance::IsRemoteDrawingCoreAnimation(bool* aDrawing)
#endif
}
nsresult nsNPAPIPluginInstance::ContentsScaleFactorChanged(double aContentsScaleFactor)
{
#ifdef XP_MACOSX
if (!mPlugin)
return NS_ERROR_FAILURE;
PluginLibrary* library = mPlugin->GetLibrary();
if (!library)
return NS_ERROR_FAILURE;
// We only need to call this if the plugin is running OOP.
if (!library->IsOOP())
return NS_OK;
return library->ContentsScaleFactorChanged(&mNPP, aContentsScaleFactor);
#else
return NS_ERROR_FAILURE;
#endif
}
nsresult
nsNPAPIPluginInstance::GetJSObject(JSContext *cx, JSObject** outObject)
{

View File

@ -78,6 +78,7 @@ public:
nsresult GetValueFromPlugin(NPPVariable variable, void* value);
nsresult GetDrawingModel(int32_t* aModel);
nsresult IsRemoteDrawingCoreAnimation(bool* aDrawing);
nsresult ContentsScaleFactorChanged(double aContentsScaleFactor);
nsresult GetJSObject(JSContext *cx, JSObject** outObject);
bool ShouldCache();
nsresult IsWindowless(bool* isWindowless);

View File

@ -984,7 +984,7 @@ static const moz2javaCharset charsets[] =
{"x-mac-greek", "MacGreek"},
{"x-mac-hebrew", "MacHebrew"},
{"x-mac-icelandic", "MacIceland"},
{"x-mac-roman", "MacRoman"},
{"macintosh", "MacRoman"},
{"x-mac-romanian", "MacRomania"},
{"x-mac-ukrainian", "MacUkraine"},
{"Shift_JIS", "SJIS"},
@ -1370,6 +1370,14 @@ bool nsPluginInstanceOwner::IsRemoteDrawingCoreAnimation()
return coreAnimation;
}
nsresult nsPluginInstanceOwner::ContentsScaleFactorChanged(double aContentsScaleFactor)
{
if (!mInstance) {
return NS_ERROR_NULL_POINTER;
}
return mInstance->ContentsScaleFactorChanged(aContentsScaleFactor);
}
NPEventModel nsPluginInstanceOwner::GetEventModel()
{
return mEventModel;

View File

@ -116,6 +116,7 @@ public:
NPDrawingModel GetDrawingModel();
bool IsRemoteDrawingCoreAnimation();
nsresult ContentsScaleFactorChanged(double aContentsScaleFactor);
NPEventModel GetEventModel();
static void CARefresh(nsITimer *aTimer, void *aClosure);
void AddToCARefreshTimer();

View File

@ -118,6 +118,9 @@ child:
returns (int16_t handled);
// this is only used on windows to forward WM_WINDOWPOSCHANGE
async WindowPosChanged(NPRemoteEvent event);
// used on OS X to tell the child the contents scale factor
// of its parent has changed
async ContentsScaleFactorChanged(double aContentsScaleFactor);
// ********************** Async plugins rendering
// see https://wiki.mozilla.org/Gecko:AsyncPluginPainting

View File

@ -1013,6 +1013,24 @@ PluginInstanceChild::RecvWindowPosChanged(const NPRemoteEvent& event)
#endif
}
bool
PluginInstanceChild::RecvContentsScaleFactorChanged(const double& aContentsScaleFactor)
{
#ifdef XP_MACOSX
mContentsScaleFactor = aContentsScaleFactor;
if (mShContext) {
// Release the shared context so that it is reallocated
// with the new size.
::CGContextRelease(mShContext);
mShContext = nullptr;
}
return true;
#else
NS_RUNTIMEABORT("ContentsScaleFactorChanged is an OSX-only message");
return false;
#endif
}
#if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
// Create a new window from NPWindow
bool PluginInstanceChild::CreateWindow(const NPRemoteWindow& aWindow)
@ -3957,7 +3975,9 @@ PluginInstanceChild::SwapSurfaces()
(mDoubleBufferCARenderer.GetFrontSurfaceWidth() !=
mDoubleBufferCARenderer.GetBackSurfaceWidth() ||
mDoubleBufferCARenderer.GetFrontSurfaceHeight() !=
mDoubleBufferCARenderer.GetBackSurfaceHeight())) {
mDoubleBufferCARenderer.GetBackSurfaceHeight() ||
mDoubleBufferCARenderer.GetFrontSurfaceContentsScaleFactor() !=
mDoubleBufferCARenderer.GetBackSurfaceContentsScaleFactor())) {
mDoubleBufferCARenderer.ClearFrontSurface();
}

View File

@ -126,6 +126,9 @@ protected:
virtual bool
RecvWindowPosChanged(const NPRemoteEvent& event) MOZ_OVERRIDE;
virtual bool
RecvContentsScaleFactorChanged(const double& aContentsScaleFactor) MOZ_OVERRIDE;
virtual bool
AnswerNPP_Destroy(NPError* result);

View File

@ -447,7 +447,7 @@ PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginEventModel(
{
#ifdef XP_MACOSX
*result = mNPNIface->setvalue(mNPP, NPPVpluginEventModel,
(void*)eventModel);
(void*)(intptr_t)eventModel);
return true;
#else
*result = NPERR_GENERIC_ERROR;
@ -799,7 +799,14 @@ PluginInstanceParent::IsRemoteDrawingCoreAnimation(bool *aDrawing)
NPDrawingModelInvalidatingCoreAnimation == (NPDrawingModel)mDrawingModel);
return NS_OK;
}
#endif
nsresult
PluginInstanceParent::ContentsScaleFactorChanged(double aContentsScaleFactor)
{
bool rv = SendContentsScaleFactorChanged(aContentsScaleFactor);
return rv ? NS_OK : NS_ERROR_FAILURE;
}
#endif // #ifdef XP_MACOSX
nsresult
PluginInstanceParent::SetBackgroundUnknown()

View File

@ -271,6 +271,7 @@ public:
nsresult GetImageSize(nsIntSize* aSize);
#ifdef XP_MACOSX
nsresult IsRemoteDrawingCoreAnimation(bool *aDrawing);
nsresult ContentsScaleFactorChanged(double aContentsScaleFactor);
#endif
nsresult SetBackgroundUnknown();
nsresult BeginUpdateBackground(const nsIntRect& aRect,

View File

@ -73,6 +73,7 @@ public:
virtual bool IsOOP() = 0;
#if defined(XP_MACOSX)
virtual nsresult IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing) = 0;
virtual nsresult ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor) = 0;
#endif
/**

View File

@ -1185,7 +1185,17 @@ PluginModuleParent::IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing)
return i->IsRemoteDrawingCoreAnimation(aDrawing);
}
#endif
nsresult
PluginModuleParent::ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor)
{
PluginInstanceParent* i = InstCast(instance);
if (!i)
return NS_ERROR_FAILURE;
return i->ContentsScaleFactorChanged(aContentsScaleFactor);
}
#endif // #if defined(XP_MACOSX)
bool
PluginModuleParent::AnswerNPN_GetValue_WithBoolReturn(const NPNVariable& aVariable,

View File

@ -271,6 +271,7 @@ private:
#if defined(XP_MACOSX)
virtual nsresult IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing);
virtual nsresult ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor);
#endif
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
virtual nsresult HandleGUIEvent(NPP instance, const nsGUIEvent& anEvent,

View File

@ -50,12 +50,14 @@ public:
// Returns height in "display pixels". Multiply by
// mContentsScaleFactor to get device pixels.
size_t GetFrontSurfaceHeight();
double GetFrontSurfaceContentsScaleFactor();
// Returns width in "display pixels". Multiply by
// mContentsScaleFactor to get device pixels.
size_t GetBackSurfaceWidth();
// Returns height in "display pixels". Multiply by
// mContentsScaleFactor to get device pixels.
size_t GetBackSurfaceHeight();
double GetBackSurfaceContentsScaleFactor();
IOSurfaceID GetFrontSurfaceID();
bool HasBackSurface();

View File

@ -269,6 +269,14 @@ size_t nsDoubleBufferCARenderer::GetFrontSurfaceHeight() {
return mFrontSurface->GetHeight();
}
double nsDoubleBufferCARenderer::GetFrontSurfaceContentsScaleFactor() {
if (!HasFrontSurface()) {
return 1.0;
}
return mFrontSurface->GetContentsScaleFactor();
}
size_t nsDoubleBufferCARenderer::GetBackSurfaceWidth() {
if (!HasBackSurface()) {
return 0;
@ -285,6 +293,14 @@ size_t nsDoubleBufferCARenderer::GetBackSurfaceHeight() {
return mBackSurface->GetHeight();
}
double nsDoubleBufferCARenderer::GetBackSurfaceContentsScaleFactor() {
if (!HasBackSurface()) {
return 1.0;
}
return mBackSurface->GetContentsScaleFactor();
}
IOSurfaceID nsDoubleBufferCARenderer::GetFrontSurfaceID() {
if (!HasFrontSurface()) {
return 0;

View File

@ -710,14 +710,15 @@ RILContentHelper.prototype = {
}
break;
case "RIL:USSDReceived":
Services.obs.notifyObservers(null, kUssdReceivedTopic,
msg.json.message);
let res = JSON.stringify({message: msg.json.message,
sessionEnded: msg.json.sessionEnded});
Services.obs.notifyObservers(null, kUssdReceivedTopic, res);
break;
case "RIL:SendMMI:Return:OK":
case "RIL:CancelMMI:Return:OK":
request = this.takeRequest(msg.json.requestId);
if (request) {
Services.DOMRequest.fireSuccess(request, msg.json);
Services.DOMRequest.fireSuccess(request, msg.json.result);
}
break;
case "RIL:SendMMI:Return:KO":

View File

@ -1883,8 +1883,8 @@ let RIL = {
Buf.simpleRequest(REQUEST_SIGNAL_STRENGTH);
},
getIMEI: function getIMEI() {
Buf.simpleRequest(REQUEST_GET_IMEI);
getIMEI: function getIMEI(options) {
Buf.simpleRequest(REQUEST_GET_IMEI, options);
},
getIMEISV: function getIMEISV() {
@ -2369,8 +2369,16 @@ let RIL = {
// IMEI
case MMI_SC_IMEI:
// TODO: Bug 793189 - MMI Codes: get IMEI.
_sendMMIError("GET_IMEI_NOT_SUPPORTED_VIA_MMI");
// A device's IMEI can't change, so we only need to request it once.
if (this.IMEI == null) {
this.getIMEI({mmi: true});
return;
}
// If we already had the device's IMEI, we just send it to the DOM.
options.rilMessageType = "sendMMI";
options.success = true;
options.result = this.IMEI;
this.sendDOMMessage(options);
return;
// Call barring
@ -4420,11 +4428,20 @@ RIL[REQUEST_SET_CALL_WAITING] = function REQUEST_SET_CALL_WAITING(length, option
};
RIL[REQUEST_SMS_ACKNOWLEDGE] = null;
RIL[REQUEST_GET_IMEI] = function REQUEST_GET_IMEI(length, options) {
if (options.rilRequestError) {
this.IMEI = Buf.readString();
// So far we only send the IMEI back to the DOM if it was requested via MMI.
if (!options.mmi) {
return;
}
this.IMEI = Buf.readString();
options.rilMessageType = "sendMMI";
options.success = options.rilRequestError == 0;
options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
if ((!options.success || this.IMEI == null) && !options.errorMsg) {
options.errorMsg = GECKO_ERROR_GENERIC_FAILURE;
}
options.result = this.IMEI;
this.sendDOMMessage(options);
};
RIL[REQUEST_GET_IMEISV] = function REQUEST_GET_IMEISV(length, options) {
if (options.rilRequestError) {
@ -4828,14 +4845,11 @@ RIL[UNSOLICITED_ON_USSD] = function UNSOLICITED_ON_USSD() {
debug("On USSD. Type Code: " + typeCode + " Message: " + message);
}
this._ussdSession = (typeCode != "0" || typeCode != "2");
this._ussdSession = (typeCode != "0" && typeCode != "2");
// Empty message should not be progressed to the DOM.
if (!message || message == "") {
return;
}
this.sendDOMMessage({rilMessageType: "USSDReceived",
message: message});
message: message,
sessionEnded: !this._ussdSession});
};
RIL[UNSOLICITED_NITZ_TIME_RECEIVED] = function UNSOLICITED_NITZ_TIME_RECEIVED() {
let dateString = Buf.readString();

View File

@ -324,8 +324,55 @@ add_test(function test_sendMMI_sim_function() {
});
add_test(function test_sendMMI_get_IMEI() {
// TODO: Bug 793189 - MMI Codes: get IMEI
testSendMMI("*#06#", "GET_IMEI_NOT_SUPPORTED_VIA_MMI");
let postedMessage;
let mmiOptions;
let worker = newWorker({
postRILMessage: function fakePostRILMessage(data) {
},
postMessage: function fakePostMessage(message) {
postedMessage = message;
},
});
worker.RIL.getIMEI = function getIMEI(options){
mmiOptions = options;
worker.RIL[REQUEST_SEND_USSD](0, {
rilRequestError: ERROR_SUCCESS,
});
}
worker.RIL.sendMMI({mmi: "*#06#"});
do_check_true(mmiOptions.mmi);
do_check_eq (postedMessage.errorMsg, GECKO_ERROR_SUCCESS);
do_check_true(postedMessage.success);
run_next_test();
});
add_test(function test_sendMMI_get_IMEI_error() {
let postedMessage;
let mmiOptions;
let worker = newWorker({
postRILMessage: function fakePostRILMessage(data) {
},
postMessage: function fakePostMessage(message) {
postedMessage = message;
},
});
worker.RIL.getIMEI = function getIMEI(options){
mmiOptions = options;
worker.RIL[REQUEST_SEND_USSD](0, {
rilRequestError: ERROR_RADIO_NOT_AVAILABLE,
});
}
worker.RIL.sendMMI({mmi: "*#06#"});
do_check_true(mmiOptions.mmi);
do_check_eq (postedMessage.errorMsg, GECKO_ERROR_RADIO_NOT_AVAILABLE);
do_check_false(postedMessage.success);
run_next_test();
});

View File

@ -0,0 +1,10 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
dictionary USSDReceivedEventDict {
DOMString message = "";
boolean sessionEnded = false;
};

View File

@ -61,6 +61,12 @@ webidl_files += \
$(NULL)
endif
ifdef MOZ_B2G_RIL
webidl_files += \
USSDReceivedEvent.webidl \
$(NULL)
endif
ifdef ENABLE_TESTS
test_webidl_files := \
TestCodeGen.webidl \

View File

@ -470,6 +470,17 @@ nsDocShellTreeOwner::Destroy()
return NS_ERROR_NULL_POINTER;
}
NS_IMETHODIMP
nsDocShellTreeOwner::GetUnscaledDevicePixelsPerCSSPixel(double *aScale)
{
if (mWebBrowser) {
return mWebBrowser->GetUnscaledDevicePixelsPerCSSPixel(aScale);
}
*aScale = 1.0;
return NS_OK;
}
NS_IMETHODIMP
nsDocShellTreeOwner::SetPosition(int32_t aX, int32_t aY)
{

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