Merge last PGO-green changeset of mozilla-inbound to mozilla-central

This commit is contained in:
Ed Morley 2013-01-09 22:50:45 +00:00
commit af790907dd
88 changed files with 1629 additions and 488 deletions

View File

@ -51,16 +51,7 @@ DeviceRootActor.prototype.disconnect = function DRA_disconnect() {
* until at least the next listTabs request.
*/
DeviceRootActor.prototype.onListTabs = function DRA_onListTabs() {
let actor = this._tabActors.get(this.browser);
if (!actor) {
actor = new DeviceTabActor(this.conn, this.browser);
// this.actorID is set by ActorPool when an actor is put into one.
actor.parentID = this.actorID;
this._tabActors.set(this.browser, actor);
}
let actorPool = new ActorPool(this.conn);
actorPool.addActor(actor);
this._createExtraActors(DebuggerServer.globalActorFactories, actorPool);
@ -75,7 +66,7 @@ DeviceRootActor.prototype.onListTabs = function DRA_onListTabs() {
let response = {
'from': 'root',
'selected': 0,
'tabs': [actor.grip()]
'tabs': []
};
this._appendExtraActors(response);
return response;

View File

@ -457,13 +457,11 @@ function getJSON(element) {
// Until the input type=date/datetime/time have been implemented
// let's return their real type even if the platform returns 'text'
// Related to Bug 777279 - Implement <input type=time>
let attributeType = element.getAttribute("type") || "";
if (attributeType) {
var typeLowerCase = attributeType.toLowerCase();
switch (typeLowerCase) {
case "time":
case "datetime":
case "datetime-local":
type = typeLowerCase;

View File

@ -203,7 +203,7 @@ SettingsListener.observe('devtools.debugger.remote-enabled', false, function(val
Services.prefs.setBoolPref('devtools.debugger.remote-enabled', value);
// This preference is consulted during startup
Services.prefs.savePrefFile(null);
value ? startDebugger() : stopDebugger();
value ? RemoteDebugger.start() : RemoteDebugger.stop();
});
SettingsListener.observe('debug.log-animations.enabled', false, function(value) {

View File

@ -269,6 +269,7 @@ var shell = {
WebappsHelper.init();
AccessFu.attach(window);
UserAgentOverrides.init();
IndexedDBPromptHelper.init();
// XXX could factor out into a settings->pref map. Not worth it yet.
SettingsListener.observe("debug.fps.enabled", false, function(value) {
@ -306,6 +307,7 @@ var shell = {
delete Services.audioManager;
#endif
UserAgentOverrides.uninit();
IndexedDBPromptHelper.uninit();
},
// If this key event actually represents a hardware button, filter it here
@ -625,6 +627,9 @@ var CustomEventManager = {
case 'system-message-listener-ready':
Services.obs.notifyObservers(null, 'system-message-listener-ready', null);
break;
case 'remote-debugger-prompt':
RemoteDebugger.handleEvent(detail);
break;
}
}
}
@ -833,32 +838,87 @@ var WebappsHelper = {
}
}
// Start the debugger server.
function startDebugger() {
if (!DebuggerServer.initialized) {
// Allow remote connections.
DebuggerServer.init(function () { return true; });
DebuggerServer.addBrowserActors();
DebuggerServer.addActors('chrome://browser/content/dbg-browser-actors.js');
}
let IndexedDBPromptHelper = {
_quotaPrompt: "indexedDB-quota-prompt",
_quotaResponse: "indexedDB-quota-response",
let port = Services.prefs.getIntPref('devtools.debugger.remote-port') || 6000;
try {
DebuggerServer.openListener(port);
} catch (e) {
dump('Unable to start debugger server: ' + e + '\n');
init:
function IndexedDBPromptHelper_init() {
Services.obs.addObserver(this, this._quotaPrompt, false);
},
uninit:
function IndexedDBPromptHelper_uninit() {
Services.obs.removeObserver(this, this._quotaPrompt, false);
},
observe:
function IndexedDBPromptHelper_observe(subject, topic, data) {
if (topic != this._quotaPrompt) {
throw new Error("Unexpected topic!");
}
let observer = subject.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIObserver);
let responseTopic = this._quotaResponse;
setTimeout(function() {
observer.observe(null, responseTopic,
Ci.nsIPermissionManager.DENY_ACTION);
}, 0);
}
}
function stopDebugger() {
if (!DebuggerServer.initialized) {
return;
}
let RemoteDebugger = {
_promptDone: false,
_promptAnswer: false,
try {
DebuggerServer.closeListener();
} catch (e) {
dump('Unable to stop debugger server: ' + e + '\n');
prompt: function debugger_prompt() {
this._promptDone = false;
shell.sendChromeEvent({
"type": "remote-debugger-prompt"
});
while(!this._promptDone) {
Services.tm.currentThread.processNextEvent(true);
}
return this._promptAnswer;
},
handleEvent: function debugger_handleEvent(detail) {
this._promptAnswer = detail.value;
this._promptDone = true;
},
// Start the debugger server.
start: function debugger_start() {
if (!DebuggerServer.initialized) {
// Ask for remote connections.
DebuggerServer.init(this.prompt.bind(this));
DebuggerServer.addBrowserActors();
DebuggerServer.addActors('chrome://browser/content/dbg-browser-actors.js');
}
let port = Services.prefs.getIntPref('devtools.debugger.remote-port') || 6000;
try {
DebuggerServer.openListener(port);
} catch (e) {
dump('Unable to start debugger server: ' + e + '\n');
}
},
stop: function debugger_stop() {
if (!DebuggerServer.initialized) {
return;
}
try {
DebuggerServer.closeListener();
} catch (e) {
dump('Unable to stop debugger server: ' + e + '\n');
}
}
}

View File

@ -148,9 +148,10 @@ ContentPermissionPrompt.prototype = {
let principal = request.principal;
let isApp = principal.appStatus != Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED;
let remember = principal.appStatus == Ci.nsIPrincipal.APP_STATUS_PRIVILEGED
? true
: request.remember;
let remember = (principal.appStatus == Ci.nsIPrincipal.APP_STATUS_PRIVILEGED ||
principal.appStatus == Ci.nsIPrincipal.APP_STATUS_CERTIFIED)
? true
: request.remember;
let details = {
type: "permission-prompt",

View File

@ -114,20 +114,16 @@ DownloadElementShell.prototype = {
this._dataItem = aValue;
if (this._dataItem) {
this._active = true;
this._wasDone = this._dataItem.done;
this._wasInProgress = this._dataItem.inProgress;
this._targetFileInfoFetched = false;
this._fetchTargetFileInfo();
}
else if (this._placesNode) {
this._wasInProgress = false;
this._wasDone = this.getDownloadState(true) == nsIDM.DOWNLOAD_FINISHED;
this._targetFileInfoFetched = false;
if (this.active)
this._fetchTargetFileInfo();
}
it (this.active)
if (this.active)
this._updateStatusUI();
return aValue;
},
@ -146,8 +142,6 @@ DownloadElementShell.prototype = {
// We don't need to update the UI if we had a data item, because
// the places information isn't used in this case.
if (!this._dataItem && this._placesNode) {
this._wasInProgress = false;
this._wasDone = this.getDownloadState(true) == nsIDM.DOWNLOAD_FINISHED;
this._targetFileInfoFetched = false;
if (this.active) {
this._updateStatusUI();
@ -471,8 +465,9 @@ DownloadElementShell.prototype = {
},
/* DownloadView */
onStateChange: function DES_onStateChange() {
if (!this._wasDone && this._dataItem.done) {
onStateChange: function DES_onStateChange(aOldState) {
if (aOldState != nsIDM.DOWNLOAD_FINISHED &&
aOldState != this.dataItem.state) {
// See comment in DVI_onStateChange in downloads.js (the panel-view)
this._element.setAttribute("image", this._icon + "&state=normal");
@ -481,16 +476,6 @@ DownloadElementShell.prototype = {
this._fetchTargetFileInfo();
}
this._wasDone = this._dataItem.done;
// Update the end time using the current time if required.
if (this._wasInProgress && !this._dataItem.inProgress) {
this._endTime = Date.now();
}
this._wasDone = this._dataItem.done;
this._wasInProgress = this._dataItem.inProgress;
this._updateDownloadStatusUI();
if (this._element.selected)
goUpdateDownloadCommands();

View File

@ -856,8 +856,6 @@ function DownloadsViewItem(aDataItem, aElement)
this._element = aElement;
this.dataItem = aDataItem;
this.wasDone = this.dataItem.done;
this.wasInProgress = this.dataItem.inProgress;
this.lastEstimatedSecondsLeft = Infinity;
// Set the URI that represents the correct icon for the target file. As soon
@ -910,7 +908,7 @@ DownloadsViewItem.prototype = {
* the download might be the same as before, if the data layer received
* multiple events for the same download.
*/
onStateChange: function DVI_onStateChange()
onStateChange: function DVI_onStateChange(aOldState)
{
// If a download just finished successfully, it means that the target file
// now exists and we can extract its specific icon. To ensure that the icon
@ -918,18 +916,11 @@ DownloadsViewItem.prototype = {
// example by adding a query parameter. Since this URI has a "moz-icon"
// scheme, this only works if we add one of the parameters explicitly
// supported by the nsIMozIconURI interface.
if (!this.wasDone && this.dataItem.openable) {
if (aOldState != Ci.nsIDownloadManager.DOWNLOAD_FINISHED &&
aOldState != this.dataItem.state) {
this._element.setAttribute("image", this.image + "&state=normal");
}
// Update the end time using the current time if required.
if (this.wasInProgress && !this.dataItem.inProgress) {
this.endTime = Date.now();
}
this.wasDone = this.dataItem.done;
this.wasInProgress = this.dataItem.inProgress;
// Update the user interface after switching states.
this._element.setAttribute("state", this.dataItem.state);
this._updateProgress();

View File

@ -941,7 +941,7 @@ DownloadsDataCtor.prototype = {
//////////////////////////////////////////////////////////////////////////////
//// nsIDownloadProgressListener
onDownloadStateChange: function DD_onDownloadStateChange(aState, aDownload)
onDownloadStateChange: function DD_onDownloadStateChange(aOldState, aDownload)
{
#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
if (aDownload.isPrivate != this._isPrivate) {
@ -954,14 +954,16 @@ DownloadsDataCtor.prototype = {
// When a new download is added, it may have the same identifier of a
// download that we previously deleted during this session, and we also
// want to provide a visible indication that the download started.
let isNew = aState == nsIDM.DOWNLOAD_NOTSTARTED ||
aState == nsIDM.DOWNLOAD_QUEUED;
let isNew = aOldState == nsIDM.DOWNLOAD_NOTSTARTED ||
aOldState == nsIDM.DOWNLOAD_QUEUED;
let dataItem = this._getOrAddDataItem(aDownload, isNew);
if (!dataItem) {
return;
}
let wasInProgress = dataItem.inProgress;
dataItem.state = aDownload.state;
dataItem.referrer = aDownload.referrer && aDownload.referrer.spec;
dataItem.resumable = aDownload.resumable;
@ -969,6 +971,10 @@ DownloadsDataCtor.prototype = {
dataItem.currBytes = aDownload.amountTransferred;
dataItem.maxBytes = aDownload.size;
if (wasInProgress && !dataItem.inProgress) {
dataItem.endTime = Date.now();
}
// When a download is retried, we create a different download object from
// the database with the same ID as before. This means that the nsIDownload
// that the dataItem holds might now need updating.
@ -981,7 +987,7 @@ DownloadsDataCtor.prototype = {
}
this._views.forEach(
function (view) view.getViewItem(dataItem).onStateChange()
function (view) view.getViewItem(dataItem).onStateChange(aOldState)
);
if (isNew && !dataItem.newDownloadNotified) {
@ -1729,7 +1735,7 @@ DownloadsIndicatorDataCtor.prototype = {
let data = this._isPrivate ? PrivateDownloadsIndicatorData
: DownloadsIndicatorData;
return Object.freeze({
onStateChange: function DIVI_onStateChange()
onStateChange: function DIVI_onStateChange(aOldState)
{
if (aDataItem.state == nsIDM.DOWNLOAD_FINISHED ||
aDataItem.state == nsIDM.DOWNLOAD_FAILED) {
@ -2004,7 +2010,7 @@ DownloadsSummaryData.prototype = {
{
let self = this;
return Object.freeze({
onStateChange: function DIVI_onStateChange()
onStateChange: function DIVI_onStateChange(aOldState)
{
// Since the state of a download changed, reset the estimated time left.
self._lastRawTimeLeft = -1;

View File

@ -1896,6 +1896,7 @@ nsEventStateManager::FireContextClick()
type == NS_FORM_INPUT_FILE ||
type == NS_FORM_INPUT_NUMBER ||
type == NS_FORM_INPUT_DATE ||
type == NS_FORM_INPUT_TIME ||
type == NS_FORM_TEXTAREA);
}
else if (tag == nsGkAtoms::applet ||

View File

@ -61,6 +61,7 @@ enum InputElementTypes {
NS_FORM_INPUT_SUBMIT,
NS_FORM_INPUT_TEL,
NS_FORM_INPUT_TEXT,
NS_FORM_INPUT_TIME,
NS_FORM_INPUT_URL,
eInputElementTypesMax
};
@ -237,8 +238,9 @@ nsIFormControl::IsSingleLineTextControl(bool aExcludePassword, uint32_t aType)
aType == NS_FORM_INPUT_URL ||
// TODO: this is temporary until bug 635240 is fixed.
aType == NS_FORM_INPUT_NUMBER ||
// TODO: this is temporary until bug 773205 is fixed.
// TODO: those are temporary until bug 773205 is fixed.
aType == NS_FORM_INPUT_DATE ||
aType == NS_FORM_INPUT_TIME ||
(!aExcludePassword && aType == NS_FORM_INPUT_PASSWORD);
}

View File

@ -185,6 +185,7 @@ ShouldBeInElements(nsIFormControl* aFormControl)
case NS_FORM_INPUT_URL :
case NS_FORM_INPUT_NUMBER :
case NS_FORM_INPUT_DATE :
case NS_FORM_INPUT_TIME :
case NS_FORM_SELECT :
case NS_FORM_TEXTAREA :
case NS_FORM_FIELDSET :

View File

@ -134,6 +134,7 @@ static const nsAttrValue::EnumTable kInputTypeTable[] = {
{ "submit", NS_FORM_INPUT_SUBMIT },
{ "tel", NS_FORM_INPUT_TEL },
{ "text", NS_FORM_INPUT_TEXT },
{ "time", NS_FORM_INPUT_TIME },
{ "url", NS_FORM_INPUT_URL },
{ 0 }
};
@ -704,6 +705,7 @@ nsHTMLInputElement::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const
case NS_FORM_INPUT_URL:
case NS_FORM_INPUT_NUMBER:
case NS_FORM_INPUT_DATE:
case NS_FORM_INPUT_TIME:
if (mValueChanged) {
// We don't have our default value anymore. Set our value on
// the clone.
@ -1597,7 +1599,8 @@ NS_IMETHODIMP
nsHTMLInputElement::MozIsTextField(bool aExcludePassword, bool* aResult)
{
// TODO: temporary until bug 635240 and 773205 are fixed.
if (mType == NS_FORM_INPUT_NUMBER || mType == NS_FORM_INPUT_DATE) {
if (mType == NS_FORM_INPUT_NUMBER || mType == NS_FORM_INPUT_DATE ||
mType == NS_FORM_INPUT_TIME) {
*aResult = false;
return NS_OK;
}
@ -2690,6 +2693,7 @@ nsHTMLInputElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
keyEvent->keyCode == NS_VK_ENTER) &&
(IsSingleLineTextControl(false, mType) ||
mType == NS_FORM_INPUT_NUMBER ||
mType == NS_FORM_INPUT_TIME ||
mType == NS_FORM_INPUT_DATE)) {
FireChangeEventIfNeeded();
rv = MaybeSubmitForm(aVisitor.mPresContext);
@ -3145,6 +3149,7 @@ nsHTMLInputElement::ParseAttribute(int32_t aNamespaceID,
if (success) {
newType = aResult.GetEnumValue();
if ((newType == NS_FORM_INPUT_NUMBER ||
newType == NS_FORM_INPUT_TIME ||
newType == NS_FORM_INPUT_DATE) &&
!Preferences::GetBool("dom.experimental_forms", false)) {
newType = kInputDefaultType->value;
@ -3772,6 +3777,7 @@ nsHTMLInputElement::SaveState()
case NS_FORM_INPUT_HIDDEN:
case NS_FORM_INPUT_NUMBER:
case NS_FORM_INPUT_DATE:
case NS_FORM_INPUT_TIME:
{
if (mValueChanged) {
inputState = new nsHTMLInputElementState();
@ -3957,6 +3963,7 @@ nsHTMLInputElement::RestoreState(nsPresState* aState)
case NS_FORM_INPUT_HIDDEN:
case NS_FORM_INPUT_NUMBER:
case NS_FORM_INPUT_DATE:
case NS_FORM_INPUT_TIME:
{
SetValueInternal(inputState->GetValue(), false, true);
break;
@ -4182,6 +4189,7 @@ nsHTMLInputElement::GetValueMode() const
case NS_FORM_INPUT_URL:
case NS_FORM_INPUT_NUMBER:
case NS_FORM_INPUT_DATE:
case NS_FORM_INPUT_TIME:
return VALUE_MODE_VALUE;
default:
NS_NOTYETIMPLEMENTED("Unexpected input type in GetValueMode()");
@ -4227,6 +4235,7 @@ nsHTMLInputElement::DoesReadOnlyApply() const
case NS_FORM_INPUT_URL:
case NS_FORM_INPUT_NUMBER:
case NS_FORM_INPUT_DATE:
case NS_FORM_INPUT_TIME:
return true;
default:
NS_NOTYETIMPLEMENTED("Unexpected input type in DoesReadOnlyApply()");
@ -4264,6 +4273,7 @@ nsHTMLInputElement::DoesRequiredApply() const
case NS_FORM_INPUT_URL:
case NS_FORM_INPUT_NUMBER:
case NS_FORM_INPUT_DATE:
case NS_FORM_INPUT_TIME:
return true;
default:
NS_NOTYETIMPLEMENTED("Unexpected input type in DoesRequiredApply()");
@ -4278,7 +4288,8 @@ nsHTMLInputElement::DoesRequiredApply() const
bool
nsHTMLInputElement::PlaceholderApplies() const
{
if (mType == NS_FORM_INPUT_DATE) {
if (mType == NS_FORM_INPUT_DATE ||
mType == NS_FORM_INPUT_TIME) {
return false;
}
@ -4288,8 +4299,9 @@ nsHTMLInputElement::PlaceholderApplies() const
bool
nsHTMLInputElement::DoesPatternApply() const
{
// TODO: temporary until bug 635240 is fixed.
if (mType == NS_FORM_INPUT_NUMBER || mType == NS_FORM_INPUT_DATE) {
// TODO: temporary until bug 635240 and bug 773205 are fixed.
if (mType == NS_FORM_INPUT_NUMBER || mType == NS_FORM_INPUT_DATE ||
mType == NS_FORM_INPUT_TIME) {
return false;
}
@ -4322,6 +4334,8 @@ nsHTMLInputElement::DoesMinMaxApply() const
case NS_FORM_INPUT_TEL:
case NS_FORM_INPUT_EMAIL:
case NS_FORM_INPUT_URL:
// TODO: temp until bug 781572 is fixed.
case NS_FORM_INPUT_TIME:
return false;
default:
NS_NOTYETIMPLEMENTED("Unexpected input type in DoesRequiredApply()");
@ -4497,7 +4511,8 @@ nsHTMLInputElement::HasPatternMismatch() const
bool
nsHTMLInputElement::IsRangeOverflow() const
{
if (!DoesMinMaxApply()) {
// Ignore type=time until bug 781572 is fixed.
if (!DoesMinMaxApply() || mType == NS_FORM_INPUT_TIME) {
return false;
}

View File

@ -201,11 +201,11 @@ reflectLimitedEnumerated({
attribute: "type",
validValues: [ "hidden", "text", "search", "tel", "url", "email", "password",
"checkbox", "radio", "file", "submit", "image", "reset",
"button", "date", "number" ],
"button", "date", "time", "number" ],
invalidValues: [ "this-is-probably-a-wrong-type", "", "tulip" ],
defaultValue: "text",
unsupportedValues: [ "datetime", "month", "week", "time",
"datetime-local", "range", "color" ]
unsupportedValues: [ "datetime", "month", "week", "datetime-local",
"range", "color" ]
});
// .defaultValue

View File

@ -26,12 +26,13 @@ var inputTypes =
[
"text", "password", "search", "tel", "hidden", "checkbox", "radio",
"submit", "image", "reset", "button", "email", "url", "number", "date",
"time",
];
var todoTypes =
[
"range", "color",
"month", "week", "time", "datetime", "datetime-local",
"month", "week", "datetime", "datetime-local",
];
var valueModeValue =
@ -121,9 +122,10 @@ function sanitizeValue(aType, aValue)
return aValue.replace(/[\n\r]/g, "").replace(/^\s+|\s+$/g, "");
case "date":
return "";
case "time":
return "";
case "month":
case "week":
case "time":
case "datetime":
case "datetime-local":
// TODO: write the sanitize algorithm.
@ -163,6 +165,11 @@ function checkSanitizing(element)
"1.234567898765432",
];
// TODO: temp
if (element.type == 'time') {
return;
}
for (value of testData) {
element.setAttribute('value', value);
is(element.value, sanitizeValue(type, value),

View File

@ -31,7 +31,7 @@ var types = [
[ 'date', true ],
[ 'month', true, true ],
[ 'week', true, true ],
[ 'time', true, true ],
[ 'time', true ],
[ 'datetime-local', true, true ],
[ 'number', true ],
[ 'range', true, true ],
@ -88,6 +88,10 @@ for (var data of types) {
continue;
}
if (input.type == 'time') {
continue;
}
checkValidity(input, true, apply, false);
if (input.type == 'date') {

View File

@ -31,7 +31,7 @@ var types = [
[ 'date', true ],
[ 'month', true, true ],
[ 'week', true, true ],
[ 'time', true, true ],
[ 'time', true ],
[ 'datetime-local', true, true ],
[ 'number', true ],
[ 'range', true, true ],
@ -88,6 +88,10 @@ for (var data of types) {
continue;
}
if (input.type == 'time') {
continue;
}
checkValidity(input, true, apply, false);
if (input.type == 'date') {

View File

@ -49,6 +49,7 @@ var gInputTestData = [
['url', true],
['number', false],
['date', false],
['time', false],
];
/**
@ -62,7 +63,6 @@ var gInputTodoData = [
['datetime', false],
['month', false],
['week', false],
['time', false],
['datetime-local', false],
];

View File

@ -261,10 +261,9 @@ var input = document.getElementById('i');
// and |invalidTypes| are the ones which do not accept it.
var validTypes = Array('text', 'password', 'search', 'tel', 'email', 'url');
var barredTypes = Array('hidden', 'reset', 'button', 'submit', 'image');
var invalidTypes = Array('checkbox', 'radio', 'file', 'number', 'date');
// TODO: 'datetime', 'month', 'week', 'time', 'datetime-local',
// 'range', and 'color' do not accept the @pattern too but are not
// implemented yet.
var invalidTypes = Array('checkbox', 'radio', 'file', 'number', 'date', 'time');
// TODO: 'datetime', 'month', 'week', 'datetime-local', 'range' and 'color'
// do not accept the @pattern too but are not implemented yet.
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", true]]}, function() {

View File

@ -166,6 +166,8 @@ function checkInputRequiredValidity(type)
element.value = '42';
} else if (element.type == 'date') {
element.value = '2010-10-10';
} else if (element.type == 'time') {
element.value = '21:21';
} else {
element.value = 'foo';
}
@ -375,10 +377,10 @@ for (type of typeRequireNotApply) {
}
// Now, checking for all types which accept the required attribute.
// TODO: check 'datetime', 'month', 'week', 'time' and 'datetime-local'
// TODO: check 'datetime', 'month', 'week' and 'datetime-local'
// when they will be implemented.
var typeRequireApply = ["text", "password", "search", "tel", "email", "url",
"number", "date"];
"number", "date", "time"];
for (type of typeRequireApply) {
checkInputRequiredValidity(type);

View File

@ -31,7 +31,7 @@ var types = [
[ 'date', true ],
[ 'month', true, true ],
[ 'week', true, true ],
[ 'time', true, true ],
[ 'time', true ],
[ 'datetime-local', true, true ],
[ 'number', true ],
[ 'range', true, true ],
@ -85,6 +85,10 @@ for (var data of types) {
continue;
}
if (input.type == 'time') {
continue;
}
checkValidity(input, true, apply);
input.step = '0';

View File

@ -36,11 +36,12 @@ var testData = [
[ "password", true ],
[ "number", true ],
[ "date", true ],
[ "time", true ],
// 'file' is treated separatly.
];
var todoTypes = [
"datetime", "month", "week", "time", "datetime-local", "range", "color"
"datetime", "month", "week", "datetime-local", "range", "color"
];
SimpleTest.waitForExplicitFinish();

View File

@ -217,8 +217,8 @@ this.DOMApplicationRegistry = {
});
},
// Installs a 3rd party packaged app.
installPreinstalledPackage: function installPreinstalledPackage(aId) {
// Installs a 3rd party app.
installPreinstalledApp: function installPreinstalledApp(aId) {
#ifdef MOZ_WIDGET_GONK
let app = this.webapps[aId];
let baseDir;
@ -229,30 +229,46 @@ this.DOMApplicationRegistry = {
return;
}
let filesToMove;
let isPackage;
let updateFile = baseDir.clone();
updateFile.append("update.webapp");
if (!updateFile.exists()) {
// The update manifest is missing, bail out.
return;
// The update manifest is missing, this is a hosted app only if there is
// no application.zip
let appFile = baseDir.clone();
appFile.append("application.zip");
if (appFile.exists()) {
return;
}
isPackage = false;
filesToMove = ["manifest.webapp"];
} else {
isPackage = true;
filesToMove = ["application.zip", "update.webapp"];
}
debug("Installing 3rd party packaged app : " + aId +
debug("Installing 3rd party app : " + aId +
" from " + baseDir.path);
// We copy this app to DIRECTORY_NAME/$aId, and set the base path as needed.
let destDir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", aId], true, true);
["application.zip", "update.webapp"]
.forEach(function(aFile) {
filesToMove.forEach(function(aFile) {
let file = baseDir.clone();
file.append(aFile);
file.copyTo(destDir, aFile);
let newFile = destDir.clone();
newFile.append(aFile);
});
app.basePath = FileUtils.getDir(DIRECTORY_NAME, ["webapps"], true, true)
.path;
if (!isPackage) {
return;
}
app.origin = "app://" + aId;
app.removable = true;
@ -311,7 +327,7 @@ this.DOMApplicationRegistry = {
let localId = this.webapps[id].localId;
let permMgr = Cc["@mozilla.org/permissionmanager;1"]
.getService(Ci.nsIPermissionManager);
permMgr.RemovePermissionsForApp(localId);
permMgr.RemovePermissionsForApp(localId, false);
Services.cookies.removeCookiesForApp(localId, false);
this._clearPrivateData(localId, false);
}
@ -384,7 +400,7 @@ this.DOMApplicationRegistry = {
if (runUpdate) {
// At first run, install preloaded apps and set up their permissions.
for (let id in this.webapps) {
this.installPreinstalledPackage(id);
this.installPreinstalledApp(id);
if (!this.webapps[id]) {
continue;
}
@ -392,7 +408,7 @@ this.DOMApplicationRegistry = {
this.updatePermissionsForApp(id);
}
// Need to update the persisted list of apps since
// installPreinstalledPackage() removes the ones failing to install.
// installPreinstalledApp() removes the ones failing to install.
this._saveApps();
}
this.registerAppsHandlers(runUpdate);
@ -1221,8 +1237,15 @@ this.DOMApplicationRegistry = {
true);
}
// For non-removable hosted apps, we just check the appcache.
if (!app.removable) {
// For non-removable hosted apps, we only check the appcache.
let onlyCheckAppCache = false;
#ifdef MOZ_WIDGET_GONK
let appDir = FileUtils.getDir("coreAppsDir", ["webapps"], false);
onlyCheckAppCache = (app.basePath == appDir.path);
#endif
if (onlyCheckAppCache) {
// Bail out for packaged apps.
if (app.origin.startsWith("app://")) {
aData.error = "NOT_UPDATABLE";
@ -1259,6 +1282,7 @@ this.DOMApplicationRegistry = {
updateSvc.checkForUpdate(Services.io.newURI(aData.manifestURL, null, null),
app.localId, false, updateObserver);
});
return;
}
@ -1275,6 +1299,7 @@ this.DOMApplicationRegistry = {
this.createLoadContext(app.installerAppId, app.installerIsBrowser);
xhr.addEventListener("load", (function() {
debug("Got http status=" + xhr.status + " for " + aData.manifestURL);
if (xhr.status == 200) {
let manifest = xhr.response;
if (manifest == null) {
@ -1313,6 +1338,7 @@ this.DOMApplicationRegistry = {
sendError("NETWORK_ERROR");
}).bind(this), false);
debug("Checking manifest at " + aData.manifestURL);
xhr.send(null);
},
@ -1873,6 +1899,11 @@ this.DOMApplicationRegistry = {
bufferedOutputStream.close();
outputStream.close();
if (!Components.isSuccessCode(aStatusCode)) {
cleanup("NETWORK_ERROR");
return;
}
if (requestChannel.responseStatus == 304) {
// The package's Etag has not changed.
// We send a "applied" event right away.
@ -1894,11 +1925,6 @@ this.DOMApplicationRegistry = {
return;
}
if (!Components.isSuccessCode(aStatusCode)) {
cleanup("NETWORK_ERROR");
return;
}
let certdb;
try {
certdb = Cc["@mozilla.org/security/x509certdb;1"]

View File

@ -1285,7 +1285,7 @@ BluetoothOppManager::OnDisconnect()
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->NotifyObservers(mDsFile, "file-watcher-update", data.get());
obs->NotifyObservers(mDsFile, "file-watcher-notify", data.get());
}
}
}

View File

@ -238,6 +238,25 @@ BluetoothService::~BluetoothService()
Cleanup();
}
PLDHashOperator
RemoveObserversExceptBluetoothManager
(const nsAString& key,
nsAutoPtr<BluetoothSignalObserverList>& value,
void* arg)
{
if (!key.EqualsLiteral("/")) {
static_cast<BluetoothService*>(arg)->RemoveObserverFromTable(key);
}
return PL_DHASH_NEXT;
}
void
BluetoothService::RemoveObserverFromTable(const nsAString& key)
{
mBluetoothSignalObserverTable.Remove(key);
}
// static
BluetoothService*
BluetoothService::Create()
@ -306,6 +325,8 @@ BluetoothService::RegisterBluetoothSignalHandler(const nsAString& aNodeName,
ol = new BluetoothSignalObserverList();
mBluetoothSignalObserverTable.Put(aNodeName, ol);
}
ol->RemoveObserver(aHandler);
ol->AddObserver(aHandler);
}
@ -419,10 +440,19 @@ BluetoothService::SetEnabled(bool aEnabled)
* cleared after turned off bluetooth
*/
while (iter.HasMore()) {
RegisterBluetoothSignalHandler(managerPath, (BluetoothSignalObserver*)iter.GetNext());
RegisterBluetoothSignalHandler(
managerPath,
(BluetoothSignalObserver*)iter.GetNext());
}
} else {
mBluetoothSignalObserverTable.Clear();
/**
* Remove all handlers except BluetoothManager when turning off bluetooth
* since it is possible that the event 'onAdapterAdded' would be fired after
* BluetoothManagers of child process are registered. Please see Bug 827759
* for more details.
*/
mBluetoothSignalObserverTable.Enumerate(
RemoveObserversExceptBluetoothManager, this);
}
/**

View File

@ -306,6 +306,9 @@ public:
bool
IsToggling() const;
void
RemoveObserverFromTable(const nsAString& key);
protected:
BluetoothService()
: mEnabled(false)

View File

@ -196,7 +196,7 @@ CameraControlImpl::Get(JSContext* aCx, uint32_t aKey, JS::Value* aValue)
nsresult
CameraControlImpl::Set(nsICameraShutterCallback* aOnShutter)
{
mOnShutterCb = new nsMainThreadPtrHolder<nsICameraShutterCallback>(aOnShutter);
mOnShutterCb = aOnShutter;
return NS_OK;
}
@ -210,7 +210,7 @@ CameraControlImpl::Get(nsICameraShutterCallback** aOnShutter)
nsresult
CameraControlImpl::Set(nsICameraClosedCallback* aOnClosed)
{
mOnClosedCb = new nsMainThreadPtrHolder<nsICameraClosedCallback>(aOnClosed);
mOnClosedCb = aOnClosed;
return NS_OK;
}
@ -224,7 +224,7 @@ CameraControlImpl::Get(nsICameraClosedCallback** aOnClosed)
nsresult
CameraControlImpl::Set(nsICameraRecorderStateChange* aOnRecorderStateChange)
{
mOnRecorderStateChangeCb = new nsMainThreadPtrHolder<nsICameraRecorderStateChange>(aOnRecorderStateChange);
mOnRecorderStateChangeCb = aOnRecorderStateChange;
return NS_OK;
}
@ -258,7 +258,7 @@ void
CameraControlImpl::OnShutterInternal()
{
DOM_CAMERA_LOGI("** SNAP **\n");
if (mOnShutterCb.get()) {
if (mOnShutterCb) {
mOnShutterCb->HandleEvent();
}
}
@ -277,7 +277,7 @@ void
CameraControlImpl::OnClosedInternal()
{
DOM_CAMERA_LOGI("Camera hardware was closed\n");
if (mOnClosedCb.get()) {
if (mOnClosedCb) {
mOnClosedCb->HandleEvent();
}
}
@ -390,10 +390,9 @@ GetPreviewStreamResult::Run()
*/
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsICameraPreviewStreamCallback> onSuccess = mOnSuccessCb.get();
if (onSuccess && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
if (mOnSuccessCb && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
nsCOMPtr<nsIDOMMediaStream> stream = new DOMCameraPreview(mCameraControl, mWidth, mHeight, mFramesPerSecond);
onSuccess->HandleEvent(stream);
mOnSuccessCb->HandleEvent(stream);
}
return NS_OK;
}

View File

@ -5,8 +5,8 @@
#ifndef DOM_CAMERA_CAMERACONTROLIMPL_H
#define DOM_CAMERA_CAMERACONTROLIMPL_H
#include "nsCOMPtr.h"
#include "nsDOMFile.h"
#include "nsProxyRelease.h"
#include "DictionaryHelpers.h"
#include "nsIDOMDeviceStorage.h"
#include "DOMCameraManager.h"
@ -143,13 +143,13 @@ protected:
*/
DOMCameraPreview* mDOMPreview;
nsMainThreadPtrHandle<nsICameraAutoFocusCallback> mAutoFocusOnSuccessCb;
nsMainThreadPtrHandle<nsICameraErrorCallback> mAutoFocusOnErrorCb;
nsMainThreadPtrHandle<nsICameraTakePictureCallback> mTakePictureOnSuccessCb;
nsMainThreadPtrHandle<nsICameraErrorCallback> mTakePictureOnErrorCb;
nsMainThreadPtrHandle<nsICameraShutterCallback> mOnShutterCb;
nsMainThreadPtrHandle<nsICameraClosedCallback> mOnClosedCb;
nsMainThreadPtrHandle<nsICameraRecorderStateChange> mOnRecorderStateChangeCb;
nsCOMPtr<nsICameraAutoFocusCallback> mAutoFocusOnSuccessCb;
nsCOMPtr<nsICameraErrorCallback> mAutoFocusOnErrorCb;
nsCOMPtr<nsICameraTakePictureCallback> mTakePictureOnSuccessCb;
nsCOMPtr<nsICameraErrorCallback> mTakePictureOnErrorCb;
nsCOMPtr<nsICameraShutterCallback> mOnShutterCb;
nsCOMPtr<nsICameraClosedCallback> mOnClosedCb;
nsCOMPtr<nsICameraRecorderStateChange> mOnRecorderStateChangeCb;
private:
CameraControlImpl(const CameraControlImpl&) MOZ_DELETE;
@ -161,7 +161,7 @@ class CameraErrorResult : public nsRunnable
{
public:
CameraErrorResult(nsICameraErrorCallback* onError, const nsString& aErrorMsg, uint64_t aWindowId)
: mOnErrorCb(new nsMainThreadPtrHolder<nsICameraErrorCallback>(onError))
: mOnErrorCb(onError)
, mErrorMsg(aErrorMsg)
, mWindowId(aWindowId)
{ }
@ -170,14 +170,14 @@ public:
{
MOZ_ASSERT(NS_IsMainThread());
if (mOnErrorCb.get() && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
if (mOnErrorCb && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
mOnErrorCb->HandleEvent(mErrorMsg);
}
return NS_OK;
}
protected:
nsMainThreadPtrHandle<nsICameraErrorCallback> mOnErrorCb;
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
const nsString mErrorMsg;
uint64_t mWindowId;
};
@ -186,7 +186,7 @@ protected:
class GetPreviewStreamResult : public nsRunnable
{
public:
GetPreviewStreamResult(CameraControlImpl* aCameraControl, uint32_t aWidth, uint32_t aHeight, uint32_t aFramesPerSecond, nsMainThreadPtrHandle<nsICameraPreviewStreamCallback>& onSuccess, uint64_t aWindowId)
GetPreviewStreamResult(CameraControlImpl* aCameraControl, uint32_t aWidth, uint32_t aHeight, uint32_t aFramesPerSecond, nsICameraPreviewStreamCallback* onSuccess, uint64_t aWindowId)
: mCameraControl(aCameraControl)
, mWidth(aWidth)
, mHeight(aHeight)
@ -210,7 +210,7 @@ protected:
uint32_t mWidth;
uint32_t mHeight;
uint32_t mFramesPerSecond;
nsMainThreadPtrHandle<nsICameraPreviewStreamCallback> mOnSuccessCb;
nsCOMPtr<nsICameraPreviewStreamCallback> mOnSuccessCb;
uint64_t mWindowId;
};
@ -221,8 +221,8 @@ public:
GetPreviewStreamTask(CameraControlImpl* aCameraControl, dom::CameraSize aSize, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError)
: mSize(aSize)
, mCameraControl(aCameraControl)
, mOnSuccessCb(new nsMainThreadPtrHolder<nsICameraPreviewStreamCallback>(onSuccess))
, mOnErrorCb(new nsMainThreadPtrHolder<nsICameraErrorCallback>(onError))
, mOnSuccessCb(onSuccess)
, mOnErrorCb(onError)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
@ -236,7 +236,7 @@ public:
{
nsresult rv = mCameraControl->GetPreviewStreamImpl(this);
if (NS_FAILED(rv) && mOnErrorCb.get()) {
if (NS_FAILED(rv) && mOnErrorCb) {
rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE"), mCameraControl->GetWindowId()));
NS_ENSURE_SUCCESS(rv, rv);
}
@ -245,8 +245,8 @@ public:
dom::CameraSize mSize;
nsRefPtr<CameraControlImpl> mCameraControl;
nsMainThreadPtrHandle<nsICameraPreviewStreamCallback> mOnSuccessCb;
nsMainThreadPtrHandle<nsICameraErrorCallback> mOnErrorCb;
nsCOMPtr<nsICameraPreviewStreamCallback> mOnSuccessCb;
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
};
// Return the autofocus status to JS. Runs on the main thread.
@ -255,7 +255,7 @@ class AutoFocusResult : public nsRunnable
public:
AutoFocusResult(bool aSuccess, nsICameraAutoFocusCallback* onSuccess, uint64_t aWindowId)
: mSuccess(aSuccess)
, mOnSuccessCb(new nsMainThreadPtrHolder<nsICameraAutoFocusCallback>(onSuccess))
, mOnSuccessCb(onSuccess)
, mWindowId(aWindowId)
{ }
@ -265,7 +265,7 @@ public:
{
MOZ_ASSERT(NS_IsMainThread());
if (mOnSuccessCb.get() && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
if (mOnSuccessCb && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
mOnSuccessCb->HandleEvent(mSuccess);
}
return NS_OK;
@ -273,7 +273,7 @@ public:
protected:
bool mSuccess;
nsMainThreadPtrHandle<nsICameraAutoFocusCallback> mOnSuccessCb;
nsCOMPtr<nsICameraAutoFocusCallback> mOnSuccessCb;
uint64_t mWindowId;
};
@ -283,8 +283,8 @@ class AutoFocusTask : public nsRunnable
public:
AutoFocusTask(CameraControlImpl* aCameraControl, nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError)
: mCameraControl(aCameraControl)
, mOnSuccessCb(new nsMainThreadPtrHolder<nsICameraAutoFocusCallback>(onSuccess))
, mOnErrorCb(new nsMainThreadPtrHolder<nsICameraErrorCallback>(onError))
, mOnSuccessCb(onSuccess)
, mOnErrorCb(onError)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
@ -300,7 +300,7 @@ public:
nsresult rv = mCameraControl->AutoFocusImpl(this);
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
if (NS_FAILED(rv) && mOnErrorCb.get()) {
if (NS_FAILED(rv) && mOnErrorCb) {
rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE"), mCameraControl->GetWindowId()));
NS_ENSURE_SUCCESS(rv, rv);
}
@ -308,19 +308,17 @@ public:
}
nsRefPtr<CameraControlImpl> mCameraControl;
nsMainThreadPtrHandle<nsICameraAutoFocusCallback> mOnSuccessCb;
nsMainThreadPtrHandle<nsICameraErrorCallback> mOnErrorCb;
nsCOMPtr<nsICameraAutoFocusCallback> mOnSuccessCb;
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
};
// Return the captured picture to JS. Runs on the main thread.
class TakePictureResult : public nsRunnable
{
public:
TakePictureResult(uint8_t* aData, uint64_t aLength, const nsAString& aMimeType, nsICameraTakePictureCallback* onSuccess, uint64_t aWindowId)
: mData(aData)
, mLength(aLength)
, mMimeType(aMimeType)
, mOnSuccessCb(new nsMainThreadPtrHolder<nsICameraTakePictureCallback>(onSuccess))
TakePictureResult(nsIDOMBlob* aImage, nsICameraTakePictureCallback* onSuccess, uint64_t aWindowId)
: mImage(aImage)
, mOnSuccessCb(onSuccess)
, mWindowId(aWindowId)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
@ -336,21 +334,16 @@ public:
MOZ_ASSERT(NS_IsMainThread());
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
if (mOnSuccessCb.get() && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
nsCOMPtr<nsIDOMBlob> image = new nsDOMMemoryFile(static_cast<void*>(mData), static_cast<uint64_t>(mLength), mMimeType);
mOnSuccessCb->HandleEvent(image);
} else {
delete[] mData;
if (mOnSuccessCb && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
mOnSuccessCb->HandleEvent(mImage);
}
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
return NS_OK;
}
protected:
uint8_t* mData;
uint64_t mLength;
nsString mMimeType;
nsMainThreadPtrHandle<nsICameraTakePictureCallback> mOnSuccessCb;
nsCOMPtr<nsIDOMBlob> mImage;
nsCOMPtr<nsICameraTakePictureCallback> mOnSuccessCb;
uint64_t mWindowId;
};
@ -364,8 +357,8 @@ public:
, mRotation(aRotation)
, mFileFormat(aFileFormat)
, mPosition(aPosition)
, mOnSuccessCb(new nsMainThreadPtrHolder<nsICameraTakePictureCallback>(onSuccess))
, mOnErrorCb(new nsMainThreadPtrHolder<nsICameraErrorCallback>(onError))
, mOnSuccessCb(onSuccess)
, mOnErrorCb(onError)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
@ -381,7 +374,7 @@ public:
nsresult rv = mCameraControl->TakePictureImpl(this);
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
if (NS_FAILED(rv) && mOnErrorCb.get()) {
if (NS_FAILED(rv) && mOnErrorCb) {
rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE"), mCameraControl->GetWindowId()));
NS_ENSURE_SUCCESS(rv, rv);
}
@ -393,8 +386,8 @@ public:
int32_t mRotation;
nsString mFileFormat;
dom::CameraPosition mPosition;
nsMainThreadPtrHandle<nsICameraTakePictureCallback> mOnSuccessCb;
nsMainThreadPtrHandle<nsICameraErrorCallback> mOnErrorCb;
nsCOMPtr<nsICameraTakePictureCallback> mOnSuccessCb;
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
};
// Return the result of starting recording. Runs on the main thread.
@ -402,7 +395,7 @@ class StartRecordingResult : public nsRunnable
{
public:
StartRecordingResult(nsICameraStartRecordingCallback* onSuccess, uint64_t aWindowId)
: mOnSuccessCb(new nsMainThreadPtrHolder<nsICameraStartRecordingCallback>(onSuccess))
: mOnSuccessCb(onSuccess)
, mWindowId(aWindowId)
{ }
@ -412,14 +405,14 @@ public:
{
MOZ_ASSERT(NS_IsMainThread());
if (mOnSuccessCb.get() && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
if (mOnSuccessCb && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
mOnSuccessCb->HandleEvent();
}
return NS_OK;
}
protected:
nsMainThreadPtrHandle<nsICameraStartRecordingCallback> mOnSuccessCb;
nsCOMPtr<nsICameraStartRecordingCallback> mOnSuccessCb;
uint64_t mWindowId;
};
@ -432,8 +425,8 @@ public:
, mOptions(aOptions)
, mFolder(aFolder)
, mFilename(aFilename)
, mOnSuccessCb(new nsMainThreadPtrHolder<nsICameraStartRecordingCallback>(onSuccess))
, mOnErrorCb(new nsMainThreadPtrHolder<nsICameraErrorCallback>(onError))
, mOnSuccessCb(onSuccess)
, mOnErrorCb(onError)
, mWindowId(aWindowId)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
@ -468,8 +461,8 @@ public:
dom::CameraStartRecordingOptions mOptions;
nsCOMPtr<nsIFile> mFolder;
nsString mFilename;
nsMainThreadPtrHandle<nsICameraStartRecordingCallback> mOnSuccessCb;
nsMainThreadPtrHandle<nsICameraErrorCallback> mOnErrorCb;
nsCOMPtr<nsICameraStartRecordingCallback> mOnSuccessCb;
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
uint64_t mWindowId;
};
@ -563,8 +556,8 @@ class GetPreviewStreamVideoModeResult : public nsRunnable
{
public:
GetPreviewStreamVideoModeResult(nsIDOMMediaStream* aStream, nsICameraPreviewStreamCallback* onSuccess)
: mStream(new nsMainThreadPtrHolder<nsIDOMMediaStream>(aStream))
, mOnSuccessCb(new nsMainThreadPtrHolder<nsICameraPreviewStreamCallback>(onSuccess))
: mStream(aStream)
, mOnSuccessCb(onSuccess)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
@ -578,15 +571,15 @@ public:
{
MOZ_ASSERT(NS_IsMainThread());
if (mOnSuccessCb.get()) {
if (mOnSuccessCb) {
mOnSuccessCb->HandleEvent(mStream);
}
return NS_OK;
}
protected:
nsMainThreadPtrHandle<nsIDOMMediaStream> mStream;
nsMainThreadPtrHandle<nsICameraPreviewStreamCallback> mOnSuccessCb;
nsCOMPtr<nsIDOMMediaStream> mStream;
nsCOMPtr<nsICameraPreviewStreamCallback> mOnSuccessCb;
};
// Get the video mode preview stream.
@ -596,8 +589,8 @@ public:
GetPreviewStreamVideoModeTask(CameraControlImpl* aCameraControl, dom::CameraRecorderOptions aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError)
: mCameraControl(aCameraControl)
, mOptions(aOptions)
, mOnSuccessCb(new nsMainThreadPtrHolder<nsICameraPreviewStreamCallback>(onSuccess))
, mOnErrorCb(new nsMainThreadPtrHolder<nsICameraErrorCallback>(onError))
, mOnSuccessCb(onSuccess)
, mOnErrorCb(onError)
{ }
NS_IMETHOD Run()
@ -606,7 +599,7 @@ public:
nsresult rv = mCameraControl->GetPreviewStreamVideoModeImpl(this);
DOM_CAMERA_LOGI("%s:%d -- AFTER IMPL : rv = %d\n", __func__, __LINE__, rv);
if (NS_FAILED(rv) && mOnErrorCb.get()) {
if (NS_FAILED(rv) && mOnErrorCb) {
rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE"), mCameraControl->GetWindowId()));
NS_ENSURE_SUCCESS(rv, rv);
}
@ -615,8 +608,8 @@ public:
nsRefPtr<CameraControlImpl> mCameraControl;
dom::CameraRecorderOptions mOptions;
nsMainThreadPtrHandle<nsICameraPreviewStreamCallback> mOnSuccessCb;
nsMainThreadPtrHandle<nsICameraErrorCallback> mOnErrorCb;
nsCOMPtr<nsICameraPreviewStreamCallback> mOnSuccessCb;
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
};
// Return the result of releasing the camera hardware. Runs on the main thread.
@ -624,7 +617,7 @@ class ReleaseHardwareResult : public nsRunnable
{
public:
ReleaseHardwareResult(nsICameraReleaseCallback* onSuccess, uint64_t aWindowId)
: mOnSuccessCb(new nsMainThreadPtrHolder<nsICameraReleaseCallback>(onSuccess))
: mOnSuccessCb(onSuccess)
, mWindowId(aWindowId)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
@ -639,14 +632,14 @@ public:
{
MOZ_ASSERT(NS_IsMainThread());
if (mOnSuccessCb.get() && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
if (mOnSuccessCb && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
mOnSuccessCb->HandleEvent();
}
return NS_OK;
}
protected:
nsMainThreadPtrHandle<nsICameraReleaseCallback> mOnSuccessCb;
nsCOMPtr<nsICameraReleaseCallback> mOnSuccessCb;
uint64_t mWindowId;
};
@ -656,8 +649,8 @@ class ReleaseHardwareTask : public nsRunnable
public:
ReleaseHardwareTask(CameraControlImpl* aCameraControl, nsICameraReleaseCallback* onSuccess, nsICameraErrorCallback* onError)
: mCameraControl(aCameraControl)
, mOnSuccessCb(new nsMainThreadPtrHolder<nsICameraReleaseCallback>(onSuccess))
, mOnErrorCb(new nsMainThreadPtrHolder<nsICameraErrorCallback>(onError))
, mOnSuccessCb(onSuccess)
, mOnErrorCb(onError)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
@ -673,7 +666,7 @@ public:
nsresult rv = mCameraControl->ReleaseHardwareImpl(this);
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
if (NS_FAILED(rv) && mOnErrorCb.get()) {
if (NS_FAILED(rv) && mOnErrorCb) {
rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE"), mCameraControl->GetWindowId()));
NS_ENSURE_SUCCESS(rv, rv);
}
@ -681,8 +674,8 @@ public:
}
nsRefPtr<CameraControlImpl> mCameraControl;
nsMainThreadPtrHandle<nsICameraReleaseCallback> mOnSuccessCb;
nsMainThreadPtrHandle<nsICameraErrorCallback> mOnErrorCb;
nsCOMPtr<nsICameraReleaseCallback> mOnSuccessCb;
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
};
// Report that the video recorder state has changed.
@ -690,7 +683,7 @@ class CameraRecorderStateChange : public nsRunnable
{
public:
CameraRecorderStateChange(nsICameraRecorderStateChange* onStateChange, const nsString& aStateMsg, int32_t aStatus, int32_t aTrackNumber, uint64_t aWindowId)
: mOnStateChangeCb(new nsMainThreadPtrHolder<nsICameraRecorderStateChange>(onStateChange))
: mOnStateChangeCb(onStateChange)
, mStateMsg(aStateMsg)
, mStatus(aStatus)
, mTrackNumber(aTrackNumber)
@ -701,7 +694,7 @@ public:
{
MOZ_ASSERT(NS_IsMainThread());
if (mOnStateChangeCb.get() && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
if (mOnStateChangeCb && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
// For now, just pass the state message and swallow mStatus and mTrackNumber
mOnStateChangeCb->HandleStateChange(mStateMsg);
}
@ -709,7 +702,7 @@ public:
}
protected:
nsMainThreadPtrHandle<nsICameraRecorderStateChange> mOnStateChangeCb;
nsCOMPtr<nsICameraRecorderStateChange> mOnStateChangeCb;
const nsString mStateMsg;
int32_t mStatus;
int32_t mTrackNumber;

View File

@ -623,8 +623,7 @@ nsGonkCameraControl::GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStrea
SetPreviewSize(aGetPreviewStream->mSize.width, aGetPreviewStream->mSize.height);
DOM_CAMERA_LOGI("picture preview: wanted %d x %d, got %d x %d (%d fps, format %d)\n", aGetPreviewStream->mSize.width, aGetPreviewStream->mSize.height, mWidth, mHeight, mFps, mFormat);
nsMainThreadPtrHandle<nsICameraPreviewStreamCallback> onSuccess = aGetPreviewStream->mOnSuccessCb;
nsCOMPtr<GetPreviewStreamResult> getPreviewStreamResult = new GetPreviewStreamResult(this, mWidth, mHeight, mFps, onSuccess, mWindowId);
nsCOMPtr<GetPreviewStreamResult> getPreviewStreamResult = new GetPreviewStreamResult(this, mWidth, mHeight, mFps, aGetPreviewStream->mOnSuccessCb, mWindowId);
return NS_DispatchToMainThread(getPreviewStreamResult);
}
@ -680,16 +679,16 @@ nsGonkCameraControl::StopPreviewImpl(StopPreviewTask* aStopPreview)
nsresult
nsGonkCameraControl::AutoFocusImpl(AutoFocusTask* aAutoFocus)
{
nsMainThreadPtrHandle<nsICameraAutoFocusCallback> cb = mAutoFocusOnSuccessCb;
if (cb.get()) {
nsCOMPtr<nsICameraAutoFocusCallback> cb = mAutoFocusOnSuccessCb;
if (cb) {
/**
* We already have a callback, so someone has already
* called autoFocus() -- cancel it.
*/
mAutoFocusOnSuccessCb = nullptr;
nsMainThreadPtrHandle<nsICameraErrorCallback> ecb = mAutoFocusOnErrorCb;
nsCOMPtr<nsICameraErrorCallback> ecb = mAutoFocusOnErrorCb;
mAutoFocusOnErrorCb = nullptr;
if (ecb.get()) {
if (ecb) {
nsresult rv = NS_DispatchToMainThread(new CameraErrorResult(ecb, NS_LITERAL_STRING("CANCELLED"), mWindowId));
NS_ENSURE_SUCCESS(rv, rv);
}
@ -748,16 +747,16 @@ nsGonkCameraControl::SetupThumbnail(uint32_t aPictureWidth, uint32_t aPictureHei
nsresult
nsGonkCameraControl::TakePictureImpl(TakePictureTask* aTakePicture)
{
nsMainThreadPtrHandle<nsICameraTakePictureCallback> cb = mTakePictureOnSuccessCb;
if (cb.get()) {
nsCOMPtr<nsICameraTakePictureCallback> cb = mTakePictureOnSuccessCb;
if (cb) {
/**
* We already have a callback, so someone has already
* called TakePicture() -- cancel it.
*/
mTakePictureOnSuccessCb = nullptr;
nsMainThreadPtrHandle<nsICameraErrorCallback> ecb = mTakePictureOnErrorCb;
nsCOMPtr<nsICameraErrorCallback> ecb = mTakePictureOnErrorCb;
mTakePictureOnErrorCb = nullptr;
if (ecb.get()) {
if (ecb) {
nsresult rv = NS_DispatchToMainThread(new CameraErrorResult(ecb, NS_LITERAL_STRING("CANCELLED"), mWindowId));
NS_ENSURE_SUCCESS(rv, rv);
}
@ -916,7 +915,7 @@ public:
nsString data;
CopyASCIItoUTF16(mType, data);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->NotifyObservers(mFile, "file-watcher-update", data.get());
obs->NotifyObservers(mFile, "file-watcher-notify", data.get());
return NS_OK;
}
@ -977,7 +976,8 @@ nsGonkCameraControl::TakePictureComplete(uint8_t* aData, uint32_t aLength)
memcpy(data, aData, aLength);
// TODO: see bug 779144.
nsCOMPtr<nsIRunnable> takePictureResult = new TakePictureResult(data, aLength, NS_LITERAL_STRING("image/jpeg"), mTakePictureOnSuccessCb, mWindowId);
nsIDOMBlob* blob = new nsDOMMemoryFile(static_cast<void*>(data), static_cast<uint64_t>(aLength), NS_LITERAL_STRING("image/jpeg"));
nsCOMPtr<nsIRunnable> takePictureResult = new TakePictureResult(blob, mTakePictureOnSuccessCb, mWindowId);
/**
* Remember to set these to null so that we don't hold any extra
* references to our document's window.
@ -1335,7 +1335,7 @@ nsGonkCameraControl::ReleaseHardwareImpl(ReleaseHardwareTask* aReleaseHardware)
// release the hardware handle
GonkCameraHardware::ReleaseHandle(mHwHandle, true /* unregister */);
if (aReleaseHardware && aReleaseHardware->mOnSuccessCb.get()) {
if (aReleaseHardware && aReleaseHardware->mOnSuccessCb) {
nsCOMPtr<nsIRunnable> releaseHardwareResult = new ReleaseHardwareResult(aReleaseHardware->mOnSuccessCb, mWindowId);
return NS_DispatchToMainThread(releaseHardwareResult);
}

View File

@ -18,7 +18,7 @@ Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
const DB_NAME = "contacts";
const DB_VERSION = 5;
const DB_VERSION = 6;
const STORE_NAME = "contacts";
this.ContactDB = function ContactDB(aGlobal) {
@ -58,7 +58,6 @@ ContactDB.prototype = {
objectStore.createIndex("name", "properties.name", { unique: false, multiEntry: true });
objectStore.createIndex("familyName", "properties.familyName", { unique: false, multiEntry: true });
objectStore.createIndex("givenName", "properties.givenName", { unique: false, multiEntry: true });
objectStore.createIndex("tel", "properties.tel", { unique: false, multiEntry: true });
objectStore.createIndex("email", "properties.email", { unique: false, multiEntry: true });
objectStore.createIndex("note", "properties.note", { unique: false, multiEntry: true });
@ -78,7 +77,9 @@ ContactDB.prototype = {
objectStore = aTransaction.objectStore(STORE_NAME);
}
// Delete old tel index.
objectStore.deleteIndex("tel");
if (objectStore.indexNames.contains("tel")) {
objectStore.deleteIndex("tel");
}
// Upgrade existing tel field in the DB.
objectStore.openCursor().onsuccess = function(event) {
@ -192,6 +193,44 @@ ContactDB.prototype = {
cursor.continue();
}
};
} else if (currVersion == 5) {
if (DEBUG) debug("Add index for equals tel searches");
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
// Delete old tel index (not on the right field).
if (objectStore.indexNames.contains("tel")) {
objectStore.deleteIndex("tel");
}
// Create new index for "equals" searches
objectStore.createIndex("tel", "search.exactTel", { unique: false, multiEntry: true });
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
if (cursor.value.properties.tel) {
if (DEBUG) debug("upgrade : " + JSON.stringify(cursor.value));
cursor.value.properties.tel.forEach(
function(duple) {
let number = duple.value.toString();
let parsedNumber = PhoneNumberUtils.parse(number);
cursor.value.search.exactTel = [number];
if (parsedNumber &&
parsedNumber.internationalNumber &&
number !== parsedNumber.internationalNumber) {
cursor.value.search.exactTel.push(parsedNumber.internationalNumber);
}
}
)
cursor.update(cursor.value);
}
if (DEBUG) debug("upgrade : " + JSON.stringify(cursor.value));
cursor.continue();
}
};
}
}
},
@ -233,6 +272,7 @@ ContactDB.prototype = {
email: [],
category: [],
tel: [],
exactTel: [],
org: [],
jobTitle: [],
note: [],
@ -251,6 +291,7 @@ ContactDB.prototype = {
// Chop off the first characters
let number = aContact.properties[field][i].value;
contact.search.exactTel.push(number);
let search = {};
if (number) {
for (let i = 0; i < number.length; i++) {
@ -273,6 +314,7 @@ ContactDB.prototype = {
debug("NationalFormat: " + parsedNumber.nationalFormat);
if (parsedNumber.internationalNumber &&
number.toString() !== parsedNumber.internationalNumber) {
contact.search.exactTel.push(parsedNumber.internationalNumber);
let digits = parsedNumber.internationalNumber.match(/\d/g);
if (digits) {
digits = digits.join('');

View File

@ -52,6 +52,12 @@ var properties1 = {
tel: [{type: ["work"], value: number1.local, carrier: "testCarrier"} , {type: ["home", "fax"], value: number2.local}],
};
var shortNumber = "888";
var properties2 = {
name: "Testname2",
tel: [{type: ["work"], value: shortNumber, carrier: "testCarrier"}]
};
var req;
var index = 0;
var createResult1;
@ -82,6 +88,17 @@ var steps = [
};
req.onerror = onFailure;
},
function () {
ok(true, "Adding a new contact2");
var createResult2 = new mozContact();
createResult2.init(properties2);
req = navigator.mozContacts.save(createResult2);
req.onsuccess = function () {
ok(createResult2.id, "The contact now has an ID.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for local number");
var options = {filterBy: ["tel"],
@ -110,6 +127,44 @@ var steps = [
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for a short number matching the prefix");
var shortNumber = number1.local.substring(0, 3);
var options = {filterBy: ["tel"],
filterOp: "equals",
filterValue: shortNumber};
req = mozContacts.find(options);
req.onsuccess = function() {
ok(req.result.length == 0, "The prefix short number should not match any contact.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for a short number matching the suffix");
var shortNumber = number1.local.substring(number1.local.length - 3);
var options = {filterBy: ["tel"],
filterOp: "equals",
filterValue: shortNumber};
req = mozContacts.find(options);
req.onsuccess = function() {
ok(req.result.length == 0, "The suffix short number should not match any contact.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for a short number matching a contact");
var options = {filterBy: ["tel"],
filterOp: "equals",
filterValue: shortNumber};
req = mozContacts.find(options);
req.onsuccess = function() {
ok(req.result.length == 1, "Found the contact equally matching the shortNumber.");
next();
};
req.onerror = onFailure;
},
function() {
ok(true, "Modifying number");
findResult1.tel[0].value = number2.local;
@ -207,4 +262,4 @@ ok(true, "test passed");
</script>
</pre>
</body>
</html>
</html>

View File

@ -10,6 +10,7 @@
#include "nsIPrincipal.h"
#include "nsIObserver.h"
#include "nsDOMEventTargetHelper.h"
#include "mozilla/StaticPtr.h"
class DeviceStorageFile MOZ_FINAL
: public nsISupports {
@ -43,6 +44,18 @@ private:
void AppendRelativePath();
};
class FileUpdateDispatcher MOZ_FINAL
: public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
static FileUpdateDispatcher* GetSingleton();
private:
static mozilla::StaticRefPtr<FileUpdateDispatcher> sSingleton;
};
class nsDOMDeviceStorage MOZ_FINAL
: public nsIDOMDeviceStorage
, public nsDOMEventTargetHelper

View File

@ -223,6 +223,56 @@ DeviceStorageTypeChecker::GetAccessForRequest(const DeviceStorageRequestType aRe
return NS_OK;
}
NS_IMPL_ISUPPORTS1(FileUpdateDispatcher, nsIObserver)
mozilla::StaticRefPtr<FileUpdateDispatcher> FileUpdateDispatcher::sSingleton;
FileUpdateDispatcher*
FileUpdateDispatcher::GetSingleton()
{
if (sSingleton) {
return sSingleton;
}
sSingleton = new FileUpdateDispatcher();
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->AddObserver(sSingleton, "file-watcher-notify", false);
ClearOnShutdown(&sSingleton);
return sSingleton;
}
NS_IMETHODIMP
FileUpdateDispatcher::Observe(nsISupports *aSubject,
const char *aTopic,
const PRUnichar *aData)
{
if (XRE_GetProcessType() != GeckoProcessType_Default) {
DeviceStorageFile* file = static_cast<DeviceStorageFile*>(aSubject);
if (!file || !file->mFile) {
NS_WARNING("Device storage file looks invalid!");
return NS_OK;
}
nsString fullpath;
nsresult rv = file->mFile->GetPath(fullpath);
if (NS_FAILED(rv)) {
NS_WARNING("Could not get path from the nsIFile!");
return NS_OK;
}
ContentChild::GetSingleton()->SendFilePathUpdateNotify(file->mStorageType,
fullpath,
NS_ConvertUTF16toUTF8(aData));
} else {
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->NotifyObservers(aSubject, "file-watcher-update", aData);
}
return NS_OK;
}
class IOEventComplete : public nsRunnable
{
public:
@ -240,7 +290,8 @@ public:
nsString data;
CopyASCIItoUTF16(mType, data);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->NotifyObservers(mFile, "file-watcher-update", data.get());
obs->NotifyObservers(mFile, "file-watcher-notify", data.get());
return NS_OK;
}
@ -1558,6 +1609,18 @@ public:
return NS_ERROR_FAILURE;
}
DeviceStorageTypeChecker* typeChecker = DeviceStorageTypeChecker::CreateOrGet();
if (!typeChecker) {
return NS_OK;
}
if (!typeChecker->Check(mFile->mStorageType, mFile->mFile) ||
!typeChecker->Check(mFile->mStorageType, mBlob)) {
r = new PostErrorEvent(mRequest, POST_ERROR_EVENT_ILLEGAL_TYPE);
NS_DispatchToMainThread(r);
return NS_OK;
}
if (XRE_GetProcessType() != GeckoProcessType_Default) {
BlobChild* actor = ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlob);
@ -1582,6 +1645,17 @@ public:
case DEVICE_STORAGE_REQUEST_READ:
case DEVICE_STORAGE_REQUEST_WRITE:
{
DeviceStorageTypeChecker* typeChecker = DeviceStorageTypeChecker::CreateOrGet();
if (!typeChecker) {
return NS_OK;
}
if (!typeChecker->Check(mFile->mStorageType, mFile->mFile)) {
r = new PostErrorEvent(mRequest, POST_ERROR_EVENT_ILLEGAL_TYPE);
NS_DispatchToMainThread(r);
return NS_OK;
}
if (XRE_GetProcessType() != GeckoProcessType_Default) {
PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
DeviceStorageGetParams params(mFile->mStorageType, mFile->mPath, fullpath);
@ -1595,6 +1669,17 @@ public:
case DEVICE_STORAGE_REQUEST_DELETE:
{
DeviceStorageTypeChecker* typeChecker = DeviceStorageTypeChecker::CreateOrGet();
if (!typeChecker) {
return NS_OK;
}
if (!typeChecker->Check(mFile->mStorageType, mFile->mFile)) {
r = new PostErrorEvent(mRequest, POST_ERROR_EVENT_ILLEGAL_TYPE);
NS_DispatchToMainThread(r);
return NS_OK;
}
if (XRE_GetProcessType() != GeckoProcessType_Default) {
PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
DeviceStorageDeleteParams params(mFile->mStorageType, fullpath);

View File

@ -30,6 +30,7 @@ MOCHITEST_FILES = \
test_stat.html \
test_watch.html \
test_watchOther.html \
test_823965.html \
devicestorage_common.js \
$(NULL)

View File

@ -0,0 +1,94 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=823965
-->
<head>
<title>Test for the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=823965">Mozilla Bug 823965</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
var gFileName = "devicestorage/hi.png";
var gData = "My name is Doug Turner (?!?). My IRC nick is DougT. I like Maple cookies."
var gDataBlob = new Blob([gData], {type: 'image/png'});
function getSuccess(e) {
var storage = navigator.getDeviceStorage("pictures");
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
ok(e.target.result.name == gFileName, "File name should match");
ok(e.target.result.size > 0, "File size be greater than zero");
ok(e.target.result.type, "File should have a mime type");
ok(e.target.result.lastModifiedDate, "File should have a last modified date");
var mreq = storage.enumerate();
mreq.onsuccess = function() {
var storage2 = navigator.getDeviceStorage('music');
var dreq = storage2.delete(mreq.result.name);
dreq.onerror = function () {
ok(true, "The bug has been fixed");
devicestorage_cleanup();
};
dreq.onsuccess = function () {
ok(false, "The bug has been fixed");
devicestorage_cleanup();
};
};
mreq.onerror = getError;
}
function getError(e) {
ok(false, "getError was called : " + e.target.error.name);
devicestorage_cleanup();
}
function addSuccess(e) {
ok(e.target.result == gFileName, "File name should match");
var storage = navigator.getDeviceStorage("pictures");
request = storage.get(gFileName);
request.onsuccess = getSuccess;
request.onerror = getError;
ok(true, "addSuccess was called");
}
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
var storage = navigator.getDeviceStorage("pictures");
ok(storage, "Should have gotten a storage");
request = storage.addNamed(gDataBlob, "devicestorage/hi.png");
ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;
request.onerror = addError;
</script>
</pre>
</body>
</html>

View File

@ -60,12 +60,12 @@ function TestAdd(iframe, data) {
function TestGet(iframe, data) {
createTestFile();
createTestFile(data.fileExtension);
var storage = iframe.contentDocument.defaultView.navigator.getDeviceStorage(data.type);
isnot(storage, null, "Should be able to get storage object for " + data.type);
request = storage.get("testfile");
request = storage.get("testfile" + data.fileExtension);
isnot(request, null, "Should be able to get request");
request.onsuccess = function() {
@ -81,12 +81,12 @@ function TestGet(iframe, data) {
function TestDelete(iframe, data) {
createTestFile();
createTestFile(data.fileExtension);
var storage = iframe.contentDocument.defaultView.navigator.getDeviceStorage(data.type);
isnot(storage, null, "Should be able to get storage object for " + data.type);
request = storage.delete("testfile");
request = storage.delete("testfile" + data.fileExtension);
isnot(request, null, "Should be able to get request");
request.onsuccess = function() {
@ -103,7 +103,7 @@ function TestDelete(iframe, data) {
function TestEnumerate(iframe, data) {
createTestFile();
createTestFile(data.fileExtension);
var storage = iframe.contentDocument.defaultView.navigator.getDeviceStorage(data.type);
isnot(storage, null, "Should be able to get storage object for " + data.type);
@ -137,21 +137,25 @@ var gData = [
{
type: 'pictures',
shouldPass: false,
fileExtension: '.png',
test: TestGet
},
{
type: 'videos',
shouldPass: false,
fileExtension: '.ogv',
test: TestGet
},
{
type: 'music',
shouldPass: false,
fileExtension: '.ogg',
test: TestGet
},
{
type: 'sdcard',
shouldPass: false,
fileExtension: '.txt',
test: TestGet
},
@ -159,6 +163,7 @@ var gData = [
{
type: 'pictures',
shouldPass: true,
fileExtension: '.png',
permissions: ["device-storage:pictures"],
@ -167,6 +172,7 @@ var gData = [
{
type: 'videos',
shouldPass: true,
fileExtension: '.ogv',
permissions: ["device-storage:videos"],
@ -175,6 +181,7 @@ var gData = [
{
type: 'music',
shouldPass: true,
fileExtension: '.ogg',
permissions: ["device-storage:music"],
@ -183,6 +190,7 @@ var gData = [
{
type: 'sdcard',
shouldPass: true,
fileExtension: '.txt',
permissions: ["device-storage:sdcard"],
@ -193,6 +201,7 @@ var gData = [
{
type: 'pictures',
shouldPass: true,
fileExtension: '.png',
app: "https://example.com/manifest_cert.webapp",
permissions: ["device-storage:pictures"],
@ -202,6 +211,7 @@ var gData = [
{
type: 'videos',
shouldPass: true,
fileExtension: '.ogv',
app: "https://example.com/manifest_cert.webapp",
permissions: ["device-storage:videos"],
@ -211,6 +221,7 @@ var gData = [
{
type: 'music',
shouldPass: true,
fileExtension: '.ogg',
app: "https://example.com/manifest_cert.webapp",
permissions: ["device-storage:music"],
@ -220,6 +231,7 @@ var gData = [
{
type: 'sdcard',
shouldPass: true,
fileExtension: '.txt',
app: "https://example.com/manifest_cert.webapp",
permissions: ["device-storage:sdcard"],
@ -356,21 +368,25 @@ var gData = [
{
type: 'pictures',
shouldPass: false,
fileExtension: '.png',
test: TestDelete
},
{
type: 'videos',
shouldPass: false,
fileExtension: '.ogv',
test: TestDelete
},
{
type: 'music',
shouldPass: false,
fileExtension: '.ogg',
test: TestDelete
},
{
type: 'sdcard',
shouldPass: false,
fileExtension: '.txt',
test: TestDelete
},
@ -378,6 +394,7 @@ var gData = [
{
type: 'pictures',
shouldPass: true,
fileExtension: '.png',
permissions: ["device-storage:pictures"],
@ -386,6 +403,7 @@ var gData = [
{
type: 'videos',
shouldPass: true,
fileExtension: '.ogv',
permissions: ["device-storage:videos"],
@ -394,6 +412,7 @@ var gData = [
{
type: 'music',
shouldPass: true,
fileExtension: '.ogg',
permissions: ["device-storage:music"],
@ -402,6 +421,7 @@ var gData = [
{
type: 'sdcard',
shouldPass: true,
fileExtension: '.txt',
permissions: ["device-storage:sdcard"],
@ -412,6 +432,7 @@ var gData = [
{
type: 'pictures',
shouldPass: true,
fileExtension: '.png',
app: "https://example.com/manifest_cert.webapp",
permissions: ["device-storage:pictures"],
@ -421,6 +442,7 @@ var gData = [
{
type: 'videos',
shouldPass: true,
fileExtension: '.ogv',
app: "https://example.com/manifest_cert.webapp",
permissions: ["device-storage:videos"],
@ -430,6 +452,7 @@ var gData = [
{
type: 'music',
shouldPass: true,
fileExtension: '.ogg',
app: "https://example.com/manifest_cert.webapp",
permissions: ["device-storage:music"],
@ -439,6 +462,7 @@ var gData = [
{
type: 'sdcard',
shouldPass: true,
fileExtension: '.txt',
app: "https://example.com/manifest_cert.webapp",
permissions: ["device-storage:sdcard"],
@ -590,7 +614,7 @@ function runTest() {
}
}
function createTestFile() {
function createTestFile(extension) {
try {
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
@ -598,12 +622,12 @@ try {
var f = directoryService.get("TmpD", Ci.nsIFile);
f.appendRelativePath("device-storage-testing");
f.remove(true);
f.appendRelativePath("testfile");
f.appendRelativePath("testfile" + extension);
f.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
} catch(e) {}
}
createTestFile();
createTestFile('.txt');
var gTestRunner = runTest();
SpecialPowers.addPermission("browser", true, gTestUri);

View File

@ -343,6 +343,9 @@ ContentChild::InitXPCOM()
bool isOffline;
SendGetXPCOMProcessAttributes(&isOffline);
RecvSetOffline(isOffline);
DebugOnly<FileUpdateDispatcher*> observer = FileUpdateDispatcher::GetSingleton();
NS_ASSERTION(observer, "FileUpdateDispatcher is null");
}
PMemoryReportRequestChild*
@ -1010,7 +1013,7 @@ ContentChild::RecvFlushMemory(const nsString& reason)
mozilla::services::GetObserverService();
if (os)
os->NotifyObservers(nullptr, "memory-pressure", reason.get());
return true;
return true;
}
bool

View File

@ -359,7 +359,7 @@ PrivilegesForApp(mozIApplication* aApp)
const SpecialPermission specialPermissions[] = {
// FIXME/bug 785592: implement a CameraBridge so we don't have
// to hack around with OS permissions
{ "camera", base::PRIVILEGES_INHERIT },
{ "camera", base::PRIVILEGES_CAMERA },
// FIXME/bug 793034: change our video architecture so that we
// can stream video from remote processes
{ "deprecated-hwvideo", base::PRIVILEGES_VIDEO }
@ -507,6 +507,9 @@ ContentParent::Init()
unused << SendActivateA11y();
}
#endif
DebugOnly<FileUpdateDispatcher*> observer = FileUpdateDispatcher::GetSingleton();
NS_ASSERTION(observer, "FileUpdateDispatcher is null");
}
void
@ -1969,6 +1972,25 @@ ContentParent::RecvAsyncMessage(const nsString& aMsg,
return true;
}
bool
ContentParent::RecvFilePathUpdateNotify(const nsString& aType, const nsString& aFilePath, const nsCString& aReason)
{
nsCOMPtr<nsIFile> file;
nsresult rv = NS_NewLocalFile(aFilePath, false, getter_AddRefs(file));
if (NS_FAILED(rv)) {
// ignore
return true;
}
nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(aType, file);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (!obs) {
return false;
}
obs->NotifyObservers(dsf, "file-watcher-update", NS_ConvertASCIItoUTF16(aReason).get());
return true;
}
bool
ContentParent::RecvAddGeolocationListener(const IPC::Principal& aPrincipal)
{

View File

@ -302,6 +302,10 @@ private:
virtual bool RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData);
virtual bool RecvFilePathUpdateNotify(const nsString& aType,
const nsString& aFilePath,
const nsCString& aReason);
virtual bool RecvAddGeolocationListener(const IPC::Principal& aPrincipal);
virtual bool RecvRemoveGeolocationListener();
virtual bool RecvSetGeolocationHigherAccuracy(const bool& aEnable);

View File

@ -443,6 +443,9 @@ parent:
async AudioChannelChangedNotification();
async FilePathUpdateNotify(nsString aType,
nsString aFilepath,
nsCString aReason);
both:
AsyncMessage(nsString aMessage, ClonedMessageData aData);
};

View File

@ -9,7 +9,6 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
const RIL_MMSSERVICE_CONTRACTID = "@mozilla.org/mms/rilmmsservice;1";
@ -21,14 +20,6 @@ const kNetworkInterfaceStateChangedTopic = "network-interface-state-changed";
const kXpcomShutdownObserverTopic = "xpcom-shutdown";
const kPrefenceChangedObserverTopic = "nsPref:changed";
// File modes for saving MMS attachments.
const FILE_OPEN_MODE = FileUtils.MODE_CREATE
| FileUtils.MODE_WRONLY
| FileUtils.MODE_TRUNCATE;
// Size of each segment in a nsIStorageStream. Must be a power of two.
const STORAGE_STREAM_SEGMENT_SIZE = 4096;
// HTTP status codes:
// @see http://tools.ietf.org/html/rfc2616#page-39
const HTTP_STATUS_OK = 200;
@ -446,79 +437,6 @@ MmsService.prototype = {
}).bind(this));
},
/**
* @param file
* A nsIFile object indicating where to save the data.
* @param data
* An array of raw octets.
* @param callback
* Callback function when I/O is done.
*
* @return An nsIRequest representing the copy operation returned by
* NetUtil.asyncCopy().
*/
saveContentToFile: function saveContentToFile(file, data, callback) {
// Write to a StorageStream for NetUtil.asyncCopy()
let sstream = Cc["@mozilla.org/storagestream;1"]
.createInstance(Ci.nsIStorageStream);
sstream.init(STORAGE_STREAM_SEGMENT_SIZE, data.length, null);
let bostream = Cc["@mozilla.org/binaryoutputstream;1"]
.createInstance(Ci.nsIBinaryOutputStream);
bostream.setOutputStream(sstream.getOutputStream(0));
bostream.writeByteArray(data, data.length);
bostream.close();
// Write message body to file
let ofstream = FileUtils.openSafeFileOutputStream(file, FILE_OPEN_MODE);
return NetUtil.asyncCopy(sstream.newInputStream(0), ofstream, callback);
},
/**
* @param msg
* A MMS message object.
* @param callback
* A callback function that accepts one argument as retrieved message.
*/
saveMessageContent: function saveMessageContent(msg, callback) {
function saveCallback(obj, counter, status) {
obj.saved = Components.isSuccessCode(status);
debug("saveMessageContent: " + obj.file.path + ", saved: " + obj.saved);
// The async copy callback may not be invoked in order, so we only
// callback after all of them were done.
counter.count++;
if (counter.count >= counter.max) {
if (callback) {
callback(msg);
}
}
}
let tid = msg.headers["x-mms-transaction-id"];
if (msg.parts) {
let counter = {max: msg.parts.length, count: 0};
msg.parts.forEach((function (part, index) {
part.file = FileUtils.getFile("ProfD", ["mms", tid, index], true);
if (!part.content) {
saveCallback(part, counter, Cr.NS_ERROR_NOT_AVAILABLE);
} else {
this.saveContentToFile(part.file, part.content,
saveCallback.bind(null, part, counter));
}
}).bind(this));
} else if (msg.content) {
msg.file = FileUtils.getFile("ProfD", ["mms", tid, "content"], true);
this.saveContentToFile(msg.file, msg.content,
saveCallback.bind(null, msg, {max: 1, count: 0}));
} else {
// Nothing to save here.
if (callback) {
callback(msg);
}
}
},
/**
* @param data
* A wrapped object containing raw PDU data.
@ -650,8 +568,9 @@ MmsService.prototype = {
callbackIfValid(status, msg);
return;
}
this.saveMessageContent(msg, callbackIfValid.bind(null, MMS.MMS_PDU_ERROR_OK));
// Todo: Please add code for inserting msg into database
// right here.
// see bug id: 811252 - B2G MMS: implement MMS database
},
/**

View File

@ -2237,7 +2237,12 @@ this.PduHelper = {
headers = this.parseHeaders(data, headersEnd, headers);
let content = Octet.decodeMultiple(data, contentEnd);
let octetArray = Octet.decodeMultiple(data, contentEnd);
let content = null;
if (octetArray) {
content = new Blob([octetArray],
{"type" : headers["content-type"].media});
}
parts[i] = {
index: i,

View File

@ -383,9 +383,9 @@ function getTxBytes(params, callback) {
function setAccessPoint(params, callback) {
let command = "softap set " + params.ifname +
" " + params.wifictrlinterfacename +
" " + params.ssid +
" \"" + params.ssid + "\"" +
" " + params.security +
" " + params.key +
" \"" + params.key + "\"" +
" " + "6 0 8";
return doCommand(command, callback);
}

View File

@ -1470,7 +1470,11 @@ let RIL = {
debug("Setting manual network selection: " + options.mcc + options.mnc);
}
let numeric = String(options.mcc) + options.mnc;
// TODO: Bug 828307 - B2G RIL: Change to store MNC/MCC values from integer to string
let mnc = options.mnc.toString();
if (mnc.length == 1)
mnc = "0" + mnc;
let numeric = options.mcc.toString() + mnc;
Buf.newParcel(REQUEST_SET_NETWORK_SELECTION_MANUAL, options);
Buf.writeString(numeric);
Buf.sendParcel();
@ -7693,7 +7697,7 @@ let StkProactiveCmdHelper = {
retrieveTextString: function retrieveTextString(length) {
if (!length) {
// null string.
return null;
return {textString: null};
}
let text = {
@ -9120,7 +9124,10 @@ let ICCRecordHelper = {
getPNN: function getPNN() {
let pnn = [];
function callback(options) {
let pnnElement = RIL.iccInfoPrivate.PNN = {};
let pnnElement = {
fullName: "",
shortName: ""
};
let len = Buf.readUint32();
let readLen = 0;
while (len > readLen) {

View File

@ -815,6 +815,74 @@ add_test(function test_stk_proactive_command_event_list() {
run_next_test();
});
/**
* Verify Proactive Command : Get Input
*/
add_test(function test_stk_proactive_command_get_input() {
let worker = newUint8Worker();
let pduHelper = worker.GsmPDUHelper;
let berHelper = worker.BerTlvHelper;
let stkHelper = worker.StkProactiveCmdHelper;
let stkCmdHelper = worker.StkCommandParamsFactory;
let get_input_1 = [
0xD0,
0x1E,
0x81, 0x03, 0x01, 0x23, 0x8F,
0x82, 0x02, 0x81, 0x82,
0x8D, 0x05, 0x04, 0x54, 0x65, 0x78, 0x74,
0x91, 0x02, 0x01, 0x10,
0x17, 0x08, 0x04, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74];
for (let i = 0; i < get_input_1.length; i++) {
pduHelper.writeHexOctet(get_input_1[i]);
}
let berTlv = berHelper.decode(get_input_1.length);
let ctlvs = berTlv.value;
let tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs);
do_check_eq(tlv.value.commandNumber, 0x01);
do_check_eq(tlv.value.typeOfCommand, STK_CMD_GET_INPUT);
let input = stkCmdHelper.createParam(tlv.value, ctlvs);
do_check_eq(input.text, "Text");
do_check_eq(input.isAlphabet, true);
do_check_eq(input.isUCS2, true);
do_check_eq(input.hideInput, true);
do_check_eq(input.isPacked, true);
do_check_eq(input.isHelpAvailable, true);
do_check_eq(input.minLength, 0x01);
do_check_eq(input.maxLength, 0x10);
do_check_eq(input.defaultText, "Default");
let get_input_2 = [
0xD0,
0x11,
0x81, 0x03, 0x01, 0x23, 0x00,
0x82, 0x02, 0x81, 0x82,
0x8D, 0x00,
0x91, 0x02, 0x01, 0x10,
0x17, 0x00];
for (let i = 0; i < get_input_2.length; i++) {
pduHelper.writeHexOctet(get_input_2[i]);
}
berTlv = berHelper.decode(get_input_2.length);
ctlvs = berTlv.value;
tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs);
do_check_eq(tlv.value.commandNumber, 0x01);
do_check_eq(tlv.value.typeOfCommand, STK_CMD_GET_INPUT);
input = stkCmdHelper.createParam(tlv.value, ctlvs);
do_check_eq(input.text, null);
do_check_eq(input.minLength, 0x01);
do_check_eq(input.maxLength, 0x10);
do_check_eq(input.defaultText, null);
run_next_test();
});
add_test(function test_spn_display_condition() {
let worker = newWorker({
postRILMessage: function fakePostRILMessage(data) {

View File

@ -6,10 +6,12 @@
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
<script type="text/javascript">
SimpleTest.waitForExplicitFinish();
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
Components.utils.import("resource://gre/modules/Services.jsm");
const Ci = Components.interfaces;
const CONTENT_PAGE = "http://mochi.test:8888/chrome/dom/tests/mochitest/localstorage/page_blank.html";
const slavePath = "/tests/dom/tests/mochitest/localstorage/";
@ -19,17 +21,15 @@ var quota;
try {
quota = Services.prefs.getIntPref("dom.storage.default_quota");
} catch (ex) {
quota = 5*1024;
quota = 5 * 1024;
}
Services.prefs.setIntPref("browser.startup.page", 0);
Services.prefs.setIntPref("dom.storage.default_quota", 1);
var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIWebNavigation).QueryInterface(Ci.nsIDocShellTreeItem).
rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindow);
var slaveLoadsPending = 1;
var slaveOrigin = "";
var slave = null;
@ -37,10 +37,11 @@ var failureRegExp = new RegExp("^FAILURE");
function startTest() {
testOnWindow(true, function(aWindow) {
info("Private window loaded");
var frame = aWindow.content.document.createElement("iframe");
aWindow.content.document.body.appendChild(frame);
aWindow.content.addEventListener("message", function(aEvt) {
onMessageReceived(aEvt, aWindow)
aWindow.content.addEventListener("message", function(aEvent) {
onMessageReceived(aEvent, aWindow)
}, false);
slave = aWindow.content.frames[0];
@ -51,6 +52,7 @@ function startTest() {
function doNextTest(aWindow) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
info("Running test: " + currentTest);
switch (currentTest) {
// Initialy setup the quota to testing value of 1024B and
// set a 500 bytes key with name length 1 (allocate 501 bytes)
@ -125,6 +127,7 @@ function doNextTest(aWindow) {
break;
default:
Services.prefs.clearUserPref("browser.startup.page")
Services.prefs.setIntPref("dom.storage.default_quota", quota);
aWindow.close();
SimpleTest.finish();
@ -134,29 +137,23 @@ function doNextTest(aWindow) {
}
function onMessageReceived(event, aWindow) {
info("Message received: " + event.data);
switch (event.data) {
// Indication of the frame onload event
case "frame loaded":
if (--slaveLoadsPending)
break;
// Just fall through...
// Indication of successfully finished step of a test
case "perf":
if (event.data == "perf")
doStep();
slave.postMessage("step", slaveOrigin);
break;
// Indication of all test parts finish (from any of the frames)
case "done":
aWindow.content.localStorage.clear();
slaveLoadsPending = 1;
doNextTest(aWindow);
break;
// Any other message indicates error or succes message of a test
default:
SimpleTest.ok(!event.data.match(failureRegExp), event.data);
@ -169,7 +166,7 @@ function testOnWindow(aIsPrivate, aCallback) {
win.addEventListener("load", function onLoad() {
win.removeEventListener("load", onLoad, false);
win.addEventListener("DOMContentLoaded", function onInnerLoad() {
if (win.content.location.href == "about:privatebrowsing") {
if (win.content.location.href != CONTENT_PAGE) {
win.gBrowser.loadURI(CONTENT_PAGE);
return;
}
@ -180,13 +177,8 @@ function testOnWindow(aIsPrivate, aCallback) {
}, true);
}
function doStep() {
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="startTest();">
</body>
</html>
</html>

View File

@ -3271,6 +3271,7 @@ nsWebBrowserPersist::CloneNodeWithFixedUpAttributes(
case NS_FORM_INPUT_URL:
case NS_FORM_INPUT_NUMBER:
case NS_FORM_INPUT_DATE:
case NS_FORM_INPUT_TIME:
nodeAsInput->GetValue(valueStr);
// Avoid superfluous value="" serialization
if (valueStr.IsEmpty())

View File

@ -126,7 +126,7 @@ GetHostForPrincipal(nsIPrincipal* aPrincipal, nsACString& aHost)
return NS_OK;
}
class AppUninstallObserver MOZ_FINAL : public nsIObserver {
class AppClearDataObserver MOZ_FINAL : public nsIObserver {
public:
NS_DECL_ISUPPORTS
@ -134,24 +134,29 @@ public:
NS_IMETHODIMP
Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *data)
{
MOZ_ASSERT(!nsCRT::strcmp(aTopic, "webapps-uninstall"));
MOZ_ASSERT(!nsCRT::strcmp(aTopic, "webapps-clear-data"));
nsCOMPtr<nsIAppsService> appsService = do_GetService("@mozilla.org/AppsService;1");
nsCOMPtr<mozIApplication> app;
appsService->GetAppFromObserverMessage(nsAutoString(data), getter_AddRefs(app));
NS_ENSURE_TRUE(app, NS_ERROR_UNEXPECTED);
nsCOMPtr<mozIApplicationClearPrivateDataParams> params =
do_QueryInterface(aSubject);
if (!params) {
NS_ERROR("'webapps-clear-data' notification's subject should be a mozIApplicationClearPrivateDataParams");
return NS_ERROR_UNEXPECTED;
}
uint32_t appId;
app->GetLocalId(&appId);
MOZ_ASSERT(appId != nsIScriptSecurityManager::NO_APP_ID);
nsresult rv = params->GetAppId(&appId);
NS_ENSURE_SUCCESS(rv, rv);
bool browserOnly;
rv = params->GetBrowserOnly(&browserOnly);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPermissionManager> permManager = do_GetService("@mozilla.org/permissionmanager;1");
return permManager->RemovePermissionsForApp(appId);
return permManager->RemovePermissionsForApp(appId, browserOnly);
}
};
NS_IMPL_ISUPPORTS1(AppUninstallObserver, nsIObserver)
NS_IMPL_ISUPPORTS1(AppClearDataObserver, nsIObserver)
} // anonymous namespace
@ -271,10 +276,10 @@ NS_IMETHODIMP DeleteFromMozHostListener::HandleCompletion(uint16_t aReason)
}
/* static */ void
nsPermissionManager::AppUninstallObserverInit()
nsPermissionManager::AppClearDataObserverInit()
{
nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1");
observerService->AddObserver(new AppUninstallObserver(), "webapps-uninstall", /* holdsWeak= */ false);
observerService->AddObserver(new AppClearDataObserver(), "webapps-clear-data", /* holdsWeak= */ false);
}
////////////////////////////////////////////////////////////////////////////////
@ -1162,7 +1167,7 @@ nsPermissionManager::GetPermissionsForApp(nsPermissionManager::PermissionHashKey
}
NS_IMETHODIMP
nsPermissionManager::RemovePermissionsForApp(uint32_t aAppId)
nsPermissionManager::RemovePermissionsForApp(uint32_t aAppId, bool aBrowserOnly)
{
ENSURE_NOT_CHILD_PROCESS;
NS_ENSURE_ARG(aAppId != nsIScriptSecurityManager::NO_APP_ID);
@ -1179,6 +1184,10 @@ nsPermissionManager::RemovePermissionsForApp(uint32_t aAppId)
sql.AppendLiteral("DELETE FROM moz_hosts WHERE appId=");
sql.AppendInt(aAppId);
if (aBrowserOnly) {
sql.AppendLiteral(" AND isInBrowserElement=1");
}
nsCOMPtr<mozIStorageAsyncStatement> removeStmt;
nsresult rv = mDBConn->CreateAsyncStatement(sql, getter_AddRefs(removeStmt));
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -202,7 +202,7 @@ public:
* That way, we can prevent have nsPermissionManager created at startup just
* to be able to clear data when an application is uninstalled.
*/
static void AppUninstallObserverInit();
static void AppClearDataObserverInit();
private:
int32_t GetTypeIndex(const char *aTypeString,

View File

@ -54,8 +54,10 @@ MOCHITEST_FILES = \
MOCHITEST_CHROME_FILES = \
test_permissionmanager_app_isolation.html \
test_app_cleardata_permissions.html \
test_app_uninstall_permissions.html \
test_app_uninstall_cookies.html \
frame_clear_browser_data.html \
channel_utils.js \
$(NULL)

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<body>
</body>
<script>
addEventListener('message', function(e) {
if (e.data == 'clear') {
navigator.mozApps.getSelf().onsuccess = function() {
this.result.clearBrowserData();
document.body.innerHTML = "<done></done>";
};
}
});
</script>
</html>

View File

@ -0,0 +1,213 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Tests that clearing mozbrowser private data removes the onlyInBrowser permissions</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
</head>
<body>
<p id="display"></p>
<div id="content">
<iframe src="http://example.com/tests/error404"></iframe>
</div>
<pre id="test">
<script type="application/javascript;version=1.7">
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cu = Components.utils;
SimpleTest.waitForExplicitFinish();
var permManager = Cc["@mozilla.org/permissionmanager;1"]
.getService(Ci.nsIPermissionManager);
var appsService = Cc['@mozilla.org/AppsService;1']
.getService(Ci.nsIAppsService);
var secMan = Cc['@mozilla.org/scriptsecuritymanager;1']
.getService(Ci.nsIScriptSecurityManager);
var ioService = Cc["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var Webapps = {};
Cu.import("resource://gre/modules/Webapps.jsm", Webapps);
/**
* This function will make sure that the next applications we try to install
* will be installed. That means it will behave like if the user allowed the app
* to be installed in the door hanger.
*/
function confirmNextInstall() {
var panel = window.top.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler.ownerDocument.defaultView
.PopupNotifications.panel
panel.addEventListener("popupshown", function() {
panel.removeEventListener("popupshown", arguments.callee, false);
this.childNodes[0].button.doCommand();
}, false);
}
// If aAppId = -1, returns permissions count, regardless of app.
function getPermissionCountForApp(aAppId) {
var nbPermissions = 0;
var enumerator = permManager.enumerator;
while (enumerator.hasMoreElements()) {
var permission = enumerator.getNext().QueryInterface(Ci.nsIPermission);
if (permission.appId == aAppId || aAppId == -1) {
nbPermissions++;
}
}
return nbPermissions;
}
permManager.addFromPrincipal(window.document.nodePrincipal, "webapps-manage",
Ci.nsIPermissionManager.ALLOW_ACTION);
permManager.addFromPrincipal(window.document.nodePrincipal, "browser",
Ci.nsIPermissionManager.ALLOW_ACTION);
var previousPrefs = {
mozBrowserFramesEnabled: null,
installerDryRun: null,
};
// Save the prefs we want to change (so we can re-set them later) and set them
// to the needed value.
try {
previousPrefs.mozBrowserFramesEnabled = SpecialPowers.getBoolPref('dom.mozBrowserFramesEnabled');
} catch(e)
{
}
SpecialPowers.setBoolPref('dom.mozBrowserFramesEnabled', true);
try {
previousPrefs.installerDryRun = SpecialPowers.getBoolPref('browser.mozApps.installer.dry_run');
} catch(e) {
}
SpecialPowers.setBoolPref('browser.mozApps.installer.dry_run', true);
// We want to simulate that all apps are launchable, for testing purpose.
var gPreviousLaunchableValue = Webapps.DOMApplicationRegistry.allAppsLaunchable;
Webapps.DOMApplicationRegistry.allAppsLaunchable = true;
// URL of the manifest of the app we want to install.
const gManifestURL = "http://www.example.com:80/chrome/dom/tests/mochitest/webapps/apps/basic.webapp";
// ID of the installed app.
var gTestAppId = 0;
addLoadEvent(function() {
confirmNextInstall();
navigator.mozApps.install(gManifestURL, null).onsuccess = function() {
gTestAppId = appsService.getAppLocalIdByManifestURL(gManifestURL);
is(getPermissionCountForApp(gTestAppId), 0, "App should have no permission");
var currentPermissionCount = getPermissionCountForApp(-1);
var principal = secMan.getAppCodebasePrincipal(ioService.newURI("http://www.example.com", null, null),
gTestAppId, true);
permManager.addFromPrincipal(principal, "foobar", Ci.nsIPermissionManager.ALLOW_ACTION);
permManager.addFromPrincipal(principal, "foo", Ci.nsIPermissionManager.DENY_ACTION);
permManager.addFromPrincipal(principal, "bar", Ci.nsIPermissionManager.ALLOW_ACTION, Ci.nsIPermissionManager.EXPIRE_SESSION, 0);
principal = secMan.getAppCodebasePrincipal(ioService.newURI("http://www.example.org", null, null),
gTestAppId, true);
permManager.addFromPrincipal(principal, "foobar", Ci.nsIPermissionManager.ALLOW_ACTION);
is(getPermissionCountForApp(gTestAppId), 4, "App should have 4 permissions");
var frame = document.createElement('iframe');
frame.setAttribute('mozbrowser', '');
frame.setAttribute('mozapp', gManifestURL);
frame.src = 'http://www.example.com/chrome/extensions/cookie/test/frame_clear_browser_data.html';
frame.name = 'app';
frame.addEventListener('load', appFrameLoadEvent);
document.body.appendChild(frame);
};
});
function appFrameLoadEvent() {
/*
* The app frame has been loaded. We can now add permissions for the app to
* create browsers and we will load a page in this browser and wait for the
* load event.
*/
permManager.addFromPrincipal(window.frames[1].document.nodePrincipal, "browser",
Ci.nsIPermissionManager.ALLOW_ACTION);
var frame = document.createElement('iframe');
frame.setAttribute('mozbrowser', '');
frame.src = 'http://example.com/tests/error404_2';
frame.addEventListener('load', browserLoadEvent);
document.getElementsByName('app')[0].contentDocument.body.appendChild(frame);
}
function browserLoadEvent() {
/*
* The browser inside the app has loaded.
*/
frames[1].postMessage("clear", "http://www.example.com");
waitForClearBrowserData();
};
function waitForClearBrowserData() {
SimpleTest.executeSoon(function() {
if (frames[1].document.getElementsByTagName('done').length == 0) {
waitForClearBrowserData();
} else {
checks();
}
});
}
function checks() {
navigator.mozApps.mgmt.getAll().onsuccess = function() {
for (i in this.result) {
var app = this.result[i];
if (app.manifestURL == gManifestURL) {
is(getPermissionCountForApp(gTestAppId), 0, "App should have 0 permissions");
Webapps.DOMApplicationRegistry.allAppsLaunchable = gPreviousLaunchableValue;
// Now we uninstall the app and make sure everything is clean.
app.uninstall().onsuccess = function() {
is(getPermissionCountForApp(gTestAppId), 0, "App should have 0 permissions");
finish();
};
}
}
};
}
/**
* This method will be called when the test will be done. It is going to clear
* all storage data, permissions, etc.
*/
function finish() {
permManager.removeFromPrincipal(window.document.nodePrincipal, "webapps-manage",
Ci.nsIPermissionManager.ALLOW_ACTION);
permManager.removeFromPrincipal(window.document.nodePrincipal, "browser",
Ci.nsIPermissionManager.ALLOW_ACTION);
SpecialPowers.setBoolPref('dom.mozBrowserFramesEnabled', previousPrefs.mozBrowserFramesEnabled);
SpecialPowers.setBoolPref('browser.mozApps.installer.dry_run', previousPrefs.installerDryRun);
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

View File

@ -29,10 +29,6 @@
# include <private/android_filesystem_config.h>
# define CHILD_UNPRIVILEGED_UID AID_APP
# define CHILD_UNPRIVILEGED_GID AID_APP
# define CHILD_CAMERA_UID AID_SYSTEM
# define CHILD_CAMERA_GID AID_SDCARD_RW
# define CHILD_VIDEO_UID AID_MEDIA
# define CHILD_VIDEO_GID AID_AUDIO
#else
/*
* On platforms that are not gonk based, we fall back to an arbitrary
@ -239,7 +235,7 @@ bool LaunchApp(const std::vector<std::string>& argv,
gid_t gid = CHILD_UNPRIVILEGED_GID;
uid_t uid = CHILD_UNPRIVILEGED_UID;
#ifdef MOZ_WIDGET_GONK
if (privs == PRIVILEGES_UNPRIVILEGED) {
{
static bool checked_pix_max, pix_max_ok;
if (!checked_pix_max) {
checked_pix_max = true;
@ -266,12 +262,20 @@ bool LaunchApp(const std::vector<std::string>& argv,
}
gid += getpid();
uid += getpid();
} else if (privs == PRIVILEGES_CAMERA) {
uid = CHILD_CAMERA_UID;
gid = CHILD_CAMERA_GID;
} else if (privs == PRIVILEGES_VIDEO) {
uid = CHILD_VIDEO_UID;
gid = CHILD_VIDEO_GID;
}
if (privs == PRIVILEGES_CAMERA) {
gid_t groups[] = { AID_AUDIO, AID_CAMERA, AID_SDCARD_RW };
if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) != 0) {
DLOG(ERROR) << "FAILED TO setgroups() CHILD PROCESS, path: " << argv_cstr[0];
_exit(127);
}
}
else if (privs == PRIVILEGES_VIDEO) {
gid_t groups[] = { AID_AUDIO, AID_MEDIA };
if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) != 0) {
DLOG(ERROR) << "FAILED TO setgroups() CHILD PROCESS, path: " << argv_cstr[0];
_exit(127);
}
}
#endif
if (setgid(gid) != 0) {

View File

@ -2827,7 +2827,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
ret=Type.BOOL))
openmeth.addstmts([
StmtExpr(ExprAssn(p.otherProcessVar(), ExprLiteral.ZERO)),
StmtExpr(ExprAssn(p.otherProcessVar(), ExprCall(ExprVar('base::GetCurrentProcessHandle')))),
StmtReturn(ExprCall(ExprSelect(p.channelVar(), '.', 'Open'),
[ aChannel, aMessageLoop, sidevar ]))
])

View File

@ -3434,6 +3434,8 @@ nsCSSFrameConstructor::FindInputData(Element* aElement,
SIMPLE_INT_CREATE(NS_FORM_INPUT_NUMBER, NS_NewTextControlFrame),
// TODO: this is temporary until a frame is written: bug 773205.
SIMPLE_INT_CREATE(NS_FORM_INPUT_DATE, NS_NewTextControlFrame),
// TODO: this is temporary until a frame is written: bug 773205
SIMPLE_INT_CREATE(NS_FORM_INPUT_TIME, NS_NewTextControlFrame),
{ NS_FORM_INPUT_SUBMIT,
FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
nsCSSAnonBoxes::buttonContent) },

View File

@ -260,7 +260,7 @@ nsLayoutStatics::Initialize()
InitProcessPriorityManager();
nsPermissionManager::AppUninstallObserverInit();
nsPermissionManager::AppClearDataObserverInit();
nsCookieService::AppClearDataObserverInit();
nsApplicationCacheService::AppClearDataObserverInit();

View File

@ -314,12 +314,6 @@ nsTransitionManager::UpdateThrottledStyle(dom::Element* aElement,
// We also need it for processing of the changes.
nsChangeHint styleChange =
oldStyle->CalcStyleDifference(newStyle, nsChangeHint(0));
// This isn't particularly dangerous, but I want to catch if it happens:
NS_ABORT_IF_FALSE(NS_IsHintSubset(styleChange,
NS_CombineHint(nsChangeHint_UpdateOpacityLayer,
NS_CombineHint(nsChangeHint_UpdateTransformLayer,
nsChangeHint_UpdateOverflow))),
"unexpected change hint");
aChangeList.AppendChange(primaryFrame, primaryFrame->GetContent(),
styleChange);

View File

@ -1 +1,15 @@
{"addons":[{"id":"fullscreen@mbrubeck.limpet.net","name":"Full Screen","version":"3.2","iconURL":"http://static-cdn.addons.mozilla.net/en-US/firefox/images/addon_icon/252573-32.png?modified=1310547725","homepageURL":"https://addons.mozilla.org/en-US/android/addon/full-screen-252573/?src=api"},{"id":"cloudviewer@starkravingfinkle.org","name":"Cloud Viewer","version":"2.1","iconURL":"https://static-ssl-cdn.addons.mozilla.net/img/uploads/addon_icons/295/295895-32.png?modified=1333044963","homepageURL":"https://addons.mozilla.org/en-US/android/addon/cloud-viewer/?src=api"}]}
{
"addons": [{
"id": "fullscreen@mbrubeck.limpet.net",
"name": "Full Screen",
"version": "3.4",
"iconURL": "https://addons.cdn.mozilla.net/img/uploads/addon_icons/252/252573-32.png?modified=1354183977",
"homepageURL": "https://addons.mozilla.org/en-US/android/addon/full-screen-252573/?src=api"
}, {
"id": "cloudviewer@starkravingfinkle.org",
"name": "Cloud Viewer",
"version": "2.1",
"iconURL": "https://addons.cdn.mozilla.net/img/uploads/addon_icons/295/295895-32.png?modified=1353947644",
"homepageURL": "https://addons.mozilla.org/en-US/android/addon/cloud-viewer/?src=api"
}]
}

View File

@ -23,6 +23,7 @@ import android.util.Log;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.ConcurrentLinkedQueue;
@ -730,7 +731,30 @@ final class GeckoEditable
mActionQueue.syncWithGecko();
target = mText;
}
Object ret = method.invoke(target, args);
Object ret;
try {
ret = method.invoke(target, args);
} catch (InvocationTargetException e) {
// Bug 817386
// Most likely Gecko has changed the text while GeckoInputConnection is
// trying to access the text. If we pass through the exception here, Fennec
// will crash due to a lack of exception handler. Log the exception and
// return an empty value instead.
if (!(e.getCause() instanceof IndexOutOfBoundsException)) {
// Only handle IndexOutOfBoundsException for now,
// as other exceptions might signal other bugs
throw e;
}
Log.w(LOGTAG, "Exception in GeckoEditable." + method.getName(), e.getCause());
Class<?> retClass = method.getReturnType();
if (retClass != Void.TYPE && retClass.isPrimitive()) {
ret = retClass.newInstance();
} else if (retClass == String.class) {
ret = "";
} else {
ret = null;
}
}
if (DEBUG) {
StringBuilder log = new StringBuilder(method.getName());
log.append("(");

View File

@ -477,9 +477,9 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
// At this point, we have just switched to displaying a different document than we
// we previously displaying. This means we need to abort any panning/zooming animations
// that are in progress and send an updated display port request to browser.js as soon
// as possible. We accomplish this by passing true to abortPanZoomAnimation, which
// sends the request after aborting the animation. The display port request is actually
// a full viewport update, which is fine because if browser.js has somehow moved to
// as possible. The call to PanZoomController.abortAnimation accomplishes this by calling the
// forceRedraw function, which sends the viewport to gecko. The display port request is
// actually a full viewport update, which is fine because if browser.js has somehow moved to
// be out of sync with this first-paint viewport, then we force them back in sync.
abortPanZoomAnimation();
@ -690,7 +690,7 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
}
/** Implementation of PanZoomTarget */
public void setForceRedraw() {
public void forceRedraw() {
mForceRedraw = true;
if (mGeckoIsReady) {
geometryChanged();

View File

@ -205,7 +205,7 @@ public class LayerView extends FrameLayout {
public void setInputConnectionHandler(InputConnectionHandler inputConnectionHandler) {
mInputConnectionHandler = inputConnectionHandler;
mLayerClient.setForceRedraw();
mLayerClient.forceRedraw();
}
@Override

View File

@ -282,7 +282,7 @@ public class PanZoomController
// We just interrupted a double-tap animation, so force a redraw in
// case this touchstart is just a tap that doesn't end up triggering
// a redraw
mTarget.setForceRedraw();
mTarget.forceRedraw();
// fall through
case FLING:
case BOUNCE:
@ -735,7 +735,7 @@ public class PanZoomController
stopAnimationTimer();
// Force a viewport synchronisation
mTarget.setForceRedraw();
mTarget.forceRedraw();
}
/* Returns the nearest viewport metrics with no overscroll visible. */
@ -926,7 +926,7 @@ public class PanZoomController
startTouch(detector.getFocusX(), detector.getFocusY(), detector.getEventTime());
// Force a viewport synchronisation
mTarget.setForceRedraw();
mTarget.forceRedraw();
PointF point = new PointF(detector.getFocusX(), detector.getFocusY());
GeckoEvent event = GeckoEvent.createNativeGestureEvent(GeckoEvent.ACTION_MAGNIFY_END, point, getMetrics().zoomFactor);

View File

@ -17,7 +17,8 @@ public interface PanZoomTarget {
public void setAnimationTarget(ImmutableViewportMetrics viewport);
public void setViewportMetrics(ImmutableViewportMetrics viewport);
public void setForceRedraw();
/** This triggers an (asynchronous) viewport update/redraw. */
public void forceRedraw();
public boolean post(Runnable action);
public Object getLock();

View File

@ -476,7 +476,7 @@ let WeaveGlue = {
// Show the day-of-week and time (HH:MM) of last sync
let lastSync = Weave.Svc.Prefs.get("lastSync");
if (lastSync != null) {
let syncDate = new Date(lastSync).toLocaleFormat("%a %R");
let syncDate = new Date(lastSync).toLocaleFormat("%a %H:%M");
let dateStr = this._bundle.formatStringFromName("lastSync2.label", [syncDate], 1);
sync.setAttribute("title", dateStr);
}

View File

@ -1,8 +1,5 @@
. "$topsrcdir/mobile/xul/config/mozconfigs/android/common"
# Nightlies only since this has a cost in performance
ac_add_options --enable-js-diagnostics
# Build Fennec
ac_add_options --enable-application=mobile

View File

@ -36,7 +36,7 @@ interface nsIObserver;
interface nsIPrincipal;
interface nsIDOMWindow;
[scriptable, uuid(6c68cd87-4569-4695-8bc8-ad609f624b96)]
[scriptable, uuid(9b6ffbb9-5536-4216-afcf-1b7cd7b54005)]
interface nsIPermissionManager : nsISupports
{
/**
@ -192,8 +192,12 @@ interface nsIPermissionManager : nsISupports
/**
* Remove all permissions associated with a given app id.
* @param aAppId The appId of the app
* @param aBrowserOnly Whether we should remove permissions associated with
* a browser element (true) or all permissions (false).
*/
void removePermissionsForApp(in unsigned long appId);
void removePermissionsForApp(in unsigned long appId,
in boolean browserOnly);
};
%{ C++

View File

@ -291,6 +291,7 @@ nsHttpChannel::nsHttpChannel()
, mCachedContentIsPartial(false)
, mTransactionReplaced(false)
, mAuthRetryPending(false)
, mProxyAuthPending(false)
, mResuming(false)
, mInitedCacheEntry(false)
, mFallbackChannel(false)
@ -1277,6 +1278,9 @@ nsHttpChannel::ProcessResponse()
// authentication prompt has been invoked and result
// is expected asynchronously
mAuthRetryPending = true;
if (httpStatus == 407 || mTransaction->ProxyConnectFailed())
mProxyAuthPending = true;
// suspend the transaction pump to stop receiving the
// unauthenticated content data. We will throw that data
// away when user provides credentials or resume the pump
@ -3619,8 +3623,16 @@ nsHttpChannel::InitOfflineCacheEntry()
}
if (!mResponseHead || mResponseHead->NoStore()) {
if (mResponseHead->NoStore()) {
mOfflineCacheEntry->AsyncDoom(nullptr);
}
CloseOfflineCacheEntry();
if (mResponseHead->NoStore()) {
return NS_ERROR_NOT_AVAILABLE;
}
return NS_OK;
}
@ -4134,6 +4146,7 @@ NS_IMETHODIMP nsHttpChannel::OnAuthAvailable()
// triggers process of throwing away the unauthenticated data already
// coming from the network
mAuthRetryPending = true;
mProxyAuthPending = false;
LOG(("Resuming the transaction, we got credentials from user"));
mTransactionPump->Resume();
@ -4145,12 +4158,23 @@ NS_IMETHODIMP nsHttpChannel::OnAuthCancelled(bool userCancel)
LOG(("nsHttpChannel::OnAuthCancelled [this=%p]", this));
if (mTransactionPump) {
// If the channel is trying to authenticate to a proxy and
// that was canceled we cannot show the http response body
// from the 40x as that might mislead the user into thinking
// it was a end host response instead of a proxy reponse.
// This must check explicitly whether a proxy auth was being done
// because we do want to show the content if this is an error from
// the origin server.
if (mProxyAuthPending)
Cancel(NS_ERROR_PROXY_CONNECTION_REFUSED);
// ensure call of OnStartRequest of the current listener here,
// it would not be called otherwise at all
nsresult rv = CallOnStartRequest();
// drop mAuthRetryPending flag and resume the transaction
// this resumes load of the unauthenticated content data
// this resumes load of the unauthenticated content data (which
// may have been canceled if we don't want to show it)
mAuthRetryPending = false;
LOG(("Resuming the transaction, user cancelled the auth dialog"));
mTransactionPump->Resume();
@ -4158,7 +4182,8 @@ NS_IMETHODIMP nsHttpChannel::OnAuthCancelled(bool userCancel)
if (NS_FAILED(rv))
mTransactionPump->Cancel(rv);
}
mProxyAuthPending = false;
return NS_OK;
}

View File

@ -331,6 +331,7 @@ private:
uint32_t mCachedContentIsPartial : 1;
uint32_t mTransactionReplaced : 1;
uint32_t mAuthRetryPending : 1;
uint32_t mProxyAuthPending : 1;
uint32_t mResuming : 1;
uint32_t mInitedCacheEntry : 1;
// True if we are loading a fallback cache entry from the

View File

@ -10,6 +10,9 @@ function createURI(s) {
}
function run_test() {
// Set up a profile.
do_get_profile();
var secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
const kURI1 = "http://example.com";
var app1 = secMan.getAppCodebasePrincipal(createURI(kURI1), 1, false);
@ -49,4 +52,4 @@ function run_test() {
do_check_eq(domain.value, "example.com");
do_check_eq(user.value, "user2");
do_check_eq(pass.value, "pass2");
}
}

View File

@ -165,7 +165,9 @@ var listener = {
onStartRequest: function test_onStartR(request, ctx) {
try {
if (!Components.isSuccessCode(request.status))
// Proxy auth cancellation return failures to avoid spoofing
if (!Components.isSuccessCode(request.status) &&
(this.expectedCode != 407))
do_throw("Channel should have a success code!");
if (!(request instanceof Ci.nsIHttpChannel))

View File

@ -57,8 +57,8 @@ function asyncCheckCacheEntryExistance(entryName, shouldExist)
do_check_eq(status, Cr.NS_OK);
do_check_true(!!descriptor);
} else {
todo_check_eq(status, Cr.NS_ERROR_CACHE_KEY_NOT_FOUND); // bug 761040
todo_check_null(descriptor); // bug 761040
do_check_eq(status, Cr.NS_ERROR_CACHE_KEY_NOT_FOUND);
do_check_null(descriptor);
}
run_next_test();
};
@ -101,15 +101,14 @@ function noStoreHandler(metadata, response)
}
function checkNoStore(request, buffer)
{
todo_check_eq(buffer, ""); // bug 761040
do_check_eq(buffer, "");
asyncCheckCacheEntryExistance(noStoreEntry, false);
run_next_test();
}
add_test(function test_noStore() {
var chan = make_channel_for_offline_use(baseURI + noStoreEntry);
// The no-store should cause the channel to fail to load.
chan.asyncOpen(new ChannelListener(checkNoStore, chan
/*, TODO(bug 761040): CL_EXPECT_FAILURE*/),
chan.asyncOpen(new ChannelListener(checkNoStore, chan, CL_EXPECT_FAILURE),
null);
});

View File

@ -84,6 +84,7 @@ function run_all_tests() {
let gTests;
function run_test() {
do_get_profile();
do_test_pending();
httpserv = new HttpServer();
httpserv.registerPathHandler("/cached", cached_handler);
@ -105,4 +106,4 @@ function doneSecondLoad(req, buffer, expected) {
} catch (x) {
do_test_finished();
}
}
}

View File

@ -306,6 +306,7 @@
"toolkit/components/passwordmgr/test/test_master_password_cleanup.html": "",
"toolkit/components/passwordmgr/test/test_notifications.html": "",
"toolkit/components/passwordmgr/test/test_notifications_popup.html": "",
"toolkit/components/passwordmgr/test/test_privbrowsing_perwindowpb.html": "",
"toolkit/components/passwordmgr/test/test_prompt.html": "TIMED_OUT",
"toolkit/components/passwordmgr/test/test_prompt_async.html": "TIMED_OUT",
"toolkit/components/passwordmgr/test/test_xhr.html": "TIMED_OUT",

View File

@ -1,6 +1,6 @@
{
"talos.zip": {
"url": "http://build.mozilla.org/talos/zips/talos.766a17c47b0d.zip",
"url": "http://build.mozilla.org/talos/zips/talos.6de61e505cf3.zip",
"path": ""
}
}

View File

@ -738,6 +738,11 @@ function do_register_cleanup(aFunction)
* @return nsILocalFile of the profile directory.
*/
function do_get_profile() {
if (!runningInParent) {
_dump("TEST-INFO | (xpcshell/head.js) | Ignoring profile creation from child process.\n");
return null;
}
if (!_profileInitialized) {
// Since we have a profile, we will notify profile shutdown topics at
// the end of the current test, to ensure correct cleanup on shutdown.

View File

@ -92,6 +92,12 @@ MOCHITEST_FILES += \
test_prompt.html \
$(NULL)
endif
else
MOCHITEST_FILES += \
privbrowsing_perwindowpb_iframe.html \
test_privbrowsing_perwindowpb.html \
$(NULL)
endif
# This test doesn't pass because we can't ensure a cross-platform

View File

@ -0,0 +1,8 @@
<!DOCTYPE HTML>
<html>
<head>
</head>
<body>
<iframe id="iframe"></iframe>
</body>
</html>

View File

@ -0,0 +1,293 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=248970
-->
<head>
<title>Test for Bug 248970</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="notification_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=248970">Mozilla Bug 248970</a>
<p id="display"></p>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 248970 **/
// based on test_notifications.html
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cr = Components.results;
var testpath = document.location.pathname + "/../";
var prefix = "http://test2.example.com" + testpath;
var subtests = [
"subtst_privbrowsing_1.html", // 1
"subtst_privbrowsing_1.html", // 2
"subtst_privbrowsing_1.html", // 3
"subtst_privbrowsing_2.html", // 4
"subtst_privbrowsing_2.html", // 5
"subtst_privbrowsing_2.html", // 6
"subtst_privbrowsing_3.html", // 7
"subtst_privbrowsing_3.html", // 8
"subtst_privbrowsing_4.html", // 9
"subtst_privbrowsing_3.html" // 10
];
var testNum = 0;
function loadNextTest() {
// run the initialization code for each test
switch (++ testNum) {
case 1:
popupNotifications = normalWindowPopupNotifications;
iframe = normalWindowIframe;
break;
case 2:
popupNotifications = privateWindowPopupNotifications;
iframe = privateWindowIframe;
break;
case 3:
popupNotifications = normalWindowPopupNotifications;
iframe = normalWindowIframe;
break;
case 4:
pwmgr.addLogin(login);
break;
case 5:
popupNotifications = privateWindowPopupNotifications;
iframe = privateWindowIframe;
break;
case 6:
popupNotifications = normalWindowPopupNotifications;
iframe = normalWindowIframe;
break;
case 7:
pwmgr.addLogin(login);
break;
case 8:
popupNotifications = privateWindowPopupNotifications;
iframe = privateWindowIframe;
break;
case 9:
break;
case 10:
popupNotifications = normalWindowPopupNotifications;
iframe = normalWindowIframe;
break;
default:
ok(false, "Unexpected call to loadNextTest for test #" + testNum);
}
ok(true, "Starting test #" + testNum);
iframe.src = prefix + subtests[testNum-1];
}
function checkTest() {
var popup;
switch (testNum) {
case 1:
// run outside of private mode, popup notification should appear
popup = getPopup(popupNotifications, "password-save");
ok(popup, "got popup notification");
popup.remove();
break;
case 2:
// run inside of private mode, popup notification should not appear
popup = getPopup(popupNotifications, "password-save");
ok(!popup, "checking for no popup notification");
break;
case 3:
// run outside of private mode, popup notification should appear
popup = getPopup(popupNotifications, "password-save");
ok(popup, "got popup notification");
popup.remove();
break;
case 4:
// run outside of private mode, popup notification should appear
popup = getPopup(popupNotifications, "password-change");
ok(popup, "got popup notification");
popup.remove();
break;
case 5:
// run inside of private mode, popup notification should not appear
popup = getPopup(popupNotifications, "password-change");
ok(!popup, "checking for no popup notification");
break;
case 6:
// run outside of private mode, popup notification should appear
popup = getPopup(popupNotifications, "password-change");
ok(popup, "got popup notification");
popup.remove();
pwmgr.removeLogin(login);
break;
case 7:
// verify that the user/pass pair was autofilled
var gotUser = iframe.contentDocument.getElementById("user").textContent;
var gotPass = iframe.contentDocument.getElementById("pass").textContent;
is(gotUser, "notifyu1", "Checking submitted username");
is(gotPass, "notifyp1", "Checking submitted password");
break;
case 8:
// verify that the user/pass pair was not autofilled
var gotUser = iframe.contentDocument.getElementById("user").textContent;
var gotPass = iframe.contentDocument.getElementById("pass").textContent;
is(gotUser, "", "Checking submitted username");
is(gotPass, "", "Checking submitted password");
break;
case 9:
// verify that the user/pass pair was available for autocomplete
var gotUser = iframe.contentDocument.getElementById("user").textContent;
var gotPass = iframe.contentDocument.getElementById("pass").textContent;
is(gotUser, "notifyu1", "Checking submitted username");
is(gotPass, "notifyp1", "Checking submitted password");
break;
case 10:
// verify that the user/pass pair was autofilled
var gotUser = iframe.contentDocument.getElementById("user").textContent;
var gotPass = iframe.contentDocument.getElementById("pass").textContent;
is(gotUser, "notifyu1", "Checking submitted username");
is(gotPass, "notifyp1", "Checking submitted password");
pwmgr.removeLogin(login);
break;
default:
ok(false, "Unexpected call to checkTest for test #" + testNum);
}
}
var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
var contentPage = "http://mochi.test:8888/tests/toolkit/components/passwordmgr/test/privbrowsing_perwindowpb_iframe.html";
var testWindows = [];
function testOnWindow(aIsPrivate, aCallback) {
var win = mainWindow.OpenBrowserWindow({private: aIsPrivate});
win.addEventListener("load", function onLoad() {
win.removeEventListener("load", onLoad, false);
win.addEventListener("DOMContentLoaded", function onInnerLoad() {
if (win.content.location.href == "about:privatebrowsing") {
win.gBrowser.loadURI(contentPage);
return;
}
win.removeEventListener("DOMContentLoaded", onInnerLoad, true);
testWindows.push(win);
SimpleTest.executeSoon(function() { aCallback(win); });
}, true);
SimpleTest.executeSoon(function() { win.gBrowser.loadURI(contentPage); });
}, true);
}
var ignoreLoad = false;
function handleLoad(aEvent) {
// ignore every other load event ... We get one for loading the subtest (which
// we want to ignore), and another when the subtest's form submits itself
// (which we want to handle, to start the next test).
ignoreLoad = !ignoreLoad;
if (ignoreLoad) {
ok(true, "Ignoring load of subtest #" + testNum);
return;
}
ok(true, "Processing submission of subtest #" + testNum);
checkTest();
if (testNum < subtests.length) {
loadNextTest();
} else {
ok(true, "private browsing notification tests finished.");
testWindows.forEach(function(aWin) {
aWin.close();
});
SimpleTest.finish();
}
}
var pwmgr = Cc["@mozilla.org/login-manager;1"].
getService(Ci.nsILoginManager);
ok(pwmgr != null, "Access pwmgr");
// We need to make sure no logins have been stored by previous tests
// for forms in |url|, otherwise the change password notification
// would turn into a prompt, and the test will fail.
var url = "http://test2.example.com";
is(pwmgr.countLogins(url, "", null), 0, "No logins should be stored for " + url);
var nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1",
Ci.nsILoginInfo, "init");
var login = new nsLoginInfo(url, url, null, "notifyu1", "notifyp1", "user", "pass");
var normalWindow;
var privateWindow;
var iframe;
var normalWindowIframe;
var privateWindowIframe;
var popupNotifications;
var normalWindowPopupNotifications;
var privateWindowPopupNotifications;
testOnWindow(false, function(aWin) {
var selectedBrowser = aWin.gBrowser.selectedBrowser;
normalWindowIframe = selectedBrowser.contentDocument.getElementById("iframe");
normalWindowIframe.onload = handleLoad;
selectedBrowser.focus();
normalWindowPopupNotifications = getPopupNotifications(selectedBrowser.contentWindow.top);
ok(normalWindowPopupNotifications, "Got popupNotifications in normal window");
// ignore the first load for this window;
ignoreLoad = false;
testOnWindow(true, function(aPrivateWin) {
selectedBrowser = aPrivateWin.gBrowser.selectedBrowser;
privateWindowIframe = selectedBrowser.contentDocument.getElementById("iframe");
privateWindowIframe.onload = handleLoad;
selectedBrowser.focus();
privateWindowPopupNotifications = getPopupNotifications(selectedBrowser.contentWindow.top);
ok(privateWindowPopupNotifications, "Got popupNotifications in private window");
// ignore the first load for this window;
ignoreLoad = false;
SimpleTest.executeSoon(loadNextTest);
});
});
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

View File

@ -266,7 +266,15 @@
ok(true, "doTest testNum 4");
expectedLoads = 1;
expectedDialogs = 2;
iframe1Doc.location.reload();
iframe1.src = exampleCom + "authenticate.sjs?"+
"user=user4name&"+
"pass=user4pass&"+
"realm=mochirealm4&"+
"proxy_user=proxy_user3&"+
"proxy_pass=proxy_pass3&"+
"proxy_realm=proxy_realm3";
break;
case 5:
@ -295,7 +303,14 @@
ok(true, "doTest testNum 6");
expectedLoads = 1;
expectedDialogs = 2;
iframe1Doc.location.reload();
iframe1.src = exampleCom + "authenticate.sjs?"+
"user=user5name&"+
"pass=user5pass&"+
"realm=mochirealm5&"+
"proxy_user=proxy_user4&"+
"proxy_pass=proxy_pass4&"+
"proxy_realm=proxy_realm4&"+
"huge=1";
break;
case 7:
@ -346,6 +361,7 @@
case 3:
dialog.cancelDialog();
setTimeout(onFrameLoad(), 10); // there are no successful frames for test 3
break;
case 4:
@ -357,6 +373,7 @@
case 5:
dialog.cancelDialog();
setTimeout(onFrameLoad(), 10); // there are no successful frames for test 5
break;
case 6:
@ -435,11 +452,9 @@
case 3:
ok(true, "doCheck testNum 3");
is(monitor.windowsRegistered, 1, "Registered 1 open dialog");
var authok1 = iframe1Doc.getElementById("ok").textContent;
var proxyok1 = iframe1Doc.getElementById("proxy").textContent;
is(authok1, "FAIL", "WWW Authorization FAILED, frame1");
is(proxyok1, "FAIL", "Proxy Authorization FAILED, frame1");
// ensure that the page content is not displayed on failed proxy auth
is(iframe1Doc.getElementById("ok"), undefined, "frame did not load");
break;
case 4:
@ -455,14 +470,9 @@
case 5:
ok(true, "doCheck testNum 5");
is(monitor.windowsRegistered, 1, "Registered 1 open dialog");
var authok1 = iframe1Doc.getElementById("ok").textContent;
var proxyok1 = iframe1Doc.getElementById("proxy").textContent;
var footnote = iframe1Doc.getElementById("footnote").textContent;
is(authok1, "FAIL", "WWW Authorization FAILED, frame1");
is(proxyok1, "FAIL", "Proxy Authorization FAILED, frame1");
is(footnote, "This is a footnote after the huge content fill",
"Footnote present and loaded completely");
// ensure that the page content is not displayed on failed proxy auth
is(iframe1Doc.getElementById("footnote"), undefined, "frame did not load");
break;
case 6:

View File

@ -98,6 +98,13 @@ Form History test: form field autocomplete
<button type="submit">Submit</button>
</form>
<!-- form with input type='time' -->
<form id="form15" onsubmit="return false;">
<input type="time" name="field12">
<button type="submit">Submit</button>
</form>
</div>
<pre id="test">
@ -141,11 +148,11 @@ fh.addEntry("field8", "value");
fh.addEntry("field9", "value");
fh.addEntry("field10", "42");
fh.addEntry("field11", "2010-10-10");
fh.addEntry("field12", "21:21");
fh.addEntry("searchbar-history", "blacklist test");
// All these non-implemeted types might need autocomplete tests in the future.
var todoTypes = [ "datetime", "month", "week", "time", "datetime-local",
"range", "color" ];
var todoTypes = [ "datetime", "month", "week", "datetime-local", "range", "color" ];
var todoInput = document.createElement("input");
for (var type of todoTypes) {
todoInput.type = type;
@ -748,6 +755,17 @@ function runTest(testNum) {
doKey("return");
checkForm("2010-10-10");
input = $_(15, "field12");
restoreForm();
doKey("down");
break;
case 406:
checkMenuEntries(["21:21"]);
doKey("down");
doKey("return");
checkForm("21:21");
// Go to test 500.
fh.addEntry("field1", "value1");
input = $_(1, "field1");

View File

@ -185,9 +185,11 @@ var DebuggerServer = {
*/
addBrowserActors: function DS_addBrowserActors() {
this.addActors("chrome://global/content/devtools/dbg-browser-actors.js");
#ifndef MOZ_B2G
this.addActors("chrome://global/content/devtools/dbg-webconsole-actors.js");
this.addTabActor(this.WebConsoleActor, "consoleActor");
this.addGlobalActor(this.WebConsoleActor, "consoleActor");
#endif
if ("nsIProfiler" in Ci)
this.addActors("chrome://global/content/devtools/dbg-profiler-actors.js");
},

View File

@ -4,7 +4,7 @@
toolkit.jar:
content/global/devtools/dbg-transport.js (debugger/dbg-transport.js)
content/global/devtools/dbg-server.js (debugger/server/dbg-server.js)
* content/global/devtools/dbg-server.js (debugger/server/dbg-server.js)
content/global/devtools/dbg-script-actors.js (debugger/server/dbg-script-actors.js)
content/global/devtools/dbg-browser-actors.js (debugger/server/dbg-browser-actors.js)
content/global/devtools/dbg-webconsole-actors.js (webconsole/dbg-webconsole-actors.js)

View File

@ -476,6 +476,18 @@ nsOfflineCacheUpdateItem::OnStopRequest(nsIRequest *aRequest,
mUpdate->OnByteProgress(mBytesRead);
}
if (NS_FAILED(aStatus)) {
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
if (httpChannel) {
bool isNoStore;
if (NS_SUCCEEDED(httpChannel->IsNoStoreResponse(&isNoStore))
&& isNoStore) {
LogToConsole("Offline cache manifest item has Cache-control: no-store header",
this);
}
}
}
// We need to notify the update that the load is complete, but we
// want to give the channel a chance to close the cache entries.
NS_DispatchToCurrentThread(this);

View File

@ -162,7 +162,8 @@ nsWindow::nsWindow() :
mIMEComposing(false),
mIMEMaskSelectionUpdate(false),
mIMEMaskTextUpdate(false),
mIMEMaskEventsCount(1) // Mask IME events since there's no focus yet
mIMEMaskEventsCount(1), // Mask IME events since there's no focus yet
mIMESelectionChanged(false)
{
}
@ -2064,9 +2065,12 @@ nsWindow::OnIMEFocusChange(bool aFocus)
if (aFocus) {
mIMETextChanges.Clear();
mIMESelectionChange = IMEChange();
mIMESelectionChanged = false;
// OnIMETextChange also notifies selection
OnIMETextChange(0, INT32_MAX, INT32_MAX);
// Use 'INT32_MAX / 2' here because subsequent text changes might
// combine with this text change, and overflow might occur if
// we just use INT32_MAX
OnIMETextChange(0, INT32_MAX / 2, INT32_MAX / 2);
FlushIMEChanges();
} else {
// Mask events because we lost focus. On the next focus event, Gecko will notify
@ -2086,7 +2090,7 @@ nsWindow::OnIMEFocusChange(bool aFocus)
void
nsWindow::PostFlushIMEChanges()
{
if (!mIMETextChanges.IsEmpty() || !mIMESelectionChange.IsEmpty()) {
if (!mIMETextChanges.IsEmpty() || mIMESelectionChanged) {
// Already posted
return;
}
@ -2101,7 +2105,6 @@ nsWindow::FlushIMEChanges()
nsRefPtr<nsWindow> kungFuDeathGrip(this);
for (uint32_t i = 0; i < mIMETextChanges.Length(); i++) {
IMEChange &change = mIMETextChanges[i];
MOZ_ASSERT(change.IsTextChange());
nsQueryContentEvent event(true, NS_QUERY_TEXT_CONTENT, this);
InitEvent(event, nullptr);
@ -2119,12 +2122,18 @@ nsWindow::FlushIMEChanges()
}
mIMETextChanges.Clear();
if (!mIMESelectionChange.IsEmpty()) {
MOZ_ASSERT(!mIMESelectionChange.IsTextChange());
if (mIMESelectionChanged) {
nsQueryContentEvent event(true, NS_QUERY_SELECTED_TEXT, this);
InitEvent(event, nullptr);
DispatchEvent(&event);
if (!event.mSucceeded)
return;
AndroidBridge::NotifyIMEChange(nullptr, 0,
mIMESelectionChange.mStart,
mIMESelectionChange.mOldEnd, -1);
mIMESelectionChange = IMEChange();
event.GetSelectionStart(),
event.GetSelectionEnd(), -1);
mIMESelectionChanged = false;
}
}
@ -2138,7 +2147,7 @@ nsWindow::OnIMETextChange(uint32_t aStart, uint32_t aOldEnd, uint32_t aNewEnd)
aStart, aOldEnd, aNewEnd);
/* Make sure Java's selection is up-to-date */
mIMESelectionChange = IMEChange();
mIMESelectionChanged = false;
OnIMESelectionChange();
PostFlushIMEChanges();
@ -2209,17 +2218,8 @@ nsWindow::OnIMESelectionChange(void)
ALOGIME("IME: OnIMESelectionChange");
nsRefPtr<nsWindow> kungFuDeathGrip(this);
nsQueryContentEvent event(true, NS_QUERY_SELECTED_TEXT, this);
InitEvent(event, nullptr);
DispatchEvent(&event);
if (!event.mSucceeded)
return NS_OK;
PostFlushIMEChanges();
mIMESelectionChange = IMEChange((int32_t)event.GetSelectionStart(),
(int32_t)event.GetSelectionEnd());
mIMESelectionChanged = true;
return NS_OK;
}

View File

@ -201,21 +201,13 @@ protected:
mStart(start), mOldEnd(oldEnd), mNewEnd(newEnd)
{
}
IMEChange(int32_t start, int32_t end) :
mStart(start), mOldEnd(end), mNewEnd(-1)
{
}
bool IsEmpty()
{
return mStart < 0;
}
bool IsTextChange()
{
return mNewEnd >= 0;
}
};
nsAutoTArray<IMEChange, 4> mIMETextChanges;
IMEChange mIMESelectionChange;
bool mIMESelectionChanged;
InputContext mInputContext;

View File

@ -27,6 +27,7 @@
#include "nsIScreenManager.h"
#include "nsMathUtils.h"
#include "nsServiceManagerUtils.h"
#include "cutils/properties.h"
#define LOG_TAG "HWComposer"
@ -49,6 +50,14 @@ enum {
HWC_USE_COPYBIT
};
// HWC layer flags
enum {
// Draw a solid color rectangle
// The color should be set on the transform member of the hwc_layer_t struct
// The expected format is a 32 bit ABGR with 8 bits per component
HWC_COLOR_FILL = 0x8
};
namespace mozilla {
static StaticRefPtr<HwcComposer2D> sInstance;
@ -79,6 +88,10 @@ HwcComposer2D::Init(hwc_display_t dpy, hwc_surface_t sur)
mScreenWidth = screenSize.width;
mScreenHeight = screenSize.height;
char propValue[PROPERTY_VALUE_MAX];
property_get("ro.display.colorfill", propValue, "0");
mColorFill = (atoi(propValue) == 1) ? true : false;
mDpy = dpy;
mSur = sur;
@ -232,7 +245,7 @@ HwcComposer2D::PrepareLayerList(Layer* aLayer,
// that require intermediate surfaces. That means all the
// GetEffective*() coordinates are relative to the framebuffer.
const bool TESTING = true;
bool fillColor = false;
const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion();
if (visibleRegion.IsEmpty()) {
@ -249,8 +262,7 @@ HwcComposer2D::PrepareLayerList(Layer* aLayer,
return false;
}
if (!TESTING &&
visibleRegion.GetNumRects() > 1) {
if (visibleRegion.GetNumRects() > 1) {
// FIXME/bug 808339
LOGD("Layer has nontrivial visible region");
return false;
@ -279,8 +291,12 @@ HwcComposer2D::PrepareLayerList(Layer* aLayer,
if (!state.mSurface ||
state.mSurface->type() != SurfaceDescriptor::TSurfaceDescriptorGralloc) {
LOGD("Layer doesn't have a gralloc buffer");
return false;
if (aLayer->AsColorLayer() && mColorFill) {
fillColor = true;
} else {
LOGD("Layer doesn't have a gralloc buffer");
return false;
}
}
if (state.BufferRotated()) {
LOGD("Layer has a rotated buffer");
@ -304,12 +320,18 @@ HwcComposer2D::PrepareLayerList(Layer* aLayer,
}
}
sp<GraphicBuffer> buffer = GrallocBufferActor::GetFrom(*state.mSurface);
sp<GraphicBuffer> buffer = fillColor ? nullptr : GrallocBufferActor::GetFrom(*state.mSurface);
nsIntRect visibleRect = visibleRegion.GetBounds();
nsIntRect bufferRect = nsIntRect(0, 0, int(buffer->getWidth()),
int(buffer->getHeight()));
nsIntRect bufferRect;
if (fillColor) {
bufferRect = nsIntRect(0, 0, visibleRect.width,
visibleRect.height);
} else {
bufferRect = nsIntRect(0, 0, int(buffer->getWidth()),
int(buffer->getHeight()));
}
hwc_layer_t& hwcLayer = mList->hwLayers[current];
@ -319,43 +341,42 @@ HwcComposer2D::PrepareLayerList(Layer* aLayer,
return true;
}
buffer_handle_t handle = buffer->getNativeBuffer()->handle;
buffer_handle_t handle = fillColor ? nullptr : buffer->getNativeBuffer()->handle;
hwcLayer.handle = handle;
hwcLayer.blending = HWC_BLENDING_NONE;
hwcLayer.flags = 0;
hwcLayer.hints = 0;
hwcLayer.blending = HWC_BLENDING_NONE;
hwcLayer.compositionType = HWC_USE_COPYBIT;
if (transform.xx == 0) {
if (transform.xy < 0) {
hwcLayer.transform = HWC_TRANSFORM_ROT_90;
LOGD("Layer buffer rotated 90 degrees");
if (!fillColor) {
if (transform.xx == 0) {
if (transform.xy < 0) {
hwcLayer.transform = HWC_TRANSFORM_ROT_90;
LOGD("Layer buffer rotated 90 degrees");
} else {
hwcLayer.transform = HWC_TRANSFORM_ROT_270;
LOGD("Layer buffer rotated 270 degrees");
}
} else if (transform.xx < 0) {
hwcLayer.transform = HWC_TRANSFORM_ROT_180;
LOGD("Layer buffer rotated 180 degrees");
} else {
hwcLayer.transform = 0;
}
else {
hwcLayer.transform = HWC_TRANSFORM_ROT_270;
LOGD("Layer buffer rotated 270 degrees");
}
}
else if (transform.xx < 0) {
hwcLayer.transform = HWC_TRANSFORM_ROT_180;
LOGD("Layer buffer rotated 180 degrees");
}
else {
hwcLayer.transform = 0;
}
hwcLayer.transform |= state.YFlipped() ? HWC_TRANSFORM_FLIP_V : 0;
hwc_region_t region;
region.numRects = 1;
region.rects = &(hwcLayer.displayFrame);
hwcLayer.visibleRegionScreen = region;
hwcLayer.transform |= state.YFlipped() ? HWC_TRANSFORM_FLIP_V : 0;
hwc_region_t region;
region.numRects = 1;
region.rects = &(hwcLayer.displayFrame);
hwcLayer.visibleRegionScreen = region;
} else {
hwcLayer.flags |= HWC_COLOR_FILL;
ColorLayer* colorLayer = static_cast<ColorLayer*>(layerGL->GetLayer());
hwcLayer.transform = colorLayer->GetColor().Packed();
}
mList->numHwLayers++;
return true;
}

View File

@ -55,6 +55,7 @@ private:
nsCOMPtr<nsIScreen> mScreen;
int mScreenWidth, mScreenHeight;
int mMaxLayerCount;
bool mColorFill;
};
} // namespace mozilla

View File

@ -354,7 +354,7 @@ nsTextStore::~nsTextStore()
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore instance is destroyed, "
"mWidget=0x%p, mDocumentMgr=0x%p, mContext=0x%p",
this, mWidget, mDocumentMgr, mContext));
this, mWidget.get(), mDocumentMgr.get(), mContext.get()));
if (mCompositionTimer) {
mCompositionTimer->Cancel();
@ -1978,7 +1978,7 @@ nsTextStore::GetWnd(TsViewCookie vcView,
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::GetWnd(vcView=%ld, phwnd=0x%p), "
"mWidget=0x%p",
this, vcView, phwnd, mWidget));
this, vcView, phwnd, mWidget.get()));
if (vcView != TEXTSTORE_DEFAULT_VIEW) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
@ -2234,7 +2234,8 @@ nsTextStore::InsertTextAtSelectionInternal(const nsAString &aInsertStr,
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() succeeded: "
"mWidget=0x%p, mWidget->Destroyed()=%s, aTextChange={ acpStart=%ld, "
"acpOldEnd=%ld, acpNewEnd=%ld }",
this, mWidget, GetBoolName(mWidget ? mWidget->Destroyed() : true),
this, mWidget.get(),
GetBoolName(mWidget ? mWidget->Destroyed() : true),
aTextChange ? aTextChange->acpStart : 0,
aTextChange ? aTextChange->acpOldEnd : 0,
aTextChange ? aTextChange->acpNewEnd : 0));

View File

@ -22,7 +22,7 @@
#ifdef ANDROID
#include <stdio.h>
#define LOW_MEMORY_THRESHOLD_KB (512 * 1024)
#define LOW_MEMORY_THRESHOLD_KB (384 * 1024)
#endif
static nsMemoryImpl sGlobalMemory;