merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2016-12-14 16:41:28 +01:00
commit fd4709f9c1
54 changed files with 788 additions and 680 deletions

View File

@ -403,9 +403,10 @@ DocAccessibleParent::RecvShutdown()
{
Destroy();
if (!static_cast<dom::TabParent*>(Manager())->IsDestroyed()) {
auto mgr = static_cast<dom::TabParent*>(Manager());
if (!mgr->IsDestroyed()) {
if (!PDocAccessibleParent::Send__delete__(this)) {
return IPC_FAIL_NO_REASON(this);
return IPC_FAIL_NO_REASON(mgr);
}
}

View File

@ -317,62 +317,7 @@ Target.prototype = {
},
_logHistogram(metric) {
if (!developerHUD._telemetry || metric.skipTelemetry) {
return;
}
metric.appName = this.appName;
if (!metric.appName) {
return;
}
let metricName = metric.name.toUpperCase();
let metricAppName = metric.appName.toUpperCase();
if (!metric.custom) {
let keyedMetricName = 'DEVTOOLS_HUD_' + metricName;
try {
let keyed = Services.telemetry.getKeyedHistogramById(keyedMetricName);
if (keyed) {
keyed.add(metric.appName, parseInt(metric.value, 10));
developerHUD._histograms.add(keyedMetricName);
telemetryDebug(keyedMetricName, metric.value, metric.appName);
}
} catch(err) {
console.error('Histogram error is metricname added to histograms.json:'
+ keyedMetricName);
}
} else {
let histogramName = CUSTOM_HISTOGRAM_PREFIX + metricAppName + '_'
+ metricName;
// This is a call to add a value to an existing histogram.
if (typeof metric.value !== 'undefined') {
Services.telemetry.getAddonHistogram(metricAppName,
CUSTOM_HISTOGRAM_PREFIX + metricName).add(parseInt(metric.value, 10));
telemetryDebug(histogramName, metric.value);
return;
}
// The histogram already exists and are not adding data to it.
if (developerHUD._customHistograms.has(histogramName)) {
return;
}
// This is a call to create a new histogram.
try {
let metricType = parseInt(metric.type, 10);
if (metricType === Services.telemetry.HISTOGRAM_COUNT) {
Services.telemetry.registerAddonHistogram(metricAppName,
CUSTOM_HISTOGRAM_PREFIX + metricName, metricType);
} else {
Services.telemetry.registerAddonHistogram(metricAppName,
CUSTOM_HISTOGRAM_PREFIX + metricName, metricType, metric.min,
metric.max, metric.buckets);
}
developerHUD._customHistograms.add(histogramName);
} catch (err) {
console.error('Histogram error: ' + err);
}
}
//method left as no-op as histograms are not in use anymore.
}
};

View File

@ -1147,7 +1147,7 @@ var gBrowserInit = {
// we are swapping in.
gBrowser.updateBrowserRemoteness(gBrowser.selectedBrowser,
tabToOpen.linkedBrowser.isRemoteBrowser,
tabToOpen.linkedBrowser.remoteType);
{ remoteType: tabToOpen.linkedBrowser.remoteType });
gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, tabToOpen);
} catch (e) {
Cu.reportError(e);
@ -4254,13 +4254,13 @@ var XULBrowserWindow = {
forceInitialBrowserRemote: function(aRemoteType) {
let initBrowser =
document.getAnonymousElementByAttribute(gBrowser, "anonid", "initialBrowser");
gBrowser.updateBrowserRemoteness(initBrowser, true, aRemoteType, null);
gBrowser.updateBrowserRemoteness(initBrowser, true, { remoteType: aRemoteType });
},
forceInitialBrowserNonRemote: function(aOpener) {
let initBrowser =
document.getAnonymousElementByAttribute(gBrowser, "anonid", "initialBrowser");
gBrowser.updateBrowserRemoteness(initBrowser, false, E10SUtils.NOT_REMOTE, aOpener);
gBrowser.updateBrowserRemoteness(initBrowser, false, { opener: aOpener });
},
setDefaultStatus: function(status) {
@ -4669,6 +4669,17 @@ var XULBrowserWindow = {
if (loadingDone)
return;
this.onStatusChange(gBrowser.webProgress, null, 0, aMessage);
},
navigateAndRestoreByIndex: function XWB_navigateAndRestoreByIndex(aBrowser, aIndex) {
let tab = gBrowser.getTabForBrowser(aBrowser);
if (tab) {
SessionStore.navigateAndRestore(tab, {}, aIndex);
return;
}
throw new Error("Trying to navigateAndRestore a browser which was " +
"not attached to this tabbrowser is unsupported");
}
};

View File

@ -1669,38 +1669,37 @@
<method name="updateBrowserRemoteness">
<parameter name="aBrowser"/>
<parameter name="aShouldBeRemote"/>
<parameter name="aNewRemoteType"/>
<parameter name="aOpener"/>
<parameter name="aFreshProcess"/>
<parameter name="aOptions"/>
<body>
<![CDATA[
aOptions = aOptions || {};
let isRemote = aBrowser.getAttribute("remote") == "true";
if (!gMultiProcessBrowser && aShouldBeRemote) {
throw new Error("Cannot switch to remote browser in a window " +
"without the remote tabs load context.");
}
let isRemote = aBrowser.getAttribute("remote") == "true";
// If going remote and no aNewRemoteType then use default.
if (aShouldBeRemote && !aNewRemoteType) {
aNewRemoteType = E10SUtils.DEFAULT_REMOTE_TYPE;
// Default values for remoteType
if (!aOptions.remoteType) {
aOptions.remoteType = aShouldBeRemote ? E10SUtils.DEFAULT_REMOTE_TYPE : E10SUtils.NOT_REMOTE;
}
// If we are passed an opener, we must be making the browser non-remote, and
// if the browser is _currently_ non-remote, we need the openers to match,
// because it is already too late to change it.
if (aOpener) {
if (aOptions.opener) {
if (aShouldBeRemote) {
throw new Error("Cannot set an opener on a browser which should be remote!");
}
if (!isRemote && aBrowser.contentWindow.opener != aOpener) {
if (!isRemote && aBrowser.contentWindow.opener != aOptions.opener) {
throw new Error("Cannot change opener on an already non-remote browser!");
}
}
// Abort if we're not going to change anything
if (isRemote == aShouldBeRemote && !aFreshProcess &&
(!isRemote || aBrowser.getAttribute("remoteType") == aNewRemoteType)) {
if (isRemote == aShouldBeRemote && !aOptions.newFrameloader && !aOptions.freshProcess &&
(!isRemote || aBrowser.getAttribute("remoteType") == aOptions.remoteType)) {
return false;
}
@ -1739,7 +1738,7 @@
parent.removeChild(aBrowser);
if (aShouldBeRemote) {
aBrowser.setAttribute("remote", "true");
aBrowser.setAttribute("remoteType", aNewRemoteType);
aBrowser.setAttribute("remoteType", aOptions.remoteType);
} else {
aBrowser.setAttribute("remote", "false");
aBrowser.removeAttribute("remoteType");
@ -1749,13 +1748,15 @@
// turns this normal property into a field.
aBrowser.relatedBrowser = relatedBrowser;
// Set the opener window on the browser, such that when the frame
// loader is created the opener is set correctly.
aBrowser.presetOpenerWindow(aOpener);
if (aOptions.opener) {
// Set the opener window on the browser, such that when the frame
// loader is created the opener is set correctly.
aBrowser.presetOpenerWindow(aOptions.opener);
}
// Set the freshProcess attribute so that the frameloader knows to
// create a new process
if (aFreshProcess) {
if (aOptions.freshProcess) {
aBrowser.setAttribute("freshProcess", "true");
}
@ -1830,24 +1831,24 @@
<method name="updateBrowserRemotenessByURL">
<parameter name="aBrowser"/>
<parameter name="aURL"/>
<parameter name="aFreshProcess"/>
<parameter name="aOptions"/>
<body>
<![CDATA[
aOptions = aOptions || {};
if (!gMultiProcessBrowser)
return this.updateBrowserRemoteness(aBrowser, false);
// If this URL can't load in the current browser then flip it to the
// correct type.
let currentRemoteType = aBrowser.remoteType;
let requiredRemoteType =
aOptions.remoteType =
E10SUtils.getRemoteTypeForURI(aURL, gMultiProcessBrowser,
currentRemoteType);
if (currentRemoteType != requiredRemoteType || aFreshProcess) {
return this.updateBrowserRemoteness(aBrowser,
!!requiredRemoteType,
requiredRemoteType,
/* aOpener */ null,
aFreshProcess);
if (currentRemoteType != aOptions.remoteType ||
aOptions.freshProcess || aOptions.newFrameloader) {
let remote = aOptions.remoteType != E10SUtils.NOT_REMOTE;
return this.updateBrowserRemoteness(aBrowser, remote, aOptions);
}
return false;
@ -2525,6 +2526,13 @@
var browser = this.getBrowserForTab(aTab);
// Start closing the FrameLoaderOwners which are inactive, so that
// they are cleaned up as well.
let frameLoader = browser.frameLoader;
if (frameLoader && frameLoader.groupedSessionHistory) {
frameLoader.groupedSessionHistory.closeInactiveFrameLoaderOwners();
}
if (!aTab._pendingPermitUnload && !aAdoptedByTab && !aSkipPermitUnload) {
// We need to block while calling permitUnload() because it
// processes the event queue and may lead to another removeTab()
@ -2916,11 +2924,29 @@
<method name="swapBrowsers">
<parameter name="aOurTab"/>
<parameter name="aOtherBrowser"/>
<parameter name="aOtherTab"/>
<parameter name="aFlags"/>
<body>
<![CDATA[
this._swapBrowserDocShells(aOurTab, aOtherBrowser, aFlags);
let otherBrowser = aOtherTab.linkedBrowser;
let otherTabBrowser = otherBrowser.getTabBrowser();
// We aren't closing the other tab so, we also need to swap its tablisteners.
let filter = otherTabBrowser._tabFilters.get(aOtherTab);
let tabListener = otherTabBrowser._tabListeners.get(aOtherTab);
otherBrowser.webProgress.removeProgressListener(filter);
filter.removeProgressListener(tabListener);
// Perform the docshell swap through the common mechanism.
this._swapBrowserDocShells(aOurTab, otherBrowser, aFlags);
// Restore the listeners for the swapped in tab.
tabListener = otherTabBrowser.mTabProgressListener(aOtherTab, otherBrowser, false, false);
otherTabBrowser._tabListeners.set(aOtherTab, tabListener);
const notifyAll = Ci.nsIWebProgress.NOTIFY_ALL;
filter.addProgressListener(tabListener, notifyAll);
otherBrowser.webProgress.addProgressListener(filter, notifyAll);
]]>
</body>
</method>

View File

@ -492,3 +492,5 @@ tags = mcb
[browser_newwindow_focus.js]
skip-if = (os == "linux" && !e10s) # Bug 1263254 - Perma fails on Linux without e10s for some reason.
[browser_bug1299667.js]
[browser_close_dependent_tabs.js]
skip-if = !e10s # GroupedSHistory is e10s-only

View File

@ -0,0 +1,51 @@
add_task(function* () {
yield SpecialPowers.pushPrefEnv({
set: [["browser.groupedhistory.enabled", true]]
});
// Wait for a process change and then fulfil the promise.
function awaitProcessChange(browser) {
return new Promise(resolve => {
browser.addEventListener("BrowserChangedProcess", function bcp(e) {
browser.removeEventListener("BrowserChangedProcess", bcp);
ok(true, "The browser changed process!");
resolve();
});
});
}
let tab2;
// Test 1: Create prerendered browser, and don't switch to it, then close the tab
yield BrowserTestUtils.withNewTab({ gBrowser, url: "data:text/html,a" }, function* (browser1) {
// Set up the grouped SHEntry setup
tab2 = gBrowser.loadOneTab("data:text/html,b", {
referrerPolicy: Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT,
allowThirdPartyFixup: true,
relatedToCurrent: true,
isPrerendered: true,
});
});
// At this point tab2 should be closed
todo(!tab2.linkedBrowser, "The new tab should be closed");
yield BrowserTestUtils.removeTab(tab2); // XXX: Shouldn't be needed once the todo is fixed
// Test 2: Create prerendered browser, switch to it, then close the tab
yield BrowserTestUtils.withNewTab({ gBrowser, url: "data:text/html,a" }, function* (browser1) {
// Set up the grouped SHEntry setup
tab2 = gBrowser.loadOneTab("data:text/html,b", {
referrerPolicy: Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT,
allowThirdPartyFixup: true,
relatedToCurrent: true,
isPrerendered: true,
});
yield BrowserTestUtils.browserLoaded(tab2.linkedBrowser);
browser1.frameLoader.appendPartialSessionHistoryAndSwap(
tab2.linkedBrowser.frameLoader);
yield awaitProcessChange(browser1);
});
// At this point tab2 should be closed
ok(!tab2.linkedBrowser, "The new tab should be closed");
});

View File

@ -3611,8 +3611,17 @@ var SessionStoreInternal = {
// flip the remoteness of any browser that is not being displayed.
this.markTabAsRestoring(aTab);
// We need a new frameloader either if we are reloading into a fresh
// process, or we have a browser with a grouped session history (as we don't
// support restoring into browsers with grouped session histories directly).
let newFrameloader =
aReloadInFreshProcess || !!browser.frameLoader.groupedSessionHistory;
let isRemotenessUpdate =
tabbrowser.updateBrowserRemotenessByURL(browser, uri, aReloadInFreshProcess);
tabbrowser.updateBrowserRemotenessByURL(browser, uri, {
freshProcess: aReloadInFreshProcess,
newFrameloader: newFrameloader,
});
if (isRemotenessUpdate) {
// We updated the remoteness, so we need to send the history down again.
//

View File

@ -32,8 +32,8 @@
},
{
"version": "clang 4.0pre/r286542",
"size": 206088429,
"digest": "a6de709a5097d98084b6111e340f53cd8397736f783aa6f76c9d45bcb694d3983ab3b7aea7f96756fcc4ee44f7b0e57df5ebabbd59242cd51942742fe1769d9a",
"size": 222604502,
"digest": "cea6119131adb66e0b7ec5030b00922ac95e4e97249fcab9561a848ea60b7f80536c9171a07136afcb79decbcdb20099a5e7ee493013710b8ba5ae072ad40851",
"algorithm": "sha512",
"filename": "clang.tar.bz2",
"unpack": true

View File

@ -33,8 +33,8 @@
},
{
"version": "clang 4.0pre/r286542",
"size": 210049255,
"digest": "8da8c653ea1948c13aa152cf0b1b0fa94e9619c49006ec80cc625d33cbf2dafa3533764f38fc0213e469cc786a738e5099f0e39d52e30f9a711718e8a3124311",
"size": 226755339,
"digest": "3c598607c36e70788ca7dbdf0d835f9e44fbcaa7b1ed77ef9971d743a5a230bebc0ccd2bcdf97f63ed4546d1b83f4c3556f35c30589c755aaaefbd674f750e22",
"algorithm": "sha512",
"filename": "clang.tar.bz2",
"unpack": true

View File

@ -137,6 +137,11 @@ def install_libgcc(gcc_dir, clang_dir):
copy_dir_contents(include_dir, clang_include_dir)
def install_import_library(build_dir, clang_dir):
shutil.copy2(os.path.join(build_dir, "lib", "clang.lib"),
os.path.join(clang_dir, "lib"))
def svn_co(source_dir, url, directory, revision):
run_in(source_dir, ["svn", "co", "-q", "-r", revision, url, directory])
@ -211,7 +216,10 @@ def build_one_stage(cc, cxx, src_dir, stage_dir, build_libcxx,
if is_linux():
install_libgcc(gcc_dir, inst_dir)
# For some reasons the import library clang.lib of clang.exe is not
# installed, so we copy it by ourselves.
if is_windows():
install_import_library(build_dir, inst_dir)
def get_compiler(config, key):
if key not in config:

View File

@ -39,9 +39,19 @@ interface nsIGroupedSHistory : nsISupports
* corresponding to the given global index. Note it doesn't swap frameloaders,
* but rather return the target loader for the caller to swap.
*
* @param aGlobalIndex The global index to navigate to.
* @param aTargetLoaderToSwap The owner frameloader of the to-be-navigate
* partial session history.
* This function may throw NS_ERROR_NOT_AVAILABLE if the frameloader to swap
* to is dead.
*
* @param aGlobalIndex
* The global index to navigate to.
* @return The frameloader which needs to be swapped in, or null if no
* frameloader needs to be swapped.
*/
void gotoIndex(in unsigned long aGlobalIndex, out nsIFrameLoader aTargetLoaderToSwap);
nsIFrameLoader gotoIndex(in unsigned long aGlobalIndex);
/**
* Close the FrameLoaderOwners of the inactive PartialSHistories in this GlobalSHistory.
* This does not remove the PartialSHistories from the GroupedSHistory.
*/
void closeInactiveFrameLoaderOwners();
};

View File

@ -91,3 +91,5 @@ skip-if = true # Bug 1220415
[browser_timelineMarkers-04.js]
[browser_timelineMarkers-05.js]
[browser_ua_emulation.js]
[browser_grouped_shistory_dead_navigate.js]
skip-if = !e10s

View File

@ -0,0 +1,44 @@
add_task(function* () {
yield SpecialPowers.pushPrefEnv({
set: [["browser.groupedhistory.enabled", true]]
});
// Wait for a process change and then fulfil the promise.
function awaitProcessChange(browser) {
return new Promise(resolve => {
browser.addEventListener("BrowserChangedProcess", function bcp(e) {
browser.removeEventListener("BrowserChangedProcess", bcp);
ok(true, "The browser changed process!");
resolve();
});
});
}
yield BrowserTestUtils.withNewTab({ gBrowser, url: "data:text/html,a" }, function* (browser1) {
// Set up the grouped SHEntry setup
let tab2 = gBrowser.loadOneTab("data:text/html,b", {
referrerPolicy: Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT,
allowThirdPartyFixup: true,
relatedToCurrent: true,
isPrerendered: true,
});
yield BrowserTestUtils.browserLoaded(tab2.linkedBrowser);
browser1.frameLoader.appendPartialSessionHistoryAndSwap(
tab2.linkedBrowser.frameLoader);
yield awaitProcessChange(browser1);
// Close tab2 such that the back frameloader is dead
yield BrowserTestUtils.removeTab(tab2);
browser1.goBack();
yield BrowserTestUtils.browserLoaded(browser1);
yield ContentTask.spawn(browser1, null, function() {
is(content.window.location + "", "data:text/html,a");
let webNav = content.window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation);
is(webNav.canGoForward, true, "canGoForward is correct");
is(webNav.canGoBack, false, "canGoBack is correct");
});
is(browser1.frameLoader.groupedSessionHistory, null,
"browser1's session history is now complete");
});
});

View File

@ -75,11 +75,6 @@ const gMozillaSpecificProperties = {
from: "ignore",
to: "stretch-to-fit"
},
"-moz-tab-size": {
// https://drafts.csswg.org/css-text-3/#propdef-tab-size
from: "1",
to: "5"
},
"-moz-text-size-adjust": {
// https://drafts.csswg.org/css-size-adjust/#propdef-text-size-adjust
from: "none",

View File

@ -99,6 +99,9 @@ NS_IMETHODIMP
GroupedSHistory::GotoIndex(uint32_t aGlobalIndex,
nsIFrameLoader** aTargetLoaderToSwap)
{
MOZ_ASSERT(aTargetLoaderToSwap);
*aTargetLoaderToSwap = nullptr;
nsCOMPtr<nsIPartialSHistory> currentPartialHistory =
mPartialHistories[mIndexOfActivePartialHistory];
if (!currentPartialHistory) {
@ -118,7 +121,15 @@ GroupedSHistory::GotoIndex(uint32_t aGlobalIndex,
uint32_t count = partialHistory->GetCount();
if (offset <= aGlobalIndex && (offset + count) > aGlobalIndex) {
uint32_t targetIndex = aGlobalIndex - offset;
partialHistory->GetOwnerFrameLoader(aTargetLoaderToSwap);
// Check if we are trying to swap to a dead frameloader, and return
// NS_ERROR_NOT_AVAILABLE if we are.
nsCOMPtr<nsIFrameLoader> frameLoader;
partialHistory->GetOwnerFrameLoader(getter_AddRefs(frameLoader));
if (!frameLoader || frameLoader->GetIsDead()) {
return NS_ERROR_NOT_AVAILABLE;
}
if ((size_t)mIndexOfActivePartialHistory == i) {
return NS_OK;
}
@ -127,6 +138,9 @@ GroupedSHistory::GotoIndex(uint32_t aGlobalIndex,
NS_FAILED(partialHistory->OnActive(mCount, targetIndex))) {
return NS_ERROR_FAILURE;
}
// Return the target frameloader to the caller.
frameLoader.forget(aTargetLoaderToSwap);
return NS_OK;
}
}
@ -168,5 +182,18 @@ GroupedSHistory::GroupedHistoryEnabled() {
return Preferences::GetBool("browser.groupedhistory.enabled", false);
}
NS_IMETHODIMP
GroupedSHistory::CloseInactiveFrameLoaderOwners()
{
for (int32_t i = 0; i < mPartialHistories.Count(); ++i) {
if (i != mIndexOfActivePartialHistory) {
nsCOMPtr<nsIFrameLoader> loader;
mPartialHistories[i]->GetOwnerFrameLoader(getter_AddRefs(loader));
loader->RequestFrameLoaderClose();
}
}
return NS_OK;
}
} // namespace dom
} // namespace mozilla

View File

@ -76,7 +76,6 @@ CalculateNewBackPressureDelayMS(uint32_t aBacklogDepth)
TimeoutManager::TimeoutManager(nsGlobalWindow& aWindow)
: mWindow(aWindow),
mTimeoutInsertionPoint(nullptr),
mTimeoutIdCounter(1),
mTimeoutFiringDepth(0),
mRunningTimeout(nullptr),
@ -226,7 +225,7 @@ TimeoutManager::ClearTimeout(int32_t aTimerId, Timeout::Reason aReason)
uint32_t timerId = (uint32_t)aTimerId;
Timeout* timeout;
for (timeout = mTimeouts.getFirst(); timeout; timeout = timeout->getNext()) {
for (timeout = mTimeouts.GetFirst(); timeout; timeout = timeout->getNext()) {
if (timeout->mTimeoutId == timerId && timeout->mReason == aReason) {
if (timeout->mRunning) {
/* We're running from inside the timeout. Mark this
@ -296,7 +295,7 @@ TimeoutManager::RunTimeout(Timeout* aTimeout)
// whose mWhen is greater than deadline, since once that happens we know
// nothing past that point is expired.
last_expired_timeout = nullptr;
for (Timeout* timeout = mTimeouts.getFirst();
for (Timeout* timeout = mTimeouts.GetFirst();
timeout && timeout->mWhen <= deadline;
timeout = timeout->getNext()) {
if (timeout->mFiringDepth == 0) {
@ -339,12 +338,12 @@ TimeoutManager::RunTimeout(Timeout* aTimeout)
last_expired_timeout->setNext(dummy_timeout);
RefPtr<Timeout> timeoutExtraRef(dummy_timeout);
last_insertion_point = mTimeoutInsertionPoint;
// If we ever start setting mTimeoutInsertionPoint to a non-dummy timeout,
// the logic in ResetTimersForThrottleReduction will need to change.
mTimeoutInsertionPoint = dummy_timeout;
last_insertion_point = mTimeouts.InsertionPoint();
// If we ever start setting insertion point to a non-dummy timeout, the logic
// in ResetTimersForThrottleReduction will need to change.
mTimeouts.SetInsertionPoint(dummy_timeout);
for (Timeout* timeout = mTimeouts.getFirst();
for (Timeout* timeout = mTimeouts.GetFirst();
timeout != dummy_timeout && !mWindow.IsFrozen();
timeout = nextTimeout) {
nextTimeout = timeout->getNext();
@ -387,7 +386,7 @@ TimeoutManager::RunTimeout(Timeout* aTimeout)
MOZ_ASSERT(dummy_timeout->HasRefCntOne(), "dummy_timeout may leak");
Unused << timeoutExtraRef.forget().take();
mTimeoutInsertionPoint = last_insertion_point;
mTimeouts.SetInsertionPoint(last_insertion_point);
return;
}
@ -417,7 +416,7 @@ TimeoutManager::RunTimeout(Timeout* aTimeout)
timeoutExtraRef = nullptr;
MOZ_ASSERT(dummy_timeout->HasRefCntOne(), "dummy_timeout may leak");
mTimeoutInsertionPoint = last_insertion_point;
mTimeouts.SetInsertionPoint(last_insertion_point);
MaybeApplyBackPressure();
}
@ -598,15 +597,15 @@ TimeoutManager::ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS
TimeStamp now = TimeStamp::Now();
// If mTimeoutInsertionPoint is non-null, we're in the middle of firing
// timers and the timers we're planning to fire all come before
// mTimeoutInsertionPoint; mTimeoutInsertionPoint itself is a dummy timeout
// with an mWhen that may be semi-bogus. In that case, we don't need to do
// anything with mTimeoutInsertionPoint or anything before it, so should
// start at the timer after mTimeoutInsertionPoint, if there is one.
// If insertion point is non-null, we're in the middle of firing timers and
// the timers we're planning to fire all come before insertion point;
// insertion point itself is a dummy timeout with an mWhen that may be
// semi-bogus. In that case, we don't need to do anything with insertion
// point or anything before it, so should start at the timer after insertion
// point, if there is one.
// Otherwise, start at the beginning of the list.
for (Timeout* timeout = mTimeoutInsertionPoint ?
mTimeoutInsertionPoint->getNext() : mTimeouts.getFirst();
for (Timeout* timeout = mTimeouts.InsertionPoint() ?
mTimeouts.InsertionPoint()->getNext() : mTimeouts.GetFirst();
timeout; ) {
// It's important that this check be <= so that we guarantee that
// taking std::max with |now| won't make a quantity equal to
@ -687,14 +686,15 @@ TimeoutManager::ClearAllTimeouts()
Timeout* timeout;
Timeout* nextTimeout;
for (timeout = mTimeouts.getFirst(); timeout; timeout = nextTimeout) {
for (timeout = mTimeouts.GetFirst(); timeout; timeout = nextTimeout) {
/* If RunTimeout() is higher up on the stack for this
window, e.g. as a result of document.write from a timeout,
then we need to reset the list insertion point for
newly-created timeouts in case the user adds a timeout,
before we pop the stack back to RunTimeout. */
if (mRunningTimeout == timeout)
mTimeoutInsertionPoint = nullptr;
if (mRunningTimeout == timeout) {
mTimeouts.SetInsertionPoint(nullptr);
}
nextTimeout = timeout->getNext();
@ -716,18 +716,17 @@ TimeoutManager::ClearAllTimeouts()
}
// Clear out our list
mTimeouts.clear();
mTimeouts.Clear();
}
void
TimeoutManager::InsertTimeoutIntoList(Timeout* aTimeout)
{
// Start at mLastTimeout and go backwards. Don't go further than
// mTimeoutInsertionPoint, though. This optimizes for the common case of
// insertion at the end.
// Start at mLastTimeout and go backwards. Don't go further than insertion
// point, though. This optimizes for the common case of insertion at the end.
Timeout* prevSibling;
for (prevSibling = mTimeouts.getLast();
prevSibling && prevSibling != mTimeoutInsertionPoint &&
for (prevSibling = mTimeouts.GetLast();
prevSibling && prevSibling != mTimeouts.InsertionPoint() &&
// This condition needs to match the one in SetTimeoutOrInterval that
// determines whether to set mWhen or mTimeRemaining.
(mWindow.IsFrozen() ?
@ -741,7 +740,7 @@ TimeoutManager::InsertTimeoutIntoList(Timeout* aTimeout)
if (prevSibling) {
prevSibling->setNext(aTimeout);
} else {
mTimeouts.insertFront(aTimeout);
mTimeouts.InsertFront(aTimeout);
}
aTimeout->mFiringDepth = 0;
@ -775,7 +774,7 @@ TimeoutManager::EndRunningTimeout(Timeout* aTimeout)
void
TimeoutManager::UnmarkGrayTimers()
{
for (Timeout* timeout = mTimeouts.getFirst();
for (Timeout* timeout = mTimeouts.GetFirst();
timeout;
timeout = timeout->getNext()) {
if (timeout->mScriptHandler) {
@ -787,7 +786,7 @@ TimeoutManager::UnmarkGrayTimers()
void
TimeoutManager::Suspend()
{
for (Timeout* t = mTimeouts.getFirst(); t; t = t->getNext()) {
for (Timeout* t = mTimeouts.GetFirst(); t; t = t->getNext()) {
// Leave the timers with the current time remaining. This will
// cause the timers to potentially fire when the window is
// Resume()'d. Time effectively passes while suspended.
@ -810,7 +809,7 @@ TimeoutManager::Resume()
TimeStamp now = TimeStamp::Now();
DebugOnly<bool> _seenDummyTimeout = false;
for (Timeout* t = mTimeouts.getFirst(); t; t = t->getNext()) {
for (Timeout* t = mTimeouts.GetFirst(); t; t = t->getNext()) {
// There's a chance we're being called with RunTimeout on the stack in which
// case we have a dummy timeout in the list that *must not* be resumed. It
// can be identified by a null mWindow.
@ -856,7 +855,7 @@ void
TimeoutManager::Freeze()
{
TimeStamp now = TimeStamp::Now();
for (Timeout *t = mTimeouts.getFirst(); t; t = t->getNext()) {
for (Timeout *t = mTimeouts.GetFirst(); t; t = t->getNext()) {
// Save the current remaining time for this timeout. We will
// re-apply it when the window is Thaw()'d. This effectively
// shifts timers to the right as if time does not pass while
@ -879,7 +878,7 @@ TimeoutManager::Thaw()
TimeStamp now = TimeStamp::Now();
DebugOnly<bool> _seenDummyTimeout = false;
for (Timeout *t = mTimeouts.getFirst(); t; t = t->getNext()) {
for (Timeout *t = mTimeouts.GetFirst(); t; t = t->getNext()) {
// There's a chance we're being called with RunTimeout on the stack in which
// case we have a dummy timeout in the list that *must not* be resumed. It
// can be identified by a null mWindow.

View File

@ -28,7 +28,7 @@ public:
static uint32_t GetNestingLevel() { return sNestingLevel; }
static void SetNestingLevel(uint32_t aLevel) { sNestingLevel = aLevel; }
bool HasTimeouts() const { return !mTimeouts.isEmpty(); }
bool HasTimeouts() const { return !mTimeouts.IsEmpty(); }
nsresult SetTimeout(nsITimeoutHandler* aHandler,
int32_t interval, bool aIsInterval,
@ -87,7 +87,7 @@ public:
template <class Callable>
void ForEachTimeout(Callable c)
{
for (Timeout* timeout = mTimeouts.getFirst();
for (Timeout* timeout = mTimeouts.GetFirst();
timeout;
timeout = timeout->getNext()) {
c(timeout);
@ -98,18 +98,46 @@ private:
nsresult ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS);
private:
typedef mozilla::LinkedList<mozilla::dom::Timeout> TimeoutList;
struct Timeouts {
Timeouts()
: mTimeoutInsertionPoint(nullptr)
{
}
const Timeout* GetFirst() const { return mTimeoutList.getFirst(); }
Timeout* GetFirst() { return mTimeoutList.getFirst(); }
const Timeout* GetLast() const { return mTimeoutList.getLast(); }
Timeout* GetLast() { return mTimeoutList.getLast(); }
bool IsEmpty() const { return mTimeoutList.isEmpty(); }
void InsertFront(Timeout* aTimeout) { mTimeoutList.insertFront(aTimeout); }
void Clear() { mTimeoutList.clear(); }
void SetInsertionPoint(Timeout* aTimeout)
{
mTimeoutInsertionPoint = aTimeout;
}
Timeout* InsertionPoint()
{
return mTimeoutInsertionPoint;
}
private:
// mTimeoutList is generally sorted by mWhen, unless mTimeoutInsertionPoint is
// non-null. In that case, the dummy timeout pointed to by
// mTimeoutInsertionPoint may have a later mWhen than some of the timeouts
// that come after it.
TimeoutList mTimeoutList;
// If mTimeoutInsertionPoint is non-null, insertions should happen after it.
// This is a dummy timeout at the moment; if that ever changes, the logic in
// ResetTimersForThrottleReduction needs to change.
mozilla::dom::Timeout* mTimeoutInsertionPoint;
};
// Each nsGlobalWindow object has a TimeoutManager member. This reference
// points to that holder object.
nsGlobalWindow& mWindow;
// mTimeouts is generally sorted by mWhen, unless mTimeoutInsertionPoint is
// non-null. In that case, the dummy timeout pointed to by
// mTimeoutInsertionPoint may have a later mWhen than some of the timeouts
// that come after it.
mozilla::LinkedList<mozilla::dom::Timeout> mTimeouts;
// If mTimeoutInsertionPoint is non-null, insertions should happen after it.
// This is a dummy timeout at the moment; if that ever changes, the logic in
// ResetTimersForThrottleReduction needs to change.
mozilla::dom::Timeout* mTimeoutInsertionPoint;
Timeouts mTimeouts;
uint32_t mTimeoutIdCounter;
uint32_t mTimeoutFiringDepth;
mozilla::dom::Timeout* mRunningTimeout;

View File

@ -515,17 +515,70 @@ public:
void
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
{
if (NS_WARN_IF(!mThis->mOwnerContent)) {
mPromise->MaybeRejectWithUndefined();
return;
}
// Navigate the loader to the new index
nsCOMPtr<nsIFrameLoader> otherLoader;
nsresult rv = mThis->mGroupedSessionHistory->
GotoIndex(mGlobalIndex, getter_AddRefs(otherLoader));
if (NS_WARN_IF(!otherLoader || NS_FAILED(rv))) {
// Check if the gotoIndex failed because the target frameloader is dead. We
// need to perform a navigateAndRestoreByIndex and then return to recover.
if (rv == NS_ERROR_NOT_AVAILABLE) {
// Get the nsIXULBrowserWindow so that we can call NavigateAndRestoreByIndex on it.
nsCOMPtr<nsIDocShell> docShell = mThis->mOwnerContent->OwnerDoc()->GetDocShell();
if (NS_WARN_IF(!docShell)) {
mPromise->MaybeRejectWithUndefined();
return;
}
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
docShell->GetTreeOwner(getter_AddRefs(treeOwner));
if (NS_WARN_IF(!treeOwner)) {
mPromise->MaybeRejectWithUndefined();
return;
}
nsCOMPtr<nsIXULWindow> window = do_GetInterface(treeOwner);
if (NS_WARN_IF(!window)) {
mPromise->MaybeRejectWithUndefined();
return;
}
nsCOMPtr<nsIXULBrowserWindow> xbw;
window->GetXULBrowserWindow(getter_AddRefs(xbw));
if (NS_WARN_IF(!xbw)) {
mPromise->MaybeRejectWithUndefined();
return;
}
nsCOMPtr<nsIBrowser> ourBrowser = do_QueryInterface(mThis->mOwnerContent);
if (NS_WARN_IF(!ourBrowser)) {
mPromise->MaybeRejectWithUndefined();
return;
}
rv = xbw->NavigateAndRestoreByIndex(ourBrowser, mGlobalIndex);
if (NS_WARN_IF(NS_FAILED(rv))) {
mPromise->MaybeRejectWithUndefined();
return;
}
mPromise->MaybeResolveWithUndefined();
return;
}
// Check for any other type of failure
if (NS_WARN_IF(NS_FAILED(rv))) {
mPromise->MaybeRejectWithUndefined();
return;
}
nsFrameLoader* other = static_cast<nsFrameLoader*>(otherLoader.get());
if (other == mThis) {
// Perform the swap.
nsFrameLoader* other = static_cast<nsFrameLoader*>(otherLoader.get());
if (!other || other == mThis) {
mPromise->MaybeRejectWithUndefined();
return;
}
@ -3575,6 +3628,13 @@ nsFrameLoader::PopulateUserContextIdFromAttribute(DocShellOriginAttributes& aAtt
return NS_OK;
}
NS_IMETHODIMP
nsFrameLoader::GetIsDead(bool* aIsDead)
{
*aIsDead = mDestroyCalled;
return NS_OK;
}
nsIMessageSender*
nsFrameLoader::GetProcessMessageManager() const
{

View File

@ -258,6 +258,11 @@ interface nsIFrameLoader : nsISupports
* across root docshells.
*/
readonly attribute nsIGroupedSHistory groupedSessionHistory;
/**
* Is `true` if the frameloader is dead (destroy has been called on it)
*/
[infallible] readonly attribute boolean isDead;
};
%{C++

View File

@ -13,6 +13,7 @@
#include "mozilla/dom/PBackgroundFileHandleParent.h"
#include "mozilla/dom/PBackgroundFileRequestParent.h"
#include "mozilla/dom/indexedDB/ActorsParent.h"
#include "mozilla/dom/indexedDB/PBackgroundIDBDatabaseParent.h"
#include "mozilla/dom/ipc/BlobParent.h"
#include "nsAutoPtr.h"
#include "nsComponentManagerUtils.h"
@ -1518,8 +1519,9 @@ BackgroundMutableFileParentBase::RecvDeleteMe()
AssertIsOnBackgroundThread();
MOZ_ASSERT(!mActorDestroyed);
IProtocol* mgr = Manager();
if (!PBackgroundMutableFileParent::Send__delete__(this)) {
return IPC_FAIL_NO_REASON(this);
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}
@ -1843,8 +1845,9 @@ FileHandle::RecvDeleteMe()
AssertIsOnBackgroundThread();
MOZ_ASSERT(!IsActorDestroyed());
IProtocol* mgr = Manager();
if (!PBackgroundFileHandleParent::Send__delete__(this)) {
return IPC_FAIL_NO_REASON(this);
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}

View File

@ -59,6 +59,7 @@
#include "mozilla/ipc/InputStreamParams.h"
#include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/ipc/PBackground.h"
#include "mozilla/ipc/PBackgroundParent.h"
#include "mozilla/Scoped.h"
#include "mozilla/storage/Variant.h"
#include "nsAutoPtr.h"
@ -13727,8 +13728,9 @@ Factory::RecvDeleteMe()
AssertIsOnBackgroundThread();
MOZ_ASSERT(!mActorDestroyed);
IProtocol* mgr = Manager();
if (!PBackgroundIDBFactoryParent::Send__delete__(this)) {
return IPC_FAIL_NO_REASON(this);
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}
@ -14666,8 +14668,9 @@ Database::RecvDeleteMe()
AssertIsOnBackgroundThread();
MOZ_ASSERT(!mActorDestroyed);
IProtocol* mgr = Manager();
if (!PBackgroundIDBDatabaseParent::Send__delete__(this)) {
return IPC_FAIL_NO_REASON(this);
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}
@ -15791,8 +15794,9 @@ NormalTransaction::RecvDeleteMe()
AssertIsOnBackgroundThread();
MOZ_ASSERT(!IsActorDestroyed());
IProtocol* mgr = Manager();
if (!PBackgroundIDBTransactionParent::Send__delete__(this)) {
return IPC_FAIL_NO_REASON(this);
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}
@ -16097,8 +16101,9 @@ VersionChangeTransaction::RecvDeleteMe()
AssertIsOnBackgroundThread();
MOZ_ASSERT(!IsActorDestroyed());
IProtocol* mgr = Manager();
if (!PBackgroundIDBVersionChangeTransactionParent::Send__delete__(this)) {
return IPC_FAIL_NO_REASON(this);
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}
@ -16892,8 +16897,9 @@ Cursor::RecvDeleteMe()
return IPC_FAIL_NO_REASON(this);
}
IProtocol* mgr = Manager();
if (!PBackgroundIDBCursorParent::Send__delete__(this)) {
return IPC_FAIL_NO_REASON(this);
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}
@ -28927,8 +28933,9 @@ Utils::RecvDeleteMe()
AssertIsOnBackgroundThread();
MOZ_ASSERT(!mActorDestroyed);
IProtocol* mgr = Manager();
if (!PBackgroundIndexedDBUtilsParent::Send__delete__(this)) {
return IPC_FAIL_NO_REASON(this);
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}

View File

@ -13,6 +13,7 @@
#include "mozilla/Services.h"
#include "mozilla/Logging.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/ipc/PBackgroundParent.h"
#include "mozilla/Preferences.h"
#include "nsIPermissionManager.h"
#include "nsThreadUtils.h"
@ -1013,8 +1014,9 @@ CamerasParent::RecvAllDone()
LOG((__PRETTY_FUNCTION__));
// Don't try to send anything to the child now
mChildIsAlive = false;
IProtocol* mgr = Manager();
if (!Send__delete__(this)) {
return IPC_FAIL_NO_REASON(this);
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}

View File

@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/Unused.h"
#include "mozilla/layers/PImageBridgeParent.h"
#include "MediaSystemResourceManagerParent.h"
@ -58,8 +59,9 @@ MediaSystemResourceManagerParent::RecvRelease(const uint32_t& aId)
mozilla::ipc::IPCResult
MediaSystemResourceManagerParent::RecvRemoveResourceManager()
{
IProtocol* mgr = Manager();
if (!PMediaSystemResourceManagerParent::Send__delete__(this)) {
return IPC_FAIL_NO_REASON(this);
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}

View File

@ -167,8 +167,9 @@ BrowserStreamParent::RecvStreamDestroyed()
mStreamPeer = nullptr;
mState = DELETING;
IProtocol* mgr = Manager();
if (!Send__delete__(this)) {
return IPC_FAIL_NO_REASON(this);
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}

View File

@ -15,8 +15,8 @@ xhr.onloadend = function(e) {
xhr.onprogress = function(e) {
if (e.loaded > 0) {
progressFired = true;
xhr.abort();
}
xhr.abort();
};
onmessage = function(e) {

View File

@ -107,6 +107,7 @@ support-files =
script_createFile.js
worker_suspended.js
window_suspended.html
!/dom/base/test/file_bug945152.jar
!/dom/base/test/file_websocket_basic_wsh.py
!/dom/base/test/file_websocket_hello_wsh.py
!/dom/base/test/file_websocket_http_resource.txt

View File

@ -673,7 +673,7 @@ XMLHttpRequestMainThread::CreatePartialBlob(ErrorResult& aRv)
// Use progress info to determine whether load is complete, but use
// mDataAvailable to ensure a slice is created based on the uncompressed
// data count.
if (mLoadTotal == mLoadTransferred) {
if (mState == State::done) {
mResponseBlob = mDOMBlob;
} else {
mResponseBlob = mDOMBlob->CreateSlice(0, mDataAvailable,
@ -688,7 +688,7 @@ XMLHttpRequestMainThread::CreatePartialBlob(ErrorResult& aRv)
}
nsAutoCString contentType;
if (mLoadTotal == mLoadTransferred) {
if (mState == State::done) {
mChannel->GetContentType(contentType);
}
@ -1790,7 +1790,15 @@ XMLHttpRequestMainThread::OnDataAvailable(nsIRequest *request,
mDataAvailable += totalRead;
ChangeState(State::loading);
// Fire the first progress event/loading state change
if (mState != State::loading) {
ChangeState(State::loading);
if (!mFlagSynchronous) {
DispatchProgressEvent(this, ProgressEventType::progress,
mLoadTransferred, mLoadTotal);
}
mProgressSinceLastProgressEvent = false;
}
if (!mFlagSynchronous && !mProgressTimerIsActive) {
StartProgressEventTimer();
@ -2098,10 +2106,6 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
bool waitingForBlobCreation = false;
if (NS_SUCCEEDED(status) &&
(mResponseType == XMLHttpRequestResponseType::_empty ||
mResponseType == XMLHttpRequestResponseType::Text)) {
mLoadTotal = mResponseBody.Length();
} else if (NS_SUCCEEDED(status) &&
(mResponseType == XMLHttpRequestResponseType::Blob ||
mResponseType == XMLHttpRequestResponseType::Moz_blob)) {
ErrorResult rv;
@ -2111,11 +2115,6 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
if (mDOMBlob) {
mResponseBlob = mDOMBlob;
mDOMBlob = nullptr;
mLoadTotal = mResponseBlob->GetSize(rv);
if (NS_WARN_IF(rv.Failed())) {
status = rv.StealNSResult();
}
} else {
// Smaller files may be written in cache map instead of separate files.
// Also, no-store response cannot be written in persistent cache.
@ -2126,8 +2125,7 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
// mBlobStorage can be null if the channel is non-file non-cacheable
// and if the response length is zero.
MaybeCreateBlobStorage();
mLoadTotal =
mBlobStorage->GetBlobWhenReady(GetOwner(), contentType, this);
mBlobStorage->GetBlobWhenReady(GetOwner(), contentType, this);
waitingForBlobCreation = true;
} else {
// mBlobSet can be null if the channel is non-file non-cacheable
@ -2148,10 +2146,6 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
}
mResponseBlob = Blob::Create(GetOwner(), blobImpl);
mLoadTotal = mResponseBlob->GetSize(rv);
if (NS_WARN_IF(rv.Failed())) {
status = rv.StealNSResult();
}
}
}
@ -2163,8 +2157,7 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
mResponseType == XMLHttpRequestResponseType::Moz_chunked_arraybuffer)) {
// set the capacity down to the actual length, to realloc back
// down to the actual size
mLoadTotal = mArrayBufferBuilder.length();
if (!mArrayBufferBuilder.setCapacity(mLoadTotal)) {
if (!mArrayBufferBuilder.setCapacity(mArrayBufferBuilder.length())) {
// this should never happen!
status = NS_ERROR_UNEXPECTED;
}
@ -2268,12 +2261,6 @@ XMLHttpRequestMainThread::ChangeStateToDone()
mTimeoutTimer->Cancel();
}
if (mLoadTransferred) {
mLoadTotal = mLoadTransferred;
} else {
mLoadTotal = -1;
}
// Per spec, fire the last download progress event, if any,
// before readystatechange=4/done. (Note that 0-sized responses
// will have not sent a progress event yet, so one must be sent here).
@ -3412,9 +3399,8 @@ XMLHttpRequestMainThread::OnProgress(nsIRequest *aRequest, nsISupports *aContext
StartProgressEventTimer();
}
} else {
mLoadTotal = lengthComputable ? aProgressMax : -1;
mLoadTotal = aProgressMax;
mLoadTransferred = aProgress;
// OnDataAvailable() handles mProgressSinceLastProgressEvent
// for the download phase.
}
@ -3631,6 +3617,7 @@ XMLHttpRequestMainThread::HandleProgressTimerCallback()
mUploadTransferred, mUploadTotal);
}
} else {
FireReadystatechangeEvent();
DispatchProgressEvent(this, ProgressEventType::progress,
mLoadTransferred, mLoadTotal);
}
@ -3809,12 +3796,6 @@ XMLHttpRequestMainThread::BlobStoreCompleted(MutableBlobStorage* aBlobStorage,
mResponseBlob = aBlob;
mBlobStorage = nullptr;
ErrorResult rv;
mLoadTotal = mResponseBlob->GetSize(rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
}
ChangeStateToDone();
}

View File

@ -319,6 +319,15 @@ bool
CSSEditUtils::IsCSSEditableProperty(nsINode* aNode,
nsIAtom* aProperty,
const nsAString* aAttribute)
{
nsCOMPtr<nsIAtom> attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr;
return IsCSSEditableProperty(aNode, aProperty, attribute);
}
bool
CSSEditUtils::IsCSSEditableProperty(nsINode* aNode,
nsIAtom* aProperty,
nsIAtom* aAttribute)
{
MOZ_ASSERT(aNode);
@ -336,13 +345,12 @@ CSSEditUtils::IsCSSEditableProperty(nsINode* aNode,
nsGkAtoms::u == aProperty ||
nsGkAtoms::strike == aProperty ||
(nsGkAtoms::font == aProperty && aAttribute &&
(aAttribute->EqualsLiteral("color") ||
aAttribute->EqualsLiteral("face")))) {
(aAttribute == nsGkAtoms::color || aAttribute == nsGkAtoms::face))) {
return true;
}
// ALIGN attribute on elements supporting it
if (aAttribute && (aAttribute->EqualsLiteral("align")) &&
if (aAttribute == nsGkAtoms::align &&
node->IsAnyOfHTMLElements(nsGkAtoms::div,
nsGkAtoms::p,
nsGkAtoms::h1,
@ -365,7 +373,7 @@ CSSEditUtils::IsCSSEditableProperty(nsINode* aNode,
return true;
}
if (aAttribute && (aAttribute->EqualsLiteral("valign")) &&
if (aAttribute == nsGkAtoms::valign &&
node->IsAnyOfHTMLElements(nsGkAtoms::col,
nsGkAtoms::colgroup,
nsGkAtoms::tbody,
@ -378,59 +386,52 @@ CSSEditUtils::IsCSSEditableProperty(nsINode* aNode,
}
// attributes TEXT, BACKGROUND and BGCOLOR on BODY
if (aAttribute && node->IsHTMLElement(nsGkAtoms::body) &&
(aAttribute->EqualsLiteral("text")
|| aAttribute->EqualsLiteral("background")
|| aAttribute->EqualsLiteral("bgcolor"))) {
if (node->IsHTMLElement(nsGkAtoms::body) &&
(aAttribute == nsGkAtoms::text || aAttribute == nsGkAtoms::background ||
aAttribute == nsGkAtoms::bgcolor)) {
return true;
}
// attribute BGCOLOR on other elements
if (aAttribute && aAttribute->EqualsLiteral("bgcolor")) {
if (aAttribute == nsGkAtoms::bgcolor) {
return true;
}
// attributes HEIGHT, WIDTH and NOWRAP on TD and TH
if (aAttribute &&
node->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th) &&
(aAttribute->EqualsLiteral("height")
|| aAttribute->EqualsLiteral("width")
|| aAttribute->EqualsLiteral("nowrap"))) {
if (node->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th) &&
(aAttribute == nsGkAtoms::height || aAttribute == nsGkAtoms::width ||
aAttribute == nsGkAtoms::nowrap)) {
return true;
}
// attributes HEIGHT and WIDTH on TABLE
if (aAttribute && node->IsHTMLElement(nsGkAtoms::table) &&
(aAttribute->EqualsLiteral("height")
|| aAttribute->EqualsLiteral("width"))) {
if (node->IsHTMLElement(nsGkAtoms::table) &&
(aAttribute == nsGkAtoms::height || aAttribute == nsGkAtoms::width)) {
return true;
}
// attributes SIZE and WIDTH on HR
if (aAttribute && node->IsHTMLElement(nsGkAtoms::hr) &&
(aAttribute->EqualsLiteral("size")
|| aAttribute->EqualsLiteral("width"))) {
if (node->IsHTMLElement(nsGkAtoms::hr) &&
(aAttribute == nsGkAtoms::size || aAttribute == nsGkAtoms::width)) {
return true;
}
// attribute TYPE on OL UL LI
if (aAttribute &&
node->IsAnyOfHTMLElements(nsGkAtoms::ol, nsGkAtoms::ul,
if (node->IsAnyOfHTMLElements(nsGkAtoms::ol, nsGkAtoms::ul,
nsGkAtoms::li) &&
aAttribute->EqualsLiteral("type")) {
aAttribute == nsGkAtoms::type) {
return true;
}
if (aAttribute && node->IsHTMLElement(nsGkAtoms::img) &&
(aAttribute->EqualsLiteral("border")
|| aAttribute->EqualsLiteral("width")
|| aAttribute->EqualsLiteral("height"))) {
if (node->IsHTMLElement(nsGkAtoms::img) &&
(aAttribute == nsGkAtoms::border || aAttribute == nsGkAtoms::width ||
aAttribute == nsGkAtoms::height)) {
return true;
}
// other elements that we can align using CSS even if they
// can't carry the html ALIGN attribute
if (aAttribute && aAttribute->EqualsLiteral("align") &&
if (aAttribute == nsGkAtoms::align &&
node->IsAnyOfHTMLElements(nsGkAtoms::ul,
nsGkAtoms::ol,
nsGkAtoms::dl,
@ -818,7 +819,7 @@ void
CSSEditUtils::GenerateCSSDeclarationsFromHTMLStyle(
Element* aElement,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
nsIAtom* aAttribute,
const nsAString* aValue,
nsTArray<nsIAtom*>& cssPropertyArray,
nsTArray<nsString>& cssValueArray,
@ -838,21 +839,20 @@ CSSEditUtils::GenerateCSSDeclarationsFromHTMLStyle(
} else if (nsGkAtoms::tt == aHTMLProperty) {
equivTable = ttEquivTable;
} else if (aAttribute) {
if (nsGkAtoms::font == aHTMLProperty &&
aAttribute->EqualsLiteral("color")) {
if (nsGkAtoms::font == aHTMLProperty && aAttribute == nsGkAtoms::color) {
equivTable = fontColorEquivTable;
} else if (nsGkAtoms::font == aHTMLProperty &&
aAttribute->EqualsLiteral("face")) {
aAttribute == nsGkAtoms::face) {
equivTable = fontFaceEquivTable;
} else if (aAttribute->EqualsLiteral("bgcolor")) {
} else if (aAttribute == nsGkAtoms::bgcolor) {
equivTable = bgcolorEquivTable;
} else if (aAttribute->EqualsLiteral("background")) {
} else if (aAttribute == nsGkAtoms::background) {
equivTable = backgroundImageEquivTable;
} else if (aAttribute->EqualsLiteral("text")) {
} else if (aAttribute == nsGkAtoms::text) {
equivTable = textColorEquivTable;
} else if (aAttribute->EqualsLiteral("border")) {
} else if (aAttribute == nsGkAtoms::border) {
equivTable = borderEquivTable;
} else if (aAttribute->EqualsLiteral("align")) {
} else if (aAttribute == nsGkAtoms::align) {
if (aElement->IsHTMLElement(nsGkAtoms::table)) {
equivTable = tableAlignEquivTable;
} else if (aElement->IsHTMLElement(nsGkAtoms::hr)) {
@ -863,17 +863,17 @@ CSSEditUtils::GenerateCSSDeclarationsFromHTMLStyle(
} else {
equivTable = textAlignEquivTable;
}
} else if (aAttribute->EqualsLiteral("valign")) {
} else if (aAttribute == nsGkAtoms::valign) {
equivTable = verticalAlignEquivTable;
} else if (aAttribute->EqualsLiteral("nowrap")) {
} else if (aAttribute == nsGkAtoms::nowrap) {
equivTable = nowrapEquivTable;
} else if (aAttribute->EqualsLiteral("width")) {
} else if (aAttribute == nsGkAtoms::width) {
equivTable = widthEquivTable;
} else if (aAttribute->EqualsLiteral("height") ||
} else if (aAttribute == nsGkAtoms::height ||
(aElement->IsHTMLElement(nsGkAtoms::hr) &&
aAttribute->EqualsLiteral("size"))) {
aAttribute == nsGkAtoms::size)) {
equivTable = heightEquivTable;
} else if (aAttribute->EqualsLiteral("type") &&
} else if (aAttribute == nsGkAtoms::type &&
aElement->IsAnyOfHTMLElements(nsGkAtoms::ol,
nsGkAtoms::ul,
nsGkAtoms::li)) {
@ -890,40 +890,46 @@ CSSEditUtils::GenerateCSSDeclarationsFromHTMLStyle(
// aValue for the node, and return in aCount the number of CSS properties set
// by the call. The Element version returns aCount instead.
int32_t
CSSEditUtils::SetCSSEquivalentToHTMLStyle(Element* aElement,
CSSEditUtils::SetCSSEquivalentToHTMLStyle(nsIDOMNode* aNode,
nsIAtom* aProperty,
const nsAString* aAttribute,
const nsAString* aValue,
bool aSuppressTransaction)
{
MOZ_ASSERT(aElement && aProperty);
MOZ_ASSERT_IF(aAttribute, aValue);
int32_t count;
// This can only fail if SetCSSProperty fails, which should only happen if
// something is pretty badly wrong. In this case we assert so that hopefully
// someone will notice, but there's nothing more sensible to do than just
// return the count and carry on.
nsresult rv = SetCSSEquivalentToHTMLStyle(aElement->AsDOMNode(),
aProperty, aAttribute,
aValue, &count,
aSuppressTransaction);
NS_ASSERTION(NS_SUCCEEDED(rv), "SetCSSEquivalentToHTMLStyle failed");
NS_ENSURE_SUCCESS(rv, count);
return count;
nsCOMPtr<Element> element = do_QueryInterface(aNode);
return SetCSSEquivalentToHTMLStyle(element,
aProperty, aAttribute,
aValue, aSuppressTransaction);
}
nsresult
CSSEditUtils::SetCSSEquivalentToHTMLStyle(nsIDOMNode* aNode,
int32_t
CSSEditUtils::SetCSSEquivalentToHTMLStyle(Element* aElement,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
const nsAString* aValue,
int32_t* aCount,
bool aSuppressTransaction)
{
nsCOMPtr<Element> element = do_QueryInterface(aNode);
*aCount = 0;
if (!element || !IsCSSEditableProperty(element, aHTMLProperty, aAttribute)) {
return NS_OK;
nsCOMPtr<nsIAtom> attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr;
return SetCSSEquivalentToHTMLStyle(aElement, aHTMLProperty, attribute,
aValue, aSuppressTransaction);
}
int32_t
CSSEditUtils::SetCSSEquivalentToHTMLStyle(Element* aElement,
nsIAtom* aHTMLProperty,
nsIAtom* aAttribute,
const nsAString* aValue,
bool aSuppressTransaction)
{
MOZ_ASSERT(aElement);
if (!IsCSSEditableProperty(aElement, aHTMLProperty, aAttribute)) {
return 0;
}
// we can apply the styles only if the node is an element and if we have
@ -932,18 +938,20 @@ CSSEditUtils::SetCSSEquivalentToHTMLStyle(nsIDOMNode* aNode,
// Find the CSS equivalence to the HTML style
nsTArray<nsIAtom*> cssPropertyArray;
nsTArray<nsString> cssValueArray;
GenerateCSSDeclarationsFromHTMLStyle(element, aHTMLProperty, aAttribute,
GenerateCSSDeclarationsFromHTMLStyle(aElement, aHTMLProperty, aAttribute,
aValue, cssPropertyArray, cssValueArray,
false);
// set the individual CSS inline styles
*aCount = cssPropertyArray.Length();
for (int32_t index = 0; index < *aCount; index++) {
nsresult rv = SetCSSProperty(*element, *cssPropertyArray[index],
size_t count = cssPropertyArray.Length();
for (size_t index = 0; index < count; index++) {
nsresult rv = SetCSSProperty(*aElement, *cssPropertyArray[index],
cssValueArray[index], aSuppressTransaction);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return 0;
}
}
return NS_OK;
return count;
}
// Remove from aNode the CSS inline style equivalent to HTMLProperty/aAttribute/aValue for the node
@ -955,20 +963,22 @@ CSSEditUtils::RemoveCSSEquivalentToHTMLStyle(nsIDOMNode* aNode,
bool aSuppressTransaction)
{
nsCOMPtr<Element> element = do_QueryInterface(aNode);
NS_ENSURE_TRUE(element, NS_OK);
nsCOMPtr<nsIAtom> attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr;
return RemoveCSSEquivalentToHTMLStyle(element, aHTMLProperty, aAttribute,
return RemoveCSSEquivalentToHTMLStyle(element, aHTMLProperty, attribute,
aValue, aSuppressTransaction);
}
nsresult
CSSEditUtils::RemoveCSSEquivalentToHTMLStyle(Element* aElement,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
nsIAtom* aAttribute,
const nsAString* aValue,
bool aSuppressTransaction)
{
MOZ_ASSERT(aElement);
if (NS_WARN_IF(!aElement)) {
return NS_OK;
}
if (!IsCSSEditableProperty(aElement, aHTMLProperty, aAttribute)) {
return NS_OK;
@ -1003,7 +1013,7 @@ CSSEditUtils::RemoveCSSEquivalentToHTMLStyle(Element* aElement,
nsresult
CSSEditUtils::GetCSSEquivalentToHTMLInlineStyleSet(nsINode* aNode,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
nsIAtom* aAttribute,
nsAString& aValueString,
StyleType aStyleType)
{
@ -1020,7 +1030,8 @@ CSSEditUtils::GetCSSEquivalentToHTMLInlineStyleSet(nsINode* aNode,
nsTArray<nsString> cssValueArray;
// get the CSS equivalence with last param true indicating we want only the
// "gettable" properties
GenerateCSSDeclarationsFromHTMLStyle(theElement, aHTMLProperty, aAttribute, nullptr,
GenerateCSSDeclarationsFromHTMLStyle(theElement, aHTMLProperty, aAttribute,
nullptr,
cssPropertyArray, cssValueArray, true);
int32_t count = cssPropertyArray.Length();
for (int32_t index = 0; index < count; index++) {
@ -1066,48 +1077,58 @@ CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet(nsINode* aNode,
StyleType aStyleType)
{
MOZ_ASSERT(aNode && aProperty);
bool isSet;
nsresult rv = IsCSSEquivalentToHTMLInlineStyleSet(aNode->AsDOMNode(),
aProperty, aAttribute,
isSet, aValue, aStyleType);
NS_ENSURE_SUCCESS(rv, false);
return isSet;
nsCOMPtr<nsIAtom> attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr;
return IsCSSEquivalentToHTMLInlineStyleSet(aNode,
aProperty, attribute,
aValue, aStyleType);
}
nsresult
bool
CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet(nsIDOMNode* aNode,
nsIAtom* aProperty,
const nsAString* aAttribute,
nsAString& aValue,
StyleType aStyleType)
{
MOZ_ASSERT(aNode && aProperty);
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
nsCOMPtr<nsIAtom> attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr;
return IsCSSEquivalentToHTMLInlineStyleSet(node, aProperty, attribute,
aValue, aStyleType);
}
bool
CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet(
nsIDOMNode* aNode,
nsINode* aNode,
nsIAtom* aHTMLProperty,
const nsAString* aHTMLAttribute,
bool& aIsSet,
nsIAtom* aHTMLAttribute,
nsAString& valueString,
StyleType aStyleType)
{
NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
NS_ENSURE_TRUE(aNode, false);
nsAutoString htmlValueString(valueString);
aIsSet = false;
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
bool isSet = false;
do {
valueString.Assign(htmlValueString);
// get the value of the CSS equivalent styles
nsresult rv =
GetCSSEquivalentToHTMLInlineStyleSet(node, aHTMLProperty, aHTMLAttribute,
GetCSSEquivalentToHTMLInlineStyleSet(aNode, aHTMLProperty, aHTMLAttribute,
valueString, aStyleType);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_SUCCESS(rv, false);
// early way out if we can
if (valueString.IsEmpty()) {
return NS_OK;
return isSet;
}
if (nsGkAtoms::b == aHTMLProperty) {
if (valueString.EqualsLiteral("bold")) {
aIsSet = true;
isSet = true;
} else if (valueString.EqualsLiteral("normal")) {
aIsSet = false;
isSet = false;
} else if (valueString.EqualsLiteral("bolder")) {
aIsSet = true;
isSet = true;
valueString.AssignLiteral("bold");
} else {
int32_t weight = 0;
@ -1115,32 +1136,31 @@ CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet(
nsAutoString value(valueString);
weight = value.ToInteger(&errorCode);
if (400 < weight) {
aIsSet = true;
isSet = true;
valueString.AssignLiteral("bold");
} else {
aIsSet = false;
isSet = false;
valueString.AssignLiteral("normal");
}
}
} else if (nsGkAtoms::i == aHTMLProperty) {
if (valueString.EqualsLiteral("italic") ||
valueString.EqualsLiteral("oblique")) {
aIsSet = true;
isSet = true;
}
} else if (nsGkAtoms::u == aHTMLProperty) {
nsAutoString val;
val.AssignLiteral("underline");
aIsSet = ChangeStyleTransaction::ValueIncludes(valueString, val);
isSet = ChangeStyleTransaction::ValueIncludes(valueString, val);
} else if (nsGkAtoms::strike == aHTMLProperty) {
nsAutoString val;
val.AssignLiteral("line-through");
aIsSet = ChangeStyleTransaction::ValueIncludes(valueString, val);
} else if (aHTMLAttribute &&
((nsGkAtoms::font == aHTMLProperty &&
aHTMLAttribute->EqualsLiteral("color")) ||
aHTMLAttribute->EqualsLiteral("bgcolor"))) {
isSet = ChangeStyleTransaction::ValueIncludes(valueString, val);
} else if ((nsGkAtoms::font == aHTMLProperty &&
aHTMLAttribute == nsGkAtoms::color) ||
aHTMLAttribute == nsGkAtoms::bgcolor) {
if (htmlValueString.IsEmpty()) {
aIsSet = true;
isSet = true;
} else {
nscolor rgba;
nsAutoString subStr;
@ -1174,54 +1194,53 @@ CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet(
htmlColor.Append(char16_t(')'));
}
aIsSet = htmlColor.Equals(valueString,
nsCaseInsensitiveStringComparator());
isSet = htmlColor.Equals(valueString,
nsCaseInsensitiveStringComparator());
} else {
aIsSet = htmlValueString.Equals(valueString,
nsCaseInsensitiveStringComparator());
isSet = htmlValueString.Equals(valueString,
nsCaseInsensitiveStringComparator());
}
}
} else if (nsGkAtoms::tt == aHTMLProperty) {
aIsSet = StringBeginsWith(valueString, NS_LITERAL_STRING("monospace"));
isSet = StringBeginsWith(valueString, NS_LITERAL_STRING("monospace"));
} else if (nsGkAtoms::font == aHTMLProperty && aHTMLAttribute &&
aHTMLAttribute->EqualsLiteral("face")) {
aHTMLAttribute == nsGkAtoms::face) {
if (!htmlValueString.IsEmpty()) {
const char16_t commaSpace[] = { char16_t(','), char16_t(' '), 0 };
const char16_t comma[] = { char16_t(','), 0 };
htmlValueString.ReplaceSubstring(commaSpace, comma);
nsAutoString valueStringNorm(valueString);
valueStringNorm.ReplaceSubstring(commaSpace, comma);
aIsSet = htmlValueString.Equals(valueStringNorm,
nsCaseInsensitiveStringComparator());
isSet = htmlValueString.Equals(valueStringNorm,
nsCaseInsensitiveStringComparator());
} else {
aIsSet = true;
isSet = true;
}
return NS_OK;
} else if (aHTMLAttribute && aHTMLAttribute->EqualsLiteral("align")) {
aIsSet = true;
return isSet;
} else if (aHTMLAttribute == nsGkAtoms::align) {
isSet = true;
} else {
aIsSet = false;
return NS_OK;
return false;
}
if (!htmlValueString.IsEmpty() &&
htmlValueString.Equals(valueString,
nsCaseInsensitiveStringComparator())) {
aIsSet = true;
isSet = true;
}
if (htmlValueString.EqualsLiteral("-moz-editor-invert-value")) {
aIsSet = !aIsSet;
isSet = !isSet;
}
if (nsGkAtoms::u == aHTMLProperty || nsGkAtoms::strike == aHTMLProperty) {
// unfortunately, the value of the text-decoration property is not inherited.
// that means that we have to look at ancestors of node to see if they are underlined
node = node->GetParentElement(); // set to null if it's not a dom element
aNode = aNode->GetParentElement(); // set to null if it's not a dom element
}
} while ((nsGkAtoms::u == aHTMLProperty ||
nsGkAtoms::strike == aHTMLProperty) && !aIsSet && node);
return NS_OK;
nsGkAtoms::strike == aHTMLProperty) && !isSet && aNode);
return isSet;
}
void

View File

@ -90,6 +90,8 @@ public:
*/
bool IsCSSEditableProperty(nsINode* aNode, nsIAtom* aProperty,
const nsAString* aAttribute);
bool IsCSSEditableProperty(nsINode* aNode, nsIAtom* aProperty,
nsIAtom* aAttribute);
/**
* Adds/remove a CSS declaration to the STYLE atrribute carried by a given
@ -188,14 +190,14 @@ public:
*
* @param aNode [IN] A DOM node.
* @param aHTMLProperty [IN] An atom containing an HTML property.
* @param aAttribute [IN] A pointer to an attribute name or nullptr if
* @param aAttribute [IN] An atom of attribute name or nullptr if
* irrelevant.
* @param aValueString [OUT] The list of CSS values.
* @param aStyleType [IN] eSpecified or eComputed.
*/
nsresult GetCSSEquivalentToHTMLInlineStyleSet(nsINode* aNode,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
nsIAtom* aAttribute,
nsAString& aValueString,
StyleType aStyleType);
@ -205,16 +207,20 @@ public:
*
* @param aNode [IN] A DOM node.
* @param aHTMLProperty [IN] An atom containing an HTML property.
* @param aAttribute [IN] A pointer to an attribute name or nullptr if
* irrelevant.
* @param aIsSet [OUT] A boolean being true if the css properties are
* set.
* @param aAttribute [IN] A pointer/atom to an attribute name or nullptr
* if irrelevant.
* @param aValueString [IN/OUT] The attribute value (in) the list of CSS
* values (out).
* @param aStyleType [IN] eSpecified or eComputed.
*
* The nsIContent variant returns aIsSet instead of using an out parameter.
* @return A boolean being true if the css properties are
* set.
*/
bool IsCSSEquivalentToHTMLInlineStyleSet(nsINode* aContent,
nsIAtom* aProperty,
nsIAtom* aAttribute,
nsAString& aValue,
StyleType aStyleType);
bool IsCSSEquivalentToHTMLInlineStyleSet(nsINode* aContent,
nsIAtom* aProperty,
const nsAString* aAttribute,
@ -227,12 +233,11 @@ public:
nsAString& aValue,
StyleType aStyleType);
nsresult IsCSSEquivalentToHTMLInlineStyleSet(nsIDOMNode* aNode,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
bool& aIsSet,
nsAString& aValueString,
StyleType aStyleType);
bool IsCSSEquivalentToHTMLInlineStyleSet(nsIDOMNode* aNode,
nsIAtom* aProperty,
const nsAString* aAttribute,
nsAString& aValue,
StyleType aStyleType);
/**
* Adds to the node the CSS inline styles equivalent to the HTML style
@ -240,27 +245,29 @@ public:
*
* @param aNode [IN] A DOM node.
* @param aHTMLProperty [IN] An atom containing an HTML property.
* @param aAttribute [IN] A pointer to an attribute name or nullptr if
* irrelevant.
* @param aAttribute [IN] A pointer/atom to an attribute name or nullptr
* if irrelevant.
* @param aValue [IN] The attribute value.
* @param aCount [OUT] The number of CSS properties set by the call.
* @param aSuppressTransaction [IN] A boolean indicating, when true,
* that no transaction should be recorded.
*
* aCount is returned by the dom::Element variant instead of being an out
* parameter.
* @return The number of CSS properties set by the call.
*/
int32_t SetCSSEquivalentToHTMLStyle(dom::Element* aElement,
nsIAtom* aProperty,
nsIAtom* aAttribute,
const nsAString* aValue,
bool aSuppressTransaction);
int32_t SetCSSEquivalentToHTMLStyle(dom::Element* aElement,
nsIAtom* aProperty,
const nsAString* aAttribute,
const nsAString* aValue,
bool aSuppressTransaction);
nsresult SetCSSEquivalentToHTMLStyle(nsIDOMNode* aNode,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
const nsAString* aValue,
int32_t* aCount,
bool aSuppressTransaction);
int32_t SetCSSEquivalentToHTMLStyle(nsIDOMNode* aNode,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
const nsAString* aValue,
bool aSuppressTransaction);
/**
* Removes from the node the CSS inline styles equivalent to the HTML style.
@ -284,7 +291,7 @@ public:
*
* @param aElement [IN] A DOM Element (must not be null).
* @param aHTMLProperty [IN] An atom containing an HTML property.
* @param aAttribute [IN] A pointer to an attribute name or nullptr if
* @param aAttribute [IN] An atom to an attribute name or nullptr if
* irrelevant.
* @param aValue [IN] The attribute value.
* @param aSuppressTransaction [IN] A boolean indicating, when true,
@ -292,7 +299,7 @@ public:
*/
nsresult RemoveCSSEquivalentToHTMLStyle(dom::Element* aElement,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
nsIAtom* aAttribute,
const nsAString* aValue,
bool aSuppressTransaction);
@ -409,7 +416,7 @@ private:
*
* @param aNode [IN] The DOM node.
* @param aHTMLProperty [IN] An atom containing an HTML property.
* @param aAttribute [IN] A pointer to an attribute name or nullptr
* @param aAttribute [IN] An atom to an attribute name or nullptr
* if irrelevant
* @param aValue [IN] The attribute value.
* @param aPropertyArray [OUT] The array of CSS properties.
@ -422,7 +429,7 @@ private:
*/
void GenerateCSSDeclarationsFromHTMLStyle(dom::Element* aNode,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
nsIAtom* aAttribute,
const nsAString* aValue,
nsTArray<nsIAtom*>& aPropertyArray,
nsTArray<nsString>& aValueArray,

View File

@ -838,19 +838,18 @@ HTMLEditRules::GetAlignment(bool* aMixed,
NS_ENSURE_TRUE(nodeToExamine, NS_ERROR_NULL_POINTER);
NS_NAMED_LITERAL_STRING(typeAttrName, "align");
nsCOMPtr<Element> blockParent = htmlEditor->GetBlock(*nodeToExamine);
NS_ENSURE_TRUE(blockParent, NS_ERROR_FAILURE);
if (htmlEditor->IsCSSEnabled() &&
htmlEditor->mCSSEditUtils->IsCSSEditableProperty(blockParent, nullptr,
&typeAttrName)) {
nsGkAtoms::align)) {
// We are in CSS mode and we know how to align this element with CSS
nsAutoString value;
// Let's get the value(s) of text-align or margin-left/margin-right
htmlEditor->mCSSEditUtils->GetCSSEquivalentToHTMLInlineStyleSet(
blockParent, nullptr, &typeAttrName, value, CSSEditUtils::eComputed);
blockParent, nullptr, nsGkAtoms::align, value, CSSEditUtils::eComputed);
if (value.EqualsLiteral("center") ||
value.EqualsLiteral("-moz-center") ||
value.EqualsLiteral("auto auto")) {
@ -4727,7 +4726,7 @@ HTMLEditRules::WillAlign(Selection& aSelection,
NS_ENSURE_SUCCESS(rv, rv);
if (useCSS) {
htmlEditor->mCSSEditUtils->SetCSSEquivalentToHTMLStyle(
curNode->AsElement(), nullptr, &NS_LITERAL_STRING("align"),
curNode->AsElement(), nullptr, nsGkAtoms::align,
&aAlignType, false);
curDiv = nullptr;
continue;
@ -7093,9 +7092,9 @@ HTMLEditRules::CacheInlineStyles(nsIDOMNode* aNode)
isSet, &outValue);
} else {
NS_ENSURE_STATE(mHTMLEditor);
mHTMLEditor->mCSSEditUtils->IsCSSEquivalentToHTMLInlineStyleSet(aNode,
mCachedStyles[j].tag, &(mCachedStyles[j].attr), isSet, outValue,
CSSEditUtils::eComputed);
isSet = mHTMLEditor->mCSSEditUtils->IsCSSEquivalentToHTMLInlineStyleSet(
aNode, mCachedStyles[j].tag, &(mCachedStyles[j].attr), outValue,
CSSEditUtils::eComputed);
}
if (isSet) {
mCachedStyles[j].mPresent = true;

View File

@ -4455,30 +4455,35 @@ HTMLEditor::SetAttributeOrEquivalent(nsIDOMElement* aElement,
nsAutoScriptBlocker scriptBlocker;
if (IsCSSEnabled() && mCSSEditUtils) {
int32_t count;
nsresult rv =
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(aElement, nullptr,
&aAttribute, &aValue,
&count,
nsCOMPtr<dom::Element> element = do_QueryInterface(aElement);
MOZ_ASSERT(element);
nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
MOZ_ASSERT(attribute);
int32_t count =
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(element, nullptr,
attribute, &aValue,
aSuppressTransaction);
NS_ENSURE_SUCCESS(rv, rv);
if (count) {
// we found an equivalence ; let's remove the HTML attribute itself if it is set
nsAutoString existingValue;
bool wasSet = false;
rv = GetAttributeValue(aElement, aAttribute, existingValue, &wasSet);
nsresult rv =
GetAttributeValue(aElement, aAttribute, existingValue, &wasSet);
NS_ENSURE_SUCCESS(rv, rv);
if (!wasSet) {
return NS_OK;
}
return aSuppressTransaction ? aElement->RemoveAttribute(aAttribute) :
RemoveAttribute(aElement, aAttribute);
return aSuppressTransaction ?
element->UnsetAttr(kNameSpaceID_None, attribute, true) :
RemoveAttribute(aElement, aAttribute);
}
// count is an integer that represents the number of CSS declarations applied to the
// element. If it is zero, we found no equivalence in this implementation for the
// attribute
if (aAttribute.EqualsLiteral("style")) {
if (attribute == nsGkAtoms::style) {
// if it is the style attribute, just add the new value to the existing style
// attribute's value
nsAutoString existingValue;
@ -4489,14 +4494,15 @@ HTMLEditor::SetAttributeOrEquivalent(nsIDOMElement* aElement,
existingValue.Append(' ');
existingValue.Append(aValue);
return aSuppressTransaction ?
aElement->SetAttribute(aAttribute, existingValue) :
element->SetAttr(kNameSpaceID_None, attribute, existingValue, true) :
SetAttribute(aElement, aAttribute, existingValue);
}
// we have no CSS equivalence for this attribute and it is not the style
// attribute; let's set it the good'n'old HTML way
return aSuppressTransaction ? aElement->SetAttribute(aAttribute, aValue) :
SetAttribute(aElement, aAttribute, aValue);
return aSuppressTransaction ?
element->SetAttr(kNameSpaceID_None, attribute, aValue, true) :
SetAttribute(aElement, aAttribute, aValue);
}
// we are not in an HTML+CSS editor; let's set the attribute the HTML way
@ -4518,7 +4524,7 @@ HTMLEditor::RemoveAttributeOrEquivalent(nsIDOMElement* aElement,
if (IsCSSEnabled() && mCSSEditUtils) {
nsresult rv =
mCSSEditUtils->RemoveCSSEquivalentToHTMLStyle(
element, nullptr, &aAttribute, nullptr, aSuppressTransaction);
element, nullptr, attribute, nullptr, aSuppressTransaction);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -4580,7 +4586,6 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor)
NS_ENSURE_SUCCESS(rv, rv);
if (!cancel && !handled) {
// Loop through the ranges in the selection
NS_NAMED_LITERAL_STRING(bgcolor, "bgcolor");
for (uint32_t i = 0; i < selection->RangeCount(); i++) {
RefPtr<nsRange> range = selection->GetRangeAt(i);
NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
@ -4599,13 +4604,15 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor)
if (blockParent && cachedBlockParent != blockParent) {
cachedBlockParent = blockParent;
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr,
&bgcolor, &aColor, false);
nsGkAtoms::bgcolor,
&aColor, false);
}
} else if (startNode == endNode &&
startNode->IsHTMLElement(nsGkAtoms::body) && isCollapsed) {
// No block in the document, let's apply the background to the body
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(startNode->AsElement(),
nullptr, &bgcolor, &aColor,
nullptr, nsGkAtoms::bgcolor,
&aColor,
false);
} else if (startNode == endNode && (endOffset - startOffset == 1 ||
(!startOffset && !endOffset))) {
@ -4616,7 +4623,8 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor)
if (blockParent && cachedBlockParent != blockParent) {
cachedBlockParent = blockParent;
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr,
&bgcolor, &aColor, false);
nsGkAtoms::bgcolor,
&aColor, false);
}
} else {
// Not the easy case. Range not contained in single text node. There
@ -4659,7 +4667,8 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor)
if (blockParent && cachedBlockParent != blockParent) {
cachedBlockParent = blockParent;
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr,
&bgcolor, &aColor,
nsGkAtoms::bgcolor,
&aColor,
false);
}
}
@ -4670,7 +4679,8 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor)
if (blockParent && cachedBlockParent != blockParent) {
cachedBlockParent = blockParent;
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr,
&bgcolor, &aColor,
nsGkAtoms::bgcolor,
&aColor,
false);
}
}
@ -4684,7 +4694,8 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor)
if (blockParent && cachedBlockParent != blockParent) {
cachedBlockParent = blockParent;
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr,
&bgcolor, &aColor,
nsGkAtoms::bgcolor,
&aColor,
false);
}
}

View File

@ -427,7 +427,7 @@ HTMLEditor::SetInlinePropertyOnNodeImpl(nsIContent& aNode,
mCSSEditUtils->IsCSSEditableProperty(&aNode, &aProperty,
aAttribute)) ||
// bgcolor is always done using CSS
aAttribute->EqualsLiteral("bgcolor");
attrAtom == nsGkAtoms::bgcolor;
if (useCSS) {
nsCOMPtr<dom::Element> tmp;
@ -442,12 +442,9 @@ HTMLEditor::SetInlinePropertyOnNodeImpl(nsIContent& aNode,
}
// Add the CSS styles corresponding to the HTML style request
int32_t count;
nsresult rv =
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(tmp->AsDOMNode(),
&aProperty, aAttribute,
&aValue, &count, false);
NS_ENSURE_SUCCESS(rv, rv);
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(tmp,
&aProperty, attrAtom,
&aValue, false);
return NS_OK;
}
@ -572,8 +569,9 @@ HTMLEditor::SplitStyleAbovePoint(nsCOMPtr<nsINode>* aNode,
// in this implementation for the node; let's check if it carries those
// CSS styles
nsAutoString firstValue;
mCSSEditUtils->IsCSSEquivalentToHTMLInlineStyleSet(GetAsDOMNode(node),
aProperty, aAttribute, isSet, firstValue, CSSEditUtils::eSpecified);
isSet = mCSSEditUtils->IsCSSEquivalentToHTMLInlineStyleSet(
node, aProperty, aAttribute, firstValue,
CSSEditUtils::eSpecified);
}
if (// node is the correct inline prop
(aProperty && node->IsHTMLElement(aProperty)) ||
@ -784,15 +782,17 @@ HTMLEditor::RemoveStyleInside(nsIContent& aNode,
// the HTML style defined by aProperty/aAttribute has a CSS equivalence in
// this implementation for the node aNode; let's check if it carries those
// css styles
nsCOMPtr<nsIAtom> attribute =
aAttribute ? NS_Atomize(*aAttribute) : nullptr;
nsAutoString propertyValue;
bool isSet = mCSSEditUtils->IsCSSEquivalentToHTMLInlineStyleSet(&aNode,
aProperty, aAttribute, propertyValue, CSSEditUtils::eSpecified);
aProperty, attribute, propertyValue, CSSEditUtils::eSpecified);
if (isSet && aNode.IsElement()) {
// yes, tmp has the corresponding css declarations in its style attribute
// let's remove them
mCSSEditUtils->RemoveCSSEquivalentToHTMLStyle(aNode.AsElement(),
aProperty,
aAttribute,
attribute,
&propertyValue,
false);
// remove the node if it is a span or font, if its style attribute is

View File

@ -7,6 +7,7 @@
#include "WebBrowserPersistDocumentParent.h"
#include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/dom/PContentParent.h"
#include "nsIInputStream.h"
#include "nsThreadUtils.h"
#include "WebBrowserPersistResourcesParent.h"
@ -84,8 +85,9 @@ WebBrowserPersistDocumentParent::RecvInitFailure(const nsresult& aFailure)
mOnReady->OnError(aFailure);
mOnReady = nullptr;
// Warning: Send__delete__ deallocates this object.
IProtocol* mgr = Manager();
if (!Send__delete__(this)) {
return IPC_FAIL_NO_REASON(this);
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}

View File

@ -163,8 +163,9 @@ mozilla::ipc::IPCResult
LayerTransactionParent::RecvShutdown()
{
Destroy();
IProtocol* mgr = Manager();
if (!Send__delete__(this)) {
return IPC_FAIL_NO_REASON(this);
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}

View File

@ -139,9 +139,13 @@ gfxFontUtils::ReadCMAPTableFormat10(const uint8_t *aBuf, uint32_t aLength,
}
nsresult
gfxFontUtils::ReadCMAPTableFormat12(const uint8_t *aBuf, uint32_t aLength,
gfxSparseBitSet& aCharacterMap)
gfxFontUtils::ReadCMAPTableFormat12or13(const uint8_t *aBuf, uint32_t aLength,
gfxSparseBitSet& aCharacterMap)
{
// Format 13 has the same structure as format 12, the only difference is
// the interpretation of the glyphID field. So we can share the code here
// that reads the table and just records character coverage.
// Ensure table is large enough that we can safely read the header
NS_ENSURE_TRUE(aLength >= sizeof(Format12CmapHeader),
NS_ERROR_GFX_CMAP_MALFORMED);
@ -149,7 +153,8 @@ gfxFontUtils::ReadCMAPTableFormat12(const uint8_t *aBuf, uint32_t aLength,
// Sanity-check header fields
const Format12CmapHeader *cmap12 =
reinterpret_cast<const Format12CmapHeader*>(aBuf);
NS_ENSURE_TRUE(uint16_t(cmap12->format) == 12,
NS_ENSURE_TRUE(uint16_t(cmap12->format) == 12 ||
uint16_t(cmap12->format) == 13,
NS_ERROR_GFX_CMAP_MALFORMED);
NS_ENSURE_TRUE(uint16_t(cmap12->reserved) == 0,
NS_ERROR_GFX_CMAP_MALFORMED);
@ -472,7 +477,7 @@ gfxFontUtils::FindPreferredSubtable(const uint8_t *aBuf, uint32_t aBufLength,
keepFormat = format;
*aTableOffset = offset;
*aSymbolEncoding = false;
} else if ((format == 10 || format == 12) &&
} else if ((format == 10 || format == 12 || format == 13) &&
acceptableUCS4Encoding(platformID, encodingID, keepFormat)) {
keepFormat = format;
*aTableOffset = offset;
@ -521,10 +526,11 @@ gfxFontUtils::ReadCMAP(const uint8_t *aBuf, uint32_t aBufLength,
aCharacterMap);
case 12:
case 13:
aUnicodeFont = true;
aSymbolFont = false;
return ReadCMAPTableFormat12(aBuf + offset, aBufLength - offset,
aCharacterMap);
return ReadCMAPTableFormat12or13(aBuf + offset, aBufLength - offset,
aCharacterMap);
default:
break;
@ -651,13 +657,17 @@ gfxFontUtils::MapCharToGlyphFormat10(const uint8_t *aBuf, uint32_t aCh)
}
uint32_t
gfxFontUtils::MapCharToGlyphFormat12(const uint8_t *aBuf, uint32_t aCh)
gfxFontUtils::MapCharToGlyphFormat12or13(const uint8_t *aBuf, uint32_t aCh)
{
// The only difference between formats 12 and 13 is the interpretation of
// the glyphId field. So the code here uses the same "Format12" structures,
// etc., to handle both subtable formats.
const Format12CmapHeader *cmap12 =
reinterpret_cast<const Format12CmapHeader*>(aBuf);
// We know that numGroups is within range for the subtable size
// because it was checked by ReadCMAPTableFormat12.
// because it was checked by ReadCMAPTableFormat12or13.
uint32_t numGroups = cmap12->numGroups;
// The array of groups immediately follows the subtable header.
@ -688,10 +698,13 @@ gfxFontUtils::MapCharToGlyphFormat12(const uint8_t *aBuf, uint32_t aCh)
}
// Check if the character is actually present in the range and return
// the corresponding glyph ID
// the corresponding glyph ID. Here is where formats 12 and 13 interpret
// the startGlyphId (12) or glyphId (13) field differently
startCharCode = groups[range].startCharCode;
if (startCharCode <= aCh && groups[range].endCharCode >= aCh) {
return groups[range].startGlyphId + aCh - startCharCode;
return uint16_t(cmap12->format) == 12
? uint16_t(groups[range].startGlyphId) + aCh - startCharCode
: uint16_t(groups[range].startGlyphId);
}
// Else it's not present, so return the .notdef glyph
@ -767,7 +780,8 @@ gfxFontUtils::MapCharToGlyph(const uint8_t *aCmapBuf, uint32_t aBufLength,
gid = MapCharToGlyphFormat10(aCmapBuf + offset, aUnicode);
break;
case 12:
gid = MapCharToGlyphFormat12(aCmapBuf + offset, aUnicode);
case 13:
gid = MapCharToGlyphFormat12or13(aCmapBuf + offset, aUnicode);
break;
default:
NS_WARNING("unsupported cmap format, glyphs will be missing");
@ -793,8 +807,9 @@ gfxFontUtils::MapCharToGlyph(const uint8_t *aCmapBuf, uint32_t aBufLength,
aUnicode);
break;
case 12:
varGID = MapCharToGlyphFormat12(aCmapBuf + offset,
aUnicode);
case 13:
varGID = MapCharToGlyphFormat12or13(aCmapBuf + offset,
aUnicode);
break;
}
}

View File

@ -781,8 +781,8 @@ public:
gfxSparseBitSet& aCharacterMap);
static nsresult
ReadCMAPTableFormat12(const uint8_t *aBuf, uint32_t aLength,
gfxSparseBitSet& aCharacterMap);
ReadCMAPTableFormat12or13(const uint8_t *aBuf, uint32_t aLength,
gfxSparseBitSet& aCharacterMap);
static nsresult
ReadCMAPTableFormat4(const uint8_t *aBuf, uint32_t aLength,
@ -810,7 +810,7 @@ public:
MapCharToGlyphFormat10(const uint8_t *aBuf, uint32_t aCh);
static uint32_t
MapCharToGlyphFormat12(const uint8_t *aBuf, uint32_t aCh);
MapCharToGlyphFormat12or13(const uint8_t *aBuf, uint32_t aCh);
static uint16_t
MapUVSToGlyphFormat14(const uint8_t *aBuf, uint32_t aCh, uint32_t aVS);

View File

@ -131,8 +131,10 @@ gfxHarfBuzzShaper::GetNominalGlyph(hb_codepoint_t unicode) const
unicode);
break;
case 12:
gid = gfxFontUtils::MapCharToGlyphFormat12(data + mSubtableOffset,
unicode);
case 13:
gid =
gfxFontUtils::MapCharToGlyphFormat12or13(data + mSubtableOffset,
unicode);
break;
default:
NS_WARNING("unsupported cmap format, glyphs will be missing");
@ -190,8 +192,10 @@ gfxHarfBuzzShaper::GetVariationGlyph(hb_codepoint_t unicode,
compat);
break;
case 12:
return gfxFontUtils::MapCharToGlyphFormat12(data + mSubtableOffset,
compat);
case 13:
return
gfxFontUtils::MapCharToGlyphFormat12or13(data + mSubtableOffset,
compat);
break;
}
}

View File

@ -4084,15 +4084,12 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
msgvar, stmts = self.makeMessage(md, errfnSendDtor, actorvar)
sendok, sendstmts = self.sendAsync(md, msgvar, actorvar)
failif = StmtIf(ExprNot(sendok))
failif.addifstmt(StmtReturn.FALSE)
method.addstmts(
stmts
+ self.genVerifyMessage(md.decl.type.verify, md.params,
errfnSendDtor, ExprVar('msg__'))
+ sendstmts
+ [ failif, Whitespace.NL ]
+ [ Whitespace.NL ]
+ self.dtorEpilogue(md, actor.var())
+ [ StmtReturn(sendok) ])

View File

@ -1341,21 +1341,6 @@ js::ReportIsNotFunction(JSContext* cx, HandleValue v)
return ReportIsNotFunction(cx, v, -1);
}
JS_FRIEND_API(void)
js::ReportASCIIErrorWithId(JSContext* cx, const char* msg, HandleId id)
{
RootedValue idv(cx);
if (!JS_IdToValue(cx, id, &idv))
return;
RootedString idstr(cx, JS::ToString(cx, idv));
if (!idstr)
return;
JSAutoByteString bytes;
if (!bytes.encodeUtf8(cx, idstr))
return;
JS_ReportErrorUTF8(cx, msg, bytes.ptr());
}
#ifdef DEBUG
bool
js::HasObjectMovedOp(JSObject* obj) {

View File

@ -2773,9 +2773,6 @@ SetPropertyIgnoringNamedGetter(JSContext* cx, JS::HandleObject obj, JS::HandleId
JS::Handle<JS::PropertyDescriptor> ownDesc,
JS::ObjectOpResult& result);
JS_FRIEND_API(void)
ReportASCIIErrorWithId(JSContext* cx, const char* msg, JS::HandleId id);
// This function is for one specific use case, please don't use this for anything else!
extern JS_FRIEND_API(bool)
ExecuteInGlobalAndReturnScope(JSContext* cx, JS::HandleObject obj, JS::HandleScript script,

View File

@ -3270,7 +3270,8 @@ GCHelperState::startBackgroundThread(State newState, const AutoLockGC& lock,
void
GCHelperState::waitForBackgroundThread(js::AutoLockGC& lock)
{
done.wait(lock.guard());
while (isBackgroundSweeping())
done.wait(lock.guard());
}
void

View File

@ -23,6 +23,21 @@ using namespace JS;
namespace xpc {
static inline void
ReportASCIIErrorWithId(JSContext* cx, const char* msg, HandleId id)
{
RootedValue idv(cx);
if (!JS_IdToValue(cx, id, &idv))
return;
RootedString idstr(cx, JS::ToString(cx, idv));
if (!idstr)
return;
JSAutoByteString bytes;
if (!bytes.encodeUtf8(cx, idstr))
return;
JS_ReportErrorUTF8(cx, msg, bytes.ptr());
}
bool
InterposeProperty(JSContext* cx, HandleObject target, const nsIID* iid, HandleId id,
MutableHandle<PropertyDescriptor> descriptor)
@ -231,7 +246,7 @@ AddonWrapper<Base>::defineProperty(JSContext* cx, HandleObject wrapper, HandleId
if (!interpDesc.object())
return Base::defineProperty(cx, wrapper, id, desc, result);
js::ReportASCIIErrorWithId(cx, "unable to modify interposed property %s", id);
ReportASCIIErrorWithId(cx, "unable to modify interposed property %s", id);
return false;
}
@ -247,7 +262,7 @@ AddonWrapper<Base>::delete_(JSContext* cx, HandleObject wrapper, HandleId id,
if (!desc.object())
return Base::delete_(cx, wrapper, id, result);
js::ReportASCIIErrorWithId(cx, "unable to delete interposed property %s", id);
ReportASCIIErrorWithId(cx, "unable to delete interposed property %s", id);
return false;
}

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<head>
<meta charset=utf-8>
<style>
body {
font-family: monospace;
font-size: 48px;
}
</style>
</head>
<body>
PASS

View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<head>
<meta charset=utf-8>
<style>
/* Adobe Blank 2 font from https://github.com/adobe-fonts/adobe-blank-2/blob/master/adobe-blank-2.css,
licensed under the SIL Open Font License, Version 1.1. http://scripts.sil.org/OFL */
@font-face {
font-family: AdobeBlank2;
src: url("data:font/opentype;base64,T1RUTwAKAIAAAwAgQ0ZGIN6nWacAAAfMAAABMURTSUcAAAABAAAJCAAAAAhPUy8yAF+xmwAAARAAAABgY21hcAE0tLwAAAasAAABAGhlYWQIOsNZAAAArAAAADZoaGVhB1oD7wAAAOQAAAAkaG10eAPoAHwAAAkAAAAACG1heHAAAlAAAAABCAAAAAZuYW1lc0mXUAAAAXAAAAU6cG9zdP+4ADIAAAesAAAAIAABAAAAAgBB1Q6SE18PPPUAAwPoAAAAANKdP6AAAAAA0p0/oAB8/4gDbANwAAAAAwACAAAAAAAAAAEAAANw/4gAAAPoAHwAfANsAAEAAAAAAAAAAAAAAAAAAAACAABQAAACAAAAAwPoAZAABQAAAooCWAAAAEsCigJYAAABXgAyANwAAAAAAAAAAAAAAAD3/67/+9///w/gAD8AAAAAQURCTwBAAAD//wNw/4gAAANwAHhgLwH/AAAAAAAAAAAAAAAgAAAAAAALAIoAAwABBAkAAACUAAAAAwABBAkAAQAaAJQAAwABBAkAAgAOAK4AAwABBAkAAwA4ALwAAwABBAkABAAaAJQAAwABBAkABQB0APQAAwABBAkABgAWAWgAAwABBAkACAA0AX4AAwABBAkACwA0AbIAAwABBAkADQKWAeYAAwABBAkADgA0BHwAQwBvAHAAeQByAGkAZwBoAHQAIACpACAAMgAwADEAMwAsACAAMgAwADEANQAgAEEAZABvAGIAZQAgAFMAeQBzAHQAZQBtAHMAIABJAG4AYwBvAHIAcABvAHIAYQB0AGUAZAAgACgAaAB0AHQAcAA6AC8ALwB3AHcAdwAuAGEAZABvAGIAZQAuAGMAbwBtAC8AKQAuAEEAZABvAGIAZQAgAEIAbABhAG4AawAgADIAUgBlAGcAdQBsAGEAcgAyAC4AMAAwADEAOwBBAEQAQgBPADsAQQBkAG8AYgBlAEIAbABhAG4AawAyADsAQQBEAE8AQgBFAFYAZQByAHMAaQBvAG4AIAAyAC4AMAAwADEAOwBQAFMAIAAyAC4AMAAwADEAOwBoAG8AdABjAG8AbgB2ACAAMQAuADAALgA4ADgAOwBtAGEAawBlAG8AdABmAC4AbABpAGIAMgAuADUALgA2ADUAMAAxADIAQQBkAG8AYgBlAEIAbABhAG4AawAyAEEAZABvAGIAZQAgAFMAeQBzAHQAZQBtAHMAIABJAG4AYwBvAHIAcABvAHIAYQB0AGUAZABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBkAG8AYgBlAC4AYwBvAG0ALwB0AHkAcABlAC8AVABoAGkAcwAgAEYAbwBuAHQAIABTAG8AZgB0AHcAYQByAGUAIABpAHMAIABsAGkAYwBlAG4AcwBlAGQAIAB1AG4AZABlAHIAIAB0AGgAZQAgAFMASQBMACAATwBwAGUAbgAgAEYAbwBuAHQAIABMAGkAYwBlAG4AcwBlACwAIABWAGUAcgBzAGkAbwBuACAAMQAuADEALgAgAFQAaABpAHMAIABGAG8AbgB0ACAAUwBvAGYAdAB3AGEAcgBlACAAaQBzACAAZABpAHMAdAByAGkAYgB1AHQAZQBkACAAbwBuACAAYQBuACAAIgBBAFMAIABJAFMAIgAgAEIAQQBTAEkAUwAsACAAVwBJAFQASABPAFUAVAAgAFcAQQBSAFIAQQBOAFQASQBFAFMAIABPAFIAIABDAE8ATgBEAEkAVABJAE8ATgBTACAATwBGACAAQQBOAFkAIABLAEkATgBEACwAIABlAGkAdABoAGUAcgAgAGUAeABwAHIAZQBzAHMAIABvAHIAIABpAG0AcABsAGkAZQBkAC4AIABTAGUAZQAgAHQAaABlACAAUwBJAEwAIABPAHAAZQBuACAARgBvAG4AdAAgAEwAaQBjAGUAbgBzAGUAIABmAG8AcgAgAHQAaABlACAAcwBwAGUAYwBpAGYAaQBjACAAbABhAG4AZwB1AGEAZwBlACwAIABwAGUAcgBtAGkAcwBzAGkAbwBuAHMAIABhAG4AZAAgAGwAaQBtAGkAdABhAHQAaQBvAG4AcwAgAGcAbwB2AGUAcgBuAGkAbgBnACAAeQBvAHUAcgAgAHUAcwBlACAAbwBmACAAdABoAGkAcwAgAEYAbwBuAHQAIABTAG8AZgB0AHcAYQByAGUALgBoAHQAdABwADoALwAvAHMAYwByAGkAcAB0AHMALgBzAGkAbAAuAG8AcgBnAC8ATwBGAEwAAAAAAAEAAwAKAAAADAANAAAAAAD0AAAAAAAAABMAAAAAAADX/wAAAAEAAOAAAAD9zwAAAAEAAP3wAAD//QAAAAEAAQAAAAH//QAAAAEAAgAAAAL//QAAAAEAAwAAAAP//QAAAAEABAAAAAT//QAAAAEABQAAAAX//QAAAAEABgAAAAb//QAAAAEABwAAAAf//QAAAAEACAAAAAj//QAAAAEACQAAAAn//QAAAAEACgAAAAr//QAAAAEACwAAAAv//QAAAAEADAAAAAz//QAAAAEADQAAAA3//QAAAAEADgAAAA7//QAAAAEADwAAAA///QAAAAEAEAAAABD//QAAAAEAAwAAAAAAAP+1ADIAAAAAAAAAAAAAAAAAAAAAAAAAAAEABAIAAQEBDEFkb2JlQmxhbmsyAAEBAS34G/gciwwe+B0B+B4Ci/sM+gD6BAUeKgAfDB+NDCL3Uw/3WRH3Vgwl96wMJAAFAQEGDlZjcEFkb2JlSWRlbnRpdHlDb3B5cmlnaHQgMjAxMywgMjAxNSBBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZCAoaHR0cDovL3d3dy5hZG9iZS5jb20vKS5BZG9iZSBCbGFuayAyQWRvYmVCbGFuazItMgAAAAABAAAAAAIBAUxO+nz7DLf6JLcB9xC3+Sy3A/cQ+gQV/nz5hPp8B/1Y/icV+dIH98X8MwWmsBX7xfg3Bfj2BqZiFf3SB/vF+DMFcGYV98X8NwX89gYOiw4AAQEBCfgfDCaX97kS+46LHAVGiwa9Cr0LAAAAA+gAfAAAAAAAAAABAAAAAA==");
}
body {
font-family: monospace;
font-size: 48px;
}
span {
font-family: AdobeBlank2;
font-size: 24px; /* smaller size to avoid risk of disrupting line height */
}
</style>
</head>
<body>
P<span> (fail) </span>A<span>&#x1234;&#x9876;&#xabcd;</span>S<span>&#x10400;&#x1f333;</span>S

View File

@ -185,6 +185,7 @@ HTTP(..) != fallback-mark-stacking-1.html fallback-mark-stacking-1-notref.html
== 745555-2.html 745555-2-ref.html
== 820255.html 820255-ref.html
HTTP(..) != 1170688.html 1170688-ref.html
fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 1320665-cmap-format-13.html 1320665-cmap-format-13-ref.html # see bug 1320665 comments 8-9
# ensure emoji chars don't render blank (bug 715798, bug 779042);
# should at least render hexboxes if there's no font support

View File

@ -3878,7 +3878,7 @@ CSS_PROP_TEXT(
VARIANT_INHERIT | VARIANT_LNCALC,
nullptr,
offsetof(nsStyleText, mTabSize),
eStyleAnimType_Discrete)
eStyleAnimType_Coord)
CSS_PROP_TABLE(
table-layout,
table_layout,

View File

@ -248,6 +248,8 @@ var supported_properties = {
// test_length_percent_calc_transition.
"stroke-width": [ test_length_transition_svg, test_percent_transition,
test_length_clamped_svg, test_percent_clamped ],
"-moz-tab-size": [ test_float_zeroToOne_transition,
test_float_aboveOne_transition, test_length_clamped ],
"text-decoration": [ test_color_shorthand_transition,
test_true_currentcolor_shorthand_transition ],
"text-decoration-color": [ test_color_transition,

View File

@ -49,8 +49,9 @@ WebSocketChannelParent::RecvDeleteSelf()
LOG(("WebSocketChannelParent::RecvDeleteSelf() %p\n", this));
mChannel = nullptr;
mAuthProvider = nullptr;
IProtocol* mgr = Manager();
if (mIPCOpen && !Send__delete__(this)) {
return IPC_FAIL_NO_REASON(this);
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}

View File

@ -1,5 +0,0 @@
[firing-events-http-no-content-length.html]
type: testharness
[ProgressEvent: firing events for HTTP with no Content-Length]
expected: FAIL

View File

@ -22,53 +22,56 @@
}
function getNextEvent(arr) {
var eventStr = arr.shift();
var event = { str: arr.shift() };
// we can only handle strings, numbers (readystates) and undefined
if (eventStr === undefined) {
if (event.str === undefined) {
return event;
}
if (typeof eventStr !== "string") {
if (Number.isInteger(eventStr)) {
eventStr = "readystatechange(" + eventStr + ")";
if (typeof event.str !== "string") {
if (Number.isInteger(event.str)) {
event.state = event.str;
event.str = "readystatechange(" + event.str + ")";
} else {
throw "Test error: unexpected event type " + eventStr;
throw "Test error: unexpected event type " + event.str;
}
}
// parse out the general type, loaded and total values
var type = eventStr.type = eventStr.split("(")[0].split(".").pop();
eventStr.mayFollowOptionalProgressEvents = type == "progress" ||
type == "load" || type == "abort" || type == "error";
var loadedAndTotal = eventStr.match(/\((\d)+,(\d)+/);
var type = event.type = event.str.split("(")[0].split(".").pop();
var loadedAndTotal = event.str.match(/.*\((\d+),(\d+),(true|false)\)/);
if (loadedAndTotal) {
eventStr.loaded = parseInt(loadedAndTotal[0]);
eventStr.total = parseInt(loadedAndTotal[1]);
event.loaded = parseInt(loadedAndTotal[1]);
event.total = parseInt(loadedAndTotal[2]);
event.lengthComputable = loadedAndTotal[3] == "true";
}
return eventStr;
return event;
}
global.assert_xhr_event_order_matches = function(expected) {
var recorded = recorded_xhr_events;
var lastRecordedLoaded = -1;
while(expected.length && recorded.length) {
var currentExpected = getNextEvent(expected),
currentRecorded = getNextEvent(recorded);
// skip to the last progress event if we've hit one
while (recorded.length && currentRecorded.type == "progress") {
assert_greater(currentRecorded.loaded, lastRecordedLoaded,
"progress event 'loaded' values must only increase");
// skip to the last progress event if we've hit one (note the next
// event after a progress event should be a LOADING readystatechange,
// if there are multiple progress events in a row).
while (recorded.length && currentRecorded.type == "progress" &&
parseInt(recorded) === 3) {
assert_greater_than(currentRecorded.loaded, lastRecordedLoaded,
"progress event 'loaded' values must only increase");
lastRecordedLoaded = currentRecorded.loaded;
currentRecorded = getNextEvent(recorded);
}
if (currentRecorded.type == "loadstart") {
if (currentRecorded.type == "loadend") {
recordedProgressCount = 0;
lastRecordedLoaded = -1;
}
assert_equals(currentRecorded, currentExpected);
assert_equals(currentRecorded.str, currentExpected.str);
}
if (recorded.length) {
throw "\nUnexpected extra events: " + recorded.join(", ");

View File

@ -9623,196 +9623,6 @@
"releaseChannelCollection": "opt-out",
"description": "Reports whether the graphics sanity test passed an OS snapshot test. 0=Pass, 1=Fail, 2=Error, 3=Timed out."
},
"DEVTOOLS_HUD_JANK": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "exponential",
"keyed": true,
"description": "The duration which a thread is blocked in ms, keyed by appName.",
"high": 5000,
"n_buckets": 10
},
"DEVTOOLS_HUD_REFLOW_DURATION": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "exponential",
"keyed": true,
"description": "The duration a reflow takes in ms, keyed by appName.",
"high": 1000,
"n_buckets": 10
},
"DEVTOOLS_HUD_REFLOWS": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "count",
"keyed": true,
"description": "A count of the number of reflows, keyed by appName."
},
"DEVTOOLS_HUD_SECURITY_CATEGORY": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "enumerated",
"keyed": true,
"description": "The security error enums, keyed by appName.",
"n_values": 8
},
"DEVTOOLS_HUD_ERRORS": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "count",
"keyed": true,
"description": "Number of errors, keyed by appName."
},
"DEVTOOLS_HUD_WARNINGS": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "count",
"keyed": true,
"description": "Number of warnings, keyed by appName."
},
"DEVTOOLS_HUD_USS": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "linear",
"keyed": true,
"low": 20000000,
"high": 100000000,
"n_buckets": 52,
"description": "The USS memory consumed by an application, keyed by appName."
},
"DEVTOOLS_HUD_APP_STARTUP_TIME_CONTENTINTERACTIVE": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "linear",
"keyed": true,
"description": "The duration in ms between application launch and the 'contentInteractive' performance mark, keyed by appName.",
"high": 2000,
"n_buckets": 10
},
"DEVTOOLS_HUD_APP_STARTUP_TIME_NAVIGATIONINTERACTIVE": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "linear",
"keyed": true,
"description": "The duration in ms between application launch and the 'navigationInteractive' performance mark, keyed by appName.",
"high": 3000,
"n_buckets": 10
},
"DEVTOOLS_HUD_APP_STARTUP_TIME_NAVIGATIONLOADED": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "linear",
"keyed": true,
"description": "The duration in ms between application launch and the 'navigationLoaded' performance mark, keyed by appName.",
"high": 4000,
"n_buckets": 10
},
"DEVTOOLS_HUD_APP_STARTUP_TIME_VISUALLYLOADED": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "linear",
"keyed": true,
"description": "The duration in ms between application launch and the 'visuallyLoaded' performance mark, keyed by appName.",
"high": 5000,
"n_buckets": 10
},
"DEVTOOLS_HUD_APP_STARTUP_TIME_MEDIAENUMERATED": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "linear",
"keyed": true,
"description": "The duration in ms between application launch and the 'mediaEnumerated' performance mark, keyed by appName.",
"high": 5000,
"n_buckets": 10
},
"DEVTOOLS_HUD_APP_STARTUP_TIME_FULLYLOADED": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "linear",
"keyed": true,
"description": "The duration in ms between application launch and the 'fullyLoaded' performance mark, keyed by appName.",
"high": 30000,
"n_buckets": 30
},
"DEVTOOLS_HUD_APP_STARTUP_TIME_SCANEND": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "linear",
"keyed": true,
"description": "The duration in ms between application launch and the 'scanEnd' performance mark, keyed by appName.",
"high": 30000,
"n_buckets": 30
},
"DEVTOOLS_HUD_APP_MEMORY_CONTENTINTERACTIVE_V2": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "linear",
"keyed": true,
"description": "The USS memory consumed by an application at the time of the 'contentInteractive' performance mark, keyed by appName.",
"low": 20000000,
"high": 30000000,
"n_buckets": 10
},
"DEVTOOLS_HUD_APP_MEMORY_NAVIGATIONINTERACTIVE_V2": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "linear",
"keyed": true,
"description": "The USS memory consumed by an application at the time of the 'navigationInteractive' performance mark, keyed by appName.",
"low": 20000000,
"high": 30000000,
"n_buckets": 10
},
"DEVTOOLS_HUD_APP_MEMORY_NAVIGATIONLOADED_V2": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "linear",
"keyed": true,
"description": "The USS memory consumed by an application at the time of the 'navigationLoaded' performance mark, keyed by appName.",
"low": 20000000,
"high": 30000000,
"n_buckets": 10
},
"DEVTOOLS_HUD_APP_MEMORY_VISUALLYLOADED_V2": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "linear",
"keyed": true,
"description": "The USS memory consumed by an application at the time of the 'visuallyLoaded' performance mark, keyed by appName.",
"low": 20000000,
"high": 30000000,
"n_buckets": 10
},
"DEVTOOLS_HUD_APP_MEMORY_MEDIAENUMERATED_V2": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "linear",
"keyed": true,
"description": "The USS memory consumed by an application at the time of the 'mediaEnumerated' performance mark, keyed by appName.",
"low": 20000000,
"high": 40000000,
"n_buckets": 10
},
"DEVTOOLS_HUD_APP_MEMORY_FULLYLOADED_V2": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "linear",
"keyed": true,
"description": "The USS memory consumed by an application at the time of the 'fullyLoaded' performance mark, keyed by appName.",
"low": 20000000,
"high": 40000000,
"n_buckets": 20
},
"DEVTOOLS_HUD_APP_MEMORY_SCANEND_V2": {
"alert_emails": ["rnicoletti@mozilla.com","thills@mozilla.com"],
"expires_in_version": "52",
"kind": "linear",
"keyed": true,
"description": "The USS memory consumed by an application at the time of the 'scanEnd' performance mark, keyed by appName.",
"low": 20000000,
"high": 40000000,
"n_buckets": 20
},
"DEVTOOLS_MEMORY_TAKE_SNAPSHOT_COUNT": {
"expires_in_version": "56",
"kind": "count",

View File

@ -893,27 +893,6 @@
"DEVTOOLS_FONTINSPECTOR_TIME_ACTIVE_SECONDS",
"DEVTOOLS_HEAP_SNAPSHOT_EDGE_COUNT",
"DEVTOOLS_HEAP_SNAPSHOT_NODE_COUNT",
"DEVTOOLS_HUD_APP_MEMORY_CONTENTINTERACTIVE_V2",
"DEVTOOLS_HUD_APP_MEMORY_FULLYLOADED_V2",
"DEVTOOLS_HUD_APP_MEMORY_MEDIAENUMERATED_V2",
"DEVTOOLS_HUD_APP_MEMORY_NAVIGATIONINTERACTIVE_V2",
"DEVTOOLS_HUD_APP_MEMORY_NAVIGATIONLOADED_V2",
"DEVTOOLS_HUD_APP_MEMORY_SCANEND_V2",
"DEVTOOLS_HUD_APP_MEMORY_VISUALLYLOADED_V2",
"DEVTOOLS_HUD_APP_STARTUP_TIME_CONTENTINTERACTIVE",
"DEVTOOLS_HUD_APP_STARTUP_TIME_FULLYLOADED",
"DEVTOOLS_HUD_APP_STARTUP_TIME_MEDIAENUMERATED",
"DEVTOOLS_HUD_APP_STARTUP_TIME_NAVIGATIONINTERACTIVE",
"DEVTOOLS_HUD_APP_STARTUP_TIME_NAVIGATIONLOADED",
"DEVTOOLS_HUD_APP_STARTUP_TIME_SCANEND",
"DEVTOOLS_HUD_APP_STARTUP_TIME_VISUALLYLOADED",
"DEVTOOLS_HUD_ERRORS",
"DEVTOOLS_HUD_JANK",
"DEVTOOLS_HUD_REFLOWS",
"DEVTOOLS_HUD_REFLOW_DURATION",
"DEVTOOLS_HUD_SECURITY_CATEGORY",
"DEVTOOLS_HUD_USS",
"DEVTOOLS_HUD_WARNINGS",
"DEVTOOLS_INSPECTOR_TIME_ACTIVE_SECONDS",
"DEVTOOLS_JSBROWSERDEBUGGER_TIME_ACTIVE_SECONDS",
"DEVTOOLS_JSDEBUGGER_TIME_ACTIVE_SECONDS",

View File

@ -1281,16 +1281,16 @@
// The request comes from a XPCOM component, we'd want to redirect
// the request to tabbrowser so tabbrowser will be setup correctly,
// and it will eventually call swapDocShells.
let tabbrowser = this.getTabBrowser();
if (tabbrowser) {
let tab = tabbrowser.getTabForBrowser(this);
if (tab) {
tabbrowser.swapBrowsers(tab, aOtherBrowser, aFlags);
return;
}
let ourTabBrowser = this.getTabBrowser();
let otherTabBrowser = aOtherBrowser.getTabBrowser();
if (ourTabBrowser && otherTabBrowser) {
let ourTab = ourTabBrowser.getTabForBrowser(this);
let otherTab = otherTabBrowser.getTabForBrowser(aOtherBrowser);
ourTabBrowser.swapBrowsers(ourTab, otherTab, aFlags);
return;
}
// If we're not attached to a tabbrowser, just swap.
// One of us is not connected to a tabbrowser, so just swap.
this.swapDocShells(aOtherBrowser);
]]>
</body>

View File

@ -8,6 +8,7 @@
#include "nsIURI.idl"
#include "nsIDOMNode.idl"
interface nsIBrowser;
interface nsIRequest;
interface nsIDOMElement;
interface nsIInputStream;
@ -73,5 +74,14 @@ interface nsIXULBrowserWindow : nsISupports
* Return the number of tabs in this window.
*/
uint32_t getTabCount();
/**
* Navigate the browser to the given history index after restoring the full history
* from SessionStore. If the browser is currently in GroupedSHistory mode, it will
* be reverted to a non-grouped history mode. If a process change is required to
* perform the load, this will also occur.
*/
void navigateAndRestoreByIndex(in nsIBrowser aBrowser, in long aIndex);
};