Merge m-c to b-s.

This commit is contained in:
Kyle Huey 2011-08-24 08:34:27 -04:00
commit 4a1055ab6c
301 changed files with 4195 additions and 4528 deletions

View File

@ -976,9 +976,11 @@ refRelationSetCB(AtkObject *aAtkObj)
while ((tempAcc = rel.Next()))
targets.AppendElement(nsAccessibleWrap::GetAtkObject(tempAcc));
atkRelation = atk_relation_new(targets.Elements(), targets.Length(), atkType);
atk_relation_set_add(relation_set, atkRelation);
g_object_unref(atkRelation);
if (targets.Length()) {
atkRelation = atk_relation_new(targets.Elements(), targets.Length(), atkType);
atk_relation_set_add(relation_set, atkRelation);
g_object_unref(atkRelation);
}
}
return relation_set;

View File

@ -156,10 +156,9 @@ Sanitizer.prototype = {
}
// Clear plugin data.
let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
const phInterface = Ci.nsIPluginHost;
const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;
ph.QueryInterface(phInterface);
let ph = Cc["@mozilla.org/plugin/host;1"].getService(phInterface);
// Determine age range in seconds. (-1 means clear all.) We don't know
// that this.range[1] is actually now, so we compute age range based
@ -195,13 +194,13 @@ Sanitizer.prototype = {
} catch (e) {}
},
get canClear()
{
return true;
}
},
offlineApps: {
clear: function ()
{

View File

@ -120,20 +120,20 @@
label=" "
onpageshow="gSyncAddDevice.onPageShow();">
<description>
&addDevice.dialog.syncKey.label;
&addDevice.dialog.recoveryKey.label;
</description>
<spacer/>
<groupbox>
<label value="&syncKeyEntry.label;"
accesskey="&syncKeyEntry.accesskey;"
<label value="&recoveryKeyEntry.label;"
accesskey="&recoveryKeyEntry.accesskey;"
control="weavePassphrase"/>
<textbox id="weavePassphrase"
readonly="true"/>
</groupbox>
<groupbox align="center">
<description>&syncKeyBackup.description;</description>
<description>&recoveryKeyBackup.description;</description>
<hbox>
<button id="printSyncKeyButton"
label="&button.syncKeyBackup.print.label;"

View File

@ -92,15 +92,15 @@ let Change = {
document.getElementById("textBox1Row").hidden = true;
document.getElementById("textBox2Row").hidden = true;
document.getElementById("passphraseLabel").value
= this._str("new.synckey.label");
= this._str("new.recoverykey.label");
document.getElementById("passphraseSpacer").hidden = false;
if (this._updatingPassphrase) {
document.getElementById("passphraseHelpBox").hidden = false;
document.title = this._str("new.synckey.title");
introText.textContent = this._str("new.synckey2.introText");
document.title = this._str("new.recoverykey.title");
introText.textContent = this._str("new.recoverykey.introText");
this._dialog.getButton("finish").label
= this._str("new.synckey.acceptButton");
= this._str("new.recoverykey.acceptButton");
}
else {
document.getElementById("generatePassphraseButton").hidden = false;
@ -111,11 +111,11 @@ let Change = {
pp = Weave.Utils.hyphenatePassphrase(pp);
this._passphraseBox.value = pp;
this._passphraseBox.focus();
document.title = this._str("change.synckey2.title");
document.title = this._str("change.recoverykey.title");
introText.textContent = this._str("change.synckey.introText2");
warningText.textContent = this._str("change.synckey2.warningText");
warningText.textContent = this._str("change.recoverykey.warningText");
this._dialog.getButton("finish").label
= this._str("change.synckey.acceptButton");
= this._str("change.recoverykey.acceptButton");
if (this._duringSetup) {
this._dialog.getButton("finish").disabled = false;
}
@ -137,7 +137,7 @@ let Change = {
else {
document.title = this._str("change.password.title");
box2label.value = this._str("new.password.confirm");
introText.textContent = this._str("change.password2.introText");
introText.textContent = this._str("change.password3.introText");
warningText.textContent = this._str("change.password.warningText");
this._dialog.getButton("finish").label
= this._str("change.password.acceptButton");
@ -195,7 +195,7 @@ let Change = {
if (this._updatingPassphrase) {
Weave.Service.passphrase = pp;
if (Weave.Service.login()) {
this._updateStatus("change.synckey2.success", "success");
this._updateStatus("change.recoverykey.success", "success");
Weave.Service.persistLogin();
}
else {
@ -203,12 +203,12 @@ let Change = {
}
}
else {
this._updateStatus("change.synckey.label", "active");
this._updateStatus("change.recoverykey.label", "active");
if (Weave.Service.changePassphrase(pp))
this._updateStatus("change.synckey2.success", "success");
this._updateStatus("change.recoverykey.success", "success");
else
this._updateStatus("change.synckey2.error", "error");
this._updateStatus("change.recoverykey.error", "error");
}
return false;

View File

@ -138,7 +138,7 @@
<vbox id="passphraseHelpBox"
hidden="true">
<description>
&existingSyncKey.description;
&existingRecoveryKey.description;
<label class="text-link"
href="https://services.mozilla.com/sync/help/manual-setup">
&addDevice.showMeHow.label;

View File

@ -196,17 +196,17 @@
</grid>
</wizardpage>
<wizardpage label="&setup.newSyncKeyPage.title.label;"
<wizardpage label="&setup.newRecoveryKeyPage.title.label;"
onextra1="gSyncSetup.onSyncOptions()"
onpageshow="gSyncSetup.onPageShow();">
<description>
&setup.newSyncKeyPage.description.label;
&setup.newRecoveryKeyPage.description.label;
</description>
<spacer/>
<groupbox>
<label value="&syncKeyEntry.label;"
accesskey="&syncKeyEntry.accesskey;"
<label value="&recoveryKeyEntry.label;"
accesskey="&recoveryKeyEntry.accesskey;"
control="weavePassphrase"/>
<textbox id="weavePassphrase"
readonly="true"
@ -214,7 +214,7 @@
</groupbox>
<groupbox align="center">
<description>&syncKeyBackup.description;</description>
<description>&recoveryKeyBackup.description;</description>
<hbox>
<button id="printSyncKeyButton"
label="&button.syncKeyBackup.print.label;"
@ -351,8 +351,8 @@
<groupbox>
<label id="existingPassphraseLabel"
value="&signIn.syncKey.label;"
accesskey="&signIn.syncKey.accesskey;"
value="&signIn.recoveryKey.label;"
accesskey="&signIn.recoveryKey.accesskey;"
control="existingPassphrase"/>
<textbox id="existingPassphrase"
oninput="gSyncSetup.checkFields()"/>
@ -370,7 +370,7 @@
<vbox id="passphraseHelpBox">
<description>
&existingSyncKey.description;
&existingRecoveryKey.description;
<label class="text-link"
href="https://services.mozilla.com/sync/help/manual-setup">
&addDevice.showMeHow.label;

View File

@ -193,8 +193,8 @@ let gSyncUtils = {
* @param elid : ID of the form element containing the passphrase.
*/
passphraseSave: function(elid) {
let dialogTitle = this.bundle.GetStringFromName("save.synckey.title");
let defaultSaveName = this.bundle.GetStringFromName("save.default.label");
let dialogTitle = this.bundle.GetStringFromName("save.recoverykey.title");
let defaultSaveName = this.bundle.GetStringFromName("save.recoverykey.defaultfilename");
this._preparePPiframe(elid, function(iframe) {
let filepicker = Cc["@mozilla.org/filepicker;1"]
.createInstance(Ci.nsIFilePicker);
@ -243,7 +243,7 @@ let gSyncUtils = {
else if (val1 && val1 == Weave.Service.password)
error = "change.password.pwSameAsPassword";
else if (val1 && val1 == Weave.Service.passphrase)
error = "change.password.pwSameAsSyncKey";
error = "change.password.pwSameAsRecoveryKey";
else if (val1 && val2) {
if (val1 == val2 && val1.length >= Weave.MIN_PASS_LENGTH)
valid = true;

View File

@ -56,8 +56,6 @@ Cc["@mozilla.org/moz/jssubscript-loader;1"].
const dm = Cc["@mozilla.org/download-manager;1"].
getService(Ci.nsIDownloadManager);
const bhist = Cc["@mozilla.org/browser/global-history;2"].
getService(Ci.nsIBrowserHistory);
const formhist = Cc["@mozilla.org/satchel/form-history;1"].
getService(Ci.nsIFormHistory2);
@ -583,7 +581,7 @@ WindowHelper.prototype = {
try {
if (wh.onunload)
wh.onunload();
doNextTest();
waitForAsyncUpdates(doNextTest);
}
catch (exc) {
win.close();
@ -698,10 +696,11 @@ function addFormEntryWithMinutesAgo(aMinutesAgo) {
*/
function addHistoryWithMinutesAgo(aMinutesAgo) {
let pURI = makeURI("http://" + aMinutesAgo + "-minutes-ago.com/");
bhist.addPageWithDetails(pURI,
aMinutesAgo + " minutes ago",
now_uSec - (aMinutesAgo * 60 * 1000 * 1000));
is(bhist.isVisited(pURI), true,
PlacesUtils.bhistory
.addPageWithDetails(pURI,
aMinutesAgo + " minutes ago",
now_uSec - (aMinutesAgo * 60 * 1000 * 1000));
is(PlacesUtils.bhistory.isVisited(pURI), true,
"Sanity check: history visit " + pURI.spec +
" should exist after creating it");
return pURI;
@ -711,11 +710,45 @@ function addHistoryWithMinutesAgo(aMinutesAgo) {
* Removes all history visits, downloads, and form entries.
*/
function blankSlate() {
bhist.removeAllPages();
PlacesUtils.bhistory.removeAllPages();
dm.cleanUp();
formhist.removeAllEntries();
}
/**
* Waits for all pending async statements on the default connection, before
* proceeding with aCallback.
*
* @param aCallback
* Function to be called when done.
* @param aScope
* Scope for the callback.
* @param aArguments
* Arguments array for the callback.
*
* @note The result is achieved by asynchronously executing a query requiring
* a write lock. Since all statements on the same connection are
* serialized, the end of this write operation means that all writes are
* complete. Note that WAL makes so that writers don't block readers, but
* this is a problem only across different connections.
*/
function waitForAsyncUpdates(aCallback, aScope, aArguments)
{
let scope = aScope || this;
let args = aArguments || [];
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
.DBConnection;
db.createAsyncStatement("BEGIN EXCLUSIVE").executeAsync();
db.createAsyncStatement("COMMIT").executeAsync({
handleResult: function() {},
handleError: function() {},
handleCompletion: function(aReason)
{
aCallback.apply(scope, args);
}
});
}
/**
* Ensures that the given pref is the expected value.
*
@ -758,7 +791,7 @@ function downloadExists(aID)
function doNextTest() {
if (gAllTests.length <= gCurrTest) {
blankSlate();
finish();
waitForAsyncUpdates(finish);
}
else {
let ct = gCurrTest;
@ -810,7 +843,7 @@ function ensureFormEntriesClearedState(aFormEntries, aShouldBeCleared) {
function ensureHistoryClearedState(aURIs, aShouldBeCleared) {
let niceStr = aShouldBeCleared ? "no longer" : "still";
aURIs.forEach(function (aURI) {
is(bhist.isVisited(aURI), !aShouldBeCleared,
is(PlacesUtils.bhistory.isVisited(aURI), !aShouldBeCleared,
"history visit " + aURI.spec + " should " + niceStr + " exist");
});
}
@ -836,5 +869,5 @@ function test() {
blankSlate();
waitForExplicitFinish();
// Kick off all the tests in the gAllTests array.
doNextTest();
waitForAsyncUpdates(doNextTest);
}

View File

@ -55,8 +55,6 @@ Cc["@mozilla.org/moz/jssubscript-loader;1"].
const dm = Cc["@mozilla.org/download-manager;1"].
getService(Ci.nsIDownloadManager);
const bhist = Cc["@mozilla.org/browser/global-history;2"].
getService(Ci.nsIBrowserHistory);
const formhist = Cc["@mozilla.org/satchel/form-history;1"].
getService(Ci.nsIFormHistory2);
@ -502,10 +500,11 @@ function addFormEntryWithMinutesAgo(aMinutesAgo) {
*/
function addHistoryWithMinutesAgo(aMinutesAgo) {
let pURI = makeURI("http://" + aMinutesAgo + "-minutes-ago.com/");
bhist.addPageWithDetails(pURI,
aMinutesAgo + " minutes ago",
now_uSec - (aMinutesAgo * 60 * 1000 * 1000));
is(bhist.isVisited(pURI), true,
PlacesUtils.bhistory
.addPageWithDetails(pURI,
aMinutesAgo + " minutes ago",
now_uSec - (aMinutesAgo * 60 * 1000 * 1000));
is(PlacesUtils.bhistory.isVisited(pURI), true,
"Sanity check: history visit " + pURI.spec +
" should exist after creating it");
return pURI;
@ -515,11 +514,45 @@ function addHistoryWithMinutesAgo(aMinutesAgo) {
* Removes all history visits, downloads, and form entries.
*/
function blankSlate() {
bhist.removeAllPages();
PlacesUtils.bhistory.removeAllPages();
dm.cleanUp();
formhist.removeAllEntries();
}
/**
* Waits for all pending async statements on the default connection, before
* proceeding with aCallback.
*
* @param aCallback
* Function to be called when done.
* @param aScope
* Scope for the callback.
* @param aArguments
* Arguments array for the callback.
*
* @note The result is achieved by asynchronously executing a query requiring
* a write lock. Since all statements on the same connection are
* serialized, the end of this write operation means that all writes are
* complete. Note that WAL makes so that writers don't block readers, but
* this is a problem only across different connections.
*/
function waitForAsyncUpdates(aCallback, aScope, aArguments)
{
let scope = aScope || this;
let args = aArguments || [];
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
.DBConnection;
db.createAsyncStatement("BEGIN EXCLUSIVE").executeAsync();
db.createAsyncStatement("COMMIT").executeAsync({
handleResult: function() {},
handleError: function() {},
handleCompletion: function(aReason)
{
aCallback.apply(scope, args);
}
});
}
/**
* Checks to see if the download with the specified ID exists.
*
@ -548,7 +581,7 @@ function downloadExists(aID)
function doNextTest() {
if (gAllTests.length <= gCurrTest) {
blankSlate();
finish();
waitForAsyncUpdates(finish);
}
else {
let ct = gCurrTest;
@ -600,7 +633,7 @@ function ensureFormEntriesClearedState(aFormEntries, aShouldBeCleared) {
function ensureHistoryClearedState(aURIs, aShouldBeCleared) {
let niceStr = aShouldBeCleared ? "no longer" : "still";
aURIs.forEach(function (aURI) {
is(bhist.isVisited(aURI), !aShouldBeCleared,
is(PlacesUtils.bhistory.isVisited(aURI), !aShouldBeCleared,
"history visit " + aURI.spec + " should " + niceStr + " exist");
});
}
@ -625,7 +658,7 @@ function openWindow(aOnloadCallback) {
// ok()/is() do...
try {
aOnloadCallback(win);
doNextTest();
waitForAsyncUpdates(doNextTest);
}
catch (exc) {
win.close();
@ -649,5 +682,5 @@ function test() {
blankSlate();
waitForExplicitFinish();
// Kick off all the tests in the gAllTests array.
doNextTest();
waitForAsyncUpdates(doNextTest);
}

View File

@ -536,7 +536,7 @@ function runNextTest() {
gCurrentTest.cleanup();
info("End of test: " + gCurrentTest.desc);
gCurrentTest = null;
executeSoon(runNextTest);
waitForAsyncUpdates(runNextTest);
return;
}

View File

@ -146,8 +146,7 @@ gTests.push({
menuNode.containerOpen = false;
bhist.removeAllPages();
nextTest();
waitForClearHistory(nextTest);
}
});

View File

@ -29,6 +29,13 @@ function openLibrary(callback, aLeftPaneRoot) {
return library;
}
/**
* Waits for completion of a clear history operation, before
* proceeding with aCallback.
*
* @param aCallback
* Function to be called when done.
*/
function waitForClearHistory(aCallback) {
Services.obs.addObserver(function observeCH(aSubject, aTopic, aData) {
Services.obs.removeObserver(observeCH, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
@ -36,3 +43,37 @@ function waitForClearHistory(aCallback) {
}, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
PlacesUtils.bhistory.removeAllPages();
}
/**
* Waits for all pending async statements on the default connection, before
* proceeding with aCallback.
*
* @param aCallback
* Function to be called when done.
* @param aScope
* Scope for the callback.
* @param aArguments
* Arguments array for the callback.
*
* @note The result is achieved by asynchronously executing a query requiring
* a write lock. Since all statements on the same connection are
* serialized, the end of this write operation means that all writes are
* complete. Note that WAL makes so that writers don't block readers, but
* this is a problem only across different connections.
*/
function waitForAsyncUpdates(aCallback, aScope, aArguments)
{
let scope = aScope || this;
let args = aArguments || [];
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
.DBConnection;
db.createAsyncStatement("BEGIN EXCLUSIVE").executeAsync();
db.createAsyncStatement("COMMIT").executeAsync({
handleResult: function() {},
handleError: function() {},
handleCompletion: function(aReason)
{
aCallback.apply(scope, args);
}
});
}

View File

@ -619,11 +619,9 @@ PrivateBrowsingService.prototype = {
}
// Plugin data
let (ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost)) {
const phInterface = Ci.nsIPluginHost;
const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;
ph.QueryInterface(phInterface);
const phInterface = Ci.nsIPluginHost;
const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;
let (ph = Cc["@mozilla.org/plugin/host;1"].getService(phInterface)) {
let tags = ph.getPluginTags();
for (let i = 0; i < tags.length; i++) {
try {

View File

@ -42,34 +42,21 @@ function test() {
// initialization
let pb = Cc["@mozilla.org/privatebrowsing;1"].
getService(Ci.nsIPrivateBrowsingService);
let bhist = Cc["@mozilla.org/browser/global-history;2"].
getService(Ci.nsIBrowserHistory);
let histsvc = Cc["@mozilla.org/browser/nav-history-service;1"].
getService(Ci.nsINavHistoryService).
QueryInterface(Ci.nsPIPlacesDatabase);
let cm = Cc["@mozilla.org/cookiemanager;1"].
getService(Ci.nsICookieManager);
waitForExplicitFinish();
const TEST_URL = "http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/title.sjs";
function cleanup() {
// delete all history items
bhist.removeAllPages();
function waitForCleanup(aCallback) {
// delete all cookies
cm.removeAll();
// delete all history items
waitForClearHistory(aCallback);
}
cleanup();
let observer = {
pass: 1,
onBeginUpdateBatch: function() {
},
onEndUpdateBatch: function() {
},
onVisit: function(aURI, aVisitID, aTime, aSessionId, aReferringId,
aTransitionType, _added) {
},
onTitleChanged: function(aURI, aPageTitle) {
if (aURI.spec != TEST_URL)
return;
@ -80,8 +67,9 @@ function test() {
break;
case 2: // the second time that the page is loaded
is(aPageTitle, "Cookie", "The page should be loaded with a cookie for the second time");
cleanup();
gBrowser.selectedTab = gBrowser.addTab(TEST_URL);
waitForCleanup(function () {
gBrowser.selectedTab = gBrowser.addTab(TEST_URL);
});
break;
case 3: // before entering the private browsing mode
is(aPageTitle, "No Cookie", "The page should be loaded without any cookie again");
@ -89,37 +77,33 @@ function test() {
pb.privateBrowsingEnabled = true;
gBrowser.selectedTab = gBrowser.addTab(TEST_URL);
executeSoon(function() {
histsvc.removeObserver(observer);
PlacesUtils.history.removeObserver(observer);
pb.privateBrowsingEnabled = false;
while (gBrowser.browsers.length > 1)
while (gBrowser.browsers.length > 1) {
gBrowser.removeCurrentTab();
cleanup();
finish();
}
waitForCleanup(finish);
});
break;
default:
ok(false, "Unexpected pass: " + (this.pass - 1));
}
},
onBeforeDeleteURI: function(aURI) {
},
onDeleteURI: function(aURI) {
},
onClearHistory: function() {
},
onPageChanged: function(aURI, aWhat, aValue) {
},
onDeleteVisits: function() {
},
QueryInterface: function(iid) {
if (iid.equals(Ci.nsINavHistoryObserver) ||
iid.equals(Ci.nsISupports)) {
return this;
}
throw Cr.NS_ERROR_NO_INTERFACE;
}
};
histsvc.addObserver(observer, false);
gBrowser.selectedTab = gBrowser.addTab(TEST_URL);
onBeginUpdateBatch: function () {},
onEndUpdateBatch: function () {},
onVisit: function () {},
onBeforeDeleteURI: function () {},
onDeleteURI: function () {},
onClearHistory: function () {},
onPageChanged: function () {},
onDeleteVisits: function() {},
QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver])
};
PlacesUtils.history.addObserver(observer, false);
waitForCleanup(function () {
gBrowser.selectedTab = gBrowser.addTab(TEST_URL);
});
}

View File

@ -9,3 +9,17 @@ registerCleanupFunction(function() {
} catch(e) {}
});
/**
* Waits for completion of a clear history operation, before
* proceeding with aCallback.
*
* @param aCallback
* Function to be called when done.
*/
function waitForClearHistory(aCallback) {
Services.obs.addObserver(function observeCH(aSubject, aTopic, aData) {
Services.obs.removeObserver(observeCH, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
aCallback();
}, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
PlacesUtils.bhistory.removeAllPages();
}

View File

@ -1,25 +1,24 @@
# LOCALIZATION NOTE (change.password.title): This (and associated change.password/passphrase) are used when the user elects to change their password.
#LOCALIZATION NOTE (change.password.title): This (and associated change.password/passphrase) are used when the user elects to change their password.
change.password.title = Change your Password
change.password.acceptButton = Change Password
change.password.status.active = Changing your password…
change.password.status.success = Your password has been changed.
change.password.status.error = There was an error changing your password.
change.password2.introText = Your password must be at least 8 characters long. It cannot be the same as either your user name or your Sync Key.
change.password3.introText = Your password must be at least 8 characters long. It cannot be the same as either your user name or your Recovery Key.
change.password.warningText = Note: All of your other devices will be unable to connect to your account once you change this password.
change.synckey2.title = My Sync Key
change.synckey.acceptButton = Change Sync Key
change.synckey.label = Changing Sync Key and uploading local data, please wait…
change.synckey2.error = There was an error while changing your Sync Key!
change.synckey2.success = Your Sync Key was successfully changed!
change.recoverykey.title = My Recovery Key
change.recoverykey.acceptButton = Change Recovery Key
change.recoverykey.label = Changing Recovery Key and uploading local data, please wait…
change.recoverykey.error = There was an error while changing your Recovery Key!
change.recoverykey.success = Your Recovery Key was successfully changed!
change.synckey.introText = Firefox Cares About Your Privacy
change.synckey.introText2 = To ensure your total privacy, all of your data is encrypted prior to being uploaded. The key to decrypt your data is not uploaded.
# LOCALIZATION NOTE (change.synckey2.warningText) "Sync" should match &syncBrand.shortName.label; from syncBrand.dtd
change.synckey2.warningText = Note: Changing this will erase all data stored on the Sync server and upload new data secured by this Sync Key. Your other devices will not sync until the new Sync Key is entered for that device.
# LOCALIZATION NOTE (change.recoverykey.warningText) "Sync" should match &syncBrand.shortName.label; from syncBrand.dtd
change.recoverykey.warningText = Note: Changing this will erase all data stored on the Sync server and upload new data secured by this Recovery Key. Your other devices will not sync until the new Recovery Key is entered for that device.
new.synckey.label = Your Sync Key
new.recoverykey.label = Your Recovery Key
# LOCALIZATION NOTE (new.password.title): This (and associated new.password/passphrase) are used on a second computer when it detects that your password or passphrase has been changed on a different device.
new.password.title = Update Password
@ -29,7 +28,6 @@ new.password.confirm = Confirm your new password
new.password.acceptButton = Update Password
new.password.status.incorrect = Password incorrect, please try again.
new.synckey.title = Update Sync Key
new.synckey2.introText = Your Sync Key was changed using another device, please enter your updated Sync Key.
new.synckey.acceptButton = Update Sync Key
new.synckey.status.incorrect = Sync Key incorrect, please try again.
new.recoverykey.title = Update Recovery Key
new.recoverykey.introText = Your Recovery Key was changed using another device, please enter your updated Recovery Key.
new.recoverykey.acceptButton = Update Recovery Key

View File

@ -19,8 +19,8 @@
<!ENTITY signIn.account2.accesskey "A">
<!ENTITY signIn.password.label "Password">
<!ENTITY signIn.password.accesskey "P">
<!ENTITY signIn.syncKey.label "Sync Key">
<!ENTITY signIn.syncKey.accesskey "K">
<!ENTITY signIn.recoveryKey.label "Recovery Key">
<!ENTITY signIn.recoveryKey.accesskey "K">
<!-- New Account Page 1: Basic Account Info -->
<!ENTITY setup.newAccountDetailsPage.title.label "Account Details">
@ -41,12 +41,12 @@
<!ENTITY setup.tosAgree2.accesskey "">
<!-- New Account Page 2: Sync Key -->
<!ENTITY setup.newSyncKeyPage.title.label "&brandShortName; Cares About Your Privacy">
<!ENTITY setup.newSyncKeyPage.description.label "To ensure your total privacy, all of your data is encrypted prior to being uploaded. The Sync Key which is necessary to decrypt your data is not uploaded.">
<!ENTITY syncKeyEntry.label "Your Sync Key">
<!ENTITY syncKeyEntry.accesskey "K">
<!ENTITY setup.newRecoveryKeyPage.title.label "&brandShortName; Cares About Your Privacy">
<!ENTITY setup.newRecoveryKeyPage.description.label "To ensure your total privacy, all of your data is encrypted prior to being uploaded. The Recovery Key which is necessary to decrypt your data is not uploaded.">
<!ENTITY recoveryKeyEntry.label "Your Recovery Key">
<!ENTITY recoveryKeyEntry.accesskey "K">
<!ENTITY syncGenerateNewKey.label "Generate a new key">
<!ENTITY syncKeyBackup.description "Your Sync Key is required to access &syncBrand.fullName.label; on other machines. Please create a backup copy. We cannot help you recover your Sync Key.">
<!ENTITY recoveryKeyBackup.description "Your Recovery Key is required to access &syncBrand.fullName.label; on other machines. Please create a backup copy. We cannot help you recover your Recovery Key.">
<!ENTITY button.syncKeyBackup.print.label "Print…">
<!ENTITY button.syncKeyBackup.print.accesskey "P">
@ -65,12 +65,12 @@
<!ENTITY addDevice.dialog.enterCode.label "Enter the code that the device provides:">
<!ENTITY addDevice.dialog.tryAgain.label "Please try again.">
<!ENTITY addDevice.dialog.successful.label "The device has been successfully added. The initial synchronization can take several minutes and will finish in the background.">
<!ENTITY addDevice.dialog.syncKey.label "To activate your device you will need to enter your Sync Key. Please print or save this key and take it with you.">
<!ENTITY addDevice.dialog.recoveryKey.label "To activate your device you will need to enter your Recovery Key. Please print or save this key and take it with you.">
<!ENTITY addDevice.dialog.connected.label "Device Connected">
<!-- Existing Account Page 2: Manual Login -->
<!ENTITY setup.signInPage.title.label "Sign In">
<!ENTITY existingSyncKey.description "You can get a copy of your Sync Key by going to &syncBrand.shortName.label; Options on your other device, and selecting &#x0022;My Sync Key&#x0022; under &#x0022;Manage Account&#x0022;.">
<!ENTITY existingRecoveryKey.description "You can get a copy of your Recovery Key by going to &syncBrand.shortName.label; Options on your other device, and selecting &#x0022;My Recovery Key&#x0022; under &#x0022;Manage Account&#x0022;.">
<!ENTITY verifying.label "Verifying…">
<!ENTITY resetPassword.label "Reset Password">
<!ENTITY resetSyncKey.label "I have lost my other device.">

View File

@ -29,8 +29,8 @@ historyDaysCount.label = #1 day of history;#1 days of history
# #1 is the number of passwords (was %S for a short while, use #1 instead, even if both work)
passwordsCount.label = #1 password;#1 passwords
save.synckey.title = Save Sync Key
save.default.label = Firefox Sync Key.html
save.recoverykey.title = Save Recovery Key
save.recoverykey.defaultfilename = Firefox Recovery Key.html
newAccount.action.label = Firefox Sync is now set up to automatically sync all of your browser data.
newAccount.change.label = You can choose exactly what to sync by selecting Sync Options below.

View File

@ -603,18 +603,37 @@ toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
#forward-button {
list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar");
-moz-transition: 250ms ease-out;
}
#forward-button[disabled="true"] {
list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar&state=disabled");
}
#forward-button:-moz-locale-dir(rtl) {
list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=toolbar");
}
#forward-button[disabled="true"]:-moz-locale-dir(rtl) {
toolbar:not([mode=icons]) #forward-button[disabled="true"] {
list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar&state=disabled");
}
toolbar:not([mode=icons]) #forward-button[disabled="true"]:-moz-locale-dir(rtl) {
list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=toolbar&state=disabled");
}
toolbar[mode=icons] #forward-button[disabled="true"] {
-moz-transform: scale(0);
opacity: 0;
pointer-events: none;
}
toolbar[mode=icons] #forward-button[disabled="true"]:-moz-locale-dir(ltr) {
margin-left: -36px;
}
toolbar[mode=icons] #forward-button[disabled="true"]:-moz-locale-dir(rtl) {
margin-right: -36px;
}
toolbar[mode=icons][iconsize=small] #forward-button[disabled="true"]:-moz-locale-dir(ltr) {
margin-left: -28px;
}
toolbar[mode=icons][iconsize=small] #forward-button[disabled="true"]:-moz-locale-dir(rtl) {
margin-right: -28px;
}
#reload-button {
list-style-image: url("moz-icon://stock/gtk-refresh?size=toolbar");
}
@ -786,7 +805,7 @@ toolbar[iconsize="small"] #forward-button {
.unified-nav-forward[_moz-menuactive] {
list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=menu") !important;
}
toolbar[iconsize="small"] #forward-button[disabled="true"] {
toolbar[iconsize="small"]:not([mode=icons]) #forward-button[disabled="true"] {
list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=menu&state=disabled");
}
@ -796,7 +815,7 @@ toolbar[iconsize="small"] #forward-button:-moz-locale-dir(rtl) {
.unified-nav-forward[_moz-menuactive]:-moz-locale-dir(rtl) {
list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu") !important;
}
toolbar[iconsize="small"] #forward-button[disabled="true"]:-moz-locale-dir(rtl) {
toolbar[iconsize="small"]:not([mode=icons]) #forward-button[disabled="true"]:-moz-locale-dir(rtl) {
list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu&state=disabled");
}

View File

@ -482,6 +482,7 @@ toolbar[mode="icons"] #forward-button:-moz-locale-dir(rtl):-moz-lwtheme {
padding: 4px 5px 5px 3px;
margin-bottom: -1px;
background: url(chrome://browser/skin/keyhole-circle.png) 0 0 no-repeat;
border-radius: 0;
}
#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #back-button:-moz-window-inactive:not(:-moz-lwtheme) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -10,4 +10,6 @@ fi
CC="$CC -arch i386"
CXX="$CXX -arch i386"
# Note, the version (10) is used by libffi's configure.
ac_add_options --target=i386-apple-darwin10
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk

View File

@ -38,10 +38,10 @@ mk_add_options MOZ_UNIFY_BDATE=1
mk_add_options MOZ_POSTFLIGHT_ALL+=build/macosx/universal/flight.mk
DARWIN_VERSION=`uname -r`
ac_add_app_options ppc --target=powerpc-apple-darwin$DARWIN_VERSION
ac_add_app_options i386 --target=i386-apple-darwin$DARWIN_VERSION
ac_add_app_options x86_64 --target=x86_64-apple-darwin$DARWIN_VERSION
# Note, the version (10) is used by libffi's configure.
ac_add_app_options ppc --target=powerpc-apple-darwin10
ac_add_app_options i386 --target=i386-apple-darwin10
ac_add_app_options x86_64 --target=x86_64-apple-darwin10
ac_add_app_options ppc --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk
ac_add_app_options i386 --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk

View File

@ -2,6 +2,7 @@ import subprocess
from devicemanager import DeviceManager, DMError
import re
import os
import sys
class DeviceManagerADB(DeviceManager):
@ -11,6 +12,7 @@ class DeviceManagerADB(DeviceManager):
self.retrylimit = retrylimit
self.retries = 0
self._sock = None
self.useRunAs = False
if packageName == None:
if os.getenv('USER'):
packageName = 'org.mozilla.fennec_' + os.getenv('USER')
@ -22,14 +24,11 @@ class DeviceManagerADB(DeviceManager):
# Initialization code that may fail: Catch exceptions here to allow
# successful initialization even if, for example, adb is not installed.
try:
root = self.getDeviceRoot()
self.verifyPackage(packageName)
self.tmpDir = root + "/tmp"
if (not self.dirExists(self.tmpDir)):
self.mkDir(self.tmpDir)
self.verifyADB()
self.verifyRunAs(packageName)
except:
self.useRunAs = False
self.packageName = None
self.tmpDir = None
try:
# a test to see if we have root privs
files = self.listFiles("/data/data")
@ -51,7 +50,7 @@ class DeviceManagerADB(DeviceManager):
try:
if (os.name == "nt"):
destname = destname.replace('\\', '/')
if (self.packageName):
if (self.useRunAs):
remoteTmpFile = self.tmpDir + "/" + os.path.basename(localname)
self.checkCmd(["push", os.path.realpath(localname), remoteTmpFile])
self.checkCmdAs(["shell", "cp", remoteTmpFile, destname])
@ -498,7 +497,7 @@ class DeviceManagerADB(DeviceManager):
return subprocess.check_call(args)
def checkCmdAs(self, args):
if (self.packageName):
if (self.useRunAs):
args.insert(1, "run-as")
args.insert(2, self.packageName)
return self.checkCmd(args)
@ -518,13 +517,44 @@ class DeviceManagerADB(DeviceManager):
self.checkCmdAs(["shell", "chmod", "777", remoteDir.strip()])
print "chmod " + remoteDir.strip()
def verifyPackage(self, packageName):
# If a valid package name is specified, it will be used for certain
# file operations, so that pushed files and directories are created
# by the uid associated with the package.
self.packageName = None
if (packageName):
data = self.runCmd(["shell", "run-as", packageName, "pwd"]).stdout.read()
if (not re.search('is unknown', data)):
def verifyADB(self):
# Check to see if adb itself can be executed.
try:
self.runCmd(["version"])
except Exception as (ex):
print "unable to execute ADB: ensure Android SDK is installed and adb is in your $PATH"
def isCpAvailable(self):
# Some Android systems may not have a cp command installed,
# or it may not be executable by the user.
data = self.runCmd(["shell", "cp"]).stdout.read()
if (re.search('Usage', data)):
return True
else:
print "unable to execute 'cp' on device; consider installing busybox from Android Market"
return False
def verifyRunAs(self, packageName):
# If a valid package name is available, and certain other
# conditions are met, devicemanagerADB can execute file operations
# via the "run-as" command, so that pushed files and directories
# are created by the uid associated with the package, more closely
# echoing conditions encountered by Fennec at run time.
# Check to see if run-as can be used here, by verifying a
# file copy via run-as.
self.useRunAs = False
devroot = self.getDeviceRoot()
if (packageName and self.isCpAvailable() and devroot):
self.tmpDir = devroot + "/tmp"
if (not self.dirExists(self.tmpDir)):
self.mkDir(self.tmpDir)
self.checkCmd(["shell", "run-as", packageName, "mkdir", devroot + "/sanity"])
self.checkCmd(["push", os.path.abspath(sys.argv[0]), self.tmpDir + "/tmpfile"])
self.checkCmd(["shell", "run-as", packageName, "cp", self.tmpDir + "/tmpfile", devroot + "/sanity"])
if (self.fileExists(devroot + "/sanity/tmpfile")):
print "will execute commands via run-as " + packageName
self.packageName = packageName
print "package set: " + self.packageName
self.useRunAs = True
self.checkCmd(["shell", "rm", devroot + "/tmp/tmpfile"])
self.checkCmd(["shell", "run-as", packageName, "rm", "-r", devroot + "/sanity"])

View File

@ -43,7 +43,6 @@ USE_AUTOCONF = 1
MOZILLA_CLIENT = 1
target = @target@
ac_configure_args = @ac_configure_args@
BUILD_MODULES = @BUILD_MODULES@
MOZILLA_VERSION = @MOZILLA_VERSION@
FIREFOX_VERSION = @FIREFOX_VERSION@

View File

@ -41,6 +41,38 @@ static BOOL sh_DoCopy(wchar_t *srcFileName, DWORD srcFileAttributes,
#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
#define STR_LEN(a) (ARRAY_LEN(a) - 1)
#ifdef __MINGW32__
/* MingW currently does not implement a wide version of the
startup routines. Workaround is to implement something like
it ourselves. */
#include <shellapi.h>
int wmain(int argc, WCHAR **argv);
int main(int argc, char **argv)
{
int result;
wchar_t *commandLine = GetCommandLineW();
int argcw = 0;
wchar_t **_argvw = CommandLineToArgvW( commandLine, &argcw );
wchar_t *argvw[argcw + 1];
int i;
if (!_argvw)
return 127;
/* CommandLineToArgvW doesn't output the ending NULL so
we have to manually add it on */
for ( i = 0; i < argcw; i++ )
argvw[i] = _argvw[i];
argvw[argcw] = NULL;
result = wmain(argcw, argvw);
LocalFree(_argvw);
return result;
}
#endif /* __MINGW32__ */
/* changes all forward slashes in token to backslashes */
void changeForwardSlashesToBackSlashes ( wchar_t *arg )
{

View File

@ -1153,8 +1153,9 @@ ifdef HAVE_DTRACE
ifndef XP_MACOSX
ifdef DTRACE_PROBE_OBJ
ifndef DTRACE_LIB_DEPENDENT
$(DTRACE_PROBE_OBJ):
dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ)
NON_DTRACE_OBJS := $(filter-out $(DTRACE_PROBE_OBJ),$(OBJS))
$(DTRACE_PROBE_OBJ): $(NON_DTRACE_OBJS)
dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) $(NON_DTRACE_OBJS)
endif
endif
endif
@ -1550,9 +1551,6 @@ export:: FORCE
@echo; sleep 2; false
endif
$(IDL_DIR)::
$(NSINSTALL) -D $@
# generate .h files from into $(XPIDL_GEN_DIR), then export to $(DIST)/include;
# warn against overriding existing .h file.
$(XPIDL_GEN_DIR)/.done:
@ -1623,14 +1621,8 @@ endif # XPIDLSRCS
#
# General rules for exporting idl files.
#
# WORK-AROUND ONLY, for mozilla/tools/module-deps/bootstrap.pl build.
# Bug to fix idl dependency problems w/o this extra build pass is
# http://bugzilla.mozilla.org/show_bug.cgi?id=145777
#
$(IDL_DIR)::
$(IDL_DIR):
$(NSINSTALL) -D $@
export-idl:: $(SUBMAKEFILES) $(MAKE_DIRS)
@ -2097,7 +2089,6 @@ showhost:
@echo "HOST_LIBRARY = $(HOST_LIBRARY)"
showbuildmods::
@echo "Build Modules = $(BUILD_MODULES)"
@echo "Module dirs = $(BUILD_MODULE_DIRS)"
documentation:

View File

@ -970,7 +970,6 @@ if test -n "$_WIN32_MSVC"; then
AC_DEFINE(HAVE_IO_H)
AC_DEFINE(HAVE_SETBUF)
AC_DEFINE(HAVE_ISATTY)
AC_DEFINE(HAVE_STDCALL)
fi
fi # COMPILE_ENVIRONMENT
@ -2492,6 +2491,8 @@ ia64*-hpux*)
if test -n "$GNU_CC"; then
CFLAGS="$CFLAGS -mstackrealign"
CXXFLAGS="$CXXFLAGS -mstackrealign"
else
AC_DEFINE(HAVE_STDCALL)
fi
MOZ_CHECK_HEADERS(mmintrin.h)
@ -5185,7 +5186,7 @@ incorrect])
MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS $_QTMOBILITY_CFLAGS"
MOZ_QT_LIBS="$MOZ_QT_LIBS $_QTMOBILITY_LIBS"
else
AC_CHECK_LIB(QtSensors QtFeedback QtLocation, main, [
AC_CHECK_LIB(QtSensors, main, [
MOZ_ENABLE_QTMOBILITY=1
MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I/usr/include/qt4/QtMobility"
MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I/usr/include/qt4/QtSensors"

View File

@ -125,10 +125,10 @@ interface nsITreeItemFrameMessageManager : nsIFrameMessageManager
nsITreeItemFrameMessageManager getChildAt(in unsigned long aIndex);
};
[scriptable, uuid(23e6ef7b-8cc5-4e8b-9391-453440a3b858)]
[scriptable, uuid(9e5c0526-aa4c-49f0-afbb-57f489cd9b59)]
interface nsIChromeFrameMessageManager : nsITreeItemFrameMessageManager
{
/*
/**
* Load a script in the (remote) frame. aURL must be the absolute URL.
* data: URLs are also supported. For example data:,dump("foo\n");
* If aAllowDelayedLoad is true, script will be loaded when the
@ -136,5 +136,10 @@ interface nsIChromeFrameMessageManager : nsITreeItemFrameMessageManager
* only if the frame is already available.
*/
void loadFrameScript(in AString aURL, in boolean aAllowDelayedLoad);
/**
* Removes aURL from the list of scripts which support delayed load.
*/
void removeDelayedFrameScript(in AString aURL);
};

View File

@ -6125,7 +6125,7 @@ nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult)
} while ((doc = doc->GetParentDocument()));
// Remove from parent.
nsINode* parent = adoptedNode->GetNodeParent();
nsCOMPtr<nsINode> parent = adoptedNode->GetNodeParent();
if (parent) {
rv = parent->RemoveChildAt(parent->IndexOf(adoptedNode), PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -177,6 +177,13 @@ nsFrameMessageManager::LoadFrameScript(const nsAString& aURL,
return NS_OK;
}
NS_IMETHODIMP
nsFrameMessageManager::RemoveDelayedFrameScript(const nsAString& aURL)
{
mPendingScripts.RemoveElement(aURL);
return NS_OK;
}
static JSBool
JSONCreator(const jschar* aBuf, uint32 aLen, void* aData)
{

View File

@ -620,7 +620,7 @@ nsINode::Normalize()
}
// Remove node
nsINode* parent = node->GetNodeParent();
nsCOMPtr<nsINode> parent = node->GetNodeParent();
NS_ASSERTION(parent || hasRemoveListeners,
"Should always have a parent unless "
"mutation events messed us up");
@ -3945,7 +3945,7 @@ nsINode::ReplaceOrInsertBefore(PRBool aReplace, nsINode* aNewChild,
}
// Remove the new child from the old parent if one exists
nsINode* oldParent = newContent->GetNodeParent();
nsCOMPtr<nsINode> oldParent = newContent->GetNodeParent();
if (oldParent) {
PRInt32 removeIndex = oldParent->IndexOf(newContent);
if (removeIndex < 0) {

View File

@ -67,6 +67,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=549682
global.addMessageListener("sync", globalListener);
global.addMessageListener("global-sync", globalListener);
global.loadFrameScript("data:,sendSyncMessage('global-sync', { data: 1234 });", true);
var toBeRemovedScript = "data:,sendAsyncMessage('toberemoved', { data: 2345 })";
var c = 0;
messageManager.addMessageListener("toberemoved", function() {
++c;
opener.wrappedJSObject.is(c, 1, "Should be called only once!");
});
// This loads the script in the existing <browser>
messageManager.loadFrameScript(toBeRemovedScript, true);
// But it won't be loaded in the dynamically created <browser>
messageManager.removeDelayedFrameScript(toBeRemovedScript);
var oldValue = globalListenerCallCount;
var b = document.createElement("browser");

View File

@ -2510,12 +2510,12 @@ nsHTMLInputElement::SanitizeValue(nsAString& aValue)
case NS_FORM_INPUT_SEARCH:
case NS_FORM_INPUT_TEL:
case NS_FORM_INPUT_PASSWORD:
case NS_FORM_INPUT_EMAIL:
{
PRUnichar crlf[] = { PRUnichar('\r'), PRUnichar('\n'), 0 };
aValue.StripChars(crlf);
}
break;
case NS_FORM_INPUT_EMAIL:
case NS_FORM_INPUT_URL:
{
PRUnichar crlf[] = { PRUnichar('\r'), PRUnichar('\n'), 0 };

View File

@ -75,8 +75,12 @@ var email = document.forms[0].elements[0];
var values = [
[ '', true ], // The empty string shouldn't be considered as invalid.
[ 'foo@bar.com', true ],
[ ' foo@bar.com', false ],
[ 'foo@bar.com ', false ],
[ ' foo@bar.com', true ],
[ 'foo@bar.com ', true ],
[ '\r\n foo@bar.com', true ],
[ 'foo@bar.com \n\r', true ],
[ '\n\n \r\rfoo@bar.com\n\n \r\r', true ],
[ '\n\r \n\rfoo@bar.com\n\r \n\r', true ],
[ 'tulip', false ],
// Some checks on the user part of the address.
[ '@bar.com', false ],
@ -163,7 +167,7 @@ values.push(["foo@bar.com" + legalCharacters, true]);
// Add domain illegal characters.
illegalCharacters = "()<>[]:;@\\,!#$%&'*+/=?^_`{|}~ \t";
for each (c in illegalCharacters) {
values.push(['foo@foo.bar' + c, false]);
values.push(['foo@foo.ba' + c + 'r', false]);
}
values.forEach(function([value, valid]) {

View File

@ -47,9 +47,9 @@ function sanitizeValue(aType, aValue)
case "password":
case "search":
case "tel":
case "email":
return aValue.replace(/[\n\r]/g, "");
case "url":
case "email":
return aValue.replace(/[\n\r]/g, "").replace(/^\s+|\s+$/g, "");
case "date":
case "month":

View File

@ -32,7 +32,6 @@ function seekStarted(evt) {
function seekEnded(evt) {
var v = evt.target;
v._gotSeekEnded = true;
v.play();
}
function loadedData(evt) {

View File

@ -0,0 +1,46 @@
<svg xmlns="http://www.w3.org/2000/svg" class="reftest-wait">
<rect fill="green" width="100" height="100">
<set id="a" attributeName="fill" to="blue"
begin="6s" end="986s"/>
<set id="b" attributeName="fill" to="orange"
begin="a.begin+69.3s;b.begin+700s" dur="700s" end="a.end"/>
<set id="c" attributeName="fill" to="yellow"
begin="0s;b.begin+700s"/>
</rect>
<script type="text/javascript">
<![CDATA[
const max_attempts = 100;
var attempts = 0;
function attemptCrash()
{
remove();
add();
if (++attempts >= max_attempts) {
document.documentElement.removeAttribute("class");
} else {
setTimeout(attemptCrash, 0);
}
}
function add()
{
const svgns = "http://www.w3.org/2000/svg";
var elem = document.createElementNS(svgns, "set");
elem.setAttribute("id", "b");
elem.setAttribute("attributeName", "fill");
elem.setAttribute("to", "orange");
elem.setAttribute("begin", "a.begin+69.3s;b.begin+700s");
elem.setAttribute("dur", "700s");
elem.setAttribute("end", "a.end");
rect = document.getElementsByTagNameNS(svgns, "rect")[0];
rect.appendChild(elem);
}
function remove()
{
var elem = document.getElementById('b');
elem.parentNode.removeChild(elem);
elem = null;
}
window.addEventListener("load", attemptCrash, false);
]]>
</script>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -34,6 +34,7 @@ load 608295-1.html
load 611927-1.svg
load 615002-1.svg
load 615872-1.svg
load 650732-1.svg
load 665334-1.svg
load 669225-1.svg
load 670313-1.svg

View File

@ -146,8 +146,14 @@ nsSMILCSSProperty::GetBaseValue() const
// (4) Populate our nsSMILValue from the computed style
if (didGetComputedVal) {
// When we parse animation values we check if they are context-sensitive or
// not so that we don't cache animation values whose meaning may change.
// For base values however this is unnecessary since on each sample the
// compositor will fetch the (computed) base value and compare it against
// the cached (computed) value and detect changes for us.
nsSMILCSSValueType::ValueFromString(mPropID, mElement,
computedStyleVal, baseValue);
computedStyleVal, baseValue,
nsnull);
}
return baseValue;
}
@ -160,22 +166,17 @@ nsSMILCSSProperty::ValueFromString(const nsAString& aStr,
{
NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);
nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue);
if (aValue.IsNull()) {
return NS_ERROR_FAILURE;
nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue,
&aPreventCachingOfSandwich);
// XXX Due to bug 536660 (or at least that seems to be the most likely
// culprit), when we have animation setting display:none on a <use> element,
// if we DON'T set the property every sample, chaos ensues.
if (!aPreventCachingOfSandwich && mPropID == eCSSProperty_display) {
aPreventCachingOfSandwich = PR_TRUE;
}
// XXXdholbert: For simplicity, just assume that all CSS values have to
// reparsed every sample. This prevents us from doing the "nothing's changed
// so don't recompose" optimization (bug 533291) for CSS properties & mapped
// attributes. If it ends up being expensive to always recompose those, we
// can be a little smarter here. We really only need to set
// aPreventCachingOfSandwich to true for "inherit" & "currentColor" (whose
// values could change at any time), for length-valued types (particularly
// those with em/ex/percent units, since their conversion ratios can change
// at any time), and for any value for 'font-family'.
aPreventCachingOfSandwich = PR_TRUE;
return NS_OK;
return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
}
nsresult

View File

@ -371,7 +371,8 @@ ValueFromStringHelper(nsCSSProperty aPropID,
Element* aTargetElement,
nsPresContext* aPresContext,
const nsAString& aString,
nsStyleAnimation::Value& aStyleAnimValue)
nsStyleAnimation::Value& aStyleAnimValue,
PRBool* aIsContextSensitive)
{
// If value is negative, we'll strip off the "-" so the CSS parser won't
// barf, and then manually make the parsed value negative.
@ -386,7 +387,8 @@ ValueFromStringHelper(nsCSSProperty aPropID,
}
nsDependentSubstring subString(aString, subStringBegin);
if (!nsStyleAnimation::ComputeValue(aPropID, aTargetElement, subString,
PR_TRUE, aStyleAnimValue)) {
PR_TRUE, aStyleAnimValue,
aIsContextSensitive)) {
return PR_FALSE;
}
if (isNegative) {
@ -409,7 +411,8 @@ void
nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID,
Element* aTargetElement,
const nsAString& aString,
nsSMILValue& aValue)
nsSMILValue& aValue,
PRBool* aIsContextSensitive)
{
NS_ABORT_IF_FALSE(aValue.IsNull(), "Outparam should be null-typed");
nsPresContext* presContext = GetPresContextForElement(aTargetElement);
@ -420,7 +423,7 @@ nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID,
nsStyleAnimation::Value parsedValue;
if (ValueFromStringHelper(aPropID, aTargetElement, presContext,
aString, parsedValue)) {
aString, parsedValue, aIsContextSensitive)) {
sSingleton.Init(aValue);
aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue, presContext);
}

View File

@ -100,13 +100,20 @@ public:
* @param aString The string to be parsed as a CSS value.
* @param [out] aValue The nsSMILValue to be populated. Should
* initially be null-typed.
* @param [out] aIsContextSensitive Set to PR_TRUE if |aString| may produce
* a different |aValue| depending on other
* CSS properties on |aTargetElement|
* or its ancestors (e.g. 'inherit).
* PR_FALSE otherwise. May be nsnull.
* Not set if the method fails.
* @pre aValue.IsNull()
* @post aValue.IsNull() || aValue.mType == nsSMILCSSValueType::sSingleton
*/
static void ValueFromString(nsCSSProperty aPropID,
Element* aTargetElement,
const nsAString& aString,
nsSMILValue& aValue);
nsSMILValue& aValue,
PRBool* aIsContextSensitive);
/**
* Creates a string representation of the given nsSMILValue.

View File

@ -67,15 +67,9 @@ nsSMILMappedAttribute::ValueFromString(const nsAString& aStr,
{
NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);
nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue);
if (aValue.IsNull()) {
return NS_ERROR_FAILURE;
}
// XXXdholbert: For simplicity, just assume that all CSS values have to
// reparsed every sample. See note in nsSMILCSSProperty::ValueFromString.
aPreventCachingOfSandwich = PR_TRUE;
return NS_OK;
nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue,
&aPreventCachingOfSandwich);
return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
}
nsSMILValue
@ -87,8 +81,12 @@ nsSMILMappedAttribute::GetBaseValue() const
baseStringValue);
nsSMILValue baseValue;
if (success) {
// For base values, we don't need to worry whether the value returned is
// context-sensitive or not since the compositor will take care of comparing
// the returned (computed) base value and its cached value and determining
// if an update is required or not.
nsSMILCSSValueType::ValueFromString(mPropID, mElement,
baseStringValue, baseValue);
baseStringValue, baseValue, nsnull);
} else {
// Attribute is unset -- use computed value.
// FIRST: Temporarily clear animated value, to make sure it doesn't pollute

View File

@ -8,7 +8,10 @@
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=533291">Mozilla Bug 533291</a>
<p id="display"></p>
<div id="content" style="display: none">
<!-- Bug 628848: The following should be display: none but we currently don't
handle percentage lengths properly when the whole fragment is display: none
-->
<div id="content" style="visibility: hidden">
<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="120px" height="120px"
onload="this.pauseAnimations()">
<g id="circleParent">
@ -19,68 +22,99 @@
<pre id="test">
<script class="testbody" type="text/javascript">
<![CDATA[
/** Test for SMIL fill modes **/
/** Test for SMIL values that are context-sensitive **/
/* See bugs 533291 and 562815.
The format of each test is basically:
1) create some animated and frozen state
2) test the animated values
3) change the context
4) test that context-sensitive animation values have changed
Ideally, after changing the context (3), the animated state would instantly
update. However, this is not currently the case for many situations.
For CSS properties we have bug 545282 - In animations involving 'inherit'
/ 'currentColor', changes to inherited value / 'color' don't show up in
animated value immediately
For SVG lengths we have bug 508206 - Relative units used in
animation don't update immediately
(There are a few of todo_is's in the following tests so that if those bugs
are ever resolved we'll know to update this test case accordingly.)
So in between (3) and (4) we force a sample. This is currently done by
calling SVGSVGElement.setCurrentTime with the same current time which has the
side effect of forcing a sample.
What we *are* testing is that we're not too zealous with caching animation
values whilst in the frozen state. Normally we'd say, "Hey, we're frozen,
let's just use the same animation result as last time" but for some
context-sensitive animation values that doesn't work.
*/
/* Global Variables */
const SVGNS = "http://www.w3.org/2000/svg";
// Animation parameters -- not used for <set> animation
const ANIM_DUR = "4s";
const TIME_ANIM_END = "4";
const TIME_AFTER_ANIM_END = "5";
// SETTIMEOUT_INTERVAL: This value just needs to be at least as large as
// nsSMILAnimationController::kTimerInterval, so we can queue up a callback
// for this far in the future and be assured that an animation sample will
// have happened before the callback fires (because we presumably already
// have an animation sample in the setTimeout queue, with a lower timeout
// value than this).
// NOTE: We only need to use timeouts here because of Bug 545282.
const SETTIMEOUT_INTERVAL = 60;
const gTestArray =
[ testBaseValueChange,
testCurrentColorChange,
testCurrentColorChangeUsingStyle,
testInheritChange,
testInheritChangeUsingStyle
];
// Index of current test in gTestArray
var gNextTestIndex = 0;
const gSvg = document.getElementById("svg");
const gCircle = document.getElementById("circle");
const gCircleParent = document.getElementById("circleParent");
SimpleTest.waitForExplicitFinish();
// MAIN FUNCTION
// -------------
function main() {
function main()
{
ok(gSvg.animationsPaused(), "should be paused by <svg> load handler");
is(gSvg.getCurrentTime(), 0, "should be paused at 0 in <svg> load handler");
if (gNextTestIndex != 0) {
ok(false, "expecting to start at first test in array.");
const tests =
[ testBaseValueChange,
testCurrentColorChange,
testCurrentColorChangeUsingStyle,
testCurrentColorChangeOnFallback,
testInheritChange,
testInheritChangeUsingStyle,
testEmUnitChangeOnProp,
testEmUnitChangeOnPropBase,
testEmUnitChangeOnLength,
testPercentUnitChangeOnProp,
testPercentUnitChangeOnLength,
testRelativeFontSize,
testRelativeFontWeight,
testRelativeFont,
testCalcFontSize,
testDashArray,
testClip
];
while (tests.length) {
tests.shift()();
}
// Kick off first test. (It will kick off the one after it, and so on.)
runNextTest();
SimpleTest.finish();
}
// HELPER FUNCTIONS
// ----------------
function createAnimFromTo(attrName, fromVal, toVal) {
var anim = document.createElementNS(SVGNS,"animate");
function createAnimSetTo(attrName, toVal)
{
var anim = document.createElementNS(SVGNS,"set");
anim.setAttribute("attributeName", attrName);
anim.setAttribute("dur", ANIM_DUR);
anim.setAttribute("begin", "0s");
anim.setAttribute("from", fromVal);
anim.setAttribute("to", toVal);
anim.setAttribute("fill", "freeze");
return gCircle.appendChild(anim);
}
function createAnimBy(attrName, byVal) {
function createAnimBy(attrName, byVal)
{
var anim = document.createElementNS(SVGNS,"animate");
anim.setAttribute("attributeName", attrName);
anim.setAttribute("dur", ANIM_DUR);
@ -90,6 +124,18 @@ function createAnimBy(attrName, byVal) {
return gCircle.appendChild(anim);
}
function createAnimFromTo(attrName, fromVal, toVal)
{
var anim = document.createElementNS(SVGNS,"animate");
anim.setAttribute("attributeName", attrName);
anim.setAttribute("dur", ANIM_DUR);
anim.setAttribute("begin","0s");
anim.setAttribute("from", fromVal);
anim.setAttribute("to", toVal);
anim.setAttribute("fill", "freeze");
return gCircle.appendChild(anim);
}
// Common setup code for each test function: seek to 0, and make sure
// the previous test cleaned up its animations.
function setupTest() {
@ -99,17 +145,6 @@ function setupTest() {
}
}
function runNextTest() {
if (gNextTestIndex == gTestArray.length) {
// No tests left! we're done.
SimpleTest.finish();
return;
}
// Call next test (and increment next-test index)
gTestArray[gNextTestIndex++]();
}
// THE TESTS
// ---------
@ -130,106 +165,400 @@ function testBaseValueChange()
"Checking animated cx after anim ends & after changing base val");
anim.parentNode.removeChild(anim); // clean up
runNextTest();
}
function testCurrentColorChange()
{
gCircle.setAttribute("color", "red"); // At first: currentColor=red
var anim = createAnimFromTo("fill", "yellow", "currentColor");
var anim = createAnimSetTo("fill", "currentColor");
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
gSvg.setCurrentTime(0); // trigger synchronous sample
is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(255, 0, 0)",
"Checking animated fill=currentColor after anim ends");
"Checking animated fill=currentColor after animating");
gCircle.setAttribute("color", "lime"); // Change: currentColor=lime
setTimeout(testCurrentColorChange_final, SETTIMEOUT_INTERVAL);
}
function testCurrentColorChange_final()
{
// Bug 545282: We should really detect this change and update immediately but
// currently we don't until we get sampled again
todo_is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
"Checking animated fill=currentColor after updating context but before " +
"sampling");
gSvg.setCurrentTime(0);
is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
"Checking animated fill=currentColor after anim ends and 'color' changes");
"Checking animated fill=currentColor after updating context");
// Clean up
gCircle.removeAttribute("color");
gCircle.firstChild.parentNode.removeChild(gCircle.firstChild);
// Kick off next test
runNextTest();
gCircle.removeChild(gCircle.firstChild);
}
function testCurrentColorChangeUsingStyle()
{
setupTest();
gCircle.setAttribute("style", "color: red"); // At first: currentColor=red
var anim = createAnimFromTo("fill", "yellow", "currentColor");
var anim = createAnimSetTo("fill", "currentColor");
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
gSvg.setCurrentTime(0);
is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(255, 0, 0)",
"Checking animated fill=currentColor after anim ends (using style attr)");
"Checking animated fill=currentColor after animating (using style attr)");
gCircle.setAttribute("style", "color: lime"); // Change: currentColor=lime
setTimeout(testCurrentColorChangeUsingStyle_final, SETTIMEOUT_INTERVAL);
}
function testCurrentColorChangeUsingStyle_final()
{
gSvg.setCurrentTime(0);
is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
"Checking animated fill=currentColor after anim ends and 'color' changes "
"Checking animated fill=currentColor after updating context "
+ "(using style attr)");
// Clean up
gCircle.removeAttribute("style");
gCircle.firstChild.parentNode.removeChild(gCircle.firstChild);
runNextTest();
gCircle.removeChild(gCircle.firstChild);
}
function getFallbackColor(pServerStr)
{
return pServerStr.substr(pServerStr.indexOf(" ")+1);
}
function testCurrentColorChangeOnFallback()
{
setupTest();
gCircle.setAttribute("color", "red"); // At first: currentColor=red
var anim = createAnimSetTo("fill", "url(#missingGrad) currentColor");
gSvg.setCurrentTime(0);
var fallback =
getFallbackColor(SMILUtil.getComputedStyleSimple(gCircle, "fill"));
is(fallback, "rgb(255, 0, 0)",
"Checking animated fallback fill=currentColor after animating");
gCircle.setAttribute("color", "lime"); // Change: currentColor=lime
gSvg.setCurrentTime(0);
fallback = getFallbackColor(SMILUtil.getComputedStyleSimple(gCircle, "fill"));
is(fallback, "rgb(0, 255, 0)",
"Checking animated fallback fill=currentColor after updating context");
gCircle.removeAttribute("style");
gCircle.removeChild(gCircle.firstChild);
}
function testInheritChange()
{
setupTest();
gCircleParent.setAttribute("fill", "red"); // At first: inherit=red
var anim = createAnimFromTo("fill", "yellow", "inherit");
var anim = createAnimSetTo("fill", "inherit");
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
gSvg.setCurrentTime(0);
is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(255, 0, 0)",
"Checking animated fill=inherit after anim ends");
"Checking animated fill=inherit after animating");
gCircleParent.setAttribute("fill", "lime"); // Change: inherit=lime
setTimeout(testInheritChange_final, SETTIMEOUT_INTERVAL);
}
function testInheritChange_final() {
gSvg.setCurrentTime(0);
is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
"Checking animated fill=inherit after anim ends and parent val changes");
"Checking animated fill=inherit after updating context");
gCircleParent.removeAttribute("fill");
gCircle.firstChild.parentNode.removeChild(gCircle.firstChild);
runNextTest();
gCircle.removeChild(gCircle.firstChild);
}
function testInheritChangeUsingStyle()
{
setupTest();
gCircleParent.setAttribute("style", "fill: red"); // At first: inherit=red
var anim = createAnimFromTo("fill", "yellow", "inherit");
var anim = createAnimSetTo("fill", "inherit");
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
gSvg.setCurrentTime(0);
is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(255, 0, 0)",
"Checking animated fill=inherit after anim ends (using style attr)");
"Checking animated fill=inherit after animating (using style attr)");
gCircleParent.setAttribute("style", "fill: lime"); // Change: inherit=lime
setTimeout(testInheritChangeUsingStyle_final, SETTIMEOUT_INTERVAL);
}
function testInheritChangeUsingStyle_final() {
gSvg.setCurrentTime(0);
is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
"Checking animated fill=inherit after anim ends and parent val changes "
"Checking animated fill=inherit after updating context "
+ "(using style attr)");
gCircleParent.removeAttribute("style");
gCircle.firstChild.parentNode.removeChild(gCircle.firstChild);
runNextTest();
gCircle.removeChild(gCircle.firstChild);
}
function testEmUnitChangeOnProp()
{
setupTest();
gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
var anim = createAnimSetTo("font-size", "2em");
gSvg.setCurrentTime(0);
is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "20px",
"Checking animated font-size=2em after animating ends");
gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
gSvg.setCurrentTime(0);
is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "40px",
"Checking animated font-size=2em after updating context");
gCircleParent.removeAttribute("font-size");
gCircle.removeChild(gCircle.firstChild);
}
function testEmUnitChangeOnPropBase()
{
// Test the case where the base value for our animation sandwich is
// context-sensitive.
// Currently, this is taken care of by the compositor which keeps a cached
// base value and compares it with the current base value. This test then just
// serves as a regression test in case the compositor's behaviour changes.
setupTest();
gSvg.setAttribute("font-size", "10px"); // At first: font-size: 10px
gCircleParent.setAttribute("font-size", "1em"); // Base: 10px
var anim = createAnimBy("font-size", "10px");
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "20px",
"Checking animated font-size=20px after anim ends");
gSvg.setAttribute("font-size", "20px"); // Change: font-size: 20px
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "30px",
"Checking animated font-size=30px after updating context");
gCircleParent.removeAttribute("font-size");
gCircle.removeChild(gCircle.firstChild);
}
function testEmUnitChangeOnLength()
{
setupTest();
gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
var anim = createAnimSetTo("cx", "2em");
gSvg.setCurrentTime(0);
is(gCircle.cx.animVal.value, 20,
"Checking animated length=2em after animating");
gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
// Bug 508206: We should really detect this change and update immediately but
// currently we don't until we get sampled again
todo_is(gCircle.cx.animVal.value, 40,
"Checking animated length=2em after updating context but before sampling");
gSvg.setCurrentTime(0);
is(gCircle.cx.animVal.value, 40,
"Checking animated length=2em after updating context and after " +
"resampling");
gCircleParent.removeAttribute("font-size");
gCircle.removeChild(gCircle.firstChild);
}
function testPercentUnitChangeOnProp()
{
setupTest();
gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
var anim = createAnimSetTo("font-size", "150%");
gSvg.setCurrentTime(0);
is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "15px",
"Checking animated font-size=150% after animating");
gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
gSvg.setCurrentTime(0);
is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "30px",
"Checking animated font-size=150% after updating context");
gCircleParent.removeAttribute("font-size");
gCircle.removeChild(gCircle.firstChild);
}
function testPercentUnitChangeOnLength()
{
setupTest();
var oldHeight = gSvg.getAttribute("height");
gSvg.setAttribute("height", "100px"); // At first: viewport height: 100px
var anim = createAnimSetTo("cy", "100%");
gSvg.setCurrentTime(0); // Force synchronous sample so animation takes effect
// Due to bug 627594 (SVGLength.value for percent value lengths doesn't
// reflect updated viewport until reflow) the following will fail.
// Check that it does indeed fail so that when that bug is fixed this test
// can be updated.
todo_is(gCircle.cy.animVal.value, 100,
"Checking animated length=100% after animating but before reflow");
gSvg.forceRedraw();
// Even after doing a reflow though we'll still fail due to bug 508206
// (Relative units used in animation don't update immediately)
todo_is(gCircle.cy.animVal.value, 100,
"Checking animated length=100% after animating but before resampling");
gSvg.setCurrentTime(0);
// Now we should be up to date
is(gCircle.cy.animVal.value, 100,
"Checking animated length=100% after animating");
gSvg.setAttribute("height", "50px"); // Change: height: 50px
gSvg.forceRedraw(); // Bug 627594
gSvg.setCurrentTime(0); // Bug 508206
is(gCircle.cy.animVal.value, 50,
"Checking animated length=100% after updating context");
gSvg.setAttribute("height", oldHeight);
gCircle.removeChild(gCircle.firstChild);
}
function testRelativeFontSize()
{
setupTest();
gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
var anim = createAnimSetTo("font-size", "larger");
gSvg.setCurrentTime(0);
var fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
// CSS 2 suggests a scaling factor of 1.2 so we should be looking at something
// around about 12 or so
ok(fsize > 10 && fsize < 20,
"Checking animated font-size > 10px after animating");
gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
gSvg.setCurrentTime(0);
fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
ok(fsize > 20, "Checking animated font-size > 20px after updating context");
gCircleParent.removeAttribute("font-size");
gCircle.removeChild(gCircle.firstChild);
}
function testRelativeFontWeight()
{
setupTest();
gCircleParent.setAttribute("font-weight", "100"); // At first: font-weight 100
var anim = createAnimSetTo("font-weight", "bolder");
// CSS 2: 'bolder': Specifies the next weight that is assigned to a font
// that is darker than the inherited one. If there is no such weight, it
// simply results in the next darker numerical value (and the font remains
// unchanged), unless the inherited value was '900', in which case the
// resulting weight is also '900'.
gSvg.setCurrentTime(0);
var weight =
parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-weight"));
ok(weight > 100, "Checking animated font-weight > 100 after animating");
gCircleParent.setAttribute("font-weight", "800"); // Change: font-weight 800
gSvg.setCurrentTime(0);
weight = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-weight"));
is(weight, 900,
"Checking animated font-weight = 900 after updating context");
gCircleParent.removeAttribute("font-weight");
gCircle.removeChild(gCircle.firstChild);
}
function testRelativeFont()
{
// Test a relative font-size as part of a 'font' spec since the code path
// is different in this case
// It turns out that, due to the way we store shorthand font properties, we
// don't need to worry about marking such values as context-sensitive since we
// seem to store them in their relative form. If, however, we change the way
// we store shorthand font properties in the future, this will serve as
// a useful regression test.
setupTest();
gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
// We must be sure to set every part of the shorthand property to some
// non-context sensitive value because we want to test that even if only the
// font-size is relative we will update it appropriately.
var anim =
createAnimSetTo("font", "normal normal bold larger/normal sans-serif");
gSvg.setCurrentTime(0);
var fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
ok(fsize > 10 && fsize < 20,
"Checking size of shorthand 'font' > 10px after animating");
gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
gSvg.setCurrentTime(0);
fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
ok(fsize > 20,
"Checking size of shorthand 'font' > 20px after updating context");
gCircleParent.removeAttribute("font-size");
gCircle.removeChild(gCircle.firstChild);
}
function testCalcFontSize()
{
setupTest();
gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
var anim = createAnimSetTo("font-size", "-moz-calc(110% + 0.1em)");
gSvg.setCurrentTime(0);
var fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
// Font size should be 1.1 * 10px + 0.1 * 10px = 12
is(fsize, 12, "Checking animated calc font-size == 12px after animating");
gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
gSvg.setCurrentTime(0);
fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
is(fsize, 24, "Checking animated calc font-size == 24px after updating " +
"context");
gCircleParent.removeAttribute("font-size");
gCircle.removeChild(gCircle.firstChild);
}
function testDashArray()
{
// stroke dasharrays don't currently convert units--but if someone ever fixes
// that, hopefully this test will fail and remind us not to cache percentage
// values in that case
setupTest();
var oldHeight = gSvg.getAttribute("height");
var oldWidth = gSvg.getAttribute("width");
gSvg.setAttribute("height", "100px"); // At first: viewport: 100x100px
gSvg.setAttribute("width", "100px");
var anim = createAnimFromTo("stroke-dasharray", "0 5", "0 50%");
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
// Now we should be up to date
is(SMILUtil.getComputedStyleSimple(gCircle, "stroke-dasharray"), "0, 50%",
"Checking animated stroke-dasharray after animating");
gSvg.setAttribute("height", "50px"); // Change viewport: 50x50px
gSvg.setAttribute("width", "50px");
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
is(SMILUtil.getComputedStyleSimple(gCircle, "stroke-dasharray"), "0, 50%",
"Checking animated stroke-dasharray after updating context");
gSvg.setAttribute("height", oldHeight);
gSvg.setAttribute("width", oldWidth);
gCircle.removeChild(gCircle.firstChild);
}
function testClip()
{
setupTest();
gCircleParent.setAttribute("font-size", "20px"); // At first: font-size: 20px
// The clip property only applies to elements that establish a new
// viewport so we need to create a nested svg and add animation to that
var nestedSVG = document.createElementNS(SVGNS, "svg");
nestedSVG.setAttribute("clip", "rect(0px 0px 0px 0px)");
gCircleParent.appendChild(nestedSVG);
var anim = createAnimSetTo("clip", "rect(1em 1em 1em 1em)");
// createAnimSetTo will make the animation a child of gCircle so we need to
// move it so it targets nestedSVG instead
nestedSVG.appendChild(anim);
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
is(SMILUtil.getComputedStyleSimple(nestedSVG, "clip"),
"rect(20px, 20px, 20px, 20px)",
"Checking animated clip rect after animating");
gCircleParent.setAttribute("font-size", "10px"); // Change: font-size: 10px
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
is(SMILUtil.getComputedStyleSimple(nestedSVG, "clip"),
"rect(10px, 10px, 10px, 10px)",
"Checking animated clip rect after updating context");
gCircleParent.removeAttribute("font-size");
gCircleParent.removeChild(nestedSVG);
}
window.addEventListener("load", main, false);

View File

@ -57,7 +57,6 @@ _TEST_FILES = \
a_href_helper_04.svg \
test_animLengthObjectIdentity.xhtml \
test_animLengthReadonly.xhtml \
test_animLengthRelativeUnits.xhtml \
test_animLengthUnits.xhtml \
test_bbox.xhtml \
test_bbox-with-invalid-viewBox.xhtml \

View File

@ -1,80 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=508206
-->
<head>
<title>Test for liveness of relative units in animation</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.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=508206">Mozilla Bug 508206</a>
<p id="display"></p>
<!-- XXX The following should be display: none but that's broken by bug 413975
where we don't handle percentage lengths when the whole fragment is
display: none properly. -->
<div id="content" style="visibility: hidden">
<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="100px" height="100px"
onload="this.pauseAnimations()">
<g font-size="10px">
<circle cx="0" cy="0" r="15" fill="blue" id="circle">
<animate attributeName="cx" from="0" to="10em" dur="10s" begin="0s"
fill="freeze" id="animate"/>
<animate attributeName="cy" from="0" to="100%" dur="10s" begin="0s"
fill="freeze"/>
</circle>
</g>
</svg>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
<![CDATA[
/** Test liveness of relative units of animated lengths **/
/* Global Variables */
const svgns="http://www.w3.org/2000/svg";
var svg = document.getElementById("svg");
var circle = document.getElementById('circle');
SimpleTest.waitForExplicitFinish();
function main() {
ok(svg.animationsPaused(), "should be paused by <svg> load handler");
is(svg.getCurrentTime(), 0, "should be paused at 0 in <svg> load handler");
// Sample mid-way through the animation
svg.setCurrentTime(5);
// (1) Check values mid-way
is(circle.cx.animVal.value, 50,
"(1) Unexpected animVal for cx before changing base length");
is(circle.cy.animVal.value, 50,
"(1) Unexpected animVal for cy before changing base length");
// (2) Change the frame of reference and check values are updated immediately
// Change font-size
circle.parentNode.setAttribute('font-size', '5px');
todo_is(circle.cx.animVal.value, 25,
"(2) Unexpected animVal for cx after changing parent font-size");
// Change the viewport size
svg.setAttribute('height', '50px');
todo_is(circle.cy.animVal.value, 25,
"(2) Unexpected animVal for cy after changing containing viewport size");
SimpleTest.finish();
}
var animate = document.getElementById('animate');
if (animate && animate.targetElement) {
window.addEventListener("load", main, false);
} else {
ok(true); // Skip tests but don't report 'todo' either
SimpleTest.finish();
}
]]>
</script>
</pre>
</body>
</html>

View File

@ -429,7 +429,7 @@ static PRBool IsChromeURI(nsIURI* aURI)
/* Implementation file */
static PRIntn
static PRBool
TraverseProtos(nsHashKey *aKey, void *aData, void* aClosure)
{
nsCycleCollectionTraversalCallback *cb =
@ -439,7 +439,7 @@ TraverseProtos(nsHashKey *aKey, void *aData, void* aClosure)
return kHashEnumerateNext;
}
static PRIntn
static PRBool
UnlinkProtoJSObjects(nsHashKey *aKey, void *aData, void* aClosure)
{
nsXBLPrototypeBinding *proto = static_cast<nsXBLPrototypeBinding*>(aData);
@ -453,7 +453,7 @@ struct ProtoTracer
void *mClosure;
};
static PRIntn
static PRBool
TraceProtos(nsHashKey *aKey, void *aData, void* aClosure)
{
ProtoTracer* closure = static_cast<ProtoTracer*>(aClosure);

View File

@ -328,7 +328,7 @@ PRBool nsXBLPrototypeBinding::CompareBindingURI(nsIURI* aURI) const
return equal;
}
static PRIntn
static PRBool
TraverseInsertionPoint(nsHashKey* aKey, void* aData, void* aClosure)
{
nsCycleCollectionTraversalCallback &cb =
@ -1213,7 +1213,7 @@ nsXBLPrototypeBinding::ConstructInsertionTable(nsIContent* aContent)
PRInt32 i;
for (i = 0; i < count; i++) {
nsIContent* child = childrenElements[i];
nsIContent* parent = child->GetParent();
nsCOMPtr<nsIContent> parent = child->GetParent();
// Create an XBL insertion point entry.
nsXBLInsertionPointEntry* xblIns = nsXBLInsertionPointEntry::Create(parent);

View File

@ -4047,7 +4047,8 @@ nsXULDocument::OverlayForwardReference::Merge(nsIContent* aTargetNode,
if (attr == nsGkAtoms::removeelement &&
value.EqualsLiteral("true")) {
rv = RemoveElement(aTargetNode->GetParent(), aTargetNode);
nsCOMPtr<nsIContent> parent = aTargetNode->GetParent();
rv = RemoveElement(parent, aTargetNode);
if (NS_FAILED(rv)) return rv;
return NS_OK;

View File

@ -1324,7 +1324,7 @@ nsXULContentBuilder::RemoveGeneratedContent(nsIContent* aElement)
while (0 != (count = ungenerated.Length())) {
// Pull the next "ungenerated" element off the queue.
PRUint32 last = count - 1;
nsIContent* element = ungenerated[last];
nsCOMPtr<nsIContent> element = ungenerated[last];
ungenerated.RemoveElementAt(last);
PRUint32 i = element->GetChildCount();

View File

@ -723,11 +723,11 @@ nsDocShell::nsDocShell():
mChildOffset(0),
mBusyFlags(BUSY_FLAGS_NONE),
mAppType(nsIDocShell::APP_TYPE_UNKNOWN),
mLoadType(0),
mMarginWidth(-1),
mMarginHeight(-1),
mItemType(typeContent),
mPreviousTransIndex(-1),
mLoadType(0),
mLoadedTransIndex(-1),
mCreated(PR_FALSE),
mAllowSubframes(PR_TRUE),
@ -8452,13 +8452,13 @@ nsDocShell::InternalLoad(nsIURI * aURI,
GetCurScrollPos(ScrollOrientation_X, &cx);
GetCurScrollPos(ScrollOrientation_Y, &cy);
// We scroll whenever we're not doing a history load. Note that
// sometimes we might scroll even if we don't fire a hashchange
// event! See bug 653741.
if (!aSHEntry) {
rv = ScrollToAnchor(curHash, newHash, aLoadType);
NS_ENSURE_SUCCESS(rv, rv);
}
// ScrollToAnchor doesn't necessarily cause us to scroll the window;
// the function decides whether a scroll is appropriate based on the
// arguments it receives. But even if we don't end up scrolling,
// ScrollToAnchor performs other important tasks, such as informing
// the presShell that we have a new hash. See bug 680257.
rv = ScrollToAnchor(curHash, newHash, aLoadType);
NS_ENSURE_SUCCESS(rv, rv);
mLoadType = aLoadType;
mURIResultedInDocument = PR_TRUE;

View File

@ -120,6 +120,8 @@ _TEST_FILES = \
file_bug669671.sjs \
test_bug675587.html \
test_bfcache_plus_hash.html \
test_bug680257.html \
file_bug680257.html \
$(NULL)
ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)

View File

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<html>
<head>
<style type='text/css'>
a { color: black; }
a:target { color: red; }
</style>
</head>
<body onload='(opener || parent).popupLoaded()'>
<a id='a' href='#a'>link</a>
<a id='b' href='#b'>link2</a>
</body>
</html>

View File

@ -0,0 +1,59 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=680257
-->
<head>
<title>Test for Bug 680257</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.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=680257">Mozilla Bug 680257</a>
<script type="application/javascript;version=1.7">
SimpleTest.waitForExplicitFinish();
var popup = window.open('file_bug680257.html');
// The popup will call into popupLoaded() once it loads.
function popupLoaded() {
// runTests() needs to be called from outside popupLoaded's onload handler.
// Otherwise, the navigations we do in runTests won't create new SHEntries.
SimpleTest.executeSoon(runTests);
}
function runTests() {
checkPopupLinkStyle(false, 'Initial');
popup.location.hash = 'a';
checkPopupLinkStyle(true, 'After setting hash');
popup.history.back();
checkPopupLinkStyle(false, 'After going back');
popup.history.forward();
checkPopupLinkStyle(true, 'After going forward');
popup.close();
SimpleTest.finish();
}
function checkPopupLinkStyle(isTarget, desc) {
var link = popup.document.getElementById('a');
var style = popup.getComputedStyle(link);
var color = style.getPropertyValue('color');
// Color is red if isTarget, black otherwise.
if (isTarget) {
is(color, 'rgb(255, 0, 0)', desc);
}
else {
is(color, 'rgb(0, 0, 0)', desc);
}
}
</script>
</body>
</html>

View File

@ -8220,19 +8220,21 @@ NS_IMETHODIMP
nsGlobalWindow::GetMozIndexedDB(nsIIDBFactory** _retval)
{
if (!mIndexedDB) {
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
do_GetService(THIRDPARTYUTIL_CONTRACTID);
NS_ENSURE_TRUE(thirdPartyUtil, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (!IsChromeWindow()) {
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
do_GetService(THIRDPARTYUTIL_CONTRACTID);
NS_ENSURE_TRUE(thirdPartyUtil, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
PRBool isThirdParty;
nsresult rv = thirdPartyUtil->IsThirdPartyWindow(this, nsnull,
&isThirdParty);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
PRBool isThirdParty;
nsresult rv = thirdPartyUtil->IsThirdPartyWindow(this, nsnull,
&isThirdParty);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (isThirdParty) {
NS_WARNING("IndexedDB is not permitted in a third-party window.");
*_retval = nsnull;
return NS_OK;
if (isThirdParty) {
NS_WARNING("IndexedDB is not permitted in a third-party window.");
*_retval = nsnull;
return NS_OK;
}
}
mIndexedDB = indexedDB::IDBFactory::Create(this);

View File

@ -51,7 +51,7 @@
* http://www.w3.org/TR/DOM-Level-2-Style
*/
[builtinclass, scriptable, uuid(10f43750-b379-11e0-aff2-0800200c9a66)]
[builtinclass, scriptable, uuid(286466f1-4246-4574-afdb-2f8a03ad7cc8)]
interface nsIDOMCSS2Properties : nsISupports
{
attribute DOMString background;
@ -657,6 +657,9 @@ interface nsIDOMCSS2Properties : nsISupports
attribute DOMString MozBorderImage;
// raises(DOMException) on setting
attribute DOMString MozColumns;
// raises(DOMException) on setting
attribute DOMString MozColumnRule;
// raises(DOMException) on setting

View File

@ -45,7 +45,7 @@
* For more information on this interface, please see
* http://www.whatwg.org/specs/web-apps/current-work/#messageevent
*/
[scriptable, uuid(dc8ec5c6-ebf2-4f95-be99-cd13e3c0d0c6)]
[scriptable, uuid(9ac4fa26-4d19-4f4e-807e-b30cd0dbe56a)]
interface nsIDOMMessageEvent : nsIDOMEvent
{
/**

View File

@ -1877,17 +1877,12 @@ nsPluginInstanceOwner::HandleEvent(nsIDOMEvent* aEvent)
nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aEvent));
if (privateEvent) {
nsEvent* ievent = privateEvent->GetInternalNSEvent();
if (ievent && NS_IS_TRUSTED_EVENT(ievent) &&
(ievent->message == NS_DRAGDROP_ENTER || ievent->message == NS_DRAGDROP_OVER)) {
// set the allowed effect to none here. The plugin should set it if necessary
nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
dragEvent->GetDataTransfer(getter_AddRefs(dataTransfer));
if (dataTransfer)
dataTransfer->SetEffectAllowed(NS_LITERAL_STRING("none"));
if ((ievent && NS_IS_TRUSTED_EVENT(ievent)) &&
ievent->message != NS_DRAGDROP_ENTER && ievent->message != NS_DRAGDROP_OVER) {
aEvent->PreventDefault();
}
// Let the plugin handle drag events.
aEvent->PreventDefault();
aEvent->StopPropagation();
}
}

View File

@ -37,7 +37,7 @@
#include "QTMLocationProvider.h"
#include "nsGeoPosition.h"
#include <QFeedbackEffect>
using namespace QtMobility;
using namespace mozilla;

View File

@ -53,8 +53,13 @@
#include "nsIHTMLEditor.h"
#include "nsIComponentManager.h"
#include "nsIContentPrefService.h"
#include "nsIObserverService.h"
#include "nsServiceManagerUtils.h"
#include "nsIChromeRegistry.h"
#include "nsIPrivateBrowsingService.h"
#include "nsIContentURIGrouper.h"
#include "nsNetCID.h"
#include "nsString.h"
#include "nsReadableUtils.h"
#include "nsITextServicesFilter.h"
@ -80,6 +85,216 @@ class UpdateDictionnaryHolder {
}
};
#define CPS_PREF_NAME NS_LITERAL_STRING("spellcheck.lang")
class LastDictionary : public nsIObserver, public nsSupportsWeakReference {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
LastDictionary();
/**
* Store current dictionary for editor document url. Use content pref
* service. Or, if in private mode, store this information in memory.
*/
NS_IMETHOD StoreCurrentDictionary(nsIEditor* aEditor, const nsAString& aDictionary);
/**
* Get last stored current dictionary for editor document url.
*/
NS_IMETHOD FetchLastDictionary(nsIEditor* aEditor, nsAString& aDictionary);
/**
* Forget last current dictionary stored for editor document url.
*/
NS_IMETHOD ClearCurrentDictionary(nsIEditor* aEditor);
/**
* get uri of editor's document.
*
*/
static nsresult GetDocumentURI(nsIEditor* aEditor, nsIURI * *aURI);
PRBool mInPrivateBrowsing;
// During private browsing, dictionaries are stored in memory
nsDataHashtable<nsStringHashKey, nsString> mMemoryStorage;
};
NS_IMPL_ISUPPORTS2(LastDictionary, nsIObserver, nsISupportsWeakReference)
LastDictionary::LastDictionary():
mInPrivateBrowsing(PR_FALSE)
{
nsCOMPtr<nsIPrivateBrowsingService> pbService =
do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID);
if (pbService) {
pbService->GetPrivateBrowsingEnabled(&mInPrivateBrowsing);
mMemoryStorage.Init();
}
}
// static
nsresult
LastDictionary::GetDocumentURI(nsIEditor* aEditor, nsIURI * *aURI)
{
NS_ENSURE_ARG_POINTER(aEditor);
NS_ENSURE_ARG_POINTER(aURI);
nsCOMPtr<nsIDOMDocument> domDoc;
aEditor->GetDocument(getter_AddRefs(domDoc));
NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE);
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
nsCOMPtr<nsIURI> docUri = doc->GetDocumentURI();
NS_ENSURE_TRUE(docUri, NS_ERROR_FAILURE);
*aURI = docUri;
NS_ADDREF(*aURI);
return NS_OK;
}
NS_IMETHODIMP
LastDictionary::FetchLastDictionary(nsIEditor* aEditor, nsAString& aDictionary)
{
NS_ENSURE_ARG_POINTER(aEditor);
nsresult rv;
nsCOMPtr<nsIURI> docUri;
rv = GetDocumentURI(aEditor, getter_AddRefs(docUri));
NS_ENSURE_SUCCESS(rv, rv);
if (mInPrivateBrowsing) {
nsCOMPtr<nsIContentURIGrouper> hostnameGrouperService =
do_GetService(NS_HOSTNAME_GROUPER_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(hostnameGrouperService, NS_ERROR_NOT_AVAILABLE);
nsString group;
hostnameGrouperService->Group(docUri, group);
nsAutoString lastDict;
if (mMemoryStorage.Get(group, &lastDict)) {
aDictionary.Assign(lastDict);
} else {
aDictionary.Truncate();
}
return NS_OK;
}
nsCOMPtr<nsIContentPrefService> contentPrefService =
do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(contentPrefService, NS_ERROR_NOT_AVAILABLE);
nsCOMPtr<nsIWritableVariant> uri = do_CreateInstance(NS_VARIANT_CONTRACTID);
NS_ENSURE_TRUE(uri, NS_ERROR_OUT_OF_MEMORY);
uri->SetAsISupports(docUri);
PRBool hasPref;
if (NS_SUCCEEDED(contentPrefService->HasPref(uri, CPS_PREF_NAME, &hasPref)) && hasPref) {
nsCOMPtr<nsIVariant> pref;
contentPrefService->GetPref(uri, CPS_PREF_NAME, nsnull, getter_AddRefs(pref));
pref->GetAsAString(aDictionary);
} else {
aDictionary.Truncate();
}
return NS_OK;
}
NS_IMETHODIMP
LastDictionary::StoreCurrentDictionary(nsIEditor* aEditor, const nsAString& aDictionary)
{
NS_ENSURE_ARG_POINTER(aEditor);
nsresult rv;
nsCOMPtr<nsIURI> docUri;
rv = GetDocumentURI(aEditor, getter_AddRefs(docUri));
NS_ENSURE_SUCCESS(rv, rv);
if (mInPrivateBrowsing) {
nsCOMPtr<nsIContentURIGrouper> hostnameGrouperService =
do_GetService(NS_HOSTNAME_GROUPER_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(hostnameGrouperService, NS_ERROR_NOT_AVAILABLE);
nsString group;
hostnameGrouperService->Group(docUri, group);
if (mMemoryStorage.Put(group, nsString(aDictionary))) {
return NS_OK;
} else {
return NS_ERROR_FAILURE;
}
}
nsCOMPtr<nsIWritableVariant> uri = do_CreateInstance(NS_VARIANT_CONTRACTID);
NS_ENSURE_TRUE(uri, NS_ERROR_OUT_OF_MEMORY);
uri->SetAsISupports(docUri);
nsCOMPtr<nsIWritableVariant> prefValue = do_CreateInstance(NS_VARIANT_CONTRACTID);
NS_ENSURE_TRUE(prefValue, NS_ERROR_OUT_OF_MEMORY);
prefValue->SetAsAString(aDictionary);
nsCOMPtr<nsIContentPrefService> contentPrefService =
do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(contentPrefService, NS_ERROR_NOT_INITIALIZED);
return contentPrefService->SetPref(uri, CPS_PREF_NAME, prefValue);
}
NS_IMETHODIMP
LastDictionary::ClearCurrentDictionary(nsIEditor* aEditor)
{
NS_ENSURE_ARG_POINTER(aEditor);
nsresult rv;
nsCOMPtr<nsIURI> docUri;
rv = GetDocumentURI(aEditor, getter_AddRefs(docUri));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIContentURIGrouper> hostnameGrouperService =
do_GetService(NS_HOSTNAME_GROUPER_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(hostnameGrouperService, NS_ERROR_NOT_AVAILABLE);
nsString group;
hostnameGrouperService->Group(docUri, group);
NS_ENSURE_SUCCESS(rv, rv);
if (mMemoryStorage.IsInitialized()) {
mMemoryStorage.Remove(group);
}
nsCOMPtr<nsIWritableVariant> uri = do_CreateInstance(NS_VARIANT_CONTRACTID);
NS_ENSURE_TRUE(uri, NS_ERROR_OUT_OF_MEMORY);
uri->SetAsISupports(docUri);
nsCOMPtr<nsIContentPrefService> contentPrefService =
do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(contentPrefService, NS_ERROR_NOT_INITIALIZED);
return contentPrefService->RemovePref(uri, CPS_PREF_NAME);
}
NS_IMETHODIMP
LastDictionary::Observe(nsISupports *aSubject, char const *aTopic, PRUnichar const *aData)
{
if (strcmp(aTopic, NS_PRIVATE_BROWSING_SWITCH_TOPIC) == 0) {
if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_ENTER).Equals(aData)) {
mInPrivateBrowsing = PR_TRUE;
} else if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).Equals(aData)) {
mInPrivateBrowsing = PR_FALSE;
if (mMemoryStorage.IsInitialized()) {
mMemoryStorage.Clear();
}
}
}
return NS_OK;
}
LastDictionary* nsEditorSpellCheck::gDictionaryStore = nsnull;
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsEditorSpellCheck)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsEditorSpellCheck)
@ -89,15 +304,16 @@ NS_INTERFACE_MAP_BEGIN(nsEditorSpellCheck)
NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsEditorSpellCheck)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_2(nsEditorSpellCheck,
NS_IMPL_CYCLE_COLLECTION_3(nsEditorSpellCheck,
mEditor,
mSpellChecker,
mTxtSrvFilter)
nsEditorSpellCheck::nsEditorSpellCheck()
: mSuggestedWordIndex(0)
, mDictionaryIndex(0)
, mEditor(nsnull)
, mUpdateDictionaryRunning(PR_FALSE)
, mDictWasSetManually(PR_FALSE)
{
}
@ -135,8 +351,24 @@ nsEditorSpellCheck::CanSpellCheck(PRBool* _retval)
NS_IMETHODIMP
nsEditorSpellCheck::InitSpellChecker(nsIEditor* aEditor, PRBool aEnableSelectionChecking)
{
NS_ENSURE_TRUE(aEditor, NS_ERROR_NULL_POINTER);
mEditor = aEditor;
nsresult rv;
if (!gDictionaryStore) {
gDictionaryStore = new LastDictionary();
if (gDictionaryStore) {
NS_ADDREF(gDictionaryStore);
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (observerService) {
observerService->AddObserver(gDictionaryStore, NS_PRIVATE_BROWSING_SWITCH_TOPIC, PR_TRUE);
}
}
}
// We can spell check with any editor type
nsCOMPtr<nsITextServicesDocument>tsDoc =
do_CreateInstance("@mozilla.org/textservices/textservicesdocument;1", &rv);
@ -208,7 +440,7 @@ nsEditorSpellCheck::InitSpellChecker(nsIEditor* aEditor, PRBool aEnableSelection
// do not fail if UpdateCurrentDictionary fails because this method may
// succeed later.
UpdateCurrentDictionary(aEditor);
UpdateCurrentDictionary();
return NS_OK;
}
@ -391,7 +623,29 @@ nsEditorSpellCheck::SetCurrentDictionary(const nsAString& aDictionary)
NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
if (!mUpdateDictionaryRunning) {
mDictWasSetManually = PR_TRUE;
nsDefaultStringComparator comparator;
nsAutoString langCode;
PRInt32 dashIdx = aDictionary.FindChar('-');
if (dashIdx != -1) {
langCode.Assign(Substring(aDictionary, 0, dashIdx));
} else {
langCode.Assign(aDictionary);
}
if (mPreferredLang.IsEmpty() || !nsStyleUtil::DashMatchCompare(mPreferredLang, langCode, comparator)) {
// When user sets dictionary manually, we store this value associated
// with editor url.
gDictionaryStore->StoreCurrentDictionary(mEditor, aDictionary);
} else {
// If user sets a dictionary matching (even partially), lang defined by
// document, we consider content pref has been canceled, and we clear it.
gDictionaryStore->ClearCurrentDictionary(mEditor);
}
// Also store it in as a preference. It will be used as a default value
// when everything else fails.
Preferences::SetString("spellchecker.dictionary", aDictionary);
}
return mSpellChecker->SetCurrentDictionary(aDictionary);
}
@ -409,21 +663,6 @@ nsEditorSpellCheck::UninitSpellChecker()
return NS_OK;
}
// Save the last set dictionary to the user's preferences.
NS_IMETHODIMP
nsEditorSpellCheck::SaveDefaultDictionary()
{
if (!mDictWasSetManually) {
return NS_OK;
}
nsAutoString dictName;
nsresult rv = GetCurrentDictionary(dictName);
NS_ENSURE_SUCCESS(rv, rv);
return Preferences::SetString("spellchecker.dictionary", dictName);
}
/* void setFilter (in nsITextServicesFilter filter); */
NS_IMETHODIMP
@ -442,45 +681,51 @@ nsEditorSpellCheck::DeleteSuggestedWordList()
}
NS_IMETHODIMP
nsEditorSpellCheck::UpdateCurrentDictionary(nsIEditor* aEditor)
nsEditorSpellCheck::UpdateCurrentDictionary()
{
if (mDictWasSetManually) { // user has set dictionary manually; we better not change it.
return NS_OK;
}
nsresult rv;
UpdateDictionnaryHolder holder(this);
// Tell the spellchecker what dictionary to use:
nsAutoString dictName;
// First, try to get language with html5 algorithm
nsAutoString editorLang;
// Get language with html5 algorithm
nsCOMPtr<nsIContent> rootContent;
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(aEditor);
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
if (htmlEditor) {
rootContent = htmlEditor->GetActiveEditingHost();
} else {
nsCOMPtr<nsIDOMElement> rootElement;
rv = aEditor->GetRootElement(getter_AddRefs(rootElement));
rv = mEditor->GetRootElement(getter_AddRefs(rootElement));
NS_ENSURE_SUCCESS(rv, rv);
rootContent = do_QueryInterface(rootElement);
}
NS_ENSURE_TRUE(rootContent, NS_ERROR_FAILURE);
rootContent->GetLang(editorLang);
mPreferredLang.Truncate();
rootContent->GetLang(mPreferredLang);
if (editorLang.IsEmpty()) {
nsCOMPtr<nsIDocument> doc = rootContent->GetCurrentDoc();
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
doc->GetContentLanguage(editorLang);
// Tell the spellchecker what dictionary to use:
// First try to get dictionary from content prefs. If we have one, do not got
// further. Use this exact dictionary.
nsAutoString dictName;
rv = gDictionaryStore->FetchLastDictionary(mEditor, dictName);
if (NS_SUCCEEDED(rv) && !dictName.IsEmpty()) {
if (NS_FAILED(SetCurrentDictionary(dictName))) {
// may be dictionary was uninstalled ?
gDictionaryStore->ClearCurrentDictionary(mEditor);
}
return NS_OK;
}
if (!editorLang.IsEmpty()) {
dictName.Assign(editorLang);
if (mPreferredLang.IsEmpty()) {
nsCOMPtr<nsIDocument> doc = rootContent->GetCurrentDoc();
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
doc->GetContentLanguage(mPreferredLang);
}
// Then, try to use language computed from element
if (!mPreferredLang.IsEmpty()) {
dictName.Assign(mPreferredLang);
}
// otherwise, get language from preferences
@ -543,7 +788,7 @@ nsEditorSpellCheck::UpdateCurrentDictionary(nsIEditor* aEditor)
// If we have not set dictionary, and the editable element doesn't have a
// lang attribute, we try to get a dictionary. First try, en-US. If it does
// not work, pick the first one.
if (editorLang.IsEmpty()) {
if (mPreferredLang.IsEmpty()) {
nsAutoString currentDictionary;
rv = GetCurrentDictionary(currentDictionary);
if (NS_FAILED(rv) || currentDictionary.IsEmpty()) {
@ -567,3 +812,8 @@ nsEditorSpellCheck::UpdateCurrentDictionary(nsIEditor* aEditor)
return NS_OK;
}
void
nsEditorSpellCheck::ShutDown() {
NS_IF_RELEASE(gDictionaryStore);
}

View File

@ -43,8 +43,12 @@
#include "nsIEditorSpellCheck.h"
#include "nsISpellChecker.h"
#include "nsIObserver.h"
#include "nsIURI.h"
#include "nsWeakReference.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsDataHashtable.h"
#define NS_EDITORSPELLCHECK_CID \
{ /* {75656ad9-bd13-4c5d-939a-ec6351eea0cc} */ \
@ -52,6 +56,8 @@
{ 0x93, 0x9a, 0xec, 0x63, 0x51, 0xee, 0xa0, 0xcc }\
}
class LastDictionary;
class nsEditorSpellCheck : public nsIEditorSpellCheck
{
public:
@ -64,6 +70,10 @@ public:
/* Declare all methods in the nsIEditorSpellCheck interface */
NS_DECL_NSIEDITORSPELLCHECK
static LastDictionary* gDictionaryStore;
static void ShutDown();
protected:
nsCOMPtr<nsISpellChecker> mSpellChecker;
@ -78,9 +88,11 @@ protected:
nsresult DeleteSuggestedWordList();
nsCOMPtr<nsITextServicesFilter> mTxtSrvFilter;
nsCOMPtr<nsIEditor> mEditor;
nsString mPreferredLang;
PRPackedBool mUpdateDictionaryRunning;
PRPackedBool mDictWasSetManually;
public:
void BeginUpdateDictionary() { mUpdateDictionaryRunning = PR_TRUE ;}

View File

@ -49,11 +49,13 @@ _TEST_FILES = \
test_bug384147.html \
test_bug389350.html \
test_bug519928.html \
bug678842_subframe.html \
$(NULL)
_CHROME_TEST_FILES = \
test_bug434998.xul \
test_bug338427.html \
test_bug678842.html \
$(NULL)
libs:: $(_TEST_FILES)

View File

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<textarea id="textarea" lang="testing-XXX"></textarea>
</body>
</html>

View File

@ -0,0 +1,63 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=678842
-->
<head>
<title>Test for Bug 678842</title>
<script type="text/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>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=678842">Mozilla Bug 678842</a>
<p id="display"></p>
<iframe id="content"></iframe>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 678842 **/
SimpleTest.waitForExplicitFinish();
var content = document.getElementById('content');
// load a subframe containing an editor with a defined unknown lang. At first
// load, it will set dictionary to en-US. At second load, it will return current
// dictionary. So, we can check, dictionary is correctly remembered between
// loads.
var firstLoad = true;
var loadListener = function(evt) {
var doc = evt.target.contentDocument;
var elem = doc.getElementById('textarea');
var editor = elem.QueryInterface(Components.interfaces.nsIDOMNSEditableElement).editor;
editor.setSpellcheckUserOverride(true);
var inlineSpellChecker = editor.getInlineSpellChecker(true);
var spellchecker = inlineSpellChecker.spellChecker;
var currentDictonary = "";
try {
currentDictonary = spellchecker.GetCurrentDictionary();
} catch(e) {}
if (!currentDictonary) {
spellchecker.SetCurrentDictionary('en-US');
}
if (firstLoad) {
firstLoad = false;
is (currentDictonary, "", "unexpected lang " + currentDictonary);
content.src = 'http://mochi.test:8888/tests/editor/composer/test/bug678842_subframe.html?firstload=false';
} else {
is (currentDictonary, "en-US", "unexpected lang " + currentDictonary + " instead of en-US");
content.removeEventListener('load', loadListener, false);
SimpleTest.finish();
}
}
content.addEventListener('load', loadListener, false);
content.src = 'http://mochi.test:8888/tests/editor/composer/test/bug678842_subframe.html?firstload=true';
</script>
</pre>
</body>
</html>

View File

@ -41,7 +41,7 @@
interface nsIEditor;
interface nsITextServicesFilter;
[scriptable, uuid(3da0ce96-7d3a-48d0-80b7-2d90dab09747)]
[scriptable, uuid(af84da62-588f-409f-847d-feecc991bd93)]
interface nsIEditorSpellCheck : nsISupports
{
@ -150,14 +150,6 @@ interface nsIEditorSpellCheck : nsISupports
*/
void SetCurrentDictionary(in AString dictionary);
/**
* Call to save the currently selected dictionary as the default. The
* function UninitSpellChecker will also do this, but that function may not
* be called in some situations. This function allows the caller to force the
* default right now.
*/
void saveDefaultDictionary();
/**
* Call this to free up the spell checking object. It will also save the
* current selected language as the default for future use.
@ -192,6 +184,6 @@ interface nsIEditorSpellCheck : nsISupports
* Update the dictionary in use to be sure it corresponds to what the editor
* needs.
*/
void UpdateCurrentDictionary(in nsIEditor editor);
void UpdateCurrentDictionary();
};

View File

@ -3730,7 +3730,11 @@ nsHTMLEditRules::WillCSSIndent(nsISelection *aSelection, PRBool *aCancel, PRBool
else {
if (!curQuote)
{
// First, check that our element can contain a div.
NS_NAMED_LITERAL_STRING(divquoteType, "div");
if (!mEditor->CanContainTag(curParent, divquoteType))
return NS_OK; // cancelled
res = SplitAsNeeded(&divquoteType, address_of(curParent), &offset);
NS_ENSURE_SUCCESS(res, res);
res = mHTMLEditor->CreateNode(divquoteType, curParent, offset, getter_AddRefs(curQuote));
@ -3957,6 +3961,10 @@ nsHTMLEditRules::WillHTMLIndent(nsISelection *aSelection, PRBool *aCancel, PRBoo
if (!curQuote)
{
// First, check that our element can contain a blockquote.
if (!mEditor->CanContainTag(curParent, quoteType))
return NS_OK; // cancelled
res = SplitAsNeeded(&quoteType, address_of(curParent), &offset);
NS_ENSURE_SUCCESS(res, res);
res = mHTMLEditor->CreateNode(quoteType, curParent, offset, getter_AddRefs(curQuote));
@ -4089,10 +4097,10 @@ nsHTMLEditRules::WillOutdent(nsISelection *aSelection, PRBool *aCancel, PRBool *
nsCOMPtr<nsIDOMNode> n = curNode;
nsCOMPtr<nsIDOMNode> tmp;
curBlockQuoteIsIndentedWithCSS = PR_FALSE;
// keep looking up the hierarchy as long as we don't hit the body or a table element
// (other than an entire table)
while (!nsTextEditUtils::IsBody(n) &&
(nsHTMLEditUtils::IsTable(n) || !nsHTMLEditUtils::IsTableElement(n)))
// keep looking up the hierarchy as long as we don't hit the body or the
// active editing host or a table element (other than an entire table)
while (!nsTextEditUtils::IsBody(n) && mHTMLEditor->IsNodeInActiveEditor(n)
&& (nsHTMLEditUtils::IsTable(n) || !nsHTMLEditUtils::IsTableElement(n)))
{
n->GetParentNode(getter_AddRefs(tmp));
if (!tmp) {
@ -4785,7 +4793,11 @@ nsHTMLEditRules::WillAlign(nsISelection *aSelection,
// or if this node doesn't go in div we used earlier.
if (!curDiv || transitionList[i])
{
// First, check that our element can contain a div.
NS_NAMED_LITERAL_STRING(divType, "div");
if (!mEditor->CanContainTag(curParent, divType))
return NS_OK; // cancelled
res = SplitAsNeeded(&divType, address_of(curParent), &offset);
NS_ENSURE_SUCCESS(res, res);
res = mHTMLEditor->CreateNode(divType, curParent, offset, getter_AddRefs(curDiv));
@ -4795,9 +4807,9 @@ nsHTMLEditRules::WillAlign(nsISelection *aSelection,
// set up the alignment on the div
nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(curDiv);
res = AlignBlock(divElem, alignType, PR_TRUE);
// nsAutoString attr(NS_LITERAL_STRING("align"));
// res = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
// NS_ENSURE_SUCCESS(res, res);
//nsAutoString attr(NS_LITERAL_STRING("align"));
//res = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
//NS_ENSURE_SUCCESS(res, res);
// curDiv is now the correct thing to put curNode in
}
@ -5598,9 +5610,13 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt
// Don't walk past the editable section. Note that we need to check
// before walking up to a parent because we need to return the parent
// object, so the parent itself might not be in the editable area, but
// it's OK.
if (!mHTMLEditor->IsNodeInActiveEditor(node) &&
!mHTMLEditor->IsNodeInActiveEditor(parent)) {
// it's OK if we're not performing a block-level action.
PRBool blockLevelAction = (actionID == nsHTMLEditor::kOpIndent)
|| (actionID == nsHTMLEditor::kOpOutdent)
|| (actionID == nsHTMLEditor::kOpAlign)
|| (actionID == nsHTMLEditor::kOpMakeBasicBlock);
if (!mHTMLEditor->IsNodeInActiveEditor(parent) &&
(blockLevelAction || !mHTMLEditor->IsNodeInActiveEditor(node))) {
break;
}
@ -8935,8 +8951,17 @@ nsHTMLEditRules::RelativeChangeIndentationOfElementNode(nsIDOMNode *aNode, PRInt
}
else {
mHTMLEditor->mHTMLCSSUtils->RemoveCSSProperty(element, marginProperty, value, PR_FALSE);
if (nsHTMLEditUtils::IsDiv(aNode)) {
// we deal with a DIV ; let's see if it is useless and if we can remove it
// remove unnecessary DIV blocks:
// we could skip this section but that would cause a FAIL in
// editor/libeditor/html/tests/browserscope/richtext.html, which expects
// to unapply a CSS "indent" (<div style="margin-left: 40px;">) by
// removing the DIV container instead of just removing the CSS property.
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
if (nsHTMLEditUtils::IsDiv(aNode)
&& (node != mHTMLEditor->GetActiveEditingHost())
&& mHTMLEditor->IsNodeInActiveEditor(aNode)) {
// we deal with an editable DIV;
// let's see if it is useless and if we can remove it
nsCOMPtr<nsIDOMNamedNodeMap> attributeList;
res = element->GetAttributes(getter_AddRefs(attributeList));
NS_ENSURE_SUCCESS(res, res);

View File

@ -86,6 +86,7 @@ _TEST_FILES = \
test_bug668599.html \
test_bug674861.html \
test_bug676401.html \
test_bug677752.html \
test_CF_HTML_clipboard.html \
test_contenteditable_focus.html \
test_htmleditor_keyevent_handling.html \

View File

@ -4479,11 +4479,15 @@ const TEST_RESULTS = {
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><blockquote>`foo[bar]baz´</blockquote></body>"
},
"div": {
"valscore": 0,
"selscore": 0,
"valresult": 2,
"selresult": 3,
"output": "EXECUTION EXCEPTION: [Exception... \"Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIDOMHTMLDocument.execCommand]\" nsresult: \"0x80004005 (NS_ERROR_FAILURE)\" location: \"JS frame :: http://mochi.test:8888/tests/editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/static/js/run.js :: runSingleTest :: line 143\" data: no]"
"valscore": 1,
"selscore": 1,
"valresult": 8,
"selresult": 5,
"output": "<blockquote>`foo[bar]baz´</blockquote>",
"innerHTML": "<blockquote>`foo[bar]baz´</blockquote>",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><blockquote>`foo[bar]baz´</blockquote></div>",
"bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><blockquote>`foo[bar]baz´</blockquote></div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><blockquote>`foo[bar]baz´</blockquote></div>CAN<br>ARY</body>"
}
},
"FB:BQ_BR.BR-1_SM": {
@ -4510,11 +4514,15 @@ const TEST_RESULTS = {
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><blockquote>`fo[o´<br>`bar´<br>`b]az´</blockquote></body>"
},
"div": {
"valscore": 0,
"selscore": 0,
"valresult": 2,
"selresult": 3,
"output": "EXECUTION EXCEPTION: [Exception... \"Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIDOMHTMLDocument.execCommand]\" nsresult: \"0x80004005 (NS_ERROR_FAILURE)\" location: \"JS frame :: http://mochi.test:8888/tests/editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/static/js/run.js :: runSingleTest :: line 143\" data: no]"
"valscore": 1,
"selscore": 1,
"valresult": 8,
"selresult": 5,
"output": "<blockquote>`fo[o´<br>`bar´<br>`b]az´</blockquote>",
"innerHTML": "<blockquote>`fo[o´<br>`bar´<br>`b]az´</blockquote>",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><blockquote>`fo[o´<br>`bar´<br>`b]az´</blockquote></div>",
"bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><blockquote>`fo[o´<br>`bar´<br>`b]az´</blockquote></div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><blockquote>`fo[o´<br>`bar´<br>`b]az´</blockquote></div>CAN<br>ARY</body>"
}
},
"BC:blue_TEXT-1_SI": {
@ -4856,11 +4864,15 @@ const TEST_RESULTS = {
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><blockquote>`foo[bar]baz´</blockquote></body>"
},
"div": {
"valscore": 0,
"selscore": 0,
"valresult": 2,
"selresult": 3,
"output": "EXECUTION EXCEPTION: [Exception... \"Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIDOMHTMLDocument.execCommand]\" nsresult: \"0x80004005 (NS_ERROR_FAILURE)\" location: \"JS frame :: http://mochi.test:8888/tests/editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/static/js/run.js :: runSingleTest :: line 143\" data: no]"
"valscore": 1,
"selscore": 1,
"valresult": 8,
"selresult": 5,
"output": "<blockquote>`foo[bar]baz´</blockquote>",
"innerHTML": "<blockquote>`foo[bar]baz´</blockquote>",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><blockquote>`foo[bar]baz´</blockquote></div>",
"bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><blockquote>`foo[bar]baz´</blockquote></div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><blockquote>`foo[bar]baz´</blockquote></div>CAN<br>ARY</body>"
}
},
"JC_TEXT-1_SC": {
@ -4887,15 +4899,15 @@ const TEST_RESULTS = {
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div align=\"center\">`foo^bar´</div></body>"
},
"div": {
"valscore": 0,
"valscore": 1,
"selscore": 1,
"valresult": 7,
"valresult": 8,
"selresult": 5,
"output": "<div xmlns=\"http://www.w3.org/1999/xhtml\" align=\"center\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>",
"innerHTML": "`foo^bar´",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" align=\"center\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>",
"bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\" align=\"center\">`foo^bar´</div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div align=\"center\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>CAN<br>ARY</body>"
"output": "<div align=\"center\">`foo^bar´</div>",
"innerHTML": "<div align=\"center\">`foo^bar´</div>",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><div align=\"center\">`foo^bar´</div></div>",
"bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><div align=\"center\">`foo^bar´</div></div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><div align=\"center\">`foo^bar´</div></div>CAN<br>ARY</body>"
}
},
"JF_TEXT-1_SC": {
@ -4922,15 +4934,15 @@ const TEST_RESULTS = {
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div align=\"justify\">`foo^bar´</div></body>"
},
"div": {
"valscore": 0,
"valscore": 1,
"selscore": 1,
"valresult": 7,
"valresult": 8,
"selresult": 5,
"output": "<div xmlns=\"http://www.w3.org/1999/xhtml\" align=\"justify\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>",
"innerHTML": "`foo^bar´",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" align=\"justify\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>",
"bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\" align=\"justify\">`foo^bar´</div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div align=\"justify\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>CAN<br>ARY</body>"
"output": "<div align=\"justify\">`foo^bar´</div>",
"innerHTML": "<div align=\"justify\">`foo^bar´</div>",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><div align=\"justify\">`foo^bar´</div></div>",
"bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><div align=\"justify\">`foo^bar´</div></div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><div align=\"justify\">`foo^bar´</div></div>CAN<br>ARY</body>"
}
},
"JL_TEXT-1_SC": {
@ -4957,15 +4969,15 @@ const TEST_RESULTS = {
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div align=\"left\">`foo^bar´</div></body>"
},
"div": {
"valscore": 0,
"valscore": 1,
"selscore": 1,
"valresult": 7,
"valresult": 8,
"selresult": 5,
"output": "<div xmlns=\"http://www.w3.org/1999/xhtml\" align=\"left\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>",
"innerHTML": "`foo^bar´",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" align=\"left\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>",
"bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\" align=\"left\">`foo^bar´</div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div align=\"left\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>CAN<br>ARY</body>"
"output": "<div align=\"left\">`foo^bar´</div>",
"innerHTML": "<div align=\"left\">`foo^bar´</div>",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><div align=\"left\">`foo^bar´</div></div>",
"bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><div align=\"left\">`foo^bar´</div></div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><div align=\"left\">`foo^bar´</div></div>CAN<br>ARY</body>"
}
},
"JR_TEXT-1_SC": {
@ -4992,15 +5004,15 @@ const TEST_RESULTS = {
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div align=\"right\">`foo^bar´</div></body>"
},
"div": {
"valscore": 0,
"valscore": 1,
"selscore": 1,
"valresult": 7,
"valresult": 8,
"selresult": 5,
"output": "<div xmlns=\"http://www.w3.org/1999/xhtml\" align=\"right\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>",
"innerHTML": "`foo^bar´",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" align=\"right\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>",
"bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\" align=\"right\">`foo^bar´</div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div align=\"right\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>CAN<br>ARY</body>"
"output": "<div align=\"right\">`foo^bar´</div>",
"innerHTML": "<div align=\"right\">`foo^bar´</div>",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><div align=\"right\">`foo^bar´</div></div>",
"bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><div align=\"right\">`foo^bar´</div></div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><div align=\"right\">`foo^bar´</div></div>CAN<br>ARY</body>"
}
},
"H:H1_TEXT-1_SC": {
@ -5556,15 +5568,15 @@ const TEST_RESULTS = {
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div style=\"margin-left: 40px;\">`foo[bar]baz´</div></body>"
},
"div": {
"valscore": 0,
"valscore": 1,
"selscore": 1,
"valresult": 7,
"valresult": 8,
"selresult": 5,
"output": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"margin-left: 40px;\">`foo[bar]baz´</div>",
"innerHTML": "`foo[bar]baz´",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"margin-left: 40px;\">`foo[bar]baz´</div>",
"bodyInnerHTML": "CAN<br>ARY<div style=\"margin-left: 40px;\" id=\"editor-div\" contenteditable=\"true\">`foo[bar]baz´</div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\" style=\"margin-left: 40px;\">`foo[bar]baz´</div>CAN<br>ARY</body>"
"output": "<div style=\"margin-left: 40px;\">`foo[bar]baz´</div>",
"innerHTML": "<div style=\"margin-left: 40px;\">`foo[bar]baz´</div>",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><div style=\"margin-left: 40px;\">`foo[bar]baz´</div></div>",
"bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><div style=\"margin-left: 40px;\">`foo[bar]baz´</div></div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><div style=\"margin-left: 40px;\">`foo[bar]baz´</div></div>CAN<br>ARY</body>"
}
},
"JC_TEXT-1_SC": {
@ -5591,15 +5603,15 @@ const TEST_RESULTS = {
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div style=\"text-align: center;\">`foo^bar´</div></body>"
},
"div": {
"valscore": 0,
"valscore": 1,
"selscore": 1,
"valresult": 7,
"valresult": 8,
"selresult": 5,
"output": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"text-align: center;\">`foo^bar´</div>",
"innerHTML": "`foo^bar´",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"text-align: center;\">`foo^bar´</div>",
"bodyInnerHTML": "CAN<br>ARY<div style=\"text-align: center;\" id=\"editor-div\" contenteditable=\"true\">`foo^bar´</div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\" style=\"text-align: center;\">`foo^bar´</div>CAN<br>ARY</body>"
"output": "<div style=\"text-align: center;\">`foo^bar´</div>",
"innerHTML": "<div style=\"text-align: center;\">`foo^bar´</div>",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><div style=\"text-align: center;\">`foo^bar´</div></div>",
"bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><div style=\"text-align: center;\">`foo^bar´</div></div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><div style=\"text-align: center;\">`foo^bar´</div></div>CAN<br>ARY</body>"
}
},
"JF_TEXT-1_SC": {
@ -5626,15 +5638,15 @@ const TEST_RESULTS = {
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div style=\"text-align: justify;\">`foo^bar´</div></body>"
},
"div": {
"valscore": 0,
"valscore": 1,
"selscore": 1,
"valresult": 7,
"valresult": 8,
"selresult": 5,
"output": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"text-align: justify;\">`foo^bar´</div>",
"innerHTML": "`foo^bar´",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"text-align: justify;\">`foo^bar´</div>",
"bodyInnerHTML": "CAN<br>ARY<div style=\"text-align: justify;\" id=\"editor-div\" contenteditable=\"true\">`foo^bar´</div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\" style=\"text-align: justify;\">`foo^bar´</div>CAN<br>ARY</body>"
"output": "<div style=\"text-align: justify;\">`foo^bar´</div>",
"innerHTML": "<div style=\"text-align: justify;\">`foo^bar´</div>",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><div style=\"text-align: justify;\">`foo^bar´</div></div>",
"bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><div style=\"text-align: justify;\">`foo^bar´</div></div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><div style=\"text-align: justify;\">`foo^bar´</div></div>CAN<br>ARY</body>"
}
},
"JL_TEXT-1_SC": {
@ -5661,15 +5673,15 @@ const TEST_RESULTS = {
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div style=\"text-align: left;\">`foo^bar´</div></body>"
},
"div": {
"valscore": 0,
"valscore": 1,
"selscore": 1,
"valresult": 7,
"valresult": 8,
"selresult": 5,
"output": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"text-align: left;\">`foo^bar´</div>",
"innerHTML": "`foo^bar´",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"text-align: left;\">`foo^bar´</div>",
"bodyInnerHTML": "CAN<br>ARY<div style=\"text-align: left;\" id=\"editor-div\" contenteditable=\"true\">`foo^bar´</div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\" style=\"text-align: left;\">`foo^bar´</div>CAN<br>ARY</body>"
"output": "<div style=\"text-align: left;\">`foo^bar´</div>",
"innerHTML": "<div style=\"text-align: left;\">`foo^bar´</div>",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><div style=\"text-align: left;\">`foo^bar´</div></div>",
"bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><div style=\"text-align: left;\">`foo^bar´</div></div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><div style=\"text-align: left;\">`foo^bar´</div></div>CAN<br>ARY</body>"
}
},
"JR_TEXT-1_SC": {
@ -5696,15 +5708,15 @@ const TEST_RESULTS = {
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div style=\"text-align: right;\">`foo^bar´</div></body>"
},
"div": {
"valscore": 0,
"valscore": 1,
"selscore": 1,
"valresult": 7,
"valresult": 8,
"selresult": 5,
"output": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"text-align: right;\">`foo^bar´</div>",
"innerHTML": "`foo^bar´",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"text-align: right;\">`foo^bar´</div>",
"bodyInnerHTML": "CAN<br>ARY<div style=\"text-align: right;\" id=\"editor-div\" contenteditable=\"true\">`foo^bar´</div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\" style=\"text-align: right;\">`foo^bar´</div>CAN<br>ARY</body>"
"output": "<div style=\"text-align: right;\">`foo^bar´</div>",
"innerHTML": "<div style=\"text-align: right;\">`foo^bar´</div>",
"outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><div style=\"text-align: right;\">`foo^bar´</div></div>",
"bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><div style=\"text-align: right;\">`foo^bar´</div></div>CAN<br>ARY",
"bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><div style=\"text-align: right;\">`foo^bar´</div></div>CAN<br>ARY</body>"
}
}
}

View File

@ -42,6 +42,8 @@ function runTests()
selection.collapseToEnd();
}
/* TestCase #1
*/
const kTestCase1 =
"<p id=\"editor1\" contenteditable=\"true\">editor1</p>" +
"<p id=\"editor2\" contenteditable=\"true\">editor2</p>" +
@ -50,7 +52,7 @@ function runTests()
"non-editable text" +
"<p id=\"editor5\" contenteditable=\"true\">editor5</p>";
const kTestCase1_editor3_specialcase =
const kTestCase1_editor3_deleteAtStart =
"<p id=\"editor1\" contenteditable=\"true\">editor1</p>" +
"<p id=\"editor2\" contenteditable=\"true\">editor2</p>" +
"<div id=\"editor3\" contenteditable=\"true\"><div>ditor3</div></div>" +
@ -58,6 +60,14 @@ function runTests()
"non-editable text" +
"<p id=\"editor5\" contenteditable=\"true\">editor5</p>";
const kTestCase1_editor3_backspaceAtEnd =
"<p id=\"editor1\" contenteditable=\"true\">editor1</p>" +
"<p id=\"editor2\" contenteditable=\"true\">editor2</p>" +
"<div id=\"editor3\" contenteditable=\"true\"><div>editor</div></div>" +
"<p id=\"editor4\" contenteditable=\"true\">editor4</p>" +
"non-editable text" +
"<p id=\"editor5\" contenteditable=\"true\">editor5</p>";
container.innerHTML = kTestCase1;
var editor1 = document.getElementById("editor1");
@ -66,6 +76,9 @@ function runTests()
var editor4 = document.getElementById("editor4");
var editor5 = document.getElementById("editor5");
/* TestCase #1:
* pressing backspace key at start should not change the content.
*/
editor2.focus();
moveCaretToStartOf(editor2);
synthesizeKey("VK_BACK_SPACE", { });
@ -94,6 +107,9 @@ function runTests()
"Pressing backspace key at start of editor5 changes the content");
reset();
/* TestCase #1:
* pressing delete key at end should not change the content.
*/
editor1.focus();
moveCaretToEndOf(editor1);
synthesizeKey("VK_DELETE", { });
@ -127,14 +143,28 @@ function runTests()
"Pressing delete key at end of editor4 changes the content");
reset();
// Cases when the caret is not on text node.
/* TestCase #1: cases when the caret is not on text node.
* - pressing delete key at start should remove the first character
* - pressing backspace key at end should remove the first character
* and the adjacent blocks should not be changed.
*/
editor3.focus();
moveCaretToStartOf(editor3);
synthesizeKey("VK_DELETE", { });
is(container.innerHTML, kTestCase1_editor3_specialcase,
"Pressing delete key at end of editor3 changes the content");
is(container.innerHTML, kTestCase1_editor3_deleteAtStart,
"Pressing delete key at start of editor3 changes adjacent elements"
+ " and/or does not remove the first character.");
reset();
// Backspace doesn't work here yet.
editor3.focus();
moveCaretToEndOf(editor3);
synthesizeKey("VK_BACK_SPACE", { });
todo_is(container.innerHTML, kTestCase1_editor3_backspaceAtEnd,
"Pressing backspace key at end of editor3 changes adjacent elements"
+ " and/or does not remove the last character.");
reset();
// We can still check that adjacent elements are not affected.
editor3.focus();
moveCaretToEndOf(editor3);
synthesizeKey("VK_BACK_SPACE", { });
@ -142,6 +172,9 @@ function runTests()
"Pressing backspace key at end of editor3 changes the content");
reset();
/* TestCase #2:
* two adjacent editable <span> in a table cell.
*/
const kTestCase2 = "<table><tbody><tr><td><span id=\"editor1\" contenteditable=\"true\">test</span>" +
"<span id=\"editor2\" contenteditable=\"true\">test</span></td></tr></tbody></table>";
@ -163,6 +196,9 @@ function runTests()
"Pressing delete key at the end of editor1 changes the content for kTestCase2");
reset();
/* TestCase #3:
* editable <span> in two adjacent table cells.
*/
const kTestCase3 = "<table><tbody><tr><td><span id=\"editor1\" contenteditable=\"true\">test</span></td>" +
"<td><span id=\"editor2\" contenteditable=\"true\">test</span></td></tr></tbody></table>";
@ -184,6 +220,9 @@ function runTests()
"Pressing delete key at the end of editor1 changes the content for kTestCase3");
reset();
/* TestCase #4:
* editable <div> in two adjacent table cells.
*/
const kTestCase4 = "<table><tbody><tr><td><div id=\"editor1\" contenteditable=\"true\">test</div></td>" +
"<td><div id=\"editor2\" contenteditable=\"true\">test</div></td></tr></tbody></table>";

View File

@ -0,0 +1,107 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=677752
-->
<head>
<title>Test for Bug 677752</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.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=677752">Mozilla Bug 677752</a>
<p id="display"></p>
<div id="content">
<section contenteditable> foo bar </section>
<div contenteditable> foo bar </div>
<p contenteditable> foo bar </p>
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 677752 **/
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(runTests);
function selectEditor(aEditor) {
aEditor.focus();
var selection = window.getSelection();
selection.selectAllChildren(aEditor);
selection.collapseToStart();
}
function runTests() {
var editor, node, initialHTML;
document.execCommand('styleWithCSS', false, true);
// editable <section>
editor = document.querySelector("section[contenteditable]");
initialHTML = editor.innerHTML;
selectEditor(editor);
// editable <section>: justify
document.execCommand("justifyright", false, null);
node = editor.querySelector("*");
is(node.nodeName.toLowerCase(), "div", "'justifyright' should create a <div> in the editable <section>.");
is(node.style.textAlign, "right", "'justifyright' should create a 'text-align: right' CSS rule.");
document.execCommand("undo", false, null);
// editable <section>: indent
document.execCommand("indent", false, null);
node = editor.querySelector("*");
is(node.nodeName.toLowerCase(), "div", "'indent' should create a <div> in the editable <section>.");
is(node.style.marginLeft, "40px", "'indent' should create a 'margin-left: 40px' CSS rule.");
// editable <section>: undo with outdent
// this should remove the whole <div> but only removing the CSS rule would be acceptable, too
document.execCommand("outdent", false, null);
is(editor.innerHTML, initialHTML, "'outdent' should undo the 'indent' action.");
// editable <section>: outdent again
document.execCommand("outdent", false, null);
is(editor.innerHTML, initialHTML, "another 'outdent' should not modify the <section> element.");
// editable <div>
editor = document.querySelector("div[contenteditable]");
initialHTML = editor.innerHTML;
selectEditor(editor);
// editable <div>: justify
document.execCommand("justifyright", false, null);
node = editor.querySelector("*");
is(node.nodeName.toLowerCase(), "div", "'justifyright' should create a <div> in the editable <div>.");
is(node.style.textAlign, "right", "'justifyright' should create a 'text-align: right' CSS rule.");
document.execCommand("undo", false, null);
// editable <div>: indent
document.execCommand("indent", false, null);
node = editor.querySelector("*");
is(node.nodeName.toLowerCase(), "div", "'indent' should create a <div> in the editable <div>.");
is(node.style.marginLeft, "40px", "'indent' should create a 'margin-left: 40px' CSS rule.");
// editable <div>: undo with outdent
// this should remove the whole <div> but only removing the CSS rule would be acceptable, too
document.execCommand("outdent", false, null);
is(editor.innerHTML, initialHTML, "'outdent' should undo the 'indent' action.");
// editable <div>: outdent again
document.execCommand("outdent", false, null);
is(editor.innerHTML, initialHTML, "another 'outdent' should not modify the <div> element.");
// editable <p>
// all block-level commands should be ignored (<p><div/></p> is not valid)
editor = document.querySelector("p[contenteditable]");
initialHTML = editor.innerHTML;
selectEditor(editor);
// editable <p>: justify
document.execCommand("justifyright", false, null);
is(editor.innerHTML, initialHTML, "'justifyright' should have no effect on <p>.");
// editable <p>: indent
document.execCommand("indent", false, null);
is(editor.innerHTML, initialHTML, "'indent' should have no effect on <p>.");
// editable <p>: outdent
document.execCommand("outdent", false, null);
is(editor.innerHTML, initialHTML, "'outdent' should have no effect on <p>.");
// done
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

View File

@ -325,12 +325,10 @@ function runTests()
synthesizeKey("VK_TAB", { shiftKey: true });
check(aDescription + "Shift+Tab after Tab on UL",
true, true, !aIsTabbable && !aIsReadonly && !aIsPlaintext);
// XXX why do we fail to outdent on non-tabbable HTML editor?
is(aElement.innerHTML,
aIsReadonly || aIsTabbable ?
aIsReadonly || aIsTabbable || (!aIsPlaintext) ?
"<ul><li id=\"target\">ul list item</li></ul>" :
aIsPlaintext ? "<ul><li id=\"target\">ul list item\t</li></ul>" :
"<ul><ul><li id=\"target\">ul list item</li></ul></ul>",
"<ul><li id=\"target\">ul list item\t</li></ul>",
aDescription + "Shift+Tab after Tab on UL");
is(fm.focusedElement, aElement,
aDescription + "focus moved unexpectedly (Shift+Tab after Tab on UL)");
@ -340,10 +338,8 @@ function runTests()
check(aDescription + "Shift+Tab on UL",
true, true, !aIsTabbable && !aIsReadonly && !aIsPlaintext);
is(aElement.innerHTML,
aIsReadonly || aIsTabbable ?
"<ul><li id=\"target\">ul list item</li></ul>" :
aIsPlaintext ? "<ul><li id=\"target\">ul list item</li></ul>" :
"<ul><li id=\"target\">ul list item</li></ul>",
aIsReadonly || aIsTabbable || aIsPlaintext ?
"<ul><li id=\"target\">ul list item</li></ul>" : "ul list item",
aDescription + "Shift+Tab on UL");
is(fm.focusedElement, aElement,
aDescription + "focus moved unexpectedly (Shift+Tab on UL)");
@ -389,12 +385,10 @@ function runTests()
synthesizeKey("VK_TAB", { shiftKey: true });
check(aDescription + "Shift+Tab after Tab on OL",
true, true, !aIsTabbable && !aIsReadonly && !aIsPlaintext);
// XXX why do we fail to outdent on non-tabbable HTML editor?
is(aElement.innerHTML,
aIsReadonly || aIsTabbable ?
aIsReadonly || aIsTabbable || (!aIsPlaintext) ?
"<ol><li id=\"target\">ol list item</li></ol>" :
aIsPlaintext ? "<ol><li id=\"target\">ol list item\t</li></ol>" :
"<ol><ol><li id=\"target\">ol list item</li></ol></ol>",
"<ol><li id=\"target\">ol list item\t</li></ol>",
aDescription + "Shift+Tab after Tab on OL");
is(fm.focusedElement, aElement,
aDescription + "focus moved unexpectedly (Shift+Tab after Tab on OL)");
@ -404,10 +398,8 @@ function runTests()
check(aDescription + "Shift+Tab on OL",
true, true, !aIsTabbable && !aIsReadonly && !aIsPlaintext);
is(aElement.innerHTML,
aIsReadonly || aIsTabbable ?
"<ol><li id=\"target\">ol list item</li></ol>" :
aIsPlaintext ? "<ol><li id=\"target\">ol list item</li></ol>" :
"<ol><li id=\"target\">ol list item</li></ol>",
aIsReadonly || aIsTabbable || aIsPlaintext ?
"<ol><li id=\"target\">ol list item</li></ol>" : "ol list item",
aDescription + "Shfit+Tab on OL");
is(fm.focusedElement, aElement,
aDescription + "focus moved unexpectedly (Shift+Tab on OL)");

View File

@ -169,8 +169,30 @@ class GeckoSurfaceView
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// Force exactly one frame to render
// because the surface change is only seen after we
// have swapped the back buffer.
// The buffer size only changes after the next swap buffer.
// We need to make sure the Gecko's view resize when Android's
// buffer resizes.
if (mDrawMode == DRAW_GLES_2) {
// When we get a surfaceChange event, we have 0 to n paint events
// waiting in the Gecko event queue. We will make the first
// succeed and the abort the others.
mDrawSingleFrame = true;
if (!mInDrawing) {
// Queue at least one paint event in case none are queued.
GeckoAppShell.scheduleRedraw();
}
GeckoAppShell.geckoEventSync();
mDrawSingleFrame = false;
mAbortDraw = false;
}
if (mShowingSplashScreen)
drawSplashScreen(holder, width, height);
mSurfaceLock.lock();
try {
@ -221,6 +243,12 @@ class GeckoSurfaceView
}
} finally {
mSurfaceLock.unlock();
if (mDrawMode == DRAW_GLES_2) {
// Force a frame to be drawn before the surfaceChange returns,
// otherwise we get artifacts.
GeckoAppShell.scheduleRedraw();
GeckoAppShell.geckoEventSync();
}
}
Object syncDrawObject = null;
@ -254,7 +282,12 @@ class GeckoSurfaceView
mSoftwareBufferCopy = null;
mSoftwareBitmap = null;
GeckoEvent e = new GeckoEvent(GeckoEvent.SURFACE_DESTROYED);
GeckoAppShell.sendEventToGecko(e);
if (mDrawMode == DRAW_GLES_2) {
// Ensure GL cleanup occurs before we return.
GeckoAppShell.sendEventToGeckoSync(e);
} else {
GeckoAppShell.sendEventToGecko(e);
}
}
public Bitmap getSoftwareDrawBitmap() {
@ -293,6 +326,10 @@ class GeckoSurfaceView
public static final int DRAW_ERROR = 0;
public static final int DRAW_GLES_2 = 1;
public static final int DRAW_2D = 2;
// Drawing is disable when the surface buffer
// has changed size but we haven't yet processed the
// resize event.
public static final int DRAW_DISABLED = 3;
public int beginDrawing() {
if (mInDrawing) {
@ -300,6 +337,12 @@ class GeckoSurfaceView
return DRAW_ERROR;
}
// Once we drawn our first frame after resize we can ignore
// the other draw events until we handle the resize events.
if (mAbortDraw) {
return DRAW_DISABLED;
}
/* Grab the lock, which we'll hold while we're drawing.
* It gets released in endDrawing(), and is also used in surfaceChanged
* to make sure that we don't change our surface details while
@ -330,6 +373,9 @@ class GeckoSurfaceView
return;
}
if (mDrawSingleFrame)
mAbortDraw = true;
try {
if (!mSurfaceValid) {
Log.e(LOG_FILE_NAME, "endDrawing with false mSurfaceValid");
@ -657,6 +703,10 @@ class GeckoSurfaceView
// Are we actively between beginDrawing/endDrawing?
boolean mInDrawing;
// Used to finish the current buffer before changing the surface size
boolean mDrawSingleFrame = false;
boolean mAbortDraw = false;
// Are we waiting for a buffer to draw in surfaceChanged?
boolean mSyncDraw;

View File

@ -285,7 +285,7 @@ NS_IMETHODIMP nsSystemPrefService::GetBoolPref(const char *aPrefName, PRBool *_r
}
/* void setBoolPref (in string aPrefName, in long aValue); */
NS_IMETHODIMP nsSystemPrefService::SetBoolPref(const char *aPrefName, PRInt32 aValue)
NS_IMETHODIMP nsSystemPrefService::SetBoolPref(const char *aPrefName, PRBool aValue)
{
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@ -1765,8 +1765,7 @@ NS_IMETHODIMP mozInlineSpellChecker::UpdateCurrentDictionary()
previousDictionary.Truncate();
}
nsCOMPtr<nsIEditor> editor (do_QueryReferent(mEditor));
nsresult rv = mSpellCheck->UpdateCurrentDictionary(editor);
nsresult rv = mSpellCheck->UpdateCurrentDictionary();
nsAutoString currentDictionary;
if (NS_FAILED(mSpellCheck->GetCurrentDictionary(currentDictionary))) {

View File

@ -41,10 +41,6 @@
#include "nsICategoryManager.h"
#include "nsISupportsPrimitives.h"
// The number 130 more or less comes out of thin air.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=355178#c78 for a pseudo-rationale.
#define UNREASONABLE_WORD_LENGTH 130
#define DEFAULT_SPELL_CHECKER "@mozilla.org/spellchecker/engine;1"
NS_IMPL_CYCLE_COLLECTING_ADDREF(mozSpellChecker)
@ -149,12 +145,6 @@ mozSpellChecker::CheckWord(const nsAString &aWord, PRBool *aIsMisspelled, nsTArr
if(!mSpellCheckingEngine)
return NS_ERROR_NULL_POINTER;
// don't bother to check crazy words
if (aWord.Length() > UNREASONABLE_WORD_LENGTH) {
*aIsMisspelled = PR_TRUE;
return NS_OK;
}
*aIsMisspelled = PR_FALSE;
result = mSpellCheckingEngine->Check(PromiseFlatString(aWord).get(), &correct);
NS_ENSURE_SUCCESS(result, result);

View File

@ -50,19 +50,19 @@
#endif
typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)(
__in D2D1_FACTORY_TYPE factoryType,
__in REFIID iid,
__in_opt CONST D2D1_FACTORY_OPTIONS *pFactoryOptions,
__out void **factory
D2D1_FACTORY_TYPE factoryType,
REFIID iid,
CONST D2D1_FACTORY_OPTIONS *pFactoryOptions,
void **factory
);
typedef HRESULT (WINAPI*D3D10CreateEffectFromMemoryFunc)(
__in void *pData,
__in SIZE_T DataLength,
__in UINT FXFlags,
__in ID3D10Device *pDevice,
__in ID3D10EffectPool *pEffectPool,
__out ID3D10Effect **ppEffect
void *pData,
SIZE_T DataLength,
UINT FXFlags,
ID3D10Device *pDevice,
ID3D10EffectPool *pEffectPool,
ID3D10Effect **ppEffect
);
using namespace std;

View File

@ -40,7 +40,7 @@
#include "2D.h"
#include <D2D1.h>
#include <d2d1.h>
namespace mozilla {
namespace gfx {

View File

@ -38,7 +38,7 @@
#ifndef MOZILLA_GFX_HELPERSD2D_H_
#define MOZILLA_GFX_HELPERSD2D_H_
#include <D2D1.h>
#include <d2d1.h>
#include "2D.h"
namespace mozilla {

View File

@ -39,7 +39,7 @@
#define MOZILLA_GFX_PATHD2D_H_
#include "2D.h"
#include <D2D1.h>
#include <d2d1.h>
namespace mozilla {
namespace gfx {

View File

@ -191,96 +191,40 @@ ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset,
renderRegion = &visibleRegion;
}
mTexImage->BeginTileIteration();
if (mTexImageOnWhite) {
mTexImageOnWhite->BeginTileIteration();
NS_ASSERTION(mTexImageOnWhite->GetTileRect() == mTexImage->GetTileRect(), "component alpha textures should be the same size.");
}
nsIntRegion region(*renderRegion);
nsIntPoint origin = GetOriginOffset();
region.MoveBy(-origin); // translate into TexImage space, buffer origin might not be at texture (0,0)
// Figure out the intersecting draw region
nsIntSize texSize = mTexImage->GetSize();
nsIntRect textureRect = nsIntRect(0, 0, texSize.width, texSize.height);
textureRect.MoveBy(region.GetBounds().TopLeft());
nsIntRegion subregion;
subregion.And(region, textureRect);
if (subregion.IsEmpty()) // Region is empty, nothing to draw
return;
nsIntRegion screenRects;
nsIntRegion regionRects;
// Collect texture/screen coordinates for drawing
nsIntRegionRectIterator iter(subregion);
while (const nsIntRect* iterRect = iter.Next()) {
nsIntRect regionRect = *iterRect;
nsIntRect screenRect = regionRect;
screenRect.MoveBy(origin);
screenRects.Or(screenRects, screenRect);
regionRects.Or(regionRects, regionRect);
}
mTexImage->BeginTileIteration();
if (mTexImageOnWhite) {
NS_ASSERTION(mTexImage->GetTileCount() == mTexImageOnWhite->GetTileCount(),
"Tile count mismatch on component alpha texture");
mTexImageOnWhite->BeginTileIteration();
}
bool usingTiles = (mTexImage->GetTileCount() > 1);
do {
if (mTexImageOnWhite) {
NS_ASSERTION(mTexImageOnWhite->GetTileRect() == mTexImage->GetTileRect(), "component alpha textures should be the same size.");
nsIntRect textureRect = mTexImage->GetTileRect();
textureRect.MoveBy(region.GetBounds().x, region.GetBounds().y);
nsIntRegion subregion(region);
subregion.And(region, textureRect); // region this texture is visible in
if (subregion.IsEmpty()) {
continue;
}
nsIntRect tileRect = mTexImage->GetTileRect();
// Bind textures.
TextureImage::ScopedBindTexture texBind(mTexImage, LOCAL_GL_TEXTURE0);
TextureImage::ScopedBindTexture texOnWhiteBind(mTexImageOnWhite, LOCAL_GL_TEXTURE1);
// Draw texture. If we're using tiles, we do repeating manually, as texture
// repeat would cause each individual tile to repeat instead of the
// compound texture as a whole. This involves drawing at most 4 sections,
// 2 for each axis that has texture repeat.
for (int y = 0; y < (usingTiles ? 2 : 1); y++) {
for (int x = 0; x < (usingTiles ? 2 : 1); x++) {
nsIntRect currentTileRect(tileRect);
currentTileRect.MoveBy(x * texSize.width, y * texSize.height);
nsIntRegionRectIterator iter(subregion);
while (const nsIntRect *iterRect = iter.Next()) {
nsIntRect regionRect = *iterRect; // one rectangle of this texture's region
// translate into the correct place for this texture sub-region
nsIntRect screenRect = regionRect;
screenRect.MoveBy(origin);
program->SetLayerQuadRect(screenRect);
nsIntRegionRectIterator screenIter(screenRects);
nsIntRegionRectIterator regionIter(regionRects);
const nsIntRect* screenRect;
const nsIntRect* regionRect;
while ((screenRect = screenIter.Next()) &&
(regionRect = regionIter.Next())) {
nsIntRect tileScreenRect(*screenRect);
nsIntRect tileRegionRect(*regionRect);
// When we're using tiles, find the intersection between the tile
// rect and this region rect. Tiling is then handled by the
// outer for-loops and modifying the tile rect.
if (usingTiles) {
tileScreenRect.MoveBy(-origin);
tileScreenRect = tileScreenRect.Intersect(currentTileRect);
tileScreenRect.MoveBy(origin);
if (tileScreenRect.IsEmpty())
continue;
tileRegionRect = regionRect->Intersect(currentTileRect);
tileRegionRect.MoveBy(-currentTileRect.TopLeft());
}
program->SetLayerQuadRect(tileScreenRect);
aManager->BindAndDrawQuadWithTextureRect(program, tileRegionRect,
tileRect.Size(),
mTexImage->GetWrapMode());
}
}
regionRect.MoveBy(-mTexImage->GetTileRect().TopLeft()); // get region of tile
aManager->BindAndDrawQuadWithTextureRect(program, regionRect,
textureRect.Size(),
mTexImage->GetWrapMode());
}
if (mTexImageOnWhite)
mTexImageOnWhite->NextTile();
} while (mTexImage->NextTile());
}
@ -847,18 +791,6 @@ ShadowBufferOGL::Upload(gfxASurface* aUpdate, const nsIntRegion& aUpdated,
nsIntPoint visTopLeft = mLayer->GetVisibleRegion().GetBounds().TopLeft();
destRegion.MoveBy(-visTopLeft);
// Correct for rotation
destRegion.MoveBy(aRotation);
nsIntRect destBounds = destRegion.GetBounds();
destRegion.MoveBy((destBounds.x >= size.width) ? -size.width : 0,
(destBounds.y >= size.height) ? -size.height : 0);
// There's code to make sure that updated regions don't cross rotation
// boundaries, so assert here that this is the case
NS_ASSERTION(((destBounds.x % size.width) + destBounds.width <= size.width) &&
((destBounds.y % size.height) + destBounds.height <= size.height),
"Updated region lies across rotation boundaries!");
// NB: this gfxContext must not escape EndUpdate() below
mTexImage->DirectUpdate(aUpdate, destRegion);

View File

@ -488,7 +488,7 @@ bool Parse0514(ots::OpenTypeFile *file,
return OTS_FAILURE();
}
const uint32_t check_value =
ranges[j].unicode_value + ranges[i].additional_count;
ranges[j].unicode_value + ranges[j].additional_count;
if (ranges[j].unicode_value == 0 ||
ranges[j].unicode_value > kUnicodeUpperLimit ||
check_value > kUVSUpperLimit ||

View File

@ -126,6 +126,7 @@ private:
*/
class NS_GFX ScopedXErrorHandler
{
public:
// trivial wrapper around XErrorEvent, just adding ctor initializing by zero.
struct ErrorEvent
{
@ -137,6 +138,8 @@ class NS_GFX ScopedXErrorHandler
}
};
private:
// this ScopedXErrorHandler's ErrorEvent object
ErrorEvent mXError;

View File

@ -575,8 +575,20 @@ BasicTextureImage::BeginUpdate(nsIntRegion& aRegion)
NS_ASSERTION(!mUpdateSurface, "BeginUpdate() without EndUpdate()?");
// determine the region the client will need to repaint
GetUpdateRegion(aRegion);
mUpdateRegion = aRegion;
ImageFormat format =
(GetContentType() == gfxASurface::CONTENT_COLOR) ?
gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32;
if (mTextureState != Valid)
{
// if the texture hasn't been initialized yet, or something important
// changed, we need to recreate our backing surface and force the
// client to paint everything
mUpdateRegion = nsIntRect(nsIntPoint(0, 0), mSize);
} else {
mUpdateRegion = aRegion;
}
aRegion = mUpdateRegion;
nsIntRect rgnSize = mUpdateRegion.GetBounds();
if (!nsIntRect(nsIntPoint(0, 0), mSize).Contains(rgnSize)) {
@ -584,10 +596,7 @@ BasicTextureImage::BeginUpdate(nsIntRegion& aRegion)
return NULL;
}
ImageFormat format =
(GetContentType() == gfxASurface::CONTENT_COLOR) ?
gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32;
mUpdateSurface =
mUpdateSurface =
GetSurfaceForUpdate(gfxIntSize(rgnSize.width, rgnSize.height), format);
if (!mUpdateSurface || mUpdateSurface->CairoStatus()) {
@ -600,16 +609,6 @@ BasicTextureImage::BeginUpdate(nsIntRegion& aRegion)
return mUpdateSurface;
}
void
BasicTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
{
// if the texture hasn't been initialized yet, or something important
// changed, we need to recreate our backing surface and force the
// client to paint everything
if (mTextureState != Valid)
aForRegion = nsIntRect(nsIntPoint(0, 0), mSize);
}
void
BasicTextureImage::EndUpdate()
{
@ -730,9 +729,10 @@ TiledTextureImage::~TiledTextureImage()
bool
TiledTextureImage::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */)
{
nsIntRect bounds = aRegion.GetBounds();
nsIntRegion region;
if (mTextureState != Valid) {
nsIntRect bounds = nsIntRect(0, 0, mSize.width, mSize.height);
bounds = nsIntRect(0, 0, mSize.width, mSize.height);
region = nsIntRegion(bounds);
} else {
region = aRegion;
@ -740,8 +740,8 @@ TiledTextureImage::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion,
PRBool result = PR_TRUE;
for (unsigned i = 0; i < mImages.Length(); i++) {
int xPos = (i % mColumns) * mTileSize;
int yPos = (i / mColumns) * mTileSize;
unsigned int xPos = (i % mColumns) * mTileSize;
unsigned int yPos = (i / mColumns) * mTileSize;
nsIntRegion tileRegion;
tileRegion.And(region, nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize())); // intersect with tile
if (tileRegion.IsEmpty())
@ -757,66 +757,25 @@ TiledTextureImage::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion,
return result;
}
void
TiledTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
{
if (mTextureState != Valid) {
// if the texture hasn't been initialized yet, or something important
// changed, we need to recreate our backing surface and force the
// client to paint everything
aForRegion = nsIntRect(nsIntPoint(0, 0), mSize);
return;
}
nsIntRegion newRegion;
// We need to query each texture with the region it will be drawing and
// set aForRegion to be the combination of all of these regions
for (unsigned i = 0; i < mImages.Length(); i++) {
int xPos = (i % mColumns) * mTileSize;
int yPos = (i / mColumns) * mTileSize;
nsIntRect imageRect = nsIntRect(nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize()));
if (aForRegion.Intersects(imageRect)) {
// Make a copy of the region
nsIntRegion subRegion;
subRegion.And(aForRegion, imageRect);
// Translate it into tile-space
subRegion.MoveBy(-xPos, -yPos);
// Query region
mImages[i]->GetUpdateRegion(subRegion);
// Translate back
subRegion.MoveBy(xPos, yPos);
// Add to the accumulated region
newRegion.Or(newRegion, subRegion);
}
}
aForRegion = newRegion;
}
gfxASurface*
TiledTextureImage::BeginUpdate(nsIntRegion& aRegion)
{
NS_ASSERTION(!mInUpdate, "nested update");
mInUpdate = PR_TRUE;
// Note, we don't call GetUpdateRegion here as if the updated region is
// fully contained in a single tile, we get to avoid iterating through
// the tiles again (and a little copying).
if (mTextureState != Valid)
{
// if the texture hasn't been initialized yet, or something important
// changed, we need to recreate our backing surface and force the
// client to paint everything
aRegion = nsIntRect(nsIntPoint(0, 0), mSize);
mUpdateRegion = nsIntRect(nsIntPoint(0, 0), mSize);
} else {
mUpdateRegion = aRegion;
}
nsIntRect bounds = aRegion.GetBounds();
for (unsigned i = 0; i < mImages.Length(); i++) {
int xPos = (i % mColumns) * mTileSize;
int yPos = (i / mColumns) * mTileSize;
unsigned int xPos = (i % mColumns) * mTileSize;
unsigned int yPos = (i / mColumns) * mTileSize;
nsIntRegion imageRegion = nsIntRegion(nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize()));
// a single Image can handle this update request
@ -827,10 +786,6 @@ TiledTextureImage::BeginUpdate(nsIntRegion& aRegion)
nsRefPtr<gfxASurface> surface = mImages[i]->BeginUpdate(aRegion);
// caller expects container space
aRegion.MoveBy(xPos, yPos);
// Correct the device offset
gfxPoint offset = surface->GetDeviceOffset();
surface->SetDeviceOffset(gfxPoint(offset.x - xPos,
offset.y - yPos));
// we don't have a temp surface
mUpdateSurface = nsnull;
// remember which image to EndUpdate
@ -838,21 +793,15 @@ TiledTextureImage::BeginUpdate(nsIntRegion& aRegion)
return surface.get();
}
}
// Get the real updated region, taking into account the capabilities of
// each TextureImage tile
GetUpdateRegion(aRegion);
mUpdateRegion = aRegion;
bounds = aRegion.GetBounds();
// update covers multiple Images - create a temp surface to paint in
gfxASurface::gfxImageFormat format =
(GetContentType() == gfxASurface::CONTENT_COLOR) ?
gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32;
nsIntRect bounds = aRegion.GetBounds();
mUpdateSurface = gfxPlatform::GetPlatform()->
CreateOffscreenSurface(gfxIntSize(bounds.width, bounds.height), gfxASurface::ContentFromFormat(format));
mUpdateSurface->SetDeviceOffset(gfxPoint(-bounds.x, -bounds.y));
return mUpdateSurface;
}
@ -871,10 +820,9 @@ TiledTextureImage::EndUpdate()
// upload tiles from temp surface
for (unsigned i = 0; i < mImages.Length(); i++) {
int xPos = (i % mColumns) * mTileSize;
int yPos = (i / mColumns) * mTileSize;
unsigned int xPos = (i % mColumns) * mTileSize;
unsigned int yPos = (i / mColumns) * mTileSize;
nsIntRect imageRect = nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize());
nsIntRegion subregion;
subregion.And(mUpdateRegion, imageRect);
if (subregion.IsEmpty())
@ -894,7 +842,6 @@ TiledTextureImage::EndUpdate()
mInUpdate = PR_FALSE;
mShaderType = mImages[0]->GetShaderProgramType();
mIsRGBFormat = mImages[0]->IsRGB();
mTextureState = Valid;
}
void TiledTextureImage::BeginTileIteration()
@ -954,11 +901,6 @@ void TiledTextureImage::Resize(const nsIntSize& aSize)
mTextureState = Allocated;
}
PRUint32 TiledTextureImage::GetTileCount()
{
return mImages.Length();
}
PRBool
GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize)
{

View File

@ -193,15 +193,6 @@ public:
* followed by EndUpdate().
*/
virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion) = 0;
/**
* Retrieves the region that will require updating, given a
* region that needs to be updated. This can be used for
* making decisions about updating before calling BeginUpdate().
*
* |aRegion| is an inout param.
*/
virtual void GetUpdateRegion(nsIntRegion& aForRegion) {
};
/**
* Finish the active update and synchronize with the server, if
* necessary.
@ -227,11 +218,6 @@ public:
};
virtual GLuint GetTextureID() = 0;
virtual PRUint32 GetTileCount() {
return 1;
};
/**
* Set this TextureImage's size, and ensure a texture has been
* allocated. Must not be called between BeginUpdate and EndUpdate.
@ -362,7 +348,6 @@ public:
virtual void BindTexture(GLenum aTextureUnit);
virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion);
virtual void GetUpdateRegion(nsIntRegion& aForRegion);
virtual void EndUpdate();
virtual bool DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom = nsIntPoint(0,0));
virtual GLuint GetTextureID() { return mTexture; };
@ -407,10 +392,8 @@ public:
~TiledTextureImage();
void DumpDiv();
virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion);
virtual void GetUpdateRegion(nsIntRegion& aForRegion);
virtual void EndUpdate();
virtual void Resize(const nsIntSize& aSize);
virtual PRUint32 GetTileCount();
virtual void BeginTileIteration();
virtual PRBool NextTile();
virtual nsIntRect GetTileRect();
@ -569,6 +552,8 @@ public:
virtual void WindowDestroyed() {}
virtual void ReleaseSurface() {}
void *GetUserData(void *aKey) {
void *result = nsnull;
mUserData.Get(aKey, &result);

View File

@ -695,7 +695,9 @@ public:
#endif
sEGLLibrary.fDestroyContext(EGL_DISPLAY(), mContext);
sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
if (mSurface) {
sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
}
}
GLContextType GetContextType() {
@ -783,7 +785,7 @@ public:
// Assume that EGL has the same problem as WGL does,
// where MakeCurrent with an already-current context is
// still expensive.
if (aForce || sEGLLibrary.fGetCurrentContext() != mContext) {
if (!mSurface || aForce || sEGLLibrary.fGetCurrentContext() != mContext) {
if (mGLWidget) {
#ifdef MOZ_WIDGET_QT
static_cast<QGLWidget*>(mGLWidget)->makeCurrent();
@ -791,6 +793,12 @@ public:
succeeded = PR_FALSE;
#endif
} else {
#ifndef MOZ_WIDGET_QT
if (!mSurface) {
EGLConfig config = CreateConfig();
mSurface = CreateSurfaceForWindow(NULL, config);
}
#endif
succeeded = sEGLLibrary.fMakeCurrent(EGL_DISPLAY(),
mSurface, mSurface,
mContext);
@ -810,8 +818,7 @@ public:
#else
virtual PRBool
RenewSurface() {
sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
ReleaseSurface();
EGLConfig config = CreateConfig();
mSurface = CreateSurfaceForWindow(NULL, config);
@ -821,6 +828,18 @@ public:
}
#endif
#ifndef MOZ_WIDGET_QT
virtual void
ReleaseSurface() {
if (mSurface) {
sEGLLibrary.fMakeCurrent(EGL_DISPLAY(), EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT);
sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
mSurface = NULL;
}
}
#endif
PRBool SetupLookupFunction()
{
mLookupFunc = (PlatformLookupFunction)sEGLLibrary.fGetProcAddress;
@ -840,7 +859,11 @@ public:
PRBool SwapBuffers()
{
return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), mSurface);
if (mSurface) {
return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), mSurface);
} else {
return PR_FALSE;
}
}
// GLContext interface - returns Tiled Texture Image in our case
virtual already_AddRefed<TextureImage>
@ -1043,7 +1066,9 @@ GLContextEGL::ResizeOffscreen(const gfxIntSize& aNewSize)
SetOffscreenSize(aNewSize, pbsize);
sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
if (mSurface) {
sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
}
mSurface = surface;
@ -1207,28 +1232,27 @@ public:
}
}
virtual void GetUpdateRegion(nsIntRegion& aForRegion)
{
if (mTextureState != Valid) {
// if the texture hasn't been initialized yet, force the
// client to paint everything
aForRegion = nsIntRect(nsIntPoint(0, 0), mSize);
} else if (!mBackingSurface) {
// We can only draw a rectangle, not subregions due to
// the way that our texture upload functions work. If
// needed, we /could/ do multiple texture uploads if we have
// non-overlapping rects, but that's a tradeoff.
aForRegion = nsIntRegion(mUpdateRect);
}
}
virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion)
{
NS_ASSERTION(!mUpdateSurface, "BeginUpdate() without EndUpdate()?");
// determine the region the client will need to repaint
GetUpdateRegion(aRegion);
mUpdateRect = aRegion.GetBounds();
if (mTextureState != Valid) {
// if the texture hasn't been initialized yet, force the
// client to paint everything
mUpdateRect = nsIntRect(nsIntPoint(0, 0), mSize);
//printf_stderr("v Forcing full paint\n");
aRegion = nsIntRegion(mUpdateRect);
} else {
mUpdateRect = aRegion.GetBounds();
if (!mBackingSurface) {
// We can only draw a rectangle, not subregions due to
// the way that our texture upload functions work. If
// needed, we /could/ do multiple texture uploads if we have
// non-overlapping rects, but that's a tradeoff.
aRegion = nsIntRegion(mUpdateRect);
}
}
//printf_stderr("BeginUpdate with updateRect [%d %d %d %d]\n", mUpdateRect.x, mUpdateRect.y, mUpdateRect.width, mUpdateRect.height);
if (!nsIntRect(nsIntPoint(0, 0), mSize).Contains(mUpdateRect)) {

View File

@ -112,65 +112,70 @@ GLXLibrary::EnsureInitialized()
reporter.SetSuccessful();
}
if (PR_GetEnv("MOZ_GLX_DEBUG")) {
mDebug = PR_TRUE;
}
LibrarySymbolLoader::SymLoadStruct symbols[] = {
/* functions that were in GLX 1.0 */
{ (PRFuncPtr*) &xDestroyContext, { "glXDestroyContext", NULL } },
{ (PRFuncPtr*) &xMakeCurrent, { "glXMakeCurrent", NULL } },
{ (PRFuncPtr*) &xSwapBuffers, { "glXSwapBuffers", NULL } },
{ (PRFuncPtr*) &xQueryVersion, { "glXQueryVersion", NULL } },
{ (PRFuncPtr*) &xGetCurrentContext, { "glXGetCurrentContext", NULL } },
{ (PRFuncPtr*) &xWaitGL, { "glXWaitGL", NULL } },
{ (PRFuncPtr*) &xDestroyContextInternal, { "glXDestroyContext", NULL } },
{ (PRFuncPtr*) &xMakeCurrentInternal, { "glXMakeCurrent", NULL } },
{ (PRFuncPtr*) &xSwapBuffersInternal, { "glXSwapBuffers", NULL } },
{ (PRFuncPtr*) &xQueryVersionInternal, { "glXQueryVersion", NULL } },
{ (PRFuncPtr*) &xGetCurrentContextInternal, { "glXGetCurrentContext", NULL } },
{ (PRFuncPtr*) &xWaitGLInternal, { "glXWaitGL", NULL } },
{ (PRFuncPtr*) &xWaitXInternal, { "glXWaitX", NULL } },
/* functions introduced in GLX 1.1 */
{ (PRFuncPtr*) &xQueryExtensionsString, { "glXQueryExtensionsString", NULL } },
{ (PRFuncPtr*) &xGetClientString, { "glXGetClientString", NULL } },
{ (PRFuncPtr*) &xQueryServerString, { "glXQueryServerString", NULL } },
{ (PRFuncPtr*) &xQueryExtensionsStringInternal, { "glXQueryExtensionsString", NULL } },
{ (PRFuncPtr*) &xGetClientStringInternal, { "glXGetClientString", NULL } },
{ (PRFuncPtr*) &xQueryServerStringInternal, { "glXQueryServerString", NULL } },
{ NULL, { NULL } }
};
LibrarySymbolLoader::SymLoadStruct symbols13[] = {
/* functions introduced in GLX 1.3 */
{ (PRFuncPtr*) &xChooseFBConfig, { "glXChooseFBConfig", NULL } },
{ (PRFuncPtr*) &xGetFBConfigAttrib, { "glXGetFBConfigAttrib", NULL } },
{ (PRFuncPtr*) &xChooseFBConfigInternal, { "glXChooseFBConfig", NULL } },
{ (PRFuncPtr*) &xGetFBConfigAttribInternal, { "glXGetFBConfigAttrib", NULL } },
// WARNING: xGetFBConfigs not set in symbols13_ext
{ (PRFuncPtr*) &xGetFBConfigs, { "glXGetFBConfigs", NULL } },
{ (PRFuncPtr*) &xGetVisualFromFBConfig, { "glXGetVisualFromFBConfig", NULL } },
{ (PRFuncPtr*) &xGetFBConfigsInternal, { "glXGetFBConfigs", NULL } },
{ (PRFuncPtr*) &xGetVisualFromFBConfigInternal, { "glXGetVisualFromFBConfig", NULL } },
// WARNING: symbols13_ext sets xCreateGLXPixmapWithConfig instead
{ (PRFuncPtr*) &xCreatePixmap, { "glXCreatePixmap", NULL } },
{ (PRFuncPtr*) &xDestroyPixmap, { "glXDestroyPixmap", NULL } },
{ (PRFuncPtr*) &xCreateNewContext, { "glXCreateNewContext", NULL } },
{ (PRFuncPtr*) &xCreatePixmapInternal, { "glXCreatePixmap", NULL } },
{ (PRFuncPtr*) &xDestroyPixmapInternal, { "glXDestroyPixmap", NULL } },
{ (PRFuncPtr*) &xCreateNewContextInternal, { "glXCreateNewContext", NULL } },
{ NULL, { NULL } }
};
LibrarySymbolLoader::SymLoadStruct symbols13_ext[] = {
/* extension equivalents for functions introduced in GLX 1.3 */
// GLX_SGIX_fbconfig extension
{ (PRFuncPtr*) &xChooseFBConfig, { "glXChooseFBConfigSGIX", NULL } },
{ (PRFuncPtr*) &xGetFBConfigAttrib, { "glXGetFBConfigAttribSGIX", NULL } },
{ (PRFuncPtr*) &xChooseFBConfigInternal, { "glXChooseFBConfigSGIX", NULL } },
{ (PRFuncPtr*) &xGetFBConfigAttribInternal, { "glXGetFBConfigAttribSGIX", NULL } },
// WARNING: no xGetFBConfigs equivalent in extensions
{ (PRFuncPtr*) &xGetVisualFromFBConfig, { "glXGetVisualFromFBConfig", NULL } },
{ (PRFuncPtr*) &xGetVisualFromFBConfigInternal, { "glXGetVisualFromFBConfig", NULL } },
// WARNING: different from symbols13:
{ (PRFuncPtr*) &xCreateGLXPixmapWithConfig, { "glXCreateGLXPixmapWithConfigSGIX", NULL } },
{ (PRFuncPtr*) &xDestroyPixmap, { "glXDestroyGLXPixmap", NULL } }, // not from ext
{ (PRFuncPtr*) &xCreateNewContext, { "glXCreateContextWithConfigSGIX", NULL } },
{ (PRFuncPtr*) &xCreateGLXPixmapWithConfigInternal, { "glXCreateGLXPixmapWithConfigSGIX", NULL } },
{ (PRFuncPtr*) &xDestroyPixmapInternal, { "glXDestroyGLXPixmap", NULL } }, // not from ext
{ (PRFuncPtr*) &xCreateNewContextInternal, { "glXCreateContextWithConfigSGIX", NULL } },
{ NULL, { NULL } }
};
LibrarySymbolLoader::SymLoadStruct symbols14[] = {
/* functions introduced in GLX 1.4 */
{ (PRFuncPtr*) &xGetProcAddress, { "glXGetProcAddress", NULL } },
{ (PRFuncPtr*) &xGetProcAddressInternal, { "glXGetProcAddress", NULL } },
{ NULL, { NULL } }
};
LibrarySymbolLoader::SymLoadStruct symbols14_ext[] = {
/* extension equivalents for functions introduced in GLX 1.4 */
// GLX_ARB_get_proc_address extension
{ (PRFuncPtr*) &xGetProcAddress, { "glXGetProcAddressARB", NULL } },
{ (PRFuncPtr*) &xGetProcAddressInternal, { "glXGetProcAddressARB", NULL } },
{ NULL, { NULL } }
};
LibrarySymbolLoader::SymLoadStruct symbols_texturefrompixmap[] = {
{ (PRFuncPtr*) &xBindTexImage, { "glXBindTexImageEXT", NULL } },
{ (PRFuncPtr*) &xReleaseTexImage, { "glXReleaseTexImageEXT", NULL } },
{ (PRFuncPtr*) &xBindTexImageInternal, { "glXBindTexImageEXT", NULL } },
{ (PRFuncPtr*) &xReleaseTexImageInternal, { "glXReleaseTexImageEXT", NULL } },
{ NULL, { NULL } }
};
@ -235,7 +240,7 @@ GLXLibrary::EnsureInitialized()
if (HasExtension(extensionsStr, "GLX_EXT_texture_from_pixmap") &&
LibrarySymbolLoader::LoadSymbols(mOGLLibrary, symbols_texturefrompixmap,
(LibrarySymbolLoader::PlatformLookupFunction)xGetProcAddress))
(LibrarySymbolLoader::PlatformLookupFunction)&xGetProcAddress))
{
mHasTextureFromPixmap = PR_TRUE;
} else {
@ -326,7 +331,7 @@ GLXLibrary::BindTexImage(GLXPixmap aPixmap)
Display *display = DefaultXDisplay();
// Make sure all X drawing to the surface has finished before binding to a texture.
XSync(DefaultXDisplay(), False);
xWaitX();
xBindTexImage(display, aPixmap, GLX_FRONT_LEFT_EXT, NULL);
}
@ -341,6 +346,289 @@ GLXLibrary::ReleaseTexImage(GLXPixmap aPixmap)
xReleaseTexImage(display, aPixmap, GLX_FRONT_LEFT_EXT);
}
#ifdef DEBUG
static int (*sOldErrorHandler)(Display *, XErrorEvent *);
ScopedXErrorHandler::ErrorEvent sErrorEvent;
static int GLXErrorHandler(Display *display, XErrorEvent *ev)
{
if (!sErrorEvent.mError.error_code) {
sErrorEvent.mError = *ev;
}
return 0;
}
void
GLXLibrary::BeforeGLXCall()
{
if (mDebug) {
sOldErrorHandler = XSetErrorHandler(GLXErrorHandler);
}
}
void
GLXLibrary::AfterGLXCall()
{
if (mDebug) {
XSync(DefaultXDisplay(), False);
if (sErrorEvent.mError.error_code) {
char buffer[2048];
XGetErrorText(DefaultXDisplay(), sErrorEvent.mError.error_code, buffer, sizeof(buffer));
printf_stderr("X ERROR: %s (%i) - Request: %i.%i, Serial: %i",
buffer,
sErrorEvent.mError.error_code,
sErrorEvent.mError.request_code,
sErrorEvent.mError.minor_code,
sErrorEvent.mError.serial);
NS_ABORT();
}
XSetErrorHandler(sOldErrorHandler);
}
}
#define BEFORE_GLX_CALL do { \
sGLXLibrary.BeforeGLXCall(); \
} while (0)
#define AFTER_GLX_CALL do { \
sGLXLibrary.AfterGLXCall(); \
} while (0)
#else
#define BEFORE_GLX_CALL do { } while(0)
#define AFTER_GLX_CALL do { } while(0)
#endif
void
GLXLibrary::xDestroyContext(Display* display, GLXContext context)
{
BEFORE_GLX_CALL;
xDestroyContextInternal(display, context);
AFTER_GLX_CALL;
}
Bool
GLXLibrary::xMakeCurrent(Display* display,
GLXDrawable drawable,
GLXContext context)
{
BEFORE_GLX_CALL;
Bool result = xMakeCurrentInternal(display, drawable, context);
AFTER_GLX_CALL;
return result;
}
GLXContext
GLXLibrary::xGetCurrentContext()
{
BEFORE_GLX_CALL;
GLXContext result = xGetCurrentContextInternal();
AFTER_GLX_CALL;
return result;
}
/* static */ void*
GLXLibrary::xGetProcAddress(const char *procName)
{
BEFORE_GLX_CALL;
void* result = sGLXLibrary.xGetProcAddressInternal(procName);
AFTER_GLX_CALL;
return result;
}
GLXFBConfig*
GLXLibrary::xChooseFBConfig(Display* display,
int screen,
const int *attrib_list,
int *nelements)
{
BEFORE_GLX_CALL;
GLXFBConfig* result = xChooseFBConfigInternal(display, screen, attrib_list, nelements);
AFTER_GLX_CALL;
return result;
}
GLXFBConfig*
GLXLibrary::xGetFBConfigs(Display* display,
int screen,
int *nelements)
{
BEFORE_GLX_CALL;
GLXFBConfig* result = xGetFBConfigsInternal(display, screen, nelements);
AFTER_GLX_CALL;
return result;
}
GLXContext
GLXLibrary::xCreateNewContext(Display* display,
GLXFBConfig config,
int render_type,
GLXContext share_list,
Bool direct)
{
BEFORE_GLX_CALL;
GLXContext result = xCreateNewContextInternal(display, config,
render_type,
share_list, direct);
AFTER_GLX_CALL;
return result;
}
XVisualInfo*
GLXLibrary::xGetVisualFromFBConfig(Display* display,
GLXFBConfig config)
{
BEFORE_GLX_CALL;
XVisualInfo* result = xGetVisualFromFBConfigInternal(display, config);
AFTER_GLX_CALL;
return result;
}
int
GLXLibrary::xGetFBConfigAttrib(Display *display,
GLXFBConfig config,
int attribute,
int *value)
{
BEFORE_GLX_CALL;
int result = xGetFBConfigAttribInternal(display, config,
attribute, value);
AFTER_GLX_CALL;
return result;
}
void
GLXLibrary::xSwapBuffers(Display *display, GLXDrawable drawable)
{
BEFORE_GLX_CALL;
xSwapBuffersInternal(display, drawable);
AFTER_GLX_CALL;
}
const char *
GLXLibrary::xQueryExtensionsString(Display *display,
int screen)
{
BEFORE_GLX_CALL;
const char *result = xQueryExtensionsStringInternal(display, screen);
AFTER_GLX_CALL;
return result;
}
const char *
GLXLibrary::xGetClientString(Display *display,
int screen)
{
BEFORE_GLX_CALL;
const char *result = xGetClientStringInternal(display, screen);
AFTER_GLX_CALL;
return result;
}
const char *
GLXLibrary::xQueryServerString(Display *display,
int screen, int name)
{
BEFORE_GLX_CALL;
const char *result = xQueryServerStringInternal(display, screen, name);
AFTER_GLX_CALL;
return result;
}
GLXPixmap
GLXLibrary::xCreatePixmap(Display *display,
GLXFBConfig config,
Pixmap pixmap,
const int *attrib_list)
{
BEFORE_GLX_CALL;
GLXPixmap result = xCreatePixmapInternal(display, config,
pixmap, attrib_list);
AFTER_GLX_CALL;
return result;
}
GLXPixmap
GLXLibrary::xCreateGLXPixmapWithConfig(Display *display,
GLXFBConfig config,
Pixmap pixmap)
{
BEFORE_GLX_CALL;
GLXPixmap result = xCreateGLXPixmapWithConfigInternal(display, config, pixmap);
AFTER_GLX_CALL;
return result;
}
void
GLXLibrary::xDestroyPixmap(Display *display, GLXPixmap pixmap)
{
BEFORE_GLX_CALL;
xDestroyPixmapInternal(display, pixmap);
AFTER_GLX_CALL;
}
GLXContext
GLXLibrary::xCreateContext(Display *display,
XVisualInfo *vis,
GLXContext shareList,
Bool direct)
{
BEFORE_GLX_CALL;
GLXContext result = xCreateContextInternal(display, vis, shareList, direct);
AFTER_GLX_CALL;
return result;
}
Bool
GLXLibrary::xQueryVersion(Display *display,
int *major,
int *minor)
{
BEFORE_GLX_CALL;
Bool result = xQueryVersionInternal(display, major, minor);
AFTER_GLX_CALL;
return result;
}
void
GLXLibrary::xBindTexImage(Display *display,
GLXDrawable drawable,
int buffer,
const int *attrib_list)
{
BEFORE_GLX_CALL;
xBindTexImageInternal(display, drawable, buffer, attrib_list);
AFTER_GLX_CALL;
}
void
GLXLibrary::xReleaseTexImage(Display *display,
GLXDrawable drawable,
int buffer)
{
BEFORE_GLX_CALL;
xReleaseTexImageInternal(display, drawable, buffer);
AFTER_GLX_CALL;
}
void
GLXLibrary::xWaitGL()
{
BEFORE_GLX_CALL;
xWaitGLInternal();
AFTER_GLX_CALL;
}
void
GLXLibrary::xWaitX()
{
BEFORE_GLX_CALL;
xWaitXInternal();
AFTER_GLX_CALL;
}
GLXLibrary sGLXLibrary;
class GLContextGLX : public GLContext
@ -466,7 +754,7 @@ TRY_AGAIN_NO_SHARING:
PRBool SetupLookupFunction()
{
mLookupFunc = (PlatformLookupFunction)sGLXLibrary.xGetProcAddress;
mLookupFunc = (PlatformLookupFunction)&GLXLibrary::xGetProcAddress;
return PR_TRUE;
}
@ -1050,3 +1338,4 @@ GLContextProviderGLX::Shutdown()
} /* namespace gl */
} /* namespace mozilla */

View File

@ -49,93 +49,64 @@ class GLXLibrary
{
public:
GLXLibrary() : mInitialized(PR_FALSE), mTriedInitializing(PR_FALSE),
mHasTextureFromPixmap(PR_FALSE), mOGLLibrary(nsnull) {}
mHasTextureFromPixmap(PR_FALSE), mDebug(PR_FALSE),
mOGLLibrary(nsnull) {}
typedef void (GLAPIENTRY * PFNGLXDESTROYCONTEXTPROC) (Display*,
GLXContext);
PFNGLXDESTROYCONTEXTPROC xDestroyContext;
typedef Bool (GLAPIENTRY * PFNGLXMAKECURRENTPROC) (Display*,
GLXDrawable,
GLXContext);
PFNGLXMAKECURRENTPROC xMakeCurrent;
typedef GLXContext (GLAPIENTRY * PFNGLXGETCURRENTCONTEXT) ();
PFNGLXGETCURRENTCONTEXT xGetCurrentContext;
typedef void* (GLAPIENTRY * PFNGLXGETPROCADDRESSPROC) (const char *);
PFNGLXGETPROCADDRESSPROC xGetProcAddress;
typedef GLXFBConfig* (GLAPIENTRY * PFNGLXCHOOSEFBCONFIG) (Display *,
int,
const int *,
int *);
PFNGLXCHOOSEFBCONFIG xChooseFBConfig;
typedef GLXFBConfig* (GLAPIENTRY * PFNGLXGETFBCONFIGS) (Display *,
int,
int *);
PFNGLXGETFBCONFIGS xGetFBConfigs;
typedef GLXContext (GLAPIENTRY * PFNGLXCREATENEWCONTEXT) (Display *,
GLXFBConfig,
int,
GLXContext,
Bool);
PFNGLXCREATENEWCONTEXT xCreateNewContext;
typedef XVisualInfo* (GLAPIENTRY * PFNGLXGETVISUALFROMFBCONFIG) (Display *,
GLXFBConfig);
PFNGLXGETVISUALFROMFBCONFIG xGetVisualFromFBConfig;
typedef int (GLAPIENTRY * PFNGLXGETFBCONFIGATTRIB) (Display *,
GLXFBConfig,
int,
int *);
PFNGLXGETFBCONFIGATTRIB xGetFBConfigAttrib;
typedef void (GLAPIENTRY * PFNGLXSWAPBUFFERS) (Display *,
GLXDrawable);
PFNGLXSWAPBUFFERS xSwapBuffers;
typedef const char * (GLAPIENTRY * PFNGLXQUERYEXTENSIONSSTRING) (Display *,
int);
PFNGLXQUERYEXTENSIONSSTRING xQueryExtensionsString;
typedef const char * (GLAPIENTRY * PFNGLXGETCLIENTSTRING) (Display *,
int);
PFNGLXGETCLIENTSTRING xGetClientString;
typedef const char * (GLAPIENTRY * PFNGLXQUERYSERVERSTRING) (Display *,
int,
int);
PFNGLXQUERYSERVERSTRING xQueryServerString;
typedef GLXPixmap (GLAPIENTRY * PFNGLXCREATEPIXMAP) (Display *,
GLXFBConfig,
Pixmap,
const int *);
PFNGLXCREATEPIXMAP xCreatePixmap;
typedef GLXPixmap (GLAPIENTRY * PFNGLXCREATEGLXPIXMAPWITHCONFIG)
(Display *,
GLXFBConfig,
Pixmap);
PFNGLXCREATEGLXPIXMAPWITHCONFIG xCreateGLXPixmapWithConfig;
typedef void (GLAPIENTRY * PFNGLXDESTROYPIXMAP) (Display *,
GLXPixmap);
PFNGLXDESTROYPIXMAP xDestroyPixmap;
typedef GLXContext (GLAPIENTRY * PFNGLXCREATECONTEXT) (Display *,
XVisualInfo *,
GLXContext,
Bool);
PFNGLXCREATECONTEXT xCreateContext;
typedef Bool (GLAPIENTRY * PFNGLXQUERYVERSION) (Display *,
int *,
int *);
PFNGLXQUERYVERSION xQueryVersion;
typedef void (GLAPIENTRY * PFNGLXBINDTEXIMAGE) (Display *,
GLXDrawable,
int,
const int *);
PFNGLXBINDTEXIMAGE xBindTexImage;
typedef void (GLAPIENTRY * PFNGLXRELEASETEXIMAGE) (Display *,
GLXDrawable,
int);
PFNGLXRELEASETEXIMAGE xReleaseTexImage;
typedef void (GLAPIENTRY * PFNGLXWAITGL) ();
PFNGLXWAITGL xWaitGL;
void xDestroyContext(Display* display, GLXContext context);
Bool xMakeCurrent(Display* display,
GLXDrawable drawable,
GLXContext context);
GLXContext xGetCurrentContext();
static void* xGetProcAddress(const char *procName);
GLXFBConfig* xChooseFBConfig(Display* display,
int screen,
const int *attrib_list,
int *nelements);
GLXFBConfig* xGetFBConfigs(Display* display,
int screen,
int *nelements);
GLXContext xCreateNewContext(Display* display,
GLXFBConfig config,
int render_type,
GLXContext share_list,
Bool direct);
XVisualInfo* xGetVisualFromFBConfig(Display* display,
GLXFBConfig config);
int xGetFBConfigAttrib(Display *display,
GLXFBConfig config,
int attribute,
int *value);
void xSwapBuffers(Display *display, GLXDrawable drawable);
const char * xQueryExtensionsString(Display *display,
int screen);
const char * xGetClientString(Display *display,
int screen);
const char * xQueryServerString(Display *display,
int screen, int name);
GLXPixmap xCreatePixmap(Display *display,
GLXFBConfig config,
Pixmap pixmap,
const int *attrib_list);
GLXPixmap xCreateGLXPixmapWithConfig(Display *display,
GLXFBConfig config,
Pixmap pixmap);
void xDestroyPixmap(Display *display, GLXPixmap pixmap);
GLXContext xCreateContext(Display *display,
XVisualInfo *vis,
GLXContext shareList,
Bool direct);
Bool xQueryVersion(Display *display,
int *major,
int *minor);
void xBindTexImage(Display *display,
GLXDrawable drawable,
int buffer,
const int *attrib_list);
void xReleaseTexImage(Display *display,
GLXDrawable drawable,
int buffer);
void xWaitGL();
void xWaitX();
PRBool EnsureInitialized();
@ -148,9 +119,105 @@ public:
PRBool SupportsTextureFromPixmap(gfxASurface* aSurface);
private:
typedef void (GLAPIENTRY * PFNGLXDESTROYCONTEXTPROC) (Display*,
GLXContext);
PFNGLXDESTROYCONTEXTPROC xDestroyContextInternal;
typedef Bool (GLAPIENTRY * PFNGLXMAKECURRENTPROC) (Display*,
GLXDrawable,
GLXContext);
PFNGLXMAKECURRENTPROC xMakeCurrentInternal;
typedef GLXContext (GLAPIENTRY * PFNGLXGETCURRENTCONTEXT) ();
PFNGLXGETCURRENTCONTEXT xGetCurrentContextInternal;
typedef void* (GLAPIENTRY * PFNGLXGETPROCADDRESSPROC) (const char *);
PFNGLXGETPROCADDRESSPROC xGetProcAddressInternal;
typedef GLXFBConfig* (GLAPIENTRY * PFNGLXCHOOSEFBCONFIG) (Display *,
int,
const int *,
int *);
PFNGLXCHOOSEFBCONFIG xChooseFBConfigInternal;
typedef GLXFBConfig* (GLAPIENTRY * PFNGLXGETFBCONFIGS) (Display *,
int,
int *);
PFNGLXGETFBCONFIGS xGetFBConfigsInternal;
typedef GLXContext (GLAPIENTRY * PFNGLXCREATENEWCONTEXT) (Display *,
GLXFBConfig,
int,
GLXContext,
Bool);
PFNGLXCREATENEWCONTEXT xCreateNewContextInternal;
typedef XVisualInfo* (GLAPIENTRY * PFNGLXGETVISUALFROMFBCONFIG) (Display *,
GLXFBConfig);
PFNGLXGETVISUALFROMFBCONFIG xGetVisualFromFBConfigInternal;
typedef int (GLAPIENTRY * PFNGLXGETFBCONFIGATTRIB) (Display *,
GLXFBConfig,
int,
int *);
PFNGLXGETFBCONFIGATTRIB xGetFBConfigAttribInternal;
typedef void (GLAPIENTRY * PFNGLXSWAPBUFFERS) (Display *,
GLXDrawable);
PFNGLXSWAPBUFFERS xSwapBuffersInternal;
typedef const char * (GLAPIENTRY * PFNGLXQUERYEXTENSIONSSTRING) (Display *,
int);
PFNGLXQUERYEXTENSIONSSTRING xQueryExtensionsStringInternal;
typedef const char * (GLAPIENTRY * PFNGLXGETCLIENTSTRING) (Display *,
int);
PFNGLXGETCLIENTSTRING xGetClientStringInternal;
typedef const char * (GLAPIENTRY * PFNGLXQUERYSERVERSTRING) (Display *,
int,
int);
PFNGLXQUERYSERVERSTRING xQueryServerStringInternal;
typedef GLXPixmap (GLAPIENTRY * PFNGLXCREATEPIXMAP) (Display *,
GLXFBConfig,
Pixmap,
const int *);
PFNGLXCREATEPIXMAP xCreatePixmapInternal;
typedef GLXPixmap (GLAPIENTRY * PFNGLXCREATEGLXPIXMAPWITHCONFIG)
(Display *,
GLXFBConfig,
Pixmap);
PFNGLXCREATEGLXPIXMAPWITHCONFIG xCreateGLXPixmapWithConfigInternal;
typedef void (GLAPIENTRY * PFNGLXDESTROYPIXMAP) (Display *,
GLXPixmap);
PFNGLXDESTROYPIXMAP xDestroyPixmapInternal;
typedef GLXContext (GLAPIENTRY * PFNGLXCREATECONTEXT) (Display *,
XVisualInfo *,
GLXContext,
Bool);
PFNGLXCREATECONTEXT xCreateContextInternal;
typedef Bool (GLAPIENTRY * PFNGLXQUERYVERSION) (Display *,
int *,
int *);
PFNGLXQUERYVERSION xQueryVersionInternal;
typedef void (GLAPIENTRY * PFNGLXBINDTEXIMAGE) (Display *,
GLXDrawable,
int,
const int *);
PFNGLXBINDTEXIMAGE xBindTexImageInternal;
typedef void (GLAPIENTRY * PFNGLXRELEASETEXIMAGE) (Display *,
GLXDrawable,
int);
PFNGLXRELEASETEXIMAGE xReleaseTexImageInternal;
typedef void (GLAPIENTRY * PFNGLXWAITGL) ();
PFNGLXWAITGL xWaitGLInternal;
typedef void (GLAPIENTRY * PFNGLXWAITX) ();
PFNGLXWAITGL xWaitXInternal;
#ifdef DEBUG
void BeforeGLXCall();
void AfterGLXCall();
#endif
PRBool mInitialized;
PRBool mTriedInitializing;
PRBool mHasTextureFromPixmap;
PRBool mDebug;
PRLibrary *mOGLLibrary;
};

View File

@ -48,7 +48,6 @@ EXTRA_DEPS += $(topsrcdir)/ipc/chromium/chromium-config.mk
DEFINES += \
-DEXCLUDE_SKIA_DEPENDENCIES \
-DCHROMIUM_MOZILLA_BUILD \
$(NULL)
LOCAL_INCLUDES += \

View File

@ -64,11 +64,9 @@ void AtExitManager::ProcessCallbacksNow() {
}
}
#ifdef CHROMIUM_MOZILLA_BUILD
// static
bool AtExitManager::AlreadyRegistered() {
return !!g_top_manager;
}
#endif
} // namespace base

View File

@ -51,9 +51,7 @@ class AtExitManager {
// is possible to register new callbacks after calling this function.
static void ProcessCallbacksNow();
#ifdef CHROMIUM_MOZILLA_BUILD
static bool AlreadyRegistered();
#endif
private:
struct CallbackAndParam {

View File

@ -196,7 +196,6 @@ inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
*ptr = value;
}
#if defined(CHROMIUM_MOZILLA_BUILD)
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
Atomic64 old_value,
Atomic64 new_value) {
@ -207,7 +206,6 @@ inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
}
return x;
}
#endif
inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
*ptr = value;

View File

@ -7,7 +7,7 @@
#ifndef BASE_BASE_SWITCHES_H_
#define BASE_BASE_SWITCHES_H_
#if defined(CHROMIUM_MOZILLA_BUILD) && defined(COMPILER_MSVC)
#if defined(COMPILER_MSVC)
#include <string.h>
#endif

View File

@ -5,8 +5,6 @@
#ifndef BASE_BASICTYPES_H_
#define BASE_BASICTYPES_H_
#ifdef CHROMIUM_MOZILLA_BUILD
// Chromium includes a prtypes.h also, but it has been modified to include
// their build_config.h as well. We can therefore test for both to determine
// if someone screws up the include order.
@ -41,8 +39,6 @@
#define _WIN32
#endif
#endif // CHROMIUM_MOZILLA_BUILD
#include <limits.h> // So we can set the bounds of our types
#include <stddef.h> // For size_t
#include <string.h> // for memcpy
@ -63,7 +59,7 @@ typedef short int16;
#define _INT32
typedef int int32;
#endif
#if !(defined(CHROMIUM_MOZILLA_BUILD) && defined(PROTYPES_H))
#ifndef PROTYPES_H
typedef long long int64;
#endif
@ -81,7 +77,7 @@ typedef unsigned short uint16;
#define _UINT32
typedef unsigned int uint32;
#endif
#if !(defined(CHROMIUM_MOZILLA_BUILD) && defined(PROTYPES_H))
#ifndef PROTYPES_H
typedef unsigned long long uint64;
#endif
@ -104,7 +100,6 @@ const int32 kint32max = (( int32) 0x7FFFFFFF);
const int64 kint64min = (( int64) GG_LONGLONG(0x8000000000000000));
const int64 kint64max = (( int64) GG_LONGLONG(0x7FFFFFFFFFFFFFFF));
#if defined(CHROMIUM_MOZILLA_BUILD)
// Platform- and hardware-dependent printf specifiers
# if defined(OS_POSIX)
# define __STDC_FORMAT_MACROS 1
@ -120,7 +115,6 @@ const int64 kint64max = (( int64) GG_LONGLONG(0x7FFFFFFFFFFFFFFF));
# define PRIu64L L"I64u"
# define PRIx64L L"I64x"
# endif
#endif // defined(CHROMIUM_MOZILLA_BUILD)
// A macro to disallow the copy constructor and operator= functions
// This should be used in the private: declarations for a class

View File

@ -65,11 +65,9 @@ class CommandLine {
return current_process_commandline_;
}
#ifdef CHROMIUM_MOZILLA_BUILD
static bool IsInitialized() {
return !!current_process_commandline_;
}
#endif
// Returns true if this command line contains the given switch.
// (Switch names are case-insensitive.)

View File

@ -144,25 +144,5 @@ void StackTrace::PrintBacktrace() {
}
void StackTrace::OutputToStream(std::ostream* os) {
#ifdef CHROMIUM_MOZILLA_BUILD
return;
#else
scoped_ptr_malloc<char*> trace_symbols(
backtrace_symbols(&trace_[0], trace_.size()));
// If we can't retrieve the symbols, print an error and just dump the raw
// addresses.
if (trace_symbols.get() == NULL) {
(*os) << "Unable get symbols for backtrace (" << strerror(errno)
<< "). Dumping raw addresses in trace:\n";
for (size_t i = 0; i < trace_.size(); ++i) {
(*os) << "\t" << trace_[i] << "\n";
}
} else {
(*os) << "Backtrace:\n";
for (size_t i = 0; i < trace_.size(); ++i) {
(*os) << "\t" << trace_symbols.get()[i] << "\n";
}
}
#endif
}

View File

@ -21,13 +21,11 @@
namespace base {
#if defined(CHROMIUM_MOZILLA_BUILD)
#define DVLOG(x) LOG(ERROR)
#define CHECK_GT DCHECK_GT
#define CHECK_LT DCHECK_LT
typedef ::Lock Lock;
typedef ::AutoLock AutoLock;
#endif
// Static table of checksums for all possible 8 bit bytes.
const uint32 Histogram::kCrcTable[256] = {0x0, 0x77073096L, 0xee0e612cL,

View File

@ -45,11 +45,6 @@
#include <string>
#include <vector>
#if defined(CHROMIUM_MOZILLA_BUILD)
#define BASE_API
#else
#include "base/base_api.h"
#endif
#include "testing/gtest/include/gtest/gtest_prod.h"
#include "base/time.h"
#include "base/lock.h"
@ -264,7 +259,7 @@ class CustomHistogram;
class Histogram;
class LinearHistogram;
class BASE_API Histogram {
class Histogram {
public:
typedef int Sample; // Used for samples (and ranges of samples).
typedef int Count; // Used to count samples in a bucket.
@ -323,7 +318,7 @@ class BASE_API Histogram {
//----------------------------------------------------------------------------
// Statistic values, developed over the life of the histogram.
class BASE_API SampleSet {
class SampleSet {
public:
explicit SampleSet();
~SampleSet();
@ -582,7 +577,7 @@ class BASE_API Histogram {
// LinearHistogram is a more traditional histogram, with evenly spaced
// buckets.
class BASE_API LinearHistogram : public Histogram {
class LinearHistogram : public Histogram {
public:
virtual ~LinearHistogram();
@ -638,7 +633,7 @@ class BASE_API LinearHistogram : public Histogram {
//------------------------------------------------------------------------------
// BooleanHistogram is a histogram for booleans.
class BASE_API BooleanHistogram : public LinearHistogram {
class BooleanHistogram : public LinearHistogram {
public:
static Histogram* FactoryGet(const std::string& name, Flags flags);
@ -655,7 +650,7 @@ class BASE_API BooleanHistogram : public LinearHistogram {
//------------------------------------------------------------------------------
// CustomHistogram is a histogram for a set of custom integers.
class BASE_API CustomHistogram : public Histogram {
class CustomHistogram : public Histogram {
public:
static Histogram* FactoryGet(const std::string& name,
@ -681,7 +676,7 @@ class BASE_API CustomHistogram : public Histogram {
// general place for histograms to register, and supports a global API for
// accessing (i.e., dumping, or graphing) the data in all the histograms.
class BASE_API StatisticsRecorder {
class StatisticsRecorder {
public:
typedef std::vector<Histogram*> Histograms;

View File

@ -72,7 +72,6 @@ class IDMap {
return data_.empty();
}
#if defined(CHROMIUM_MOZILLA_BUILD)
void Clear() {
data_.clear();
}
@ -84,7 +83,6 @@ class IDMap {
return true;
return false;
}
#endif
T* Lookup(int32 id) const {
const_iterator i = data_.find(id);

View File

@ -3,9 +3,6 @@
// found in the LICENSE file.
#include "base/logging.h"
#ifdef CHROMIUM_MOZILLA_BUILD
#include "prmem.h"
#include "prprf.h"
#include "base/string_util.h"
@ -106,570 +103,3 @@ operator<<(mozilla::Logger& log, void* p)
log.printf("%p", p);
return log;
}
#else
#if defined(OS_WIN)
#include <windows.h>
typedef HANDLE FileHandle;
typedef HANDLE MutexHandle;
#elif defined(OS_MACOSX)
#include <CoreFoundation/CoreFoundation.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <mach-o/dyld.h>
#elif defined(OS_LINUX)
#include <sys/syscall.h>
#include <time.h>
#endif
#if defined(OS_POSIX)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define MAX_PATH PATH_MAX
typedef FILE* FileHandle;
typedef pthread_mutex_t* MutexHandle;
#endif
#include <ctime>
#include <iomanip>
#include <cstring>
#include <algorithm>
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/debug_util.h"
#include "base/lock_impl.h"
#include "base/string_piece.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
namespace logging {
bool g_enable_dcheck = false;
const char* const log_severity_names[LOG_NUM_SEVERITIES] = {
"INFO", "WARNING", "ERROR", "ERROR_REPORT", "FATAL" };
int min_log_level = 0;
LogLockingState lock_log_file = LOCK_LOG_FILE;
// The default set here for logging_destination will only be used if
// InitLogging is not called. On Windows, use a file next to the exe;
// on POSIX platforms, where it may not even be possible to locate the
// executable on disk, use stderr.
#if defined(OS_WIN)
LoggingDestination logging_destination = LOG_ONLY_TO_FILE;
#elif defined(OS_POSIX)
LoggingDestination logging_destination = LOG_ONLY_TO_SYSTEM_DEBUG_LOG;
#endif
const int kMaxFilteredLogLevel = LOG_WARNING;
std::string* log_filter_prefix;
// For LOG_ERROR and above, always print to stderr.
const int kAlwaysPrintErrorLevel = LOG_ERROR;
// Which log file to use? This is initialized by InitLogging or
// will be lazily initialized to the default value when it is
// first needed.
#if defined(OS_WIN)
typedef wchar_t PathChar;
typedef std::wstring PathString;
#else
typedef char PathChar;
typedef std::string PathString;
#endif
PathString* log_file_name = NULL;
// this file is lazily opened and the handle may be NULL
FileHandle log_file = NULL;
// what should be prepended to each message?
bool log_process_id = false;
bool log_thread_id = false;
bool log_timestamp = true;
bool log_tickcount = false;
// An assert handler override specified by the client to be called instead of
// the debug message dialog and process termination.
LogAssertHandlerFunction log_assert_handler = NULL;
// An report handler override specified by the client to be called instead of
// the debug message dialog.
LogReportHandlerFunction log_report_handler = NULL;
// The lock is used if log file locking is false. It helps us avoid problems
// with multiple threads writing to the log file at the same time. Use
// LockImpl directly instead of using Lock, because Lock makes logging calls.
static LockImpl* log_lock = NULL;
// When we don't use a lock, we are using a global mutex. We need to do this
// because LockFileEx is not thread safe.
#if defined(OS_WIN)
MutexHandle log_mutex = NULL;
#elif defined(OS_POSIX)
pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif
// Helper functions to wrap platform differences.
int32 CurrentProcessId() {
#if defined(OS_WIN)
return GetCurrentProcessId();
#elif defined(OS_POSIX)
return getpid();
#endif
}
int32 CurrentThreadId() {
#if defined(OS_WIN)
return GetCurrentThreadId();
#elif defined(OS_MACOSX)
return mach_thread_self();
#elif defined(OS_LINUX)
return syscall(__NR_gettid);
#endif
}
uint64 TickCount() {
#if defined(OS_WIN)
return GetTickCount();
#elif defined(OS_MACOSX)
return mach_absolute_time();
#elif defined(OS_LINUX)
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
uint64 absolute_micro =
static_cast<int64>(ts.tv_sec) * 1000000 +
static_cast<int64>(ts.tv_nsec) / 1000;
return absolute_micro;
#endif
}
void CloseFile(FileHandle log) {
#if defined(OS_WIN)
CloseHandle(log);
#else
fclose(log);
#endif
}
void DeleteFilePath(const PathString& log_name) {
#if defined(OS_WIN)
DeleteFile(log_name.c_str());
#else
unlink(log_name.c_str());
#endif
}
// Called by logging functions to ensure that debug_file is initialized
// and can be used for writing. Returns false if the file could not be
// initialized. debug_file will be NULL in this case.
bool InitializeLogFileHandle() {
if (log_file)
return true;
if (!log_file_name) {
// Nobody has called InitLogging to specify a debug log file, so here we
// initialize the log file name to a default.
#if defined(OS_WIN)
// On Windows we use the same path as the exe.
wchar_t module_name[MAX_PATH];
GetModuleFileName(NULL, module_name, MAX_PATH);
log_file_name = new std::wstring(module_name);
std::wstring::size_type last_backslash =
log_file_name->rfind('\\', log_file_name->size());
if (last_backslash != std::wstring::npos)
log_file_name->erase(last_backslash + 1);
*log_file_name += L"debug.log";
#elif defined(OS_POSIX)
// On other platforms we just use the current directory.
log_file_name = new std::string("debug.log");
#endif
}
if (logging_destination == LOG_ONLY_TO_FILE ||
logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
#if defined(OS_WIN)
log_file = CreateFile(log_file_name->c_str(), GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
// try the current directory
log_file = CreateFile(L".\\debug.log", GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
log_file = NULL;
return false;
}
}
SetFilePointer(log_file, 0, 0, FILE_END);
#elif defined(OS_POSIX)
log_file = fopen(log_file_name->c_str(), "a");
if (log_file == NULL)
return false;
#endif
}
return true;
}
void InitLogMutex() {
#if defined(OS_WIN)
if (!log_mutex) {
// \ is not a legal character in mutex names so we replace \ with /
std::wstring safe_name(*log_file_name);
std::replace(safe_name.begin(), safe_name.end(), '\\', '/');
std::wstring t(L"Global\\");
t.append(safe_name);
log_mutex = ::CreateMutex(NULL, FALSE, t.c_str());
}
#elif defined(OS_POSIX)
// statically initialized
#endif
}
void InitLogging(const PathChar* new_log_file, LoggingDestination logging_dest,
LogLockingState lock_log, OldFileDeletionState delete_old) {
g_enable_dcheck =
CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableDCHECK);
if (log_file) {
// calling InitLogging twice or after some log call has already opened the
// default log file will re-initialize to the new options
CloseFile(log_file);
log_file = NULL;
}
lock_log_file = lock_log;
logging_destination = logging_dest;
// ignore file options if logging is disabled or only to system
if (logging_destination == LOG_NONE ||
logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG)
return;
if (!log_file_name)
log_file_name = new PathString();
*log_file_name = new_log_file;
if (delete_old == DELETE_OLD_LOG_FILE)
DeleteFilePath(*log_file_name);
if (lock_log_file == LOCK_LOG_FILE) {
InitLogMutex();
} else if (!log_lock) {
log_lock = new LockImpl();
}
InitializeLogFileHandle();
}
void SetMinLogLevel(int level) {
min_log_level = level;
}
int GetMinLogLevel() {
return min_log_level;
}
void SetLogFilterPrefix(const char* filter) {
if (log_filter_prefix) {
delete log_filter_prefix;
log_filter_prefix = NULL;
}
if (filter)
log_filter_prefix = new std::string(filter);
}
void SetLogItems(bool enable_process_id, bool enable_thread_id,
bool enable_timestamp, bool enable_tickcount) {
log_process_id = enable_process_id;
log_thread_id = enable_thread_id;
log_timestamp = enable_timestamp;
log_tickcount = enable_tickcount;
}
void SetLogAssertHandler(LogAssertHandlerFunction handler) {
log_assert_handler = handler;
}
void SetLogReportHandler(LogReportHandlerFunction handler) {
log_report_handler = handler;
}
// Displays a message box to the user with the error message in it. For
// Windows programs, it's possible that the message loop is messed up on
// a fatal error, and creating a MessageBox will cause that message loop
// to be run. Instead, we try to spawn another process that displays its
// command line. We look for "Debug Message.exe" in the same directory as
// the application. If it exists, we use it, otherwise, we use a regular
// message box.
void DisplayDebugMessage(const std::string& str) {
if (str.empty())
return;
#if defined(OS_WIN)
// look for the debug dialog program next to our application
wchar_t prog_name[MAX_PATH];
GetModuleFileNameW(NULL, prog_name, MAX_PATH);
wchar_t* backslash = wcsrchr(prog_name, '\\');
if (backslash)
backslash[1] = 0;
wcscat_s(prog_name, MAX_PATH, L"debug_message.exe");
std::wstring cmdline = base::SysUTF8ToWide(str);
if (cmdline.empty())
return;
STARTUPINFO startup_info;
memset(&startup_info, 0, sizeof(startup_info));
startup_info.cb = sizeof(startup_info);
PROCESS_INFORMATION process_info;
if (CreateProcessW(prog_name, &cmdline[0], NULL, NULL, false, 0, NULL,
NULL, &startup_info, &process_info)) {
WaitForSingleObject(process_info.hProcess, INFINITE);
CloseHandle(process_info.hThread);
CloseHandle(process_info.hProcess);
} else {
// debug process broken, let's just do a message box
MessageBoxW(NULL, &cmdline[0], L"Fatal error",
MB_OK | MB_ICONHAND | MB_TOPMOST);
}
#else
fprintf(stderr, "%s\n", str.c_str());
#endif
}
#if defined(OS_WIN)
LogMessage::SaveLastError::SaveLastError() : last_error_(::GetLastError()) {
}
LogMessage::SaveLastError::~SaveLastError() {
::SetLastError(last_error_);
}
#endif // defined(OS_WIN)
LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
int ctr)
: severity_(severity) {
Init(file, line);
}
LogMessage::LogMessage(const char* file, int line, const CheckOpString& result)
: severity_(LOG_FATAL) {
Init(file, line);
stream_ << "Check failed: " << (*result.str_);
}
LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
const CheckOpString& result)
: severity_(severity) {
Init(file, line);
stream_ << "Check failed: " << (*result.str_);
}
LogMessage::LogMessage(const char* file, int line)
: severity_(LOG_INFO) {
Init(file, line);
}
LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
: severity_(severity) {
Init(file, line);
}
// writes the common header info to the stream
void LogMessage::Init(const char* file, int line) {
// log only the filename
const char* last_slash = strrchr(file, '\\');
if (last_slash)
file = last_slash + 1;
// TODO(darin): It might be nice if the columns were fixed width.
stream_ << '[';
if (log_process_id)
stream_ << CurrentProcessId() << ':';
if (log_thread_id)
stream_ << CurrentThreadId() << ':';
if (log_timestamp) {
time_t t = time(NULL);
#if _MSC_VER >= 1400
struct tm local_time = {0};
localtime_s(&local_time, &t);
struct tm* tm_time = &local_time;
#else
struct tm* tm_time = localtime(&t);
#endif
stream_ << std::setfill('0')
<< std::setw(2) << 1 + tm_time->tm_mon
<< std::setw(2) << tm_time->tm_mday
<< '/'
<< std::setw(2) << tm_time->tm_hour
<< std::setw(2) << tm_time->tm_min
<< std::setw(2) << tm_time->tm_sec
<< ':';
}
if (log_tickcount)
stream_ << TickCount() << ':';
stream_ << log_severity_names[severity_] << ":" << file <<
"(" << line << ")] ";
message_start_ = stream_.tellp();
}
LogMessage::~LogMessage() {
// TODO(brettw) modify the macros so that nothing is executed when the log
// level is too high.
if (severity_ < min_log_level)
return;
std::string str_newline(stream_.str());
#if defined(OS_WIN)
str_newline.append("\r\n");
#else
str_newline.append("\n");
#endif
if (log_filter_prefix && severity_ <= kMaxFilteredLogLevel &&
str_newline.compare(message_start_, log_filter_prefix->size(),
log_filter_prefix->data()) != 0) {
return;
}
if (logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG ||
logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
#if defined(OS_WIN)
OutputDebugStringA(str_newline.c_str());
if (severity_ >= kAlwaysPrintErrorLevel)
#endif
// TODO(erikkay): this interferes with the layout tests since it grabs
// stderr and stdout and diffs them against known data. Our info and warn
// logs add noise to that. Ideally, the layout tests would set the log
// level to ignore anything below error. When that happens, we should
// take this fprintf out of the #else so that Windows users can benefit
// from the output when running tests from the command-line. In the
// meantime, we leave this in for Mac and Linux, but until this is fixed
// they won't be able to pass any layout tests that have info or warn logs.
// See http://b/1343647
fprintf(stderr, "%s", str_newline.c_str());
} else if (severity_ >= kAlwaysPrintErrorLevel) {
// When we're only outputting to a log file, above a certain log level, we
// should still output to stderr so that we can better detect and diagnose
// problems with unit tests, especially on the buildbots.
fprintf(stderr, "%s", str_newline.c_str());
}
// write to log file
if (logging_destination != LOG_NONE &&
logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG &&
InitializeLogFileHandle()) {
// We can have multiple threads and/or processes, so try to prevent them
// from clobbering each other's writes.
if (lock_log_file == LOCK_LOG_FILE) {
// Ensure that the mutex is initialized in case the client app did not
// call InitLogging. This is not thread safe. See below.
InitLogMutex();
#if defined(OS_WIN)
DWORD r = ::WaitForSingleObject(log_mutex, INFINITE);
DCHECK(r != WAIT_ABANDONED);
#elif defined(OS_POSIX)
pthread_mutex_lock(&log_mutex);
#endif
} else {
// use the lock
if (!log_lock) {
// The client app did not call InitLogging, and so the lock has not
// been created. We do this on demand, but if two threads try to do
// this at the same time, there will be a race condition to create
// the lock. This is why InitLogging should be called from the main
// thread at the beginning of execution.
log_lock = new LockImpl();
}
log_lock->Lock();
}
#if defined(OS_WIN)
SetFilePointer(log_file, 0, 0, SEEK_END);
DWORD num_written;
WriteFile(log_file,
static_cast<const void*>(str_newline.c_str()),
static_cast<DWORD>(str_newline.length()),
&num_written,
NULL);
#else
fprintf(log_file, "%s", str_newline.c_str());
#endif
if (lock_log_file == LOCK_LOG_FILE) {
#if defined(OS_WIN)
ReleaseMutex(log_mutex);
#elif defined(OS_POSIX)
pthread_mutex_unlock(&log_mutex);
#endif
} else {
log_lock->Unlock();
}
}
if (severity_ == LOG_FATAL) {
// display a message or break into the debugger on a fatal error
if (DebugUtil::BeingDebugged()) {
DebugUtil::BreakDebugger();
} else {
#ifndef NDEBUG
// Dump a stack trace on a fatal.
StackTrace trace;
stream_ << "\n"; // Newline to separate from log message.
trace.OutputToStream(&stream_);
#endif
if (log_assert_handler) {
// make a copy of the string for the handler out of paranoia
log_assert_handler(std::string(stream_.str()));
} else {
// Don't use the string with the newline, get a fresh version to send to
// the debug message process. We also don't display assertions to the
// user in release mode. The enduser can't do anything with this
// information, and displaying message boxes when the application is
// hosed can cause additional problems.
#ifndef NDEBUG
DisplayDebugMessage(stream_.str());
#endif
// Crash the process to generate a dump.
DebugUtil::BreakDebugger();
}
}
} else if (severity_ == LOG_ERROR_REPORT) {
// We are here only if the user runs with --enable-dcheck in release mode.
if (log_report_handler) {
log_report_handler(std::string(stream_.str()));
} else {
DisplayDebugMessage(stream_.str());
}
}
}
void CloseLogFile() {
if (!log_file)
return;
CloseFile(log_file);
log_file = NULL;
}
} // namespace logging
std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) {
return out << base::SysWideToUTF8(std::wstring(wstr));
}
#endif // CHROMIUM_MOZILLA_BUILD

View File

@ -9,9 +9,6 @@
#include <cstring>
#include "base/basictypes.h"
#ifdef CHROMIUM_MOZILLA_BUILD
#include "prlog.h"
// Replace the Chromium logging code with NSPR-based logging code and
@ -123,640 +120,4 @@ const mozilla::EmptyLog& operator <<(const mozilla::EmptyLog& log, const T&)
#endif
#define assert DLOG_ASSERT
#else
#include <sstream>
//
// Optional message capabilities
// -----------------------------
// Assertion failed messages and fatal errors are displayed in a dialog box
// before the application exits. However, running this UI creates a message
// loop, which causes application messages to be processed and potentially
// dispatched to existing application windows. Since the application is in a
// bad state when this assertion dialog is displayed, these messages may not
// get processed and hang the dialog, or the application might go crazy.
//
// Therefore, it can be beneficial to display the error dialog in a separate
// process from the main application. When the logging system needs to display
// a fatal error dialog box, it will look for a program called
// "DebugMessage.exe" in the same directory as the application executable. It
// will run this application with the message as the command line, and will
// not include the name of the application as is traditional for easier
// parsing.
//
// The code for DebugMessage.exe is only one line. In WinMain, do:
// MessageBox(NULL, GetCommandLineW(), L"Fatal Error", 0);
//
// If DebugMessage.exe is not found, the logging code will use a normal
// MessageBox, potentially causing the problems discussed above.
// Instructions
// ------------
//
// Make a bunch of macros for logging. The way to log things is to stream
// things to LOG(<a particular severity level>). E.g.,
//
// LOG(INFO) << "Found " << num_cookies << " cookies";
//
// You can also do conditional logging:
//
// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
//
// The above will cause log messages to be output on the 1st, 11th, 21st, ...
// times it is executed. Note that the special COUNTER value is used to
// identify which repetition is happening.
//
// The CHECK(condition) macro is active in both debug and release builds and
// effectively performs a LOG(FATAL) which terminates the process and
// generates a crashdump unless a debugger is attached.
//
// There are also "debug mode" logging macros like the ones above:
//
// DLOG(INFO) << "Found cookies";
//
// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
//
// All "debug mode" logging is compiled away to nothing for non-debug mode
// compiles. LOG_IF and development flags also work well together
// because the code can be compiled away sometimes.
//
// We also have
//
// LOG_ASSERT(assertion);
// DLOG_ASSERT(assertion);
//
// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion;
//
// We also override the standard 'assert' to use 'DLOG_ASSERT'.
//
// The supported severity levels for macros that allow you to specify one
// are (in increasing order of severity) INFO, WARNING, ERROR, ERROR_REPORT,
// and FATAL.
//
// Very important: logging a message at the FATAL severity level causes
// the program to terminate (after the message is logged).
//
// Note the special severity of ERROR_REPORT only available/relevant in normal
// mode, which displays error dialog without terminating the program. There is
// no error dialog for severity ERROR or below in normal mode.
//
// There is also the special severity of DFATAL, which logs FATAL in
// debug mode, ERROR_REPORT in normal mode.
namespace logging {
// Where to record logging output? A flat file and/or system debug log via
// OutputDebugString. Defaults on Windows to LOG_ONLY_TO_FILE, and on
// POSIX to LOG_ONLY_TO_SYSTEM_DEBUG_LOG (aka stderr).
enum LoggingDestination { LOG_NONE,
LOG_ONLY_TO_FILE,
LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG };
// Indicates that the log file should be locked when being written to.
// Often, there is no locking, which is fine for a single threaded program.
// If logging is being done from multiple threads or there can be more than
// one process doing the logging, the file should be locked during writes to
// make each log outut atomic. Other writers will block.
//
// All processes writing to the log file must have their locking set for it to
// work properly. Defaults to DONT_LOCK_LOG_FILE.
enum LogLockingState { LOCK_LOG_FILE, DONT_LOCK_LOG_FILE };
// On startup, should we delete or append to an existing log file (if any)?
// Defaults to APPEND_TO_OLD_LOG_FILE.
enum OldFileDeletionState { DELETE_OLD_LOG_FILE, APPEND_TO_OLD_LOG_FILE };
// Sets the log file name and other global logging state. Calling this function
// is recommended, and is normally done at the beginning of application init.
// If you don't call it, all the flags will be initialized to their default
// values, and there is a race condition that may leak a critical section
// object if two threads try to do the first log at the same time.
// See the definition of the enums above for descriptions and default values.
//
// The default log file is initialized to "debug.log" in the application
// directory. You probably don't want this, especially since the program
// directory may not be writable on an enduser's system.
#if defined(OS_WIN)
void InitLogging(const wchar_t* log_file, LoggingDestination logging_dest,
LogLockingState lock_log, OldFileDeletionState delete_old);
#elif defined(OS_POSIX)
// TODO(avi): do we want to do a unification of character types here?
void InitLogging(const char* log_file, LoggingDestination logging_dest,
LogLockingState lock_log, OldFileDeletionState delete_old);
#endif
// Sets the log level. Anything at or above this level will be written to the
// log file/displayed to the user (if applicable). Anything below this level
// will be silently ignored. The log level defaults to 0 (everything is logged)
// if this function is not called.
void SetMinLogLevel(int level);
// Gets the current log level.
int GetMinLogLevel();
// Sets the log filter prefix. Any log message below LOG_ERROR severity that
// doesn't start with this prefix with be silently ignored. The filter defaults
// to NULL (everything is logged) if this function is not called. Messages
// with severity of LOG_ERROR or higher will not be filtered.
void SetLogFilterPrefix(const char* filter);
// Sets the common items you want to be prepended to each log message.
// process and thread IDs default to off, the timestamp defaults to on.
// If this function is not called, logging defaults to writing the timestamp
// only.
void SetLogItems(bool enable_process_id, bool enable_thread_id,
bool enable_timestamp, bool enable_tickcount);
// Sets the Log Assert Handler that will be used to notify of check failures.
// The default handler shows a dialog box and then terminate the process,
// however clients can use this function to override with their own handling
// (e.g. a silent one for Unit Tests)
typedef void (*LogAssertHandlerFunction)(const std::string& str);
void SetLogAssertHandler(LogAssertHandlerFunction handler);
// Sets the Log Report Handler that will be used to notify of check failures
// in non-debug mode. The default handler shows a dialog box and continues
// the execution, however clients can use this function to override with their
// own handling.
typedef void (*LogReportHandlerFunction)(const std::string& str);
void SetLogReportHandler(LogReportHandlerFunction handler);
typedef int LogSeverity;
const LogSeverity LOG_INFO = 0;
const LogSeverity LOG_WARNING = 1;
const LogSeverity LOG_ERROR = 2;
const LogSeverity LOG_ERROR_REPORT = 3;
const LogSeverity LOG_FATAL = 4;
const LogSeverity LOG_NUM_SEVERITIES = 5;
// LOG_DFATAL_LEVEL is LOG_FATAL in debug mode, ERROR_REPORT in normal mode
#ifdef NDEBUG
const LogSeverity LOG_DFATAL_LEVEL = LOG_ERROR_REPORT;
#else
const LogSeverity LOG_DFATAL_LEVEL = LOG_FATAL;
#endif
// A few definitions of macros that don't generate much code. These are used
// by LOG() and LOG_IF, etc. Since these are used all over our code, it's
// better to have compact code for these operations.
#define COMPACT_GOOGLE_LOG_INFO \
logging::LogMessage(__FILE__, __LINE__)
#define COMPACT_GOOGLE_LOG_WARNING \
logging::LogMessage(__FILE__, __LINE__, logging::LOG_WARNING)
#define COMPACT_GOOGLE_LOG_ERROR \
logging::LogMessage(__FILE__, __LINE__, logging::LOG_ERROR)
#define COMPACT_GOOGLE_LOG_ERROR_REPORT \
logging::LogMessage(__FILE__, __LINE__, logging::LOG_ERROR_REPORT)
#define COMPACT_GOOGLE_LOG_FATAL \
logging::LogMessage(__FILE__, __LINE__, logging::LOG_FATAL)
#define COMPACT_GOOGLE_LOG_DFATAL \
logging::LogMessage(__FILE__, __LINE__, logging::LOG_DFATAL_LEVEL)
// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets
// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us
// to keep using this syntax, we define this macro to do the same thing
// as COMPACT_GOOGLE_LOG_ERROR, and also define ERROR the same way that
// the Windows SDK does for consistency.
#define ERROR 0
#define COMPACT_GOOGLE_LOG_0 \
logging::LogMessage(__FILE__, __LINE__, logging::LOG_ERROR)
// We use the preprocessor's merging operator, "##", so that, e.g.,
// LOG(INFO) becomes the token COMPACT_GOOGLE_LOG_INFO. There's some funny
// subtle difference between ostream member streaming functions (e.g.,
// ostream::operator<<(int) and ostream non-member streaming functions
// (e.g., ::operator<<(ostream&, string&): it turns out that it's
// impossible to stream something like a string directly to an unnamed
// ostream. We employ a neat hack by calling the stream() member
// function of LogMessage which seems to avoid the problem.
#define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()
#define SYSLOG(severity) LOG(severity)
#define LOG_IF(severity, condition) \
!(condition) ? (void) 0 : logging::LogMessageVoidify() & LOG(severity)
#define SYSLOG_IF(severity, condition) LOG_IF(severity, condition)
#define LOG_ASSERT(condition) \
LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
#define SYSLOG_ASSERT(condition) \
SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
// CHECK dies with a fatal error if condition is not true. It is *not*
// controlled by NDEBUG, so the check will be executed regardless of
// compilation mode.
#define CHECK(condition) \
LOG_IF(FATAL, !(condition)) << "Check failed: " #condition ". "
// A container for a string pointer which can be evaluated to a bool -
// true iff the pointer is NULL.
struct CheckOpString {
CheckOpString(std::string* str) : str_(str) { }
// No destructor: if str_ is non-NULL, we're about to LOG(FATAL),
// so there's no point in cleaning up str_.
operator bool() const { return str_ != NULL; }
std::string* str_;
};
// Build the error message string. This is separate from the "Impl"
// function template because it is not performance critical and so can
// be out of line, while the "Impl" code should be inline.
template<class t1, class t2>
std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
std::ostringstream ss;
ss << names << " (" << v1 << " vs. " << v2 << ")";
std::string* msg = new std::string(ss.str());
return msg;
}
extern std::string* MakeCheckOpStringIntInt(int v1, int v2, const char* names);
template<int, int>
std::string* MakeCheckOpString(const int& v1,
const int& v2,
const char* names) {
return MakeCheckOpStringIntInt(v1, v2, names);
}
// Plus some debug-logging macros that get compiled to nothing for production
//
// DEBUG_MODE is for uses like
// if (DEBUG_MODE) foo.CheckThatFoo();
// instead of
// #ifndef NDEBUG
// foo.CheckThatFoo();
// #endif
#ifdef OFFICIAL_BUILD
// We want to have optimized code for an official build so we remove DLOGS and
// DCHECK from the executable.
#define DLOG(severity) \
true ? (void) 0 : logging::LogMessageVoidify() & LOG(severity)
#define DLOG_IF(severity, condition) \
true ? (void) 0 : logging::LogMessageVoidify() & LOG(severity)
#define DLOG_ASSERT(condition) \
true ? (void) 0 : LOG_ASSERT(condition)
enum { DEBUG_MODE = 0 };
// This macro can be followed by a sequence of stream parameters in
// non-debug mode. The DCHECK and friends macros use this so that
// the expanded expression DCHECK(foo) << "asdf" is still syntactically
// valid, even though the expression will get optimized away.
// In order to avoid variable unused warnings for code that only uses a
// variable in a CHECK, we make sure to use the macro arguments.
#define NDEBUG_EAT_STREAM_PARAMETERS \
logging::LogMessage(__FILE__, __LINE__).stream()
#define DCHECK(condition) \
while (false && (condition)) NDEBUG_EAT_STREAM_PARAMETERS
#define DCHECK_EQ(val1, val2) \
while (false && (val1) == (val2)) NDEBUG_EAT_STREAM_PARAMETERS
#define DCHECK_NE(val1, val2) \
while (false && (val1) == (val2)) NDEBUG_EAT_STREAM_PARAMETERS
#define DCHECK_LE(val1, val2) \
while (false && (val1) == (val2)) NDEBUG_EAT_STREAM_PARAMETERS
#define DCHECK_LT(val1, val2) \
while (false && (val1) == (val2)) NDEBUG_EAT_STREAM_PARAMETERS
#define DCHECK_GE(val1, val2) \
while (false && (val1) == (val2)) NDEBUG_EAT_STREAM_PARAMETERS
#define DCHECK_GT(val1, val2) \
while (false && (val1) == (val2)) NDEBUG_EAT_STREAM_PARAMETERS
#define DCHECK_STREQ(str1, str2) \
while (false && (str1) == (str2)) NDEBUG_EAT_STREAM_PARAMETERS
#define DCHECK_STRCASEEQ(str1, str2) \
while (false && (str1) == (str2)) NDEBUG_EAT_STREAM_PARAMETERS
#define DCHECK_STRNE(str1, str2) \
while (false && (str1) == (str2)) NDEBUG_EAT_STREAM_PARAMETERS
#define DCHECK_STRCASENE(str1, str2) \
while (false && (str1) == (str2)) NDEBUG_EAT_STREAM_PARAMETERS
#else
#ifndef NDEBUG
// On a regular debug build, we want to have DCHECKS and DLOGS enabled.
#define DLOG(severity) LOG(severity)
#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
#define DLOG_ASSERT(condition) LOG_ASSERT(condition)
// debug-only checking. not executed in NDEBUG mode.
enum { DEBUG_MODE = 1 };
#define DCHECK(condition) \
LOG_IF(FATAL, !(condition)) << "Check failed: " #condition ". "
// Helper macro for binary operators.
// Don't use this macro directly in your code, use DCHECK_EQ et al below.
#define DCHECK_OP(name, op, val1, val2) \
if (logging::CheckOpString _result = \
logging::Check##name##Impl((val1), (val2), #val1 " " #op " " #val2)) \
logging::LogMessage(__FILE__, __LINE__, _result).stream()
// Helper functions for string comparisons.
// To avoid bloat, the definitions are in logging.cc.
#define DECLARE_DCHECK_STROP_IMPL(func, expected) \
std::string* Check##func##expected##Impl(const char* s1, \
const char* s2, \
const char* names);
DECLARE_DCHECK_STROP_IMPL(strcmp, true)
DECLARE_DCHECK_STROP_IMPL(strcmp, false)
DECLARE_DCHECK_STROP_IMPL(_stricmp, true)
DECLARE_DCHECK_STROP_IMPL(_stricmp, false)
#undef DECLARE_DCHECK_STROP_IMPL
// Helper macro for string comparisons.
// Don't use this macro directly in your code, use CHECK_STREQ et al below.
#define DCHECK_STROP(func, op, expected, s1, s2) \
while (CheckOpString _result = \
logging::Check##func##expected##Impl((s1), (s2), \
#s1 " " #op " " #s2)) \
LOG(FATAL) << *_result.str_
// String (char*) equality/inequality checks.
// CASE versions are case-insensitive.
//
// Note that "s1" and "s2" may be temporary strings which are destroyed
// by the compiler at the end of the current "full expression"
// (e.g. DCHECK_STREQ(Foo().c_str(), Bar().c_str())).
#define DCHECK_STREQ(s1, s2) DCHECK_STROP(strcmp, ==, true, s1, s2)
#define DCHECK_STRNE(s1, s2) DCHECK_STROP(strcmp, !=, false, s1, s2)
#define DCHECK_STRCASEEQ(s1, s2) DCHECK_STROP(_stricmp, ==, true, s1, s2)
#define DCHECK_STRCASENE(s1, s2) DCHECK_STROP(_stricmp, !=, false, s1, s2)
#define DCHECK_INDEX(I,A) DCHECK(I < (sizeof(A)/sizeof(A[0])))
#define DCHECK_BOUND(B,A) DCHECK(B <= (sizeof(A)/sizeof(A[0])))
#else // NDEBUG
// On a regular release build we want to be able to enable DCHECKS through the
// command line.
#define DLOG(severity) \
true ? (void) 0 : logging::LogMessageVoidify() & LOG(severity)
#define DLOG_IF(severity, condition) \
true ? (void) 0 : logging::LogMessageVoidify() & LOG(severity)
#define DLOG_ASSERT(condition) \
true ? (void) 0 : LOG_ASSERT(condition)
enum { DEBUG_MODE = 0 };
// This macro can be followed by a sequence of stream parameters in
// non-debug mode. The DCHECK and friends macros use this so that
// the expanded expression DCHECK(foo) << "asdf" is still syntactically
// valid, even though the expression will get optimized away.
#define NDEBUG_EAT_STREAM_PARAMETERS \
logging::LogMessage(__FILE__, __LINE__).stream()
// Set to true in InitLogging when we want to enable the dchecks in release.
extern bool g_enable_dcheck;
#define DCHECK(condition) \
!logging::g_enable_dcheck ? void (0) : \
LOG_IF(ERROR_REPORT, !(condition)) << "Check failed: " #condition ". "
// Helper macro for binary operators.
// Don't use this macro directly in your code, use DCHECK_EQ et al below.
#define DCHECK_OP(name, op, val1, val2) \
if (logging::g_enable_dcheck) \
if (logging::CheckOpString _result = \
logging::Check##name##Impl((val1), (val2), #val1 " " #op " " #val2)) \
logging::LogMessage(__FILE__, __LINE__, logging::LOG_ERROR_REPORT, \
_result).stream()
#define DCHECK_STREQ(str1, str2) \
while (false) NDEBUG_EAT_STREAM_PARAMETERS
#define DCHECK_STRCASEEQ(str1, str2) \
while (false) NDEBUG_EAT_STREAM_PARAMETERS
#define DCHECK_STRNE(str1, str2) \
while (false) NDEBUG_EAT_STREAM_PARAMETERS
#define DCHECK_STRCASENE(str1, str2) \
while (false) NDEBUG_EAT_STREAM_PARAMETERS
#endif // NDEBUG
// Helper functions for DCHECK_OP macro.
// The (int, int) specialization works around the issue that the compiler
// will not instantiate the template version of the function on values of
// unnamed enum type - see comment below.
#define DEFINE_DCHECK_OP_IMPL(name, op) \
template <class t1, class t2> \
inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
const char* names) { \
if (v1 op v2) return NULL; \
else return MakeCheckOpString(v1, v2, names); \
} \
inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
if (v1 op v2) return NULL; \
else return MakeCheckOpString(v1, v2, names); \
}
DEFINE_DCHECK_OP_IMPL(EQ, ==)
DEFINE_DCHECK_OP_IMPL(NE, !=)
DEFINE_DCHECK_OP_IMPL(LE, <=)
DEFINE_DCHECK_OP_IMPL(LT, < )
DEFINE_DCHECK_OP_IMPL(GE, >=)
DEFINE_DCHECK_OP_IMPL(GT, > )
#undef DEFINE_DCHECK_OP_IMPL
// Equality/Inequality checks - compare two values, and log a LOG_FATAL message
// including the two values when the result is not as expected. The values
// must have operator<<(ostream, ...) defined.
//
// You may append to the error message like so:
// DCHECK_NE(1, 2) << ": The world must be ending!";
//
// We are very careful to ensure that each argument is evaluated exactly
// once, and that anything which is legal to pass as a function argument is
// legal here. In particular, the arguments may be temporary expressions
// which will end up being destroyed at the end of the apparent statement,
// for example:
// DCHECK_EQ(string("abc")[1], 'b');
//
// WARNING: These may not compile correctly if one of the arguments is a pointer
// and the other is NULL. To work around this, simply static_cast NULL to the
// type of the desired pointer.
#define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2)
#define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2)
#define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2)
#define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2)
#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)
#define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2)
#endif // OFFICIAL_BUILD
#define NOTREACHED() DCHECK(false)
// Redefine the standard assert to use our nice log files
#undef assert
#define assert(x) DLOG_ASSERT(x)
// This class more or less represents a particular log message. You
// create an instance of LogMessage and then stream stuff to it.
// When you finish streaming to it, ~LogMessage is called and the
// full message gets streamed to the appropriate destination.
//
// You shouldn't actually use LogMessage's constructor to log things,
// though. You should use the LOG() macro (and variants thereof)
// above.
class LogMessage {
public:
LogMessage(const char* file, int line, LogSeverity severity, int ctr);
// Two special constructors that generate reduced amounts of code at
// LOG call sites for common cases.
//
// Used for LOG(INFO): Implied are:
// severity = LOG_INFO, ctr = 0
//
// Using this constructor instead of the more complex constructor above
// saves a couple of bytes per call site.
LogMessage(const char* file, int line);
// Used for LOG(severity) where severity != INFO. Implied
// are: ctr = 0
//
// Using this constructor instead of the more complex constructor above
// saves a couple of bytes per call site.
LogMessage(const char* file, int line, LogSeverity severity);
// A special constructor used for check failures.
// Implied severity = LOG_FATAL
LogMessage(const char* file, int line, const CheckOpString& result);
// A special constructor used for check failures, with the option to
// specify severity.
LogMessage(const char* file, int line, LogSeverity severity,
const CheckOpString& result);
~LogMessage();
std::ostream& stream() { return stream_; }
private:
void Init(const char* file, int line);
LogSeverity severity_;
std::ostringstream stream_;
size_t message_start_; // Offset of the start of the message (past prefix
// info).
#if defined(OS_WIN)
// Stores the current value of GetLastError in the constructor and restores
// it in the destructor by calling SetLastError.
// This is useful since the LogMessage class uses a lot of Win32 calls
// that will lose the value of GLE and the code that called the log function
// will have lost the thread error value when the log call returns.
class SaveLastError {
public:
SaveLastError();
~SaveLastError();
unsigned long get_error() const { return last_error_; }
protected:
unsigned long last_error_;
};
SaveLastError last_error_;
#endif
DISALLOW_COPY_AND_ASSIGN(LogMessage);
};
// A non-macro interface to the log facility; (useful
// when the logging level is not a compile-time constant).
inline void LogAtLevel(int const log_level, std::string const &msg) {
LogMessage(__FILE__, __LINE__, log_level).stream() << msg;
}
// This class is used to explicitly ignore values in the conditional
// logging macros. This avoids compiler warnings like "value computed
// is not used" and "statement has no effect".
class LogMessageVoidify {
public:
LogMessageVoidify() { }
// This has to be an operator with a precedence lower than << but
// higher than ?:
void operator&(std::ostream&) { }
};
// Closes the log file explicitly if open.
// NOTE: Since the log file is opened as necessary by the action of logging
// statements, there's no guarantee that it will stay closed
// after this call.
void CloseLogFile();
} // namespace logging
// These functions are provided as a convenience for logging, which is where we
// use streams (it is against Google style to use streams in other places). It
// is designed to allow you to emit non-ASCII Unicode strings to the log file,
// which is normally ASCII. It is relatively slow, so try not to use it for
// common cases. Non-ASCII characters will be converted to UTF-8 by these
// operators.
std::ostream& operator<<(std::ostream& out, const wchar_t* wstr);
inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) {
return out << wstr.c_str();
}
// The NOTIMPLEMENTED() macro annotates codepaths which have
// not been implemented yet.
//
// The implementation of this macro is controlled by NOTIMPLEMENTED_POLICY:
// 0 -- Do nothing (stripped by compiler)
// 1 -- Warn at compile time
// 2 -- Fail at compile time
// 3 -- Fail at runtime (DCHECK)
// 4 -- [default] LOG(ERROR) at runtime
// 5 -- LOG(ERROR) at runtime, only once per call-site
#ifndef NOTIMPLEMENTED_POLICY
// Select default policy: LOG(ERROR)
#define NOTIMPLEMENTED_POLICY 4
#endif
#if defined(COMPILER_GCC)
// On Linux, with GCC, we can use __PRETTY_FUNCTION__ to get the demangled name
// of the current function in the NOTIMPLEMENTED message.
#define NOTIMPLEMENTED_MSG "Not implemented reached in " << __PRETTY_FUNCTION__
#else
#define NOTIMPLEMENTED_MSG "NOT IMPLEMENTED"
#endif
#if NOTIMPLEMENTED_POLICY == 0
#define NOTIMPLEMENTED() ;
#elif NOTIMPLEMENTED_POLICY == 1
// TODO, figure out how to generate a warning
#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
#elif NOTIMPLEMENTED_POLICY == 2
#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
#elif NOTIMPLEMENTED_POLICY == 3
#define NOTIMPLEMENTED() NOTREACHED()
#elif NOTIMPLEMENTED_POLICY == 4
#define NOTIMPLEMENTED() LOG(ERROR) << NOTIMPLEMENTED_MSG
#elif NOTIMPLEMENTED_POLICY == 5
#define NOTIMPLEMENTED() do {\
static int count = 0;\
LOG_IF(ERROR, 0 == count++) << NOTIMPLEMENTED_MSG;\
} while(0)
#endif
#endif // CHROMIUM_MOZILLA_BUILD
#endif // BASE_LOGGING_H_

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