merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2014-11-11 13:23:32 +01:00
Родитель c3888e9dfc f4ec5222e2
Коммит f3b06a58b3
107 изменённых файлов: 1301 добавлений и 1184 удалений

Просмотреть файл

@ -234,9 +234,6 @@ this.AccessFu = { // jshint ignore:line
case 'AccessFu:Input':
this.Input.setEditState(aMessage.json);
break;
case 'AccessFu:ActivateContextMenu':
this.Input.activateContextMenu(aMessage.json);
break;
case 'AccessFu:DoScroll':
this.Input.doScroll(aMessage.json);
break;
@ -283,7 +280,6 @@ this.AccessFu = { // jshint ignore:line
aMessageManager.addMessageListener('AccessFu:Present', this);
aMessageManager.addMessageListener('AccessFu:Input', this);
aMessageManager.addMessageListener('AccessFu:Ready', this);
aMessageManager.addMessageListener('AccessFu:ActivateContextMenu', this);
aMessageManager.addMessageListener('AccessFu:DoScroll', this);
},
@ -291,7 +287,6 @@ this.AccessFu = { // jshint ignore:line
aMessageManager.removeMessageListener('AccessFu:Present', this);
aMessageManager.removeMessageListener('AccessFu:Input', this);
aMessageManager.removeMessageListener('AccessFu:Ready', this);
aMessageManager.removeMessageListener('AccessFu:ActivateContextMenu', this);
aMessageManager.removeMessageListener('AccessFu:DoScroll', this);
},
@ -673,9 +668,6 @@ var Input = {
case 'doubletap1':
this.activateCurrent();
break;
case 'taphold1':
this.sendContextMenuMessage();
break;
case 'doubletaphold1':
Utils.dispatchChromeEvent('accessibility-control', 'quicknav-menu');
break;
@ -883,15 +875,6 @@ var Input = {
mm.sendAsyncMessage('AccessFu:ContextMenu', {});
},
activateContextMenu: function activateContextMenu(aDetails) {
if (Utils.MozBuildApp === 'mobile/android') {
let p = AccessFu.adjustContentBounds(aDetails.bounds,
Utils.CurrentBrowser, true).center();
Services.obs.notifyObservers(null, 'Gesture:LongPress',
JSON.stringify({x: p.x, y: p.y}));
}
},
setEditState: function setEditState(aEditState) {
Logger.debug(() => { return ['setEditState', JSON.stringify(aEditState)] });
this.editState = aEditState;

Просмотреть файл

@ -69,8 +69,13 @@ function forwardToChild(aMessage, aListener, aVCPosition) {
function activateContextMenu(aMessage) {
let position = Utils.getVirtualCursor(content.document).position;
if (!forwardToChild(aMessage, activateContextMenu, position)) {
sendAsyncMessage('AccessFu:ActivateContextMenu',
{ bounds: Utils.getBounds(position, true) });
let center = Utils.getBounds(position, true).center();
let evt = content.document.createEvent('HTMLEvents');
evt.initEvent('contextmenu', true, true);
evt.clientX = center.x;
evt.clientY = center.y;
position.DOMNode.dispatchEvent(evt);
}
}

Просмотреть файл

@ -6682,11 +6682,11 @@ var gIdentityHandler = {
this._encryptionLabel[this.IDENTITY_MODE_UNKNOWN] =
gNavigatorBundle.getString("identity.unencrypted");
this._encryptionLabel[this.IDENTITY_MODE_MIXED_DISPLAY_LOADED] =
gNavigatorBundle.getString("identity.mixed_display_loaded");
gNavigatorBundle.getString("identity.broken_loaded");
this._encryptionLabel[this.IDENTITY_MODE_MIXED_ACTIVE_LOADED] =
gNavigatorBundle.getString("identity.mixed_active_loaded2");
this._encryptionLabel[this.IDENTITY_MODE_MIXED_DISPLAY_LOADED_ACTIVE_BLOCKED] =
gNavigatorBundle.getString("identity.mixed_display_loaded");
gNavigatorBundle.getString("identity.broken_loaded");
return this._encryptionLabel;
},
get _identityPopup () {

Просмотреть файл

@ -254,7 +254,7 @@ function securityOnLoad() {
if (info.isBroken) {
hdr = pkiBundle.getString("pageInfo_MixedContent");
msg1 = pkiBundle.getString("pageInfo_Privacy_Mixed1");
msg1 = pkiBundle.getString("pageInfo_Privacy_Broken1");
msg2 = pkiBundle.getString("pageInfo_Privacy_None2");
}
else if (info.encryptionStrength > 0) {

Просмотреть файл

@ -430,33 +430,33 @@ skip-if = e10s
[browser_dbg_terminate-on-tab-close.js]
skip-if = e10s
[browser_dbg_tracing-01.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_tracing-02.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_tracing-03.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_tracing-04.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_tracing-05.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_tracing-06.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_tracing-07.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_tracing-08.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-01.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-02.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-03.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-04.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-05.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-06.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-accessibility.js]
skip-if = e10s
[browser_dbg_variables-view-data.js]

Просмотреть файл

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_tracing-01.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
function test() {
SpecialPowers.pushPrefEnv({'set': [["devtools.debugger.tracer", true]]}, () => {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
@ -37,9 +36,7 @@ function test() {
}
function clickButton() {
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
}
function testTraceLogs() {
@ -103,7 +100,6 @@ function testTraceLogs() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
});

Просмотреть файл

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_tracing-01.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
function test() {
SpecialPowers.pushPrefEnv({'set': [["devtools.debugger.tracer", true]]}, () => {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
@ -40,9 +39,7 @@ function test() {
}
function clickButton() {
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
}
function highlightCall() {
@ -72,7 +69,6 @@ function testNoneHighlighted() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
});

Просмотреть файл

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_tracing-01.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
function test() {
SpecialPowers.pushPrefEnv({'set': [["devtools.debugger.tracer", true]]}, () => {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
@ -48,9 +47,7 @@ function test() {
}
function clickButton() {
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
}
function clickTraceLog() {
@ -64,7 +61,6 @@ function testCorrectLine() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
});

Просмотреть файл

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_tracing-01.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
function test() {
SpecialPowers.pushPrefEnv({'set': [["devtools.debugger.tracer", true]]}, () => {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
@ -41,9 +40,7 @@ function test() {
}
function clickButton() {
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
}
function clickTraceCall() {
@ -78,7 +75,6 @@ function testReturn() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
});

Просмотреть файл

@ -7,14 +7,13 @@
const TAB_URL = EXAMPLE_URL + "doc_tracing-01.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gTracer, gL10N;
function test() {
SpecialPowers.pushPrefEnv({'set': [["devtools.debugger.tracer", true]]}, () => {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gTracer = gDebugger.DebuggerView.Tracer;
@ -70,14 +69,11 @@ function testNoEmptyText() {
}
function clickButton() {
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
}
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gTracer = null;

Просмотреть файл

@ -8,14 +8,13 @@
const TAB_URL = EXAMPLE_URL + "doc_tracing-01.html";
const TRACER_PREF = "devtools.debugger.tracer";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gOriginalPref = Services.prefs.getBoolPref(TRACER_PREF);
Services.prefs.setBoolPref(TRACER_PREF, false);
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
@ -32,7 +31,6 @@ function test() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
Services.prefs.setBoolPref(TRACER_PREF, gOriginalPref);

Просмотреть файл

@ -8,13 +8,13 @@
const TAB_URL = EXAMPLE_URL + "doc_tracing-01.html";
let gTab, gDebuggee, gPanel;
let gTab, gPanel;
function test() {
Task.async(function*() {
yield pushPref();
[gTab, gDebuggee, gPanel] = yield initDebugger(TAB_URL);
[gTab,, gPanel] = yield initDebugger(TAB_URL);
yield startTracing(gPanel);
yield clickButton();
@ -60,9 +60,7 @@ function test() {
}
function clickButton() {
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
}
function pushPref() {
@ -80,7 +78,6 @@ function popPref() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
});

Просмотреть файл

@ -9,7 +9,7 @@
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
let variables = aPanel.panelWin.DebuggerView.Variables;
let testScope = variables.addScope("test");

Просмотреть файл

@ -9,7 +9,7 @@
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
let variables = aPanel.panelWin.DebuggerView.Variables;
let testScope = variables.addScope("test");
let testVar = testScope.addItem("something");

Просмотреть файл

@ -9,7 +9,7 @@
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
let variables = aPanel.panelWin.DebuggerView.Variables;
let testScope = variables.addScope("test");

Просмотреть файл

@ -8,7 +8,7 @@
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
let variables = aPanel.panelWin.DebuggerView.Variables;
let testScope = variables.addScope("test");
let testVar = testScope.addItem("something");

Просмотреть файл

@ -8,7 +8,7 @@
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
let variables = aPanel.panelWin.DebuggerView.Variables;
let globalScope = variables.addScope("Test-Global");

Просмотреть файл

@ -8,11 +8,11 @@
const TAB_URL = EXAMPLE_URL + "doc_promise.html";
const test = Task.async(function* () {
const [tab, debuggee, panel] = yield initDebugger(TAB_URL);
const [tab,, panel] = yield initDebugger(TAB_URL);
yield ensureSourceIs(panel, "doc_promise.html", true);
const scopes = waitForCaretAndScopes(panel, 21);
executeSoon(debuggee.doPause);
callInTab(tab, "doPause");
yield scopes;
const variables = panel.panelWin.DebuggerView.Variables;

Просмотреть файл

@ -295,7 +295,7 @@ identity.identified.verified_by_you=You have added a security exception for this
identity.identified.state_and_country=%S, %S
identity.encrypted2=The connection to this website is secure.
identity.mixed_display_loaded=The connection to this website is not fully secure because it contains unencrypted elements (such as images).
identity.broken_loaded=The connection to this website is not fully secure because it contains unencrypted elements (such as images) or the encryption is not strong enough.
identity.mixed_active_loaded2=This website contains interactive content that isn't encrypted (such as scripts). Other people can view your information or modify the website's behavior.
identity.unencrypted=Your connection to this website is not encrypted.

Просмотреть файл

@ -3297,24 +3297,6 @@ if test "$ac_cv_cpp_unused_required" = yes ; then
fi
dnl Some compilers have trouble comparing a constant reference to a templatized
dnl class to zero, and require an explicit operator==() to be defined that takes
dnl an int. This test separates the strong from the weak.
AC_CACHE_CHECK(for trouble comparing to zero near std::operator!=(),
ac_cv_trouble_comparing_to_zero,
[AC_TRY_COMPILE([#include <algorithm>
template <class T> class Foo {};
class T2;
template <class T> int operator==(const T2*, const T&) { return 0; }
template <class T> int operator!=(const T2*, const T&) { return 0; }],
[Foo<int> f; return (0 != f);],
ac_cv_trouble_comparing_to_zero=no,
ac_cv_trouble_comparing_to_zero=yes)])
if test "$ac_cv_trouble_comparing_to_zero" = yes ; then
AC_DEFINE(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO)
fi
# try harder, when checking for __thread support, see bug 521750 comment #33 and below
# We pass MOZ_OPTIMIZE_LDFLAGS to the linker because if dead_strip is
# enabled, the linker in xcode 4.1 will crash. Without this it would crash when
@ -9039,7 +9021,6 @@ CPP_THROW_NEW
HAVE_CPP_AMBIGUITY_RESOLVING_USING
HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
HAVE_CPP_PARTIAL_SPECIALIZATION
HAVE_CPP_TROUBLE_COMPARING_TO_ZERO
NEED_CPP_UNUSED_IMPLEMENTATIONS
HAVE_GETPAGESIZE
HAVE_ICONV

Просмотреть файл

@ -515,14 +515,6 @@ DragDataProducer::Produce(DataTransfer* aDataTransfer,
// grab the href as the url, use alt text as the title of the
// area if it's there. the drag data is the image tag and src
// attribute.
nsCOMPtr<nsIURI> imageURI;
image->GetCurrentURI(getter_AddRefs(imageURI));
if (imageURI) {
nsAutoCString spec;
imageURI->GetSpec(spec);
CopyUTF8toUTF16(spec, mUrlString);
}
nsCOMPtr<nsIDOMElement> imageElement(do_QueryInterface(image));
// XXXbz Shouldn't we use the "title" attr for title? Using
// "alt" seems very wrong....
@ -530,13 +522,10 @@ DragDataProducer::Produce(DataTransfer* aDataTransfer,
imageElement->GetAttribute(NS_LITERAL_STRING("alt"), mTitleString);
}
if (mTitleString.IsEmpty()) {
mTitleString = mUrlString;
}
nsCOMPtr<imgIRequest> imgRequest;
mUrlString.Truncate();
// grab the image data, and its request.
nsCOMPtr<imgIRequest> imgRequest;
nsCOMPtr<imgIContainer> img =
nsContentUtils::GetImageFromContent(image,
getter_AddRefs(imgRequest));
@ -547,7 +536,7 @@ DragDataProducer::Produce(DataTransfer* aDataTransfer,
// Fix the file extension in the URL if necessary
if (imgRequest && mimeService) {
nsCOMPtr<nsIURI> imgUri;
imgRequest->GetURI(getter_AddRefs(imgUri));
imgRequest->GetCurrentURI(getter_AddRefs(imgUri));
nsCOMPtr<nsIURL> imgUrl(do_QueryInterface(imgUri));
@ -568,6 +557,7 @@ DragDataProducer::Produce(DataTransfer* aDataTransfer,
// pass out the image source string
CopyUTF8toUTF16(spec, mImageSourceString);
mUrlString = mImageSourceString;
bool validExtension;
if (extension.IsEmpty() ||
@ -602,6 +592,18 @@ DragDataProducer::Produce(DataTransfer* aDataTransfer,
}
}
}
if (mUrlString.IsEmpty()) {
nsCOMPtr<nsIURI> imageURI;
image->GetCurrentURI(getter_AddRefs(imageURI));
if (imageURI) {
nsAutoCString spec;
imageURI->GetSpec(spec);
CopyUTF8toUTF16(spec, mUrlString);
}
}
if (mTitleString.IsEmpty()) {
mTitleString = mUrlString;
}
if (parentLink) {
// If we are dragging around an image in an anchor, then we

Просмотреть файл

@ -6,7 +6,7 @@
dupe-manifest =
head = xpcshell-head-parent-process.js
tail =
skip-if = toolkit == 'android' || toolkit == 'gonk'
skip-if = toolkit == 'gonk'
support-files =
bug1056939.zip
GlobalObjectsChild.js
@ -21,6 +21,7 @@ support-files =
[test_blob_file_backed.js]
[test_bug1056939.js]
[test_globalObjects_ipc.js]
skip-if = toolkit == 'android'
[test_invalidate.js]
# disabled for the moment.
skip-if = true

Просмотреть файл

@ -1,8 +1,6 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
[DEFAULT]
skip-if = toolkit == 'gonk'
[test_add_put.js]
[test_add_twice_failure.js]

Просмотреть файл

@ -1173,6 +1173,7 @@ MediaCache::Update()
// Figure out where we should be reading from. It's the first
// uncached byte after the current mStreamOffset.
int64_t dataOffset = stream->GetCachedDataEndInternal(stream->mStreamOffset);
MOZ_ASSERT(dataOffset >= 0);
// Compute where we'd actually seek to to read at readOffset
int64_t desiredOffset = dataOffset;
@ -1705,6 +1706,7 @@ MediaCacheStream::NotifyDataStarted(int64_t aOffset)
ReentrantMonitorAutoEnter mon(gMediaCache->GetReentrantMonitor());
NS_WARN_IF_FALSE(aOffset == mChannelOffset,
"Server is giving us unexpected offset");
MOZ_ASSERT(aOffset >= 0);
mChannelOffset = aOffset;
if (mStreamLength >= 0) {
// If we started reading at a certain offset, then for sure
@ -2134,23 +2136,28 @@ MediaCacheStream::Seek(int32_t aWhence, int64_t aOffset)
return NS_ERROR_FAILURE;
int64_t oldOffset = mStreamOffset;
int64_t newOffset = mStreamOffset;
switch (aWhence) {
case PR_SEEK_END:
if (mStreamLength < 0)
return NS_ERROR_FAILURE;
mStreamOffset = mStreamLength + aOffset;
newOffset = mStreamLength + aOffset;
break;
case PR_SEEK_CUR:
mStreamOffset += aOffset;
newOffset += aOffset;
break;
case PR_SEEK_SET:
mStreamOffset = aOffset;
newOffset = aOffset;
break;
default:
NS_ERROR("Unknown whence");
return NS_ERROR_FAILURE;
}
if (newOffset < 0)
return NS_ERROR_FAILURE;
mStreamOffset = newOffset;
CACHE_LOG(PR_LOG_DEBUG, ("Stream %p Seek to %lld", this, (long long)mStreamOffset));
gMediaCache->NoteSeek(this, oldOffset);
@ -2192,11 +2199,10 @@ MediaCacheStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes)
break;
}
size = std::min(size, bytesRemaining);
// Clamp size until 64-bit file size issues (bug 500784) are fixed.
// Clamp size until 64-bit file size issues are fixed.
size = std::min(size, int64_t(INT32_MAX));
}
int32_t bytes;
int32_t cacheBlock = streamBlock < mBlocks.Length() ? mBlocks[streamBlock] : -1;
if (cacheBlock < 0) {
// We don't have a complete cached block here.
@ -2224,7 +2230,10 @@ MediaCacheStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes)
// We can just use the data in mPartialBlockBuffer. In fact we should
// use it rather than waiting for the block to fill and land in
// the cache.
bytes = std::min<int64_t>(size, streamWithPartialBlock->mChannelOffset - mStreamOffset);
int64_t bytes = std::min<int64_t>(size, streamWithPartialBlock->mChannelOffset - mStreamOffset);
// Clamp bytes until 64-bit file size issues are fixed.
bytes = std::min(bytes, int64_t(INT32_MAX));
NS_ABORT_IF_FALSE(bytes >= 0 && bytes <= aCount, "Bytes out of range.");
memcpy(aBuffer,
reinterpret_cast<char*>(streamWithPartialBlock->mPartialBlockBuffer.get()) + offsetInStreamBlock, bytes);
if (mCurrentMode == MODE_METADATA) {
@ -2248,6 +2257,7 @@ MediaCacheStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes)
gMediaCache->NoteBlockUsage(this, cacheBlock, mCurrentMode, TimeStamp::Now());
int64_t offset = cacheBlock*BLOCK_SIZE + offsetInStreamBlock;
int32_t bytes;
NS_ABORT_IF_FALSE(size >= 0 && size <= INT32_MAX, "Size out of range.");
nsresult rv = gMediaCache->ReadCacheFile(offset, aBuffer + count, int32_t(size), &bytes);
if (NS_FAILED(rv)) {
@ -2284,9 +2294,7 @@ MediaCacheStream::ReadAt(int64_t aOffset, char* aBuffer,
}
nsresult
MediaCacheStream::ReadFromCache(char* aBuffer,
int64_t aOffset,
int64_t aCount)
MediaCacheStream::ReadFromCache(char* aBuffer, int64_t aOffset, int64_t aCount)
{
ReentrantMonitorAutoEnter mon(gMediaCache->GetReentrantMonitor());
if (mClosed)
@ -2308,7 +2316,7 @@ MediaCacheStream::ReadFromCache(char* aBuffer,
return NS_ERROR_FAILURE;
}
size = std::min(size, bytesRemaining);
// Clamp size until 64-bit file size issues (bug 500784) are fixed.
// Clamp size until 64-bit file size issues are fixed.
size = std::min(size, int64_t(INT32_MAX));
}
@ -2319,7 +2327,10 @@ MediaCacheStream::ReadFromCache(char* aBuffer,
// We can just use the data in mPartialBlockBuffer. In fact we should
// use it rather than waiting for the block to fill and land in
// the cache.
bytes = std::min<int64_t>(size, mChannelOffset - streamOffset);
// Clamp bytes until 64-bit file size issues are fixed.
int64_t toCopy = std::min<int64_t>(size, mChannelOffset - streamOffset);
bytes = std::min(toCopy, int64_t(INT32_MAX));
NS_ABORT_IF_FALSE(bytes >= 0 && bytes <= toCopy, "Bytes out of range.");
memcpy(aBuffer + count,
reinterpret_cast<char*>(mPartialBlockBuffer.get()) + offsetInStreamBlock, bytes);
} else {

Просмотреть файл

@ -221,9 +221,6 @@ WMFAudioMFTManager::Output(int64_t aStreamOffset,
hr = buffer->Lock(&data, &maxLength, &currentLength);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
int32_t numSamples = currentLength / mAudioBytesPerSample;
int32_t numFrames = numSamples / mAudioChannels;
// Sometimes when starting decoding, the AAC decoder gives us samples
// with a negative timestamp. AAC does usually have preroll (or encoder
// delay) encoded into its bitstream, but the amount encoded to the stream
@ -245,6 +242,13 @@ WMFAudioMFTManager::Output(int64_t aStreamOffset,
int32_t numFramesToStrip = 0;
sample->GetUINT32(MFSampleExtension_Discontinuity, &discontinuity);
if (mMustRecaptureAudioPosition || discontinuity) {
// Update the output type, in case this segment has a different
// rate. This also triggers on the first sample, which can have a
// different rate than is advertised in the container, and sometimes we
// don't get a MF_E_TRANSFORM_STREAM_CHANGE when the rate changes.
hr = UpdateOutputType();
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
mAudioFrameSum = 0;
LONGLONG timestampHns = 0;
hr = sample->GetSampleTime(&timestampHns);
@ -258,15 +262,10 @@ WMFAudioMFTManager::Output(int64_t aStreamOffset,
mAudioFrameOffset = 0;
}
mMustRecaptureAudioPosition = false;
// Also update the output type, in case this segment has a different
// rate. This also triggers on the first sample, which can have a
// different rate than is advertised in the container, and sometimes
// we don't get a MF_E_TRANSFORM_STREAM_CHANGE when the rate changes.
hr = UpdateOutputType();
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
}
MOZ_ASSERT(numFramesToStrip >= 0);
int32_t numSamples = currentLength / mAudioBytesPerSample;
int32_t numFrames = numSamples / mAudioChannels;
int32_t offset = std::min<int32_t>(numFramesToStrip, numFrames);
numFrames -= offset;
numSamples -= offset * mAudioChannels;

Просмотреть файл

@ -341,8 +341,6 @@ GMPChild::PreLoadLibraries(const std::string& aPluginPath)
// This must be in sorted order and lowercase!
static const char* whitelist[] =
{
"bcrypt.dll", // Used for OutputProtectionManager handshake
"crypt32.dll", // Used for OutputProtectionManager handshake
"d3d9.dll", // Create an `IDirect3D9` to get adapter information
"dxva2.dll", // Get monitor information
"msauddecmft.dll", // AAC decoder (on Windows 8)

Просмотреть файл

@ -33,6 +33,10 @@
#include "OMXCodecProxy.h"
#include "OmxDecoder.h"
#define LOG_TAG "OmxDecoder"
#include <android/log.h>
#define ALOG(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#ifdef PR_LOGGING
PRLogModuleInfo *gOmxDecoderLog;
#define LOG(type, msg...) PR_LOG(gOmxDecoderLog, type, (msg))
@ -66,7 +70,8 @@ OmxDecoder::OmxDecoder(MediaResource *aResource,
mIsVideoSeeking(false),
mAudioMetadataRead(false),
mAudioPaused(false),
mVideoPaused(false)
mVideoPaused(false),
mVideoLastFrameTime(-1)
{
mLooper = new ALooper;
mLooper->setName("OmxDecoder");
@ -556,14 +561,43 @@ bool OmxDecoder::ReadVideo(VideoFrame *aFrame, int64_t aTimeUs,
mIsVideoSeeking = true;
}
MediaSource::ReadOptions options;
options.setSeekTo(aTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
err = mVideoSource->read(&mVideoBuffer, &options);
{
Mutex::Autolock autoLock(mSeekLock);
mIsVideoSeeking = false;
PostReleaseVideoBuffer(nullptr, FenceHandle());
MediaSource::ReadOptions::SeekMode seekMode;
// If the last timestamp of decoded frame is smaller than seekTime,
// seek to next key frame. Otherwise seek to the previos one.
if (mVideoLastFrameTime > aTimeUs || mVideoLastFrameTime == -1) {
seekMode = MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC;
} else {
seekMode = MediaSource::ReadOptions::SEEK_NEXT_SYNC;
}
bool findNextBuffer = true;
while (findNextBuffer) {
options.setSeekTo(aTimeUs, seekMode);
findNextBuffer = false;
err = mVideoSource->read(&mVideoBuffer, &options);
{
Mutex::Autolock autoLock(mSeekLock);
mIsVideoSeeking = false;
PostReleaseVideoBuffer(nullptr, FenceHandle());
}
// If there is no next Keyframe, jump to the previous key frame.
if (err == ERROR_END_OF_STREAM && seekMode == MediaSource::ReadOptions::SEEK_NEXT_SYNC) {
seekMode = MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC;
findNextBuffer = true;
{
Mutex::Autolock autoLock(mSeekLock);
mIsVideoSeeking = true;
}
continue;
} else if (err != OK) {
ALOG("Unexpected error when seeking to %lld", aTimeUs);
break;
}
if (mVideoBuffer->range_length() == 0) {
ReleaseVideoBuffer();
findNextBuffer = true;
}
}
aDoSeek = false;
} else {
err = mVideoSource->read(&mVideoBuffer);
@ -635,6 +669,7 @@ bool OmxDecoder::ReadVideo(VideoFrame *aFrame, int64_t aTimeUs,
if ((aKeyframeSkip && timeUs < aTimeUs) || length == 0) {
aFrame->mShouldSkip = true;
}
mVideoLastFrameTime = timeUs;
}
else if (err == INFO_FORMAT_CHANGED) {
// If the format changed, update our cached info.

Просмотреть файл

@ -60,6 +60,8 @@ class OmxDecoder : public OMXCodecProxy::EventListener {
int32_t mAudioChannels;
int32_t mAudioSampleRate;
int64_t mDurationUs;
int64_t mVideoLastFrameTime;
VideoFrame mVideoFrame;
AudioFrame mAudioFrame;
MP3FrameParser mMP3FrameParser;

Просмотреть файл

@ -1279,6 +1279,10 @@ EventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
mProxy->mSeenUploadLoadStart = false;
}
else {
if (!mProxy->mSeenLoadStart) {
// We've already dispatched premature abort events.
return true;
}
mProxy->mSeenLoadStart = false;
}
}
@ -2404,7 +2408,9 @@ XMLHttpRequest::UpdateState(const StateData& aStateData,
bool aUseCachedArrayBufferResponse)
{
if (aUseCachedArrayBufferResponse) {
MOZ_ASSERT(JS_IsArrayBufferObject(mStateData.mResponse.toObjectOrNull()));
MOZ_ASSERT(mStateData.mResponse.isObject() &&
JS_IsArrayBufferObject(&mStateData.mResponse.toObject()));
JS::Rooted<JS::Value> response(mWorkerPrivate->GetJSContext(),
mStateData.mResponse);
mStateData = aStateData;

Просмотреть файл

@ -447,7 +447,8 @@ nsHTMLEditRules::AfterEditInner(EditAction action,
res = PromoteRange(mDocChangeRange, action);
NS_ENSURE_SUCCESS(res, res);
// if we did a ranged deletion, make sure we have a place to put caret.
// if we did a ranged deletion or handling backspace key, make sure we have
// a place to put caret.
// Note we only want to do this if the overall operation was deletion,
// not if deletion was done along the way for EditAction::loadHTML, EditAction::insertText, etc.
// That's why this is here rather than DidDeleteSelection().
@ -2045,6 +2046,10 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection,
res = InsertBRIfNeeded(aSelection);
NS_ENSURE_SUCCESS(res, res);
// Remember that we did a ranged delete for the benefit of
// AfterEditInner().
mDidRangedDelete = true;
return NS_OK;
}

Просмотреть файл

@ -140,6 +140,7 @@ skip-if = os != "win"
[test_bug998188.html]
[test_bug1026397.html]
[test_bug1067255.html]
[test_bug1094000.html]
skip-if = e10s
[test_CF_HTML_clipboard.html]
[test_contenteditable_focus.html]

Просмотреть файл

@ -0,0 +1,104 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1094000
-->
<head>
<title>Test for Bug 1094000</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1094000">Mozilla Bug 1094000</a>
<p id="display"></p>
<div id="content">
<div id="editor0" contenteditable></div>
<div id="editor1" contenteditable><br></div>
<div id="editor2" contenteditable>a</div>
<div id="editor3" contenteditable>b</div>
<div id="editor4" contenteditable>c</div>
<div id="editor5" contenteditable>d</div>
<div id="editor6" contenteditable>e</div>
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 1094000 **/
SimpleTest.waitForExplicitFinish();
const kIsLinux = navigator.platform.indexOf("Linux") == 0;
function runTests()
{
var editor0 = document.getElementById("editor0");
var editor1 = document.getElementById("editor1");
var editor2 = document.getElementById("editor2");
var editor3 = document.getElementById("editor3");
var editor4 = document.getElementById("editor4");
var editor5 = document.getElementById("editor5");
var editor6 = document.getElementById("editor6");
ok(editor1.getBoundingClientRect().height - editor0.getBoundingClientRect().height > 1,
"an editor having a <br> element and an empty editor shouldn't be same height");
ok(Math.abs(editor1.getBoundingClientRect().height - editor2.getBoundingClientRect().height) <= 1,
"an editor having only a <br> element and an editor having \"a\" should be same height");
editor2.focus();
synthesizeKey("VK_RIGHT", {});
synthesizeKey("VK_BACK_SPACE", {});
is(editor2.innerHTML, "<br>",
"an editor which had \"a\" should have only <br> element after Backspace keypress");
ok(Math.abs(editor2.getBoundingClientRect().height - editor1.getBoundingClientRect().height) <= 1,
"an editor whose content was removed by Backspace key should have a place to put a caret");
editor3.focus();
synthesizeKey("VK_LEFT", {});
synthesizeKey("VK_DELETE", {});
is(editor3.innerHTML, "<br>",
"an editor which had \"b\" should have only <br> element after Delete keypress");
ok(Math.abs(editor3.getBoundingClientRect().height - editor1.getBoundingClientRect().height) <= 1,
"an editor whose content was removed by Delete key should have a place to put a caret");
editor4.focus();
window.getSelection().selectAllChildren(editor4);
synthesizeKey("VK_BACK_SPACE", {});
is(editor4.innerHTML, "<br>",
"an editor which had \"c\" should have only <br> element after removing selected text with Backspace key");
ok(Math.abs(editor4.getBoundingClientRect().height - editor1.getBoundingClientRect().height) <= 1,
"an editor whose content was selected and removed by Backspace key should have a place to put a caret");
editor5.focus();
window.getSelection().selectAllChildren(editor5);
synthesizeKey("VK_DELETE", {});
is(editor5.innerHTML, "<br>",
"an editor which had \"d\" should have only <br> element after removing selected text with Delete key");
ok(Math.abs(editor5.getBoundingClientRect().height - editor1.getBoundingClientRect().height) <= 1,
"an editor whose content was selected and removed by Delete key should have a place to put a caret");
editor6.focus();
window.getSelection().selectAllChildren(editor6);
synthesizeKey("x", { accelKey: true });
is(editor6.innerHTML, "<br>",
"an editor which had \"e\" should have only <br> element after removing selected text by \"Cut\"");
ok(Math.abs(editor6.getBoundingClientRect().height - editor1.getBoundingClientRect().height) <= 1,
"an editor whose content was selected and removed by \"Cut\" should have a place to put a caret");
editor0.focus();
synthesizeKey("VK_BACK_SPACE", {});
is(editor0.innerHTML, "",
"an empty editor should keep being empty even if Backspace key is pressed");
synthesizeKey("VK_DELETE", {});
is(editor0.innerHTML, "",
"an empty editor should keep being empty even if Delete key is pressed");
SimpleTest.finish();
}
SimpleTest.waitForFocus(runTests);
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -148,7 +148,9 @@ However, on the main thread, web content might be running Javascript code that p
Scroll changes driven from the main thread are just as legitimate and need to be propagated to the compositor thread, so that the visual display updates in response.
Because the cross-thread messaging is asynchronous, reconciling the two types of scroll changes is a tricky problem.
Our design solves this using various flags and generation counters that ensures compositor-driven scroll changes never overwrite content-driven scroll changes - this behaviour is usually the desired outcome.
Our design solves this using various flags and generation counters.
The general heuristic we have is that content-driven scroll position changes (e.g. scrollTo from JS) are never lost.
For instance, if the user is doing an async scroll with their finger and content does a scrollTo in the middle, then some of the async scroll would occur before the "jump" and the rest after the "jump".
### Content preventing default behaviour of input events
@ -165,3 +167,116 @@ The way the APZ implementation deals with this is that upon receiving a touch ev
It also schedules a 300ms timeout during which content is allowed to prevent scrolling.
There is an API that allows the main-thread event dispatching code to notify the APZ as to whether or not the default action should be prevented.
If the APZ content response timeout expires, or if the main-thread event dispatching code notifies the APZ of the preventDefault status, then the APZ continues with the processing of the events (which may involve discarding the events).
## Technical details
This section describes various pieces of the APZ code, and goes into more specific detail on APIs and code than the previous sections.
The primary purpose of this section is to help people who plan on making changes to the code, while also not going into so much detail that it needs to be updated with every patch.
### Overall flow of input events
This section describes how input events flow through the APZ code.
<ol>
<li value="1">
Input events arrive from the hardware/widget code into the APZ via APZCTreeManager::ReceiveInputEvent.
The thread that invokes this is called the input thread, and may or may not be the same as the Gecko main thread.
</li>
<li value="2">
Conceptually the first thing that the APZCTreeManager does is to group these events into "input blocks".
An input block is a contiguous set of events that get handled together.
For example with touch events, all events following a touchstart up to but not including the next touchstart are in the same block.
All of the events in a given block will go to the same APZC instance and will either all be processed or all be dropped.
</li>
<li value="3">
Using the first event in the input block, the APZCTreeManager does a hit-test to see which APZC it hits.
If no APZC is hit, the events are discarded and we jump to step 6.
Otherwise, the input block is tagged with the APZC and put into a global APZ input queue.
</li>
<li value="4">
<ol>
<li value="i">
If the input events are not touch events, or if the APZC is for content without touch listeners, any available events in the input block are processed.
These may trigger behaviours like scrolling or tap gestures.
</li>
<li value="ii">
If the input events are touch events and the APZC is for content with touch listeners, the events are left in the queue and a 300ms timeout is initiated.
If the timeout expires before step 9 is completed, the APZ assumes the input block was not cancelled and processes them as part of step 10.
</li>
</ol>
</li>
<li value="5">
The call stack unwinds back to APZCTreeManager::ReceiveInputEvent, which does an in-place modification of the input event so that any async transforms are removed.
</li>
<li value="6">
The call stack unwinds back to the widget code that called ReceiveInputEvent.
This code now has the event in the coordinate space Gecko is expecting, and so can dispatch it to the Gecko main thread.
</li>
<li value="7">
Gecko performs its own usual hit-testing and event dispatching for the event.
As part of this, it records whether any touch listeners cancelled the input block by calling preventDefault().
</li>
<li value="8">
The call stack unwinds back to the widget code, which sends a notification to the APZ code by calling APZCTreeManager::ContentReceivedTouch on the input thread.
This happens only once per input block.
</li>
<li value="9">
<ol>
<li value="i">
If the events were processed as part of step 4(i), the call to ContentReceivedTouch is ignored and step 10 is skipped.
</li>
<li value="ii">
If events were queued as part of step 4(ii), and steps 5-8 take less than 300ms, the ContentReceivedTouch call marks the input block ready for processing.
</li>
<li value="iii">
If events were queued as part of step 4(ii), but steps 5-8 take longer than 300ms, the ContentReceivedTouch will be ignored and step 10 will already have happened.
</li>
</ol>
</li>
<li value="10">
If events were queued as part of step 4(ii) they are now either processed (if the input block was not cancelled, or if the timeout expired) or dropped (if it was cancelled).
Processing the events may trigger behaviours like scrolling or tap gestures.
</li>
</ol>
If the CSS touch-action property is enabled, the above steps are modified as follows:
<ul>
<li>
In step 4, the APZC also requires the allowed touch-action behaviours for the input event. This is not available yet, so the events are always queued.
</li>
<li>
In step 6, the widget code determines the content element at the point under the input element, and notifies the APZ code of the allowed touch-action behaviours.
This is done via a call to APZCTreeManager::SetAllowedTouchBehavior on the input thread.
</li>
</ul>
#### Threading considerations
The bulk of the input processing in the APZ code happens on what we call "the input thread".
In practice the input thread could be the Gecko main thread, the compositor thread, or some other thread.
There are obvious downsides to using the Gecko main thread - that is, "asynchronous" panning and zooming is not really asynchronous as input events can only be processed while Gecko is idle.
However, this is the current state of things on B2G and Metro.
Using the compositor thread as the input thread could work on some platforms, but may be inefficient on others.
For example, on Android (Fennec) we receive input events from the system on a dedicated UI thread.
We would have to redispatch the input events to the compositor thread if we wanted to the input thread to be the same as the compositor thread.
This introduces a potential for higher latency, particularly if the compositor does any blocking operations - blocking SwapBuffers operations, for example.
As a result, the APZ code itself does not assume that the input thread will be the same as the Gecko main thread or the compositor thread.
#### Active vs. inactive scrollframes
The number of scrollframes on a page is potentially unbounded.
However, we do not want to create a separate layer for each scrollframe right away, as this would require large amounts of memory.
Therefore, scrollframes as designated as either "active" or "inactive".
Active scrollframes are the ones that do have their contents put on a separate layer (or set of layers), and inactive ones do not.
Consider a page with a scrollframe that is initially inactive.
When layout generates the layers for this page, it inserts a "scrollinfo" layer into the layer tree to let the APZ know that there is potentially scrollable content there.
The scrollinfo layer is an empty ContainerLayer, which does not require much extra memory.
The composition bounds of this scrollinfo layer are used on the compositor for hit-testing, and a "placeholder" APZC is created for this scrollframe.
When the user starts interacting with that content, the hit-test in the APZ code finds the placeholder APZC and starts routing it the events as usual.
The APZC eventually sends a repaint request to the main thread, and that repaint request sets a displayport on the scrollframe.
Setting the displayport activates the scrollframe and causes it to get pushed onto a separate layer (or set of layers).
This model imples that when the user initially attempts to scroll an inactive scrollframe, it will not initially scroll visually.
(This is because although the APZC is tracking the events and updating scroll position, there is no layer to which it can apply the async scroll offset.)
Only after the round-trip to the gecko thread is complete is there a layer for async scrolling to actually occur.
At that point the scrollframe will visually "jump" to the correct scroll offset.

Просмотреть файл

@ -485,6 +485,12 @@ BasicLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback,
mTransactionIncomplete = false;
if (mRoot) {
if (aFlags & END_NO_COMPOSITE) {
// Apply pending tree updates before recomputing effective
// properties.
mRoot->ApplyPendingUpdatesToSubtree();
}
// Need to do this before we call ApplyDoubleBuffering,
// which depends on correct effective transforms
if (mTarget) {
@ -499,12 +505,6 @@ BasicLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback,
if (mRoot->GetMaskLayer()) {
ToData(mRoot->GetMaskLayer())->Validate(aCallback, aCallbackData, nullptr);
}
if (aFlags & END_NO_COMPOSITE) {
// Apply pending tree updates before recomputing effective
// properties.
mRoot->ApplyPendingUpdatesToSubtree();
}
}
if (mTarget && mRoot &&

Просмотреть файл

@ -584,7 +584,7 @@ gfxDWriteFont::ProvidesGlyphWidths() const
}
int32_t
gfxDWriteFont::GetGlyphWidth(gfxContext *aCtx, uint16_t aGID)
gfxDWriteFont::GetGlyphWidth(DrawTarget& aDrawTarget, uint16_t aGID)
{
if (!mGlyphWidths) {
mGlyphWidths = new nsDataHashtable<nsUint32HashKey,int32_t>(128);

Просмотреть файл

@ -54,7 +54,7 @@ public:
virtual bool ProvidesGlyphWidths() const;
virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID);
virtual int32_t GetGlyphWidth(DrawTarget& aDrawTarget, uint16_t aGID);
virtual mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions>
GetGlyphRenderingOptions(const TextRunDrawParams* aRunParams = nullptr) MOZ_OVERRIDE;

Просмотреть файл

@ -168,7 +168,7 @@ gfxFT2FontBase::GetGlyph(uint32_t unicode, uint32_t variation_selector)
}
int32_t
gfxFT2FontBase::GetGlyphWidth(gfxContext *aCtx, uint16_t aGID)
gfxFT2FontBase::GetGlyphWidth(DrawTarget& aDrawTarget, uint16_t aGID)
{
cairo_text_extents_t extents;
GetGlyphExtents(aGID, &extents);

Просмотреть файл

@ -25,7 +25,7 @@ public:
virtual bool ProvidesGetGlyph() const { return true; }
virtual uint32_t GetGlyph(uint32_t unicode, uint32_t variation_selector);
virtual bool ProvidesGlyphWidths() const { return true; }
virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID);
virtual int32_t GetGlyphWidth(DrawTarget& aDrawTarget, uint16_t aGID);
cairo_scaled_font_t *CairoScaledFont() { return mScaledFont; };
virtual bool SetupCairoFont(gfxContext *aContext);

Просмотреть файл

@ -791,7 +791,7 @@ gfxFont::GetGlyphHAdvance(gfxContext *aCtx, uint16_t aGID)
return 0;
}
if (ProvidesGlyphWidths()) {
return GetGlyphWidth(aCtx, aGID) / 65536.0;
return GetGlyphWidth(*aCtx->GetDrawTarget(), aGID) / 65536.0;
}
if (mFUnitsConvFactor == 0.0f) {
GetMetrics(eHorizontal);
@ -806,7 +806,7 @@ gfxFont::GetGlyphHAdvance(gfxContext *aCtx, uint16_t aGID)
if (!shaper->Initialize()) {
return 0;
}
return shaper->GetGlyphHAdvance(aCtx, aGID) / 65536.0;
return shaper->GetGlyphHAdvance(aGID) / 65536.0;
}
/*static*/

Просмотреть файл

@ -1267,6 +1267,9 @@ class gfxFont {
friend class gfxHarfBuzzShaper;
friend class gfxGraphiteShaper;
protected:
typedef mozilla::gfx::DrawTarget DrawTarget;
public:
nsrefcnt AddRef(void) {
NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt");
@ -1709,7 +1712,7 @@ public:
virtual FontType GetType() const = 0;
virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont> GetScaledFont(mozilla::gfx::DrawTarget *aTarget)
virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont> GetScaledFont(DrawTarget* aTarget)
{ return gfxPlatform::GetPlatform()->GetScaledFontForFont(aTarget, this); }
bool KerningDisabled() {
@ -1820,7 +1823,7 @@ protected:
// The return value is interpreted as a horizontal advance in 16.16 fixed
// point format.
virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID) {
virtual int32_t GetGlyphWidth(DrawTarget& aDrawTarget, uint16_t aGID) {
return -1;
}

Просмотреть файл

@ -460,7 +460,7 @@ gfxGDIFont::GetGlyph(uint32_t aUnicode, uint32_t aVarSelector)
}
int32_t
gfxGDIFont::GetGlyphWidth(gfxContext *aCtx, uint16_t aGID)
gfxGDIFont::GetGlyphWidth(DrawTarget& aDrawTarget, uint16_t aGID)
{
if (!mGlyphWidths) {
mGlyphWidths = new nsDataHashtable<nsUint32HashKey,int32_t>(128);
@ -471,7 +471,7 @@ gfxGDIFont::GetGlyphWidth(gfxContext *aCtx, uint16_t aGID)
return width;
}
DCFromContext dc(aCtx);
DCFromDrawTarget dc(aDrawTarget);
AutoSelectFont fs(dc, GetHFONT());
int devWidth;

Просмотреть файл

@ -60,7 +60,7 @@ public:
virtual bool ProvidesGlyphWidths() const { return true; }
// get hinted glyph width in pixels as 16.16 fixed-point value
virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID);
virtual int32_t GetGlyphWidth(DrawTarget& aDrawTarget, uint16_t aGID);
virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
FontCacheSizes* aSizes) const;

Просмотреть файл

@ -50,7 +50,8 @@ gfxGraphiteShaper::GrGetAdvance(const void* appFontHandle, uint16_t glyphid)
{
const CallbackData *cb =
static_cast<const CallbackData*>(appFontHandle);
return FixedToFloat(cb->mFont->GetGlyphWidth(cb->mContext, glyphid));
return FixedToFloat(cb->mFont->GetGlyphWidth(*cb->mContext->GetDrawTarget(),
glyphid));
}
static inline uint32_t

Просмотреть файл

@ -184,8 +184,7 @@ struct GlyphMetrics {
};
hb_position_t
gfxHarfBuzzShaper::GetGlyphHAdvance(gfxContext *aContext,
hb_codepoint_t glyph) const
gfxHarfBuzzShaper::GetGlyphHAdvance(hb_codepoint_t glyph) const
{
// font did not implement GetGlyphWidth, so get an unhinted value
// directly from the font tables
@ -208,8 +207,7 @@ gfxHarfBuzzShaper::GetGlyphHAdvance(gfxContext *aContext,
}
hb_position_t
gfxHarfBuzzShaper::GetGlyphVAdvance(gfxContext *aContext,
hb_codepoint_t glyph) const
gfxHarfBuzzShaper::GetGlyphVAdvance(hb_codepoint_t glyph) const
{
if (!mVmtxTable) {
// Must be a "vertical" font that doesn't actually have vertical metrics;
@ -243,10 +241,9 @@ gfxHarfBuzzShaper::HBGetGlyphHAdvance(hb_font_t *font, void *font_data,
static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
gfxFont *gfxfont = fcd->mShaper->GetFont();
if (gfxfont->ProvidesGlyphWidths()) {
return gfxfont->GetGlyphWidth(fcd->mContext, glyph);
} else {
return fcd->mShaper->GetGlyphHAdvance(fcd->mContext, glyph);
return gfxfont->GetGlyphWidth(*fcd->mContext->GetDrawTarget(), glyph);
}
return fcd->mShaper->GetGlyphHAdvance(glyph);
}
/* static */
@ -258,10 +255,9 @@ gfxHarfBuzzShaper::HBGetGlyphVAdvance(hb_font_t *font, void *font_data,
static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
gfxFont *gfxfont = fcd->mShaper->GetFont();
if (gfxfont->ProvidesGlyphWidths()) {
return gfxfont->GetGlyphWidth(fcd->mContext, glyph);
} else {
return fcd->mShaper->GetGlyphVAdvance(fcd->mContext, glyph);
return gfxfont->GetGlyphWidth(*fcd->mContext->GetDrawTarget(), glyph);
}
return fcd->mShaper->GetGlyphVAdvance(glyph);
}
/* static */
@ -296,15 +292,15 @@ gfxHarfBuzzShaper::HBGetGlyphVOrigin(hb_font_t *font, void *font_data,
{
const gfxHarfBuzzShaper::FontCallbackData *fcd =
static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
fcd->mShaper->GetGlyphVOrigin(fcd->mContext, glyph, x, y);
fcd->mShaper->GetGlyphVOrigin(glyph, x, y);
return true;
}
void
gfxHarfBuzzShaper::GetGlyphVOrigin(gfxContext *aContext, hb_codepoint_t aGlyph,
gfxHarfBuzzShaper::GetGlyphVOrigin(hb_codepoint_t aGlyph,
hb_position_t *aX, hb_position_t *aY) const
{
*aX = -0.5 * GetGlyphHAdvance(aContext, aGlyph);
*aX = -0.5 * GetGlyphHAdvance(aGlyph);
if (mVORGTable) {
// We checked in Initialize() that the VORG table is safely readable,

Просмотреть файл

@ -42,13 +42,11 @@ public:
hb_codepoint_t variation_selector) const;
// get harfbuzz glyph advance, in font design units
hb_position_t GetGlyphHAdvance(gfxContext *aContext,
hb_codepoint_t glyph) const;
hb_position_t GetGlyphHAdvance(hb_codepoint_t glyph) const;
hb_position_t GetGlyphVAdvance(gfxContext *aContext,
hb_codepoint_t glyph) const;
hb_position_t GetGlyphVAdvance(hb_codepoint_t glyph) const;
void GetGlyphVOrigin(gfxContext *aContext, hb_codepoint_t aGlyph,
void GetGlyphVOrigin(hb_codepoint_t aGlyph,
hb_position_t *aX, hb_position_t *aY) const;
// get harfbuzz horizontal advance in 16.16 fixed point format.

Просмотреть файл

@ -4,10 +4,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/ArrayUtils.h"
#include "gfxWindowsPlatform.h"
#include "cairo.h"
#include "mozilla/ArrayUtils.h"
#include "gfxImageSurface.h"
#include "gfxWindowsSurface.h"
@ -80,6 +81,31 @@ using namespace mozilla::layers;
using namespace mozilla::widget;
using namespace mozilla::image;
DCFromDrawTarget::DCFromDrawTarget(DrawTarget& aDrawTarget)
{
mDC = nullptr;
if (aDrawTarget.GetBackendType() == BackendType::CAIRO) {
cairo_surface_t *surf = (cairo_surface_t*)
aDrawTarget.GetNativeSurface(NativeSurfaceType::CAIRO_SURFACE);
cairo_surface_type_t surfaceType = cairo_surface_get_type(surf);
if (surfaceType == CAIRO_SURFACE_TYPE_WIN32 ||
surfaceType == CAIRO_SURFACE_TYPE_WIN32_PRINTING) {
mDC = cairo_win32_surface_get_dc(surf);
mNeedsRelease = false;
SaveDC(mDC);
cairo_t* ctx = (cairo_t*)
aDrawTarget.GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT);
cairo_scaled_font_t* scaled = cairo_get_scaled_font(ctx);
cairo_win32_scaled_font_select_font(scaled, mDC);
}
if (!mDC) {
mDC = GetDC(nullptr);
SetGraphicsMode(mDC, GM_ADVANCED);
mNeedsRelease = true;
}
}
}
#ifdef CAIRO_HAS_D2D_SURFACE
static const char *kFeatureLevelPref =
@ -1531,7 +1557,7 @@ bool DoesD3D11DeviceWork(ID3D11Device *device)
#endif
return false;
}
if (displayLinkModuleVersion <= GFX_DRIVER_VERSION(8,6,1,36484)) {
if (displayLinkModuleVersion <= V(8,6,1,36484)) {
#if defined(MOZ_CRASHREPORTER)
CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("DisplayLink: too old version\n"));
#endif

Просмотреть файл

@ -20,8 +20,8 @@
#include "gfxDWriteFonts.h"
#endif
#include "gfxPlatform.h"
#include "gfxContext.h"
#include "gfxTypes.h"
#include "mozilla/Attributes.h"
#include "nsTArray.h"
#include "nsDataHashtable.h"
@ -44,6 +44,9 @@
#endif
namespace mozilla {
namespace gfx {
class DrawTarget;
}
namespace layers {
class DeviceManagerD3D9;
class ReadbackManagerD3D11;
@ -55,44 +58,31 @@ struct IDXGIAdapter1;
class nsIMemoryReporter;
// Utility to get a Windows HDC from a thebes context,
// used by both GDI and Uniscribe font shapers
struct DCFromContext {
DCFromContext(gfxContext *aContext) {
dc = nullptr;
nsRefPtr<gfxASurface> aSurface = aContext->CurrentSurface();
if (aSurface &&
(aSurface->GetType() == gfxSurfaceType::Win32 ||
aSurface->GetType() == gfxSurfaceType::Win32Printing))
{
dc = static_cast<gfxWindowsSurface*>(aSurface.get())->GetDC();
needsRelease = false;
SaveDC(dc);
cairo_scaled_font_t* scaled =
cairo_get_scaled_font(aContext->GetCairo());
cairo_win32_scaled_font_select_font(scaled, dc);
}
if (!dc) {
dc = GetDC(nullptr);
SetGraphicsMode(dc, GM_ADVANCED);
needsRelease = true;
}
}
/**
* Utility to get a Windows HDC from a Moz2D DrawTarget. If the DrawTarget is
* not backed by a HDC this will get the HDC for the screen device context
* instead.
*/
class MOZ_STACK_CLASS DCFromDrawTarget MOZ_FINAL
{
public:
DCFromDrawTarget(mozilla::gfx::DrawTarget& aDrawTarget);
~DCFromContext() {
if (needsRelease) {
ReleaseDC(nullptr, dc);
~DCFromDrawTarget() {
if (mNeedsRelease) {
ReleaseDC(nullptr, mDC);
} else {
RestoreDC(dc, -1);
RestoreDC(mDC, -1);
}
}
operator HDC () {
return dc;
return mDC;
}
HDC dc;
bool needsRelease;
private:
HDC mDC;
bool mNeedsRelease;
};
// ClearType parameters set by running ClearType tuner

Просмотреть файл

@ -19,7 +19,7 @@ interface nsIPrincipal;
* @version 0.1
* @see imagelib2
*/
[scriptable, builtinclass, uuid(710f22f0-558b-11e4-8ed6-0800200c9a66)]
[scriptable, builtinclass, uuid(dc61f0ea-4139-4c2a-ae69-cec82d33e089)]
interface imgIRequest : nsIRequest
{
/**
@ -83,6 +83,11 @@ interface imgIRequest : nsIRequest
*/
readonly attribute nsIURI URI;
/**
* The URI of the resource we ended up loading after all redirects, etc.
*/
readonly attribute nsIURI currentURI;
readonly attribute imgINotificationObserver notificationObserver;
readonly attribute string mimeType;

Просмотреть файл

@ -245,35 +245,6 @@ Decoder::AllocateFrame()
return rv;
}
void
Decoder::FlushInvalidations()
{
NS_ABORT_IF_FALSE(!HasDecoderError(),
"Not allowed to make more decoder calls after error!");
// If we've got an empty invalidation rect, we have nothing to do
if (mInvalidRect.IsEmpty())
return;
if (mObserver) {
#ifdef XP_MACOSX
// Bug 703231
// Because of high quality down sampling on mac we show scan lines while decoding.
// Bypass this problem by redrawing the border.
if (mImageMetadata.HasSize()) {
nsIntRect mImageBound(0, 0, mImageMetadata.GetWidth(), mImageMetadata.GetHeight());
mInvalidRect.Inflate(1);
mInvalidRect = mInvalidRect.Intersect(mImageBound);
}
#endif
mObserver->FrameChanged(&mInvalidRect);
}
// Clear the invalidation rectangle
mInvalidRect.SetEmpty();
}
void
Decoder::SetSizeOnImage()
{
@ -320,11 +291,6 @@ Decoder::PostFrameStart()
// We shouldn't already be mid-frame
NS_ABORT_IF_FALSE(!mInFrame, "Starting new frame but not done with old one!");
// We should take care of any invalidation region when wrapping up the
// previous frame
NS_ABORT_IF_FALSE(mInvalidRect.IsEmpty(),
"Start image frame with non-empty invalidation region!");
// Update our state to reflect the new frame
mFrameCount++;
mInFrame = true;
@ -334,11 +300,6 @@ Decoder::PostFrameStart()
// reported by the Image.
NS_ABORT_IF_FALSE(mFrameCount == mImage.GetNumFrames(),
"Decoder frame count doesn't match image's!");
// Fire notifications
if (mObserver) {
mObserver->OnStartFrame();
}
}
void
@ -363,9 +324,6 @@ Decoder::PostFrameStop(FrameBlender::FrameAlpha aFrameAlpha /* = FrameBlender::k
mCurrentFrame->SetBlendMethod(aBlendMethod);
mCurrentFrame->ImageUpdated(mCurrentFrame->GetRect());
// Flush any invalidations before we finish the frame
FlushInvalidations();
// Fire notifications
if (mObserver) {
mObserver->OnStopFrame();

Просмотреть файл

@ -69,14 +69,17 @@ public:
void FinishSharedDecoder();
/**
* Tells the decoder to flush any pending invalidations. This informs the image
* frame of its decoded region, and sends the appropriate OnDataAvailable call
* to consumers.
*
* This can be called any time when we're midway through decoding a frame,
* and must be called after finishing a frame (before starting a new one).
* Gets the invalidation region accumulated by the decoder so far, and clears
* the decoder's invalidation region. This means that each call to
* TakeInvalidRect() returns only the invalidation region accumulated since
* the last call to TakeInvalidRect().
*/
void FlushInvalidations();
nsIntRect TakeInvalidRect()
{
nsIntRect invalidRect = mInvalidRect;
mInvalidRect.SetEmpty();
return invalidRect;
}
// We're not COM-y, so we don't get refcounts by default
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Decoder)

Просмотреть файл

@ -484,10 +484,10 @@ RasterImage::RequestRefresh(const TimeStamp& aTime)
UpdateImageContainer();
// Explicitly call this on mStatusTracker so we're sure to not interfere
// with the decoding process
if (mStatusTracker)
mStatusTracker->FrameChanged(&res.dirtyRect);
if (mStatusTracker) {
mStatusTracker->SyncNotifyDifference(ImageStatusDiff::NoChange(),
res.dirtyRect);
}
}
if (res.animationFinished) {
@ -655,6 +655,17 @@ RasterImage::GetRequestedFrameIndex(uint32_t aWhichFrame) const
return aWhichFrame == FRAME_FIRST ? 0 : GetCurrentFrameIndex();
}
nsIntRect
RasterImage::GetFirstFrameRect()
{
if (mAnim) {
return mAnim->GetFirstFrameRefreshArea();
}
// Fall back to our size. This is implicitly zero-size if !mHasSize.
return nsIntRect(nsIntPoint(0,0), mSize);
}
//******************************************************************************
/* [notxpcom] boolean frameIsOpaque(in uint32_t aWhichFrame); */
NS_IMETHODIMP_(bool)
@ -1457,7 +1468,7 @@ RasterImage::ResetAnimation()
// Update display
if (mStatusTracker) {
nsIntRect rect = mAnim->GetFirstFrameRefreshArea();
mStatusTracker->FrameChanged(&rect);
mStatusTracker->SyncNotifyDifference(ImageStatusDiff::NoChange(), rect);
}
// Start the animation again. It may not have been running before, if
@ -1558,14 +1569,6 @@ RasterImage::AddSourceData(const char *aBuffer, uint32_t aCount)
rv = WriteToDecoder(aBuffer, aCount, DECODE_SYNC);
CONTAINER_ENSURE_SUCCESS(rv);
// We're not storing source data, so this data is probably coming straight
// from the network. In this case, we want to display data as soon as we
// get it, so we want to flush invalidations after every write.
nsRefPtr<Decoder> kungFuDeathGrip = mDecoder;
mInDecoder = true;
mDecoder->FlushInvalidations();
mInDecoder = false;
rv = FinishedSomeDecoding();
CONTAINER_ENSURE_SUCCESS(rv);
}
@ -2416,15 +2419,6 @@ RasterImage::SyncDecode()
DECODE_SYNC);
CONTAINER_ENSURE_SUCCESS(rv);
// When we're doing a sync decode, we want to get as much information from the
// image as possible. We've send the decoder all of our data, so now's a good
// time to flush any invalidations (in case we don't have all the data and what
// we got left us mid-frame).
nsRefPtr<Decoder> kungFuDeathGrip = mDecoder;
mInDecoder = true;
mDecoder->FlushInvalidations();
mInDecoder = false;
rv = FinishedSomeDecoding();
CONTAINER_ENSURE_SUCCESS(rv);
@ -2498,9 +2492,8 @@ RasterImage::NotifyNewScaledFrame()
if (mStatusTracker) {
// Send an invalidation so observers will repaint and can take advantage of
// the new scaled frame if possible.
// XXX(seth): Why does FrameChanged take a pointer and not a reference?
nsIntRect invalidationRect(0, 0, mSize.width, mSize.height);
mStatusTracker->FrameChanged(&invalidationRect);
nsIntRect rect(0, 0, mSize.width, mSize.height);
mStatusTracker->SyncNotifyDifference(ImageStatusDiff::NoChange(), rect);
}
}
@ -3001,9 +2994,12 @@ RasterImage::FinishedSomeDecoding(eShutdownIntent aIntent /* = eShutdownIntent_D
bool done = false;
bool wasSize = false;
nsIntRect invalidRect;
nsresult rv = NS_OK;
if (image->mDecoder) {
invalidRect = image->mDecoder->TakeInvalidRect();
if (request && request->mChunkCount && !image->mDecoder->IsSizeDecode()) {
Telemetry::Accumulate(Telemetry::IMAGE_DECODE_CHUNKS, request->mChunkCount);
}
@ -3046,6 +3042,17 @@ RasterImage::FinishedSomeDecoding(eShutdownIntent aIntent /* = eShutdownIntent_D
}
}
if (GetCurrentFrameIndex() > 0) {
// Don't send invalidations for animated frames after the first; let
// RequestRefresh take care of that.
invalidRect = nsIntRect();
}
if (mHasBeenDecoded && !invalidRect.IsEmpty()) {
// Don't send partial invalidations if we've been decoded before.
invalidRect = mDecoded ? GetFirstFrameRect()
: nsIntRect();
}
ImageStatusDiff diff =
request ? image->mStatusTracker->Difference(request->mStatusTracker)
: image->mStatusTracker->DecodeStateAsDifference();
@ -3058,13 +3065,15 @@ RasterImage::FinishedSomeDecoding(eShutdownIntent aIntent /* = eShutdownIntent_D
// FinishedSomeDecoding on the stack.
NS_WARNING("Recursively notifying in RasterImage::FinishedSomeDecoding!");
mStatusDiff.Combine(diff);
mInvalidRect.Union(invalidRect);
} else {
MOZ_ASSERT(mStatusDiff.IsNoChange(), "Shouldn't have an accumulated change at this point");
MOZ_ASSERT(mInvalidRect.IsEmpty(), "Shouldn't have an accumulated invalidation rect here");
while (!diff.IsNoChange()) {
while (!diff.IsNoChange() || !invalidRect.IsEmpty()) {
// Tell the observers what happened.
mNotifying = true;
image->mStatusTracker->SyncNotifyDifference(diff);
image->mStatusTracker->SyncNotifyDifference(diff, invalidRect);
mNotifying = false;
// Gather any status changes that may have occurred as a result of sending
@ -3072,6 +3081,8 @@ RasterImage::FinishedSomeDecoding(eShutdownIntent aIntent /* = eShutdownIntent_D
// notifications for them next.
diff = mStatusDiff;
mStatusDiff = ImageStatusDiff::NoChange();
invalidRect = mInvalidRect;
mInvalidRect = nsIntRect();
}
}
@ -3484,31 +3495,6 @@ RasterImage::DecodePool::DecodeSomeOfImage(RasterImage* aImg,
aImg->mDecodeRequest->mChunkCount += chunkCount;
}
// Flush invalidations (and therefore paint) now that we've decoded all the
// chunks we're going to.
//
// However, don't paint if:
//
// * This was an until-size decode. Until-size decodes are always followed
// by normal decodes, so don't bother painting.
//
// * The decoder flagged an error. The decoder may have written garbage
// into the output buffer; don't paint it to the screen.
//
// * We have all the source data. This disables progressive display of
// previously-decoded images, thus letting us finish decoding faster,
// since we don't waste time painting while we decode.
// Decoder::PostFrameStop() will flush invalidations once the decode is
// done.
if (aDecodeType != DECODE_TYPE_UNTIL_SIZE &&
!aImg->mDecoder->HasError() &&
!aImg->mHasSourceData) {
aImg->mInDecoder = true;
aImg->mDecoder->FlushInvalidations();
aImg->mInDecoder = false;
}
return NS_OK;
}

Просмотреть файл

@ -552,6 +552,8 @@ private:
uint32_t GetCurrentFrameIndex() const;
uint32_t GetRequestedFrameIndex(uint32_t aWhichFrame) const;
nsIntRect GetFirstFrameRect();
size_t SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const;
@ -662,6 +664,7 @@ private: // data
// Notification state. Used to avoid recursive notifications.
ImageStatusDiff mStatusDiff;
nsIntRect mInvalidRect;
bool mNotifying:1;
// Boolean flags (clustered together to conserve space):

Просмотреть файл

@ -571,8 +571,10 @@ VectorImage::SendInvalidationNotifications()
if (mStatusTracker) {
SurfaceCache::Discard(this);
mStatusTracker->FrameChanged(&nsIntRect::GetMaxSizedIntRect());
mStatusTracker->OnStopFrame();
ImageStatusDiff diff;
diff.diffState = FLAG_FRAME_STOPPED;
mStatusTracker->ApplyDifference(diff);
mStatusTracker->SyncNotifyDifference(diff, nsIntRect::GetMaxSizedIntRect());
}
}
@ -1119,17 +1121,11 @@ VectorImage::OnSVGDocumentLoaded()
// Tell *our* observers that we're done loading.
if (mStatusTracker) {
nsRefPtr<imgStatusTracker> clone = mStatusTracker->CloneForRecording();
imgDecoderObserver* observer = clone->GetDecoderObserver();
observer->OnStartContainer(); // Signal that width/height are available.
observer->FrameChanged(&nsIntRect::GetMaxSizedIntRect());
observer->OnStopFrame();
observer->OnStopDecode(NS_OK); // Unblock page load.
ImageStatusDiff diff = mStatusTracker->Difference(clone);
ImageStatusDiff diff;
diff.diffState = FLAG_HAS_SIZE | FLAG_FRAME_STOPPED | FLAG_DECODE_STOPPED |
FLAG_ONLOAD_UNBLOCKED;
mStatusTracker->ApplyDifference(diff);
mStatusTracker->SyncNotifyDifference(diff);
mStatusTracker->SyncNotifyDifference(diff, nsIntRect::GetMaxSizedIntRect());
}
EvaluateAnimation();

Просмотреть файл

@ -66,20 +66,6 @@ public:
*/
virtual void OnStartContainer() = 0;
/**
* Decode notification.
*
* Called when we know a frame has begun decoding.
*/
virtual void OnStartFrame() = 0;
/**
* Decode notification.
*
* called when there is more to paint.
*/
virtual void FrameChanged(const nsIntRect * aDirtyRect) = 0;
/**
* Decode notification.
*

Просмотреть файл

@ -40,14 +40,17 @@ using namespace mozilla;
using namespace mozilla::image;
#if defined(PR_LOGGING)
PRLogModuleInfo *
PRLogModuleInfo*
GetImgLog()
{
static PRLogModuleInfo *sImgLog;
static PRLogModuleInfo* sImgLog;
if (!sImgLog)
sImgLog = PR_NewLogModule("imgRequest");
return sImgLog;
}
#define LOG_TEST(level) (GetImgLog() && PR_LOG_TEST(GetImgLog(), (level)))
#else
#define LOG_TEST(level) false
#endif
NS_IMPL_ISUPPORTS(imgRequest,
@ -367,6 +370,21 @@ nsresult imgRequest::GetURI(ImageURL **aURI)
return NS_ERROR_FAILURE;
}
nsresult imgRequest::GetCurrentURI(nsIURI **aURI)
{
MOZ_ASSERT(aURI);
LOG_FUNC(GetImgLog(), "imgRequest::GetCurrentURI");
if (mCurrentURI) {
*aURI = mCurrentURI;
NS_ADDREF(*aURI);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
nsresult imgRequest::GetImageErrorCode()
{
return mImageErrorCode;
@ -1064,16 +1082,24 @@ imgRequest::OnRedirectVerifyCallback(nsresult result)
mTimedChannel = do_QueryInterface(mChannel);
mNewRedirectChannel = nullptr;
#if defined(PR_LOGGING)
nsAutoCString oldspec;
if (mCurrentURI)
mCurrentURI->GetSpec(oldspec);
LOG_MSG_WITH_PARAM(GetImgLog(), "imgRequest::OnChannelRedirect", "old", oldspec.get());
#endif
if (LOG_TEST(PR_LOG_DEBUG)) {
nsAutoCString spec;
if (mCurrentURI)
mCurrentURI->GetSpec(spec);
LOG_MSG_WITH_PARAM(GetImgLog(), "imgRequest::OnChannelRedirect", "old", spec.get());
}
// make sure we have a protocol that returns data rather than opens
// an external application, e.g. mailto:
mChannel->GetURI(getter_AddRefs(mCurrentURI));
if (LOG_TEST(PR_LOG_DEBUG)) {
nsAutoCString spec;
if (mCurrentURI)
mCurrentURI->GetSpec(spec);
LOG_MSG_WITH_PARAM(GetImgLog(), "imgRequest::OnChannelRedirect", "new", spec.get());
}
bool doesNotReturnData = false;
nsresult rv =
NS_URIChainHasFlags(mCurrentURI, nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA,

Просмотреть файл

@ -137,6 +137,7 @@ public:
// OK to use on any thread.
nsresult GetURI(ImageURL **aURI);
nsresult GetCurrentURI(nsIURI **aURI);
nsresult GetImageErrorCode(void);

Просмотреть файл

@ -537,6 +537,14 @@ NS_IMETHODIMP imgRequestProxy::GetURI(nsIURI **aURI)
return NS_OK;
}
nsresult imgRequestProxy::GetCurrentURI(nsIURI **aURI)
{
if (!GetOwner())
return NS_ERROR_FAILURE;
return GetOwner()->GetCurrentURI(aURI);
}
nsresult imgRequestProxy::GetURI(ImageURL **aURI)
{
if (!mURI)

Просмотреть файл

@ -62,22 +62,6 @@ public:
tracker->RecordStartContainer(image);
}
virtual void OnStartFrame() MOZ_OVERRIDE
{
LOG_SCOPE(GetImgLog(), "imgStatusTrackerObserver::OnStartFrame");
nsRefPtr<imgStatusTracker> tracker = mTracker.get();
if (!tracker) { return; }
tracker->RecordStartFrame();
}
virtual void FrameChanged(const nsIntRect* dirtyRect) MOZ_OVERRIDE
{
LOG_SCOPE(GetImgLog(), "imgStatusTrackerObserver::FrameChanged");
nsRefPtr<imgStatusTracker> tracker = mTracker.get();
if (!tracker) { return; }
tracker->RecordFrameChanged(dirtyRect);
}
virtual void OnStopFrame() MOZ_OVERRIDE
{
LOG_SCOPE(GetImgLog(), "imgStatusTrackerObserver::OnStopFrame");
@ -159,7 +143,6 @@ imgStatusTracker::imgStatusTracker(const imgStatusTracker& aOther)
// - mProperties, because we don't need it and it'd just point at the same
// object
// - mConsumers, because we don't need to talk to consumers
// - mInvalidRect, because the point of it is to be fired off and reset
{
mTrackerObserver = new imgStatusTrackerObserver(this);
}
@ -370,7 +353,7 @@ imgStatusTracker::NotifyCurrentState(imgRequestProxy* proxy)
#define NOTIFY_IMAGE_OBSERVERS(func) \
do { \
ProxyArray::ForwardIterator iter(proxies); \
ProxyArray::ForwardIterator iter(aProxies); \
while (iter.HasMore()) { \
nsRefPtr<imgRequestProxy> proxy = iter.GetNext().get(); \
if (proxy && !proxy->NotificationsDeferred()) { \
@ -380,57 +363,57 @@ imgStatusTracker::NotifyCurrentState(imgRequestProxy* proxy)
} while (false);
/* static */ void
imgStatusTracker::SyncNotifyState(ProxyArray& proxies,
bool hasImage, uint32_t state,
nsIntRect& dirtyRect)
imgStatusTracker::SyncNotifyState(ProxyArray& aProxies,
bool aHasImage, uint32_t aState,
const nsIntRect& aDirtyRect)
{
MOZ_ASSERT(NS_IsMainThread());
// OnStartRequest
if (state & FLAG_REQUEST_STARTED)
if (aState & FLAG_REQUEST_STARTED)
NOTIFY_IMAGE_OBSERVERS(OnStartRequest());
// OnStartContainer
if (state & FLAG_HAS_SIZE)
if (aState & FLAG_HAS_SIZE)
NOTIFY_IMAGE_OBSERVERS(OnStartContainer());
// OnStartDecode
if (state & FLAG_DECODE_STARTED)
if (aState & FLAG_DECODE_STARTED)
NOTIFY_IMAGE_OBSERVERS(OnStartDecode());
// BlockOnload
if (state & FLAG_ONLOAD_BLOCKED)
if (aState & FLAG_ONLOAD_BLOCKED)
NOTIFY_IMAGE_OBSERVERS(BlockOnload());
if (hasImage) {
if (aHasImage) {
// OnFrameUpdate
// If there's any content in this frame at all (always true for
// vector images, true for raster images that have decoded at
// least one frame) then send OnFrameUpdate.
if (!dirtyRect.IsEmpty())
NOTIFY_IMAGE_OBSERVERS(OnFrameUpdate(&dirtyRect));
if (!aDirtyRect.IsEmpty())
NOTIFY_IMAGE_OBSERVERS(OnFrameUpdate(&aDirtyRect));
if (state & FLAG_FRAME_STOPPED)
if (aState & FLAG_FRAME_STOPPED)
NOTIFY_IMAGE_OBSERVERS(OnStopFrame());
// OnImageIsAnimated
if (state & FLAG_IS_ANIMATED)
if (aState & FLAG_IS_ANIMATED)
NOTIFY_IMAGE_OBSERVERS(OnImageIsAnimated());
}
// Send UnblockOnload before OnStopDecode and OnStopRequest. This allows
// observers that can fire events when they receive those notifications to do
// so then, instead of being forced to wait for UnblockOnload.
if (state & FLAG_ONLOAD_UNBLOCKED) {
if (aState & FLAG_ONLOAD_UNBLOCKED) {
NOTIFY_IMAGE_OBSERVERS(UnblockOnload());
}
if (state & FLAG_DECODE_STOPPED) {
NS_ABORT_IF_FALSE(hasImage, "stopped decoding without ever having an image?");
if (aState & FLAG_DECODE_STOPPED) {
MOZ_ASSERT(aHasImage, "Stopped decoding without ever having an image?");
NOTIFY_IMAGE_OBSERVERS(OnStopDecode());
}
if (state & FLAG_REQUEST_STOPPED) {
NOTIFY_IMAGE_OBSERVERS(OnStopRequest(state & FLAG_MULTIPART_STOPPED));
if (aState & FLAG_REQUEST_STOPPED) {
NOTIFY_IMAGE_OBSERVERS(OnStopRequest(aState & FLAG_MULTIPART_STOPPED));
}
}
@ -440,22 +423,6 @@ imgStatusTracker::Difference(imgStatusTracker* aOther) const
MOZ_ASSERT(aOther, "aOther cannot be null");
ImageStatusDiff diff;
diff.diffState = ~mState & aOther->mState;
// Only record partial invalidations if we haven't been decoded before.
// When images are re-decoded after discarding, we don't want to display
// partially decoded versions to the user.
const uint32_t combinedState = mState | aOther->mState;
const bool doInvalidations = !(mState & FLAG_DECODE_STOPPED) ||
aOther->mState & FLAG_DECODE_STOPPED ||
combinedState & FLAG_HAS_ERROR;
// Record and reset the invalid rectangle.
// XXX(seth): We shouldn't be resetting anything here; see bug 910441.
if (doInvalidations) {
diff.invalidRect = aOther->mInvalidRect;
aOther->mInvalidRect.SetEmpty();
}
return diff;
}
@ -476,18 +443,15 @@ imgStatusTracker::ApplyDifference(const ImageStatusDiff& aDiff)
}
void
imgStatusTracker::SyncNotifyDifference(const ImageStatusDiff& diff)
imgStatusTracker::SyncNotifyDifference(const ImageStatusDiff& aDiff,
const nsIntRect& aInvalidRect /* = nsIntRect() */)
{
MOZ_ASSERT(NS_IsMainThread(), "Use mConsumers on main thread only");
LOG_SCOPE(GetImgLog(), "imgStatusTracker::SyncNotifyDifference");
nsIntRect invalidRect = mInvalidRect.Union(diff.invalidRect);
SyncNotifyState(mConsumers, !!mImage, aDiff.diffState, aInvalidRect);
SyncNotifyState(mConsumers, !!mImage, diff.diffState, invalidRect);
mInvalidRect.SetEmpty();
if (diff.diffState & FLAG_HAS_ERROR) {
if (aDiff.diffState & FLAG_HAS_ERROR) {
FireFailureNotification();
}
}
@ -648,14 +612,6 @@ imgStatusTracker::SendStartContainer(imgRequestProxy* aProxy)
aProxy->OnStartContainer();
}
void
imgStatusTracker::RecordStartFrame()
{
mInvalidRect.SetEmpty();
}
// No SendStartFrame since it's not observed below us.
void
imgStatusTracker::RecordStopFrame()
{
@ -746,23 +702,6 @@ imgStatusTracker::OnUnlockedDraw()
}
}
void
imgStatusTracker::RecordFrameChanged(const nsIntRect* aDirtyRect)
{
NS_ABORT_IF_FALSE(mImage,
"RecordFrameChanged called before we have an Image");
mInvalidRect = mInvalidRect.Union(*aDirtyRect);
}
void
imgStatusTracker::SendFrameChanged(imgRequestProxy* aProxy,
const nsIntRect* aDirtyRect)
{
MOZ_ASSERT(NS_IsMainThread());
if (!aProxy->NotificationsDeferred())
aProxy->OnFrameUpdate(aDirtyRect);
}
/* non-virtual sort-of-nsIRequestObserver methods */
void
imgStatusTracker::RecordStartRequest()
@ -895,22 +834,6 @@ imgStatusTracker::OnDiscard()
}
}
void
imgStatusTracker::FrameChanged(const nsIntRect* aDirtyRect)
{
MOZ_ASSERT(NS_IsMainThread());
RecordFrameChanged(aDirtyRect);
/* notify the kids */
ProxyArray::ForwardIterator iter(mConsumers);
while (iter.HasMore()) {
nsRefPtr<imgRequestProxy> proxy = iter.GetNext().get();
if (proxy) {
SendFrameChanged(proxy, aDirtyRect);
}
}
}
void
imgStatusTracker::OnStopFrame()
{

Просмотреть файл

@ -46,8 +46,7 @@ enum {
struct ImageStatusDiff
{
ImageStatusDiff()
: invalidRect()
, diffState(0)
: diffState(0)
{ }
static ImageStatusDiff NoChange() { return ImageStatusDiff(); }
@ -55,17 +54,14 @@ struct ImageStatusDiff
bool operator!=(const ImageStatusDiff& aOther) const { return !(*this == aOther); }
bool operator==(const ImageStatusDiff& aOther) const {
return aOther.invalidRect == invalidRect
&& aOther.diffState == diffState;
return aOther.diffState == diffState;
}
void Combine(const ImageStatusDiff& aOther) {
invalidRect = invalidRect.Union(aOther.invalidRect);
diffState |= aOther.diffState;
}
nsIntRect invalidRect;
uint32_t diffState;
uint32_t diffState;
};
} // namespace image
@ -179,7 +175,7 @@ public:
void RecordLoaded();
// Shorthand for recording all the decode notifications: StartDecode,
// StartFrame, DataAvailable, StopFrame, StopDecode.
// DataAvailable, StopFrame, StopDecode.
void RecordDecoded();
/* non-virtual imgDecoderObserver methods */
@ -189,10 +185,6 @@ public:
void SendStartDecode(imgRequestProxy* aProxy);
void RecordStartContainer(imgIContainer* aContainer);
void SendStartContainer(imgRequestProxy* aProxy);
void RecordStartFrame();
// No SendStartFrame since it's not observed below us.
void RecordFrameChanged(const nsIntRect* aDirtyRect);
void SendFrameChanged(imgRequestProxy* aProxy, const nsIntRect* aDirtyRect);
void RecordStopFrame();
void SendStopFrame(imgRequestProxy* aProxy);
void RecordStopDecode(nsresult statusg);
@ -219,7 +211,6 @@ public:
void OnDataAvailable();
void OnStopRequest(bool aLastPart, nsresult aStatus);
void OnDiscard();
void FrameChanged(const nsIntRect* aDirtyRect);
void OnUnlockedDraw();
// This is called only by VectorImage, and only to ensure tests work
// properly. Do not use it.
@ -265,9 +256,8 @@ public:
// Notify for the changes captured in an ImageStatusDiff. Because this may
// result in recursive notifications, no decoding locks may be held.
// Called on the main thread only.
void SyncNotifyDifference(const mozilla::image::ImageStatusDiff& aDiff);
nsIntRect GetInvalidRect() const { return mInvalidRect; }
void SyncNotifyDifference(const mozilla::image::ImageStatusDiff& aDiff,
const nsIntRect& aInvalidRect = nsIntRect());
private:
typedef nsTObserverArray<mozilla::WeakPtr<imgRequestProxy>> ProxyArray;
@ -282,16 +272,12 @@ private:
// Main thread only, since imgRequestProxy calls are expected on the main
// thread, and mConsumers is not threadsafe.
static void SyncNotifyState(ProxyArray& proxies,
bool hasImage, uint32_t state,
nsIntRect& dirtyRect);
static void SyncNotifyState(ProxyArray& aProxies,
bool aHasImage, uint32_t aState,
const nsIntRect& aInvalidRect);
nsCOMPtr<nsIRunnable> mRequestRunnable;
// The invalid area of the most recent frame we know about. (All previous
// frames are assumed to be fully valid.)
nsIntRect mInvalidRect;
// This weak ref should be set null when the image goes out of scope.
mozilla::image::Image* mImage;

Просмотреть файл

@ -33,6 +33,7 @@ var gRanEvent = false;
var gObserver;
var gImg1;
var gImg2;
var gFirstImageLoaded = false;
var gOuter;
var gFinished = false;
var gFirstRequest = null;
@ -71,20 +72,37 @@ function failTest() {
cleanUpAndFinish();
}
function waitForLoadAndTest(image) {
return () => {
// Draw the image into a canvas to ensure it's decoded.
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0);
// Attach the observer.
var imgLoadingContent = image.QueryInterface(Ci.nsIImageLoadingContent);
imgLoadingContent.addObserver(gOuter);
// If the other image already loaded, add both images to the document, which
// begins the real test.
if (gFirstImageLoaded) {
gContent.appendChild(gImg1);
gContent.appendChild(gImg2);
} else {
gFirstImageLoaded = true;
}
};
}
function main() {
gImg1 = new Image();
gImg2 = new Image();
// Create, customize & attach decoder observer
// Create and customize decoder observer
var obs = new ImageDecoderObserverStub();
obs.frameUpdate = frameUpdate;
gOuter = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools).createScriptedObserver(obs);
var imgLoadingContent = gImg1.QueryInterface(Ci.nsIImageLoadingContent);
imgLoadingContent.addObserver(gOuter);
imgLoadingContent = gImg2.QueryInterface(Ci.nsIImageLoadingContent);
imgLoadingContent.addObserver(gOuter);
// We want to test the cold loading behavior, so clear cache in case an
// earlier test got our image in there already.
@ -94,8 +112,9 @@ function main() {
gImg1.src = "animated1.gif";
gImg2.src = "animated2.gif";
gContent.appendChild(gImg1);
gContent.appendChild(gImg2);
// Wait for each image to load.
gImg1.addEventListener('load', waitForLoadAndTest(gImg1));
gImg2.addEventListener('load', waitForLoadAndTest(gImg2));
// In case something goes wrong, fail earlier than mochitest timeout,
// and with more information.

Просмотреть файл

@ -500,7 +500,7 @@ AsmJSHandleExecutionInterrupt()
{
AsmJSActivation *act = PerThreadData::innermostAsmJSActivation();
act->module().setInterrupted(true);
bool ret = HandleExecutionInterrupt(act->cx());
bool ret = CheckForInterrupt(act->cx());
act->module().setInterrupted(false);
return ret;
}
@ -673,8 +673,8 @@ AddressOf(AsmJSImmKind kind, ExclusiveContext *cx)
switch (kind) {
case AsmJSImm_Runtime:
return cx->runtimeAddressForJit();
case AsmJSImm_RuntimeInterrupt:
return cx->runtimeAddressOfInterrupt();
case AsmJSImm_RuntimeInterruptUint32:
return cx->runtimeAddressOfInterruptUint32();
case AsmJSImm_StackLimit:
return cx->stackLimitAddressForJitCode(StackForUntrustedScript);
case AsmJSImm_ReportOverRecursed:

Просмотреть файл

@ -2664,24 +2664,6 @@ if test "$ac_cv_cpp_unused_required" = yes ; then
fi
dnl Some compilers have trouble comparing a constant reference to a templatized
dnl class to zero, and require an explicit operator==() to be defined that takes
dnl an int. This test separates the strong from the weak.
AC_CACHE_CHECK(for trouble comparing to zero near std::operator!=(),
ac_cv_trouble_comparing_to_zero,
[AC_TRY_COMPILE([#include <algorithm>
template <class T> class Foo {};
class T2;
template <class T> int operator==(const T2*, const T&) { return 0; }
template <class T> int operator!=(const T2*, const T&) { return 0; }],
[Foo<int> f; return (0 != f);],
ac_cv_trouble_comparing_to_zero=no,
ac_cv_trouble_comparing_to_zero=yes)])
if test "$ac_cv_trouble_comparing_to_zero" = yes ; then
AC_DEFINE(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO)
fi
# try harder, when checking for __thread support, see bug 521750 comment #33 and below
# We pass MOZ_OPTIMIZE_LDFLAGS to the linker because if dead_strip is
# enabled, the linker in xcode 4.1 will crash. Without this it would crash when

Просмотреть файл

@ -271,6 +271,7 @@ class GCRuntime
void decFJMinorCollecting() { fjCollectionCounter--; }
bool triggerGC(JS::gcreason::Reason reason);
void maybeAllocTriggerZoneGC(Zone *zone, const AutoLockGC &lock);
bool triggerZoneGC(Zone *zone, JS::gcreason::Reason reason);
bool maybeGC(Zone *zone);
void maybePeriodicFullGC();
@ -481,11 +482,15 @@ class GCRuntime
void freeUnusedLifoBlocksAfterSweeping(LifoAlloc *lifo);
void freeAllLifoBlocksAfterSweeping(LifoAlloc *lifo);
// Public here for ReleaseArenaLists and FinalizeTypedArenas.
void releaseArena(ArenaHeader *aheader, const AutoLockGC &lock);
private:
// For ArenaLists::allocateFromArena()
friend class ArenaLists;
Chunk *pickChunk(const AutoLockGC &lock,
AutoMaybeStartBackgroundAllocation &maybeStartBGAlloc);
ArenaHeader *allocateArena(Chunk *chunk, Zone *zone, AllocKind kind, const AutoLockGC &lock);
inline void arenaAllocatedDuringGC(JS::Zone *zone, ArenaHeader *arena);
template <AllowGC allowGC>
@ -543,8 +548,7 @@ class GCRuntime
bool sweepPhase(SliceBudget &sliceBudget);
void endSweepPhase(bool lastGC);
void sweepZones(FreeOp *fop, bool lastGC);
void decommitArenasFromAvailableList(Chunk **availableListHeadp);
void decommitArenas();
void decommitArenas(const AutoLockGC &lock);
void expireChunksAndArenas(bool shouldShrink, const AutoLockGC &lock);
void sweepBackgroundThings();
void assertBackgroundSweepingFinished();

Просмотреть файл

@ -37,6 +37,7 @@ struct Runtime;
namespace js {
class AutoLockGC;
class FreeOp;
#ifdef DEBUG
@ -945,9 +946,10 @@ struct Chunk
inline void insertToAvailableList(Chunk **insertPoint);
inline void removeFromAvailableList();
ArenaHeader *allocateArena(JS::Zone *zone, AllocKind kind);
ArenaHeader *allocateArena(JSRuntime *rt, JS::Zone *zone, AllocKind kind,
const AutoLockGC &lock);
void releaseArena(ArenaHeader *aheader);
void releaseArena(JSRuntime *rt, ArenaHeader *aheader, const AutoLockGC &lock);
void recycleArena(ArenaHeader *aheader, SortedArenaList &dest, AllocKind thingKind,
size_t thingsPerArena);
@ -1147,17 +1149,6 @@ ArenaHeader::unsetAllocDuringSweep()
auxNextLink = 0;
}
inline void
ReleaseArenaList(ArenaHeader *aheader)
{
ArenaHeader *next;
for (; aheader; aheader = next) {
// Copy aheader->next before releasing.
next = aheader->next;
aheader->chunk()->releaseArena(aheader);
}
}
static void
AssertValidColor(const TenuredCell *thing, uint32_t color)
{

Просмотреть файл

@ -152,7 +152,7 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext *cx, bool match_only)
// Check if we have space on the stack.
Label stack_ok;
void *stack_limit = &runtime->mainThread.jitStackLimit;
void *stack_limit = runtime->mainThread.addressOfJitStackLimit();
masm.branchPtr(Assembler::Below, AbsoluteAddress(stack_limit), StackPointer, &stack_ok);
// Exit with an exception. There is not enough space on the stack
@ -502,7 +502,7 @@ NativeRegExpMacroAssembler::Backtrack()
// Check for an interrupt.
Label noInterrupt;
masm.branch32(Assembler::Equal,
AbsoluteAddress(&runtime->interrupt), Imm32(0),
AbsoluteAddress(runtime->addressOfInterruptUint32()), Imm32(0),
&noInterrupt);
masm.movePtr(ImmWord(RegExpRunStatus_Error), temp0);
masm.jump(&exit_label_);

Просмотреть файл

@ -496,7 +496,7 @@ bool
BaselineCompiler::emitStackCheck(bool earlyCheck)
{
Label skipCall;
uintptr_t *limitAddr = &cx->runtime()->mainThread.jitStackLimit;
void *limitAddr = cx->runtime()->mainThread.addressOfJitStackLimit();
uint32_t slotsSize = script->nslots() * sizeof(Value);
uint32_t tolerance = earlyCheck ? slotsSize : 0;
@ -646,7 +646,7 @@ BaselineCompiler::emitInterruptCheck()
frame.syncStack(0);
Label done;
void *interrupt = (void *)&cx->runtime()->interrupt;
void *interrupt = cx->runtimeAddressOfInterruptUint32();
masm.branch32(Assembler::Equal, AbsoluteAddress(interrupt), Imm32(0), &done);
prepareVMCall();

Просмотреть файл

@ -3772,7 +3772,7 @@ CodeGenerator::visitCheckOverRecursedPar(LCheckOverRecursedPar *lir)
Register tempReg = ToRegister(lir->getTempReg());
masm.loadPtr(Address(cxReg, offsetof(ForkJoinContext, perThreadData)), tempReg);
masm.loadPtr(Address(tempReg, offsetof(PerThreadData, jitStackLimit)), tempReg);
masm.loadPtr(Address(tempReg, PerThreadData::offsetOfJitStackLimit()), tempReg);
// Conditional forward (unlikely) branch to failure.
CheckOverRecursedFailure *ool = new(alloc()) CheckOverRecursedFailure(lir);
@ -9950,7 +9950,7 @@ CodeGenerator::visitInterruptCheck(LInterruptCheck *lir)
if (!ool)
return false;
AbsoluteAddress interruptAddr(GetIonContext()->runtime->addressOfInterrupt());
AbsoluteAddress interruptAddr(GetIonContext()->runtime->addressOfInterruptUint32());
masm.branch32(Assembler::NotEqual, interruptAddr, Imm32(0), ool->entry());
masm.bind(ool->rejoin());
return true;
@ -9960,8 +9960,8 @@ bool
CodeGenerator::visitAsmJSInterruptCheck(LAsmJSInterruptCheck *lir)
{
Register scratch = ToRegister(lir->scratch());
masm.movePtr(AsmJSImmPtr(AsmJSImm_RuntimeInterrupt), scratch);
masm.load8ZeroExtend(Address(scratch, 0), scratch);
masm.movePtr(AsmJSImmPtr(AsmJSImm_RuntimeInterruptUint32), scratch);
masm.load32(Address(scratch, 0), scratch);
Label rejoin;
masm.branch32(Assembler::Equal, scratch, Imm32(0), &rejoin);
{

Просмотреть файл

@ -43,7 +43,7 @@ CompileRuntime::addressOfJitTop()
const void *
CompileRuntime::addressOfJitStackLimit()
{
return &runtime()->mainThread.jitStackLimit;
return runtime()->mainThread.addressOfJitStackLimit();
}
const void *
@ -73,15 +73,15 @@ CompileRuntime::addressOfGCZeal()
#endif
const void *
CompileRuntime::addressOfInterrupt()
CompileRuntime::addressOfInterruptUint32()
{
return &runtime()->interrupt;
return runtime()->addressOfInterruptUint32();
}
const void *
CompileRuntime::addressOfInterruptPar()
CompileRuntime::addressOfInterruptParUint32()
{
return &runtime()->interruptPar;
return runtime()->addressOfInterruptParUint32();
}
const void *

Просмотреть файл

@ -50,8 +50,8 @@ class CompileRuntime
const void *addressOfGCZeal();
#endif
const void *addressOfInterrupt();
const void *addressOfInterruptPar();
const void *addressOfInterruptUint32();
const void *addressOfInterruptParUint32();
const void *addressOfThreadPool();

Просмотреть файл

@ -428,7 +428,7 @@ JitRuntime::ensureIonCodeAccessible(JSRuntime *rt)
ionCodeProtected_ = false;
}
if (rt->interrupt) {
if (rt->hasPendingInterrupt()) {
// The interrupt handler needs to be invoked by this thread, but we may
// be inside a signal handler and have no idea what is above us on the
// stack (probably we are executing Ion code at an arbitrary point, but
@ -1162,7 +1162,7 @@ IonScript::copyPatchableBackedges(JSContext *cx, JitCode *code,
// whether an interrupt is currently desired, matching the targets
// established by ensureIonCodeAccessible() above. We don't handle the
// interrupt immediately as the interrupt lock is held here.
if (cx->runtime()->interrupt)
if (cx->runtime()->hasPendingInterrupt())
PatchBackedge(backedge, interruptCheck, JitRuntime::BackedgeInterruptCheck);
else
PatchBackedge(backedge, loopHeader, JitRuntime::BackedgeLoopHeader);

Просмотреть файл

@ -1238,7 +1238,7 @@ MacroAssembler::loadStringChar(Register str, Register index, Register output)
void
MacroAssembler::checkInterruptFlagPar(Register tempReg, Label *fail)
{
movePtr(ImmPtr(GetIonContext()->runtime->addressOfInterruptPar()), tempReg);
movePtr(ImmPtr(GetIonContext()->runtime->addressOfInterruptParUint32()), tempReg);
branch32(Assembler::NonZero, Address(tempReg, 0), Imm32(0), fail);
}

Просмотреть файл

@ -147,7 +147,7 @@ jit::CheckOverRecursedPar(ForkJoinContext *cx)
}
#endif
if (!JS_CHECK_STACK_SIZE(cx->perThreadData->jitStackLimit, &stackDummy_)) {
if (!JS_CHECK_STACK_SIZE(cx->perThreadData->jitStackLimit(), &stackDummy_)) {
cx->bailoutRecord->joinCause(ParallelBailoutOverRecursed);
return false;
}

Просмотреть файл

@ -113,28 +113,17 @@ NewGCObject(JSContext *cx, gc::AllocKind allocKind, gc::InitialHeap initialHeap)
bool
CheckOverRecursed(JSContext *cx)
{
// IonMonkey's stackLimit is equal to nativeStackLimit by default. When we
// request an interrupt, we set the jitStackLimit to nullptr, which causes
// the stack limit check to fail.
//
// There are two states we're concerned about here:
// (1) The interrupt bit is set, and we need to fire the interrupt callback.
// (2) The stack limit has been exceeded, and we need to throw an error.
//
// Note that we can reach here if jitStackLimit is MAXADDR, but interrupt
// has not yet been set to 1. That's okay; it will be set to 1 very shortly,
// and in the interim we might just fire a few useless calls to
// CheckOverRecursed.
// We just failed the jitStackLimit check. There are two possible reasons:
// - jitStackLimit was the real stack limit and we're over-recursed
// - jitStackLimit was set to UINTPTR_MAX by JSRuntime::requestInterrupt
// and we need to call JSRuntime::handleInterrupt.
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, 0, return false);
#else
JS_CHECK_RECURSION(cx, return false);
#endif
if (cx->runtime()->interrupt)
return InterruptCheck(cx);
return true;
gc::MaybeVerifyBarriers(cx);
return cx->runtime()->handleInterrupt(cx);
}
// This function can get called in two contexts. In the usual context, it's
@ -178,10 +167,8 @@ CheckOverRecursedWithExtra(JSContext *cx, BaselineFrame *frame,
JS_CHECK_RECURSION_WITH_SP(cx, checkSp, return false);
#endif
if (cx->runtime()->interrupt)
return InterruptCheck(cx);
return true;
gc::MaybeVerifyBarriers(cx);
return cx->runtime()->handleInterrupt(cx);
}
bool

Просмотреть файл

@ -783,7 +783,7 @@ enum AsmJSImmKind
AsmJSImm_PowD = AsmJSExit::Builtin_PowD,
AsmJSImm_ATan2D = AsmJSExit::Builtin_ATan2D,
AsmJSImm_Runtime,
AsmJSImm_RuntimeInterrupt,
AsmJSImm_RuntimeInterruptUint32,
AsmJSImm_StackLimit,
AsmJSImm_ReportOverRecursed,
AsmJSImm_OnDetached,

Просмотреть файл

@ -2031,68 +2031,48 @@ JS_GetExternalStringFinalizer(JSString *str)
}
static void
SetNativeStackQuota(JSRuntime *rt, StackKind kind, size_t stackSize)
SetNativeStackQuotaAndLimit(JSRuntime *rt, StackKind kind, size_t stackSize)
{
rt->nativeStackQuota[kind] = stackSize;
if (rt->nativeStackBase)
RecomputeStackLimit(rt, kind);
}
void
js::RecomputeStackLimit(JSRuntime *rt, StackKind kind)
{
size_t stackSize = rt->nativeStackQuota[kind];
#if JS_STACK_GROWTH_DIRECTION > 0
if (stackSize == 0) {
rt->mainThread.nativeStackLimit[kind] = UINTPTR_MAX;
} else {
MOZ_ASSERT(rt->nativeStackBase <= size_t(-1) - stackSize);
rt->mainThread.nativeStackLimit[kind] =
rt->nativeStackBase + stackSize - 1;
rt->mainThread.nativeStackLimit[kind] = rt->nativeStackBase + stackSize - 1;
}
#else
if (stackSize == 0) {
rt->mainThread.nativeStackLimit[kind] = 0;
} else {
MOZ_ASSERT(rt->nativeStackBase >= stackSize);
rt->mainThread.nativeStackLimit[kind] =
rt->nativeStackBase - (stackSize - 1);
rt->mainThread.nativeStackLimit[kind] = rt->nativeStackBase - (stackSize - 1);
}
#endif
// If there's no pending interrupt request set on the runtime's main thread's
// jitStackLimit, then update it so that it reflects the new nativeStacklimit.
//
// Note that, for now, we use the untrusted limit for ion. This is fine,
// because it's the most conservative limit, and if we hit it, we'll bail
// out of ion into the interpeter, which will do a proper recursion check.
if (kind == StackForUntrustedScript) {
JSRuntime::AutoLockForInterrupt lock(rt);
if (rt->mainThread.jitStackLimit != uintptr_t(-1)) {
rt->mainThread.jitStackLimit = rt->mainThread.nativeStackLimit[kind];
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
rt->mainThread.jitStackLimit = jit::Simulator::StackLimit();
#endif
}
}
}
JS_PUBLIC_API(void)
JS_SetNativeStackQuota(JSRuntime *rt, size_t systemCodeStackSize,
size_t trustedScriptStackSize,
JS_SetNativeStackQuota(JSRuntime *rt, size_t systemCodeStackSize, size_t trustedScriptStackSize,
size_t untrustedScriptStackSize)
{
MOZ_ASSERT_IF(trustedScriptStackSize,
trustedScriptStackSize < systemCodeStackSize);
MOZ_ASSERT(rt->requestDepth == 0);
if (!trustedScriptStackSize)
trustedScriptStackSize = systemCodeStackSize;
MOZ_ASSERT_IF(untrustedScriptStackSize,
untrustedScriptStackSize < trustedScriptStackSize);
else
MOZ_ASSERT(trustedScriptStackSize < systemCodeStackSize);
if (!untrustedScriptStackSize)
untrustedScriptStackSize = trustedScriptStackSize;
SetNativeStackQuota(rt, StackForSystemCode, systemCodeStackSize);
SetNativeStackQuota(rt, StackForTrustedScript, trustedScriptStackSize);
SetNativeStackQuota(rt, StackForUntrustedScript, untrustedScriptStackSize);
else
MOZ_ASSERT(untrustedScriptStackSize < trustedScriptStackSize);
SetNativeStackQuotaAndLimit(rt, StackForSystemCode, systemCodeStackSize);
SetNativeStackQuotaAndLimit(rt, StackForTrustedScript, trustedScriptStackSize);
SetNativeStackQuotaAndLimit(rt, StackForUntrustedScript, untrustedScriptStackSize);
rt->mainThread.initJitStackLimit();
}
/************************************************************************/

Просмотреть файл

@ -2272,6 +2272,9 @@ JS_GetExternalStringFinalizer(JSString *str);
* The stack quotas for each kind of code should be monotonically descending,
* and may be specified with this function. If 0 is passed for a given kind
* of code, it defaults to the value of the next-highest-priority kind.
*
* This function may only be called immediately after the runtime is initialized
* and before any code is executed and/or interrupts requested.
*/
extern JS_PUBLIC_API(void)
JS_SetNativeStackQuota(JSRuntime *cx, size_t systemCodeStackSize,

Просмотреть файл

@ -41,7 +41,6 @@
#include "gc/Marking.h"
#include "jit/Ion.h"
#include "js/CharacterEncoding.h"
#include "vm/Debugger.h"
#include "vm/HelperThreads.h"
#include "vm/Shape.h"
@ -971,90 +970,6 @@ js_GetErrorMessage(void *userRef, const unsigned errorNumber)
return nullptr;
}
bool
js::InvokeInterruptCallback(JSContext *cx)
{
MOZ_ASSERT(cx->runtime()->requestDepth >= 1);
JSRuntime *rt = cx->runtime();
MOZ_ASSERT(rt->interrupt);
// Reset the callback counter first, then run GC and yield. If another
// thread is racing us here we will accumulate another callback request
// which will be serviced at the next opportunity.
rt->interrupt = false;
// IonMonkey sets its stack limit to UINTPTR_MAX to trigger interrupt
// callbacks.
rt->resetJitStackLimit();
cx->gcIfNeeded();
rt->interruptPar = false;
// A worker thread may have requested an interrupt after finishing an Ion
// compilation.
jit::AttachFinishedCompilations(cx);
// Important: Additional callbacks can occur inside the callback handler
// if it re-enters the JS engine. The embedding must ensure that the
// callback is disconnected before attempting such re-entry.
JSInterruptCallback cb = cx->runtime()->interruptCallback;
if (!cb)
return true;
if (cb(cx)) {
// Debugger treats invoking the interrupt callback as a "step", so
// invoke the onStep handler.
if (cx->compartment()->debugMode()) {
ScriptFrameIter iter(cx);
if (iter.script()->stepModeEnabled()) {
RootedValue rval(cx);
switch (Debugger::onSingleStep(cx, &rval)) {
case JSTRAP_ERROR:
return false;
case JSTRAP_CONTINUE:
return true;
case JSTRAP_RETURN:
// See note in Debugger::propagateForcedReturn.
Debugger::propagateForcedReturn(cx, iter.abstractFramePtr(), rval);
return false;
case JSTRAP_THROW:
cx->setPendingException(rval);
return false;
default:;
}
}
}
return true;
}
// No need to set aside any pending exception here: ComputeStackString
// already does that.
JSString *stack = ComputeStackString(cx);
JSFlatString *flat = stack ? stack->ensureFlat(cx) : nullptr;
const char16_t *chars;
AutoStableStringChars stableChars(cx);
if (flat && stableChars.initTwoByte(cx, flat))
chars = stableChars.twoByteRange().start().get();
else
chars = MOZ_UTF16("(stack not available)");
JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_WARNING, js_GetErrorMessage, nullptr,
JSMSG_TERMINATED, chars);
return false;
}
bool
js::HandleExecutionInterrupt(JSContext *cx)
{
if (cx->runtime()->interrupt)
return InvokeInterruptCallback(cx);
return true;
}
ThreadSafeContext::ThreadSafeContext(JSRuntime *rt, PerThreadData *pt, ContextKind kind)
: ContextFriendFields(rt),
contextKind_(kind),

Просмотреть файл

@ -289,7 +289,7 @@ struct ThreadSafeContext : ContextFriendFields,
PropertyName *emptyString() { return runtime_->emptyString; }
FreeOp *defaultFreeOp() { return runtime_->defaultFreeOp(); }
void *runtimeAddressForJit() { return runtime_; }
void *runtimeAddressOfInterrupt() { return &runtime_->interrupt; }
void *runtimeAddressOfInterruptUint32() { return runtime_->addressOfInterruptUint32(); }
void *stackLimitAddress(StackKind kind) { return &runtime_->mainThread.nativeStackLimit[kind]; }
void *stackLimitAddressForJitCode(StackKind kind);
size_t gcSystemPageSize() { return gc::SystemPageSize(); }
@ -782,33 +782,15 @@ extern const JSErrorFormatString js_ErrorFormatString[JSErr_Limit];
namespace js {
/*
* Invoke the interrupt callback and return false if the current execution
* is to be terminated.
*/
bool
InvokeInterruptCallback(JSContext *cx);
bool
HandleExecutionInterrupt(JSContext *cx);
/*
* Process any pending interrupt requests. Long-running inner loops in C++ must
* call this periodically to make sure they are interruptible --- that is, to
* make sure they do not prevent the slow script dialog from appearing.
*
* This can run a full GC or call the interrupt callback, which could do
* anything. In the browser, it displays the slow script dialog.
*
* If this returns true, the caller can continue; if false, the caller must
* break out of its loop. This happens if, for example, the user clicks "Stop
* script" on the slow script dialog; treat it as an uncatchable error.
*/
MOZ_ALWAYS_INLINE bool
CheckForInterrupt(JSContext *cx)
{
MOZ_ASSERT(cx->runtime()->requestDepth >= 1);
return !cx->runtime()->interrupt || InvokeInterruptCallback(cx);
// Add an inline fast-path since we have to check for interrupts in some hot
// C++ loops of library builtins.
JSRuntime *rt = cx->runtime();
if (rt->hasPendingInterrupt())
return rt->handleInterrupt(cx);
return true;
}
/************************************************************************/

Просмотреть файл

@ -545,6 +545,9 @@ Arena::finalize(FreeOp *fop, AllocKind thingKind, size_t thingSize)
return nmarked;
}
// Finalize arenas from src list, releasing empty arenas if keepArenas wasn't
// specified and inserting the others into the appropriate destination size
// bins.
template<typename T>
static inline bool
FinalizeTypedArenas(FreeOp *fop,
@ -554,11 +557,10 @@ FinalizeTypedArenas(FreeOp *fop,
SliceBudget &budget,
ArenaLists::KeepArenasEnum keepArenas)
{
/*
* Finalize arenas from src list, releasing empty arenas if keepArenas
* wasn't specified and inserting the others into the appropriate
* destination size bins.
*/
// When operating in the foreground, take the lock at the top.
Maybe<AutoLockGC> maybeLock;
if (!fop->runtime()->gc.isBackgroundSweeping())
maybeLock.emplace(fop->runtime());
/*
* During parallel sections, we sometimes finalize the parallel arenas,
@ -575,12 +577,18 @@ FinalizeTypedArenas(FreeOp *fop,
size_t nmarked = aheader->getArena()->finalize<T>(fop, thingKind, thingSize);
size_t nfree = thingsPerArena - nmarked;
if (nmarked)
if (nmarked) {
dest.insertAt(aheader, nfree);
else if (keepArenas)
} else if (keepArenas) {
aheader->chunk()->recycleArena(aheader, dest, thingKind, thingsPerArena);
else
aheader->chunk()->releaseArena(aheader);
} else if (fop->runtime()->gc.isBackgroundSweeping()) {
// When background sweeping, take the lock around each release so
// that we do not block the foreground for extended periods.
AutoLockGC lock(fop->runtime());
fop->runtime()->gc.releaseArena(aheader, lock);
} else {
fop->runtime()->gc.releaseArena(aheader, maybeLock.ref());
}
budget.step(thingsPerArena);
if (budget.isOverBudget())
@ -938,67 +946,14 @@ Chunk::fetchNextFreeArena(JSRuntime *rt)
}
ArenaHeader *
Chunk::allocateArena(Zone *zone, AllocKind thingKind)
Chunk::allocateArena(JSRuntime *rt, Zone *zone, AllocKind thingKind, const AutoLockGC &lock)
{
MOZ_ASSERT(hasAvailableArenas());
JSRuntime *rt = zone->runtimeFromAnyThread();
if (!rt->isHeapMinorCollecting() &&
!rt->isHeapCompacting() &&
rt->gc.usage.gcBytes() >= rt->gc.tunables.gcMaxBytes())
{
#ifdef JSGC_FJGENERATIONAL
// This is an approximation to the best test, which would check that
// this thread is currently promoting into the tenured area. I doubt
// the better test would make much difference.
if (!rt->isFJMinorCollecting())
return nullptr;
#else
return nullptr;
#endif
}
ArenaHeader *aheader = MOZ_LIKELY(info.numArenasFreeCommitted > 0)
ArenaHeader *aheader = info.numArenasFreeCommitted > 0
? fetchNextFreeArena(rt)
: fetchNextDecommittedArena();
aheader->init(zone, thingKind);
if (MOZ_UNLIKELY(!hasAvailableArenas()))
removeFromAvailableList();
zone->usage.addGCArena();
if (!rt->isHeapCompacting()) {
size_t usedBytes = zone->usage.gcBytes();
size_t thresholdBytes = zone->threshold.gcTriggerBytes();
size_t igcThresholdBytes = thresholdBytes * rt->gc.tunables.zoneAllocThresholdFactor();
if (usedBytes >= thresholdBytes) {
// The threshold has been surpassed, immediately trigger a GC,
// which will be done non-incrementally.
AutoUnlockGC unlock(rt);
rt->gc.triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER);
} else if (usedBytes >= igcThresholdBytes) {
// Reduce the delay to the start of the next incremental slice.
if (zone->gcDelayBytes < ArenaSize)
zone->gcDelayBytes = 0;
else
zone->gcDelayBytes -= ArenaSize;
if (!zone->gcDelayBytes) {
// Start or continue an in progress incremental GC. We do this
// to try to avoid performing non-incremental GCs on zones
// which allocate a lot of data, even when incremental slices
// can't be triggered via scheduling in the event loop.
AutoUnlockGC unlock(rt);
rt->gc.triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER);
// Delay the next slice until a certain amount of allocation
// has been performed.
zone->gcDelayBytes = rt->gc.tunables.zoneAllocDelayBytes();
}
}
}
return aheader;
}
@ -1028,20 +983,10 @@ Chunk::recycleArena(ArenaHeader *aheader, SortedArenaList &dest, AllocKind thing
}
void
Chunk::releaseArena(ArenaHeader *aheader)
Chunk::releaseArena(JSRuntime *rt, ArenaHeader *aheader, const AutoLockGC &lock)
{
MOZ_ASSERT(aheader->allocated());
MOZ_ASSERT(!aheader->hasDelayedMarking);
Zone *zone = aheader->zone;
JSRuntime *rt = zone->runtimeFromAnyThread();
Maybe<AutoLockGC> maybeLock;
if (rt->gc.isBackgroundSweeping())
maybeLock.emplace(rt);
if (rt->gc.isBackgroundSweeping())
zone->threshold.updateForRemovedArena(rt->gc.tunables);
zone->usage.removeGCArena();
aheader->setAsNotAllocated();
addArenaToFreeList(rt, aheader);
@ -1053,12 +998,10 @@ Chunk::releaseArena(ArenaHeader *aheader)
} else if (!unused()) {
MOZ_ASSERT(info.prevp);
} else {
if (maybeLock.isNothing())
maybeLock.emplace(rt);
MOZ_ASSERT(unused());
removeFromAvailableList();
decommitAllArenas(rt);
rt->gc.moveChunkToFreePool(this, maybeLock.ref());
rt->gc.moveChunkToFreePool(this, lock);
}
}
@ -1161,6 +1104,46 @@ GCRuntime::pickChunk(const AutoLockGC &lock,
return chunk;
}
ArenaHeader *
GCRuntime::allocateArena(Chunk *chunk, Zone *zone, AllocKind thingKind, const AutoLockGC &lock)
{
MOZ_ASSERT(chunk->hasAvailableArenas());
// Fail the allocation if we are over our heap size limits.
if (!isHeapMinorCollecting() &&
!isHeapCompacting() &&
usage.gcBytes() >= tunables.gcMaxBytes())
{
#ifdef JSGC_FJGENERATIONAL
// This is an approximation to the best test, which would check that
// this thread is currently promoting into the tenured area. I doubt
// the better test would make much difference.
if (!isFJMinorCollecting())
return nullptr;
#else
return nullptr;
#endif
}
ArenaHeader *aheader = chunk->allocateArena(rt, zone, thingKind, lock);
zone->usage.addGCArena();
// Trigger an incremental slice if needed.
if (!isHeapMinorCollecting() && !isHeapCompacting())
maybeAllocTriggerZoneGC(zone, lock);
return aheader;
}
void
GCRuntime::releaseArena(ArenaHeader *aheader, const AutoLockGC &lock)
{
aheader->zone->usage.removeGCArena();
if (isBackgroundSweeping())
aheader->zone->threshold.updateForRemovedArena(tunables);
return aheader->chunk()->releaseArena(rt, aheader, lock);
}
GCRuntime::GCRuntime(JSRuntime *rt) :
rt(rt),
systemZone(nullptr),
@ -1906,7 +1889,8 @@ ZoneHeapThreshold::updateForRemovedArena(const GCSchedulingTunables &tunables)
}
Allocator::Allocator(Zone *zone)
: zone_(zone)
: arenas(zone->runtimeFromMainThread()),
zone_(zone)
{}
inline void
@ -1992,7 +1976,7 @@ ArenaLists::allocateFromArena(JS::Zone *zone, AllocKind thingKind,
// Although our chunk should definitely have enough space for another arena,
// there are other valid reasons why Chunk::allocateArena() may fail.
aheader = chunk->allocateArena(zone, thingKind);
aheader = rt->gc.allocateArena(chunk, zone, thingKind, maybeLock.ref());
if (!aheader)
return nullptr;
@ -2553,6 +2537,7 @@ void
GCRuntime::releaseRelocatedArenas(ArenaHeader *relocatedList)
{
// Release the relocated arenas, now containing only forwarding pointers
AutoLockGC lock(rt);
unsigned count = 0;
while (relocatedList) {
@ -2575,16 +2560,44 @@ GCRuntime::releaseRelocatedArenas(ArenaHeader *relocatedList)
JS_MOVED_TENURED_PATTERN, Arena::thingsSpan(thingSize));
#endif
aheader->chunk()->releaseArena(aheader);
releaseArena(aheader, lock);
++count;
}
AutoLockGC lock(rt);
expireChunksAndArenas(true, lock);
}
#endif // JSGC_COMPACTING
void
ReleaseArenaList(JSRuntime *rt, ArenaHeader *aheader, const AutoLockGC &lock)
{
ArenaHeader *next;
for (; aheader; aheader = next) {
next = aheader->next;
rt->gc.releaseArena(aheader, lock);
}
}
ArenaLists::~ArenaLists()
{
AutoLockGC lock(runtime_);
for (size_t i = 0; i != FINALIZE_LIMIT; ++i) {
/*
* We can only call this during the shutdown after the last GC when
* the background finalization is disabled.
*/
MOZ_ASSERT(backgroundFinalizeState[i] == BFS_DONE);
ReleaseArenaList(runtime_, arenaLists[i].head(), lock);
}
ReleaseArenaList(runtime_, incrementalSweptArenas.head(), lock);
for (size_t i = 0; i < FINALIZE_OBJECT_LIMIT; i++)
ReleaseArenaList(runtime_, savedObjectArenas[i].head(), lock);
ReleaseArenaList(runtime_, savedEmptyObjectArenas, lock);
}
void
ArenaLists::finalizeNow(FreeOp *fop, const FinalizePhase& phase)
{
@ -2751,7 +2764,8 @@ ArenaLists::queueForegroundObjectsForSweep(FreeOp *fop)
void
ArenaLists::mergeForegroundSweptObjectArenas()
{
ReleaseArenaList(savedEmptyObjectArenas);
AutoLockGC lock(runtime_);
ReleaseArenaList(runtime_, savedEmptyObjectArenas, lock);
savedEmptyObjectArenas = nullptr;
mergeSweptArenas(FINALIZE_OBJECT0);
@ -3023,6 +3037,40 @@ GCRuntime::triggerGC(JS::gcreason::Reason reason)
return true;
}
void
GCRuntime::maybeAllocTriggerZoneGC(Zone *zone, const AutoLockGC &lock)
{
size_t usedBytes = zone->usage.gcBytes();
size_t thresholdBytes = zone->threshold.gcTriggerBytes();
size_t igcThresholdBytes = thresholdBytes * tunables.zoneAllocThresholdFactor();
if (usedBytes >= thresholdBytes) {
// The threshold has been surpassed, immediately trigger a GC,
// which will be done non-incrementally.
AutoUnlockGC unlock(rt);
triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER);
} else if (usedBytes >= igcThresholdBytes) {
// Reduce the delay to the start of the next incremental slice.
if (zone->gcDelayBytes < ArenaSize)
zone->gcDelayBytes = 0;
else
zone->gcDelayBytes -= ArenaSize;
if (!zone->gcDelayBytes) {
// Start or continue an in progress incremental GC. We do this
// to try to avoid performing non-incremental GCs on zones
// which allocate a lot of data, even when incremental slices
// can't be triggered via scheduling in the event loop.
AutoUnlockGC unlock(rt);
triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER);
// Delay the next slice until a certain amount of allocation
// has been performed.
zone->gcDelayBytes = tunables.zoneAllocDelayBytes();
}
}
}
bool
GCRuntime::triggerZoneGC(Zone *zone, JS::gcreason::Reason reason)
{
@ -3123,8 +3171,9 @@ GCRuntime::maybePeriodicFullGC()
}
void
GCRuntime::decommitArenasFromAvailableList(Chunk **availableListHeadp)
GCRuntime::decommitArenas(const AutoLockGC &lock)
{
Chunk **availableListHeadp = &availableChunkListHead;
Chunk *chunk = *availableListHeadp;
if (!chunk)
return;
@ -3231,12 +3280,6 @@ GCRuntime::decommitArenasFromAvailableList(Chunk **availableListHeadp)
}
}
void
GCRuntime::decommitArenas()
{
decommitArenasFromAvailableList(&availableChunkListHead);
}
void
GCRuntime::expireChunksAndArenas(bool shouldShrink, const AutoLockGC &lock)
{
@ -3250,7 +3293,7 @@ GCRuntime::expireChunksAndArenas(bool shouldShrink, const AutoLockGC &lock)
}
if (shouldShrink)
decommitArenas();
decommitArenas(lock);
}
void
@ -6620,7 +6663,7 @@ ArenaLists::adoptArenas(JSRuntime *rt, ArenaLists *fromArenaLists)
// Therefore, if fromHeader is empty, send it back to the
// chunk now. Otherwise, attach to |toList|.
if (fromHeader->isEmpty())
fromHeader->chunk()->releaseArena(fromHeader);
rt->gc.releaseArena(fromHeader, lock);
else
toList->insertAtCursor(fromHeader);
}

Просмотреть файл

@ -595,6 +595,8 @@ class SortedArenaList
class ArenaLists
{
JSRuntime *runtime_;
/*
* For each arena kind its free list is represented as the first span with
* free things. Initially all the spans are initialized as empty. After we
@ -639,7 +641,7 @@ class ArenaLists
ArenaHeader *savedEmptyObjectArenas;
public:
ArenaLists() {
ArenaLists(JSRuntime *rt) : runtime_(rt) {
for (size_t i = 0; i != FINALIZE_LIMIT; ++i)
freeLists[i].initAsEmpty();
for (size_t i = 0; i != FINALIZE_LIMIT; ++i)
@ -654,21 +656,7 @@ class ArenaLists
savedEmptyObjectArenas = nullptr;
}
~ArenaLists() {
for (size_t i = 0; i != FINALIZE_LIMIT; ++i) {
/*
* We can only call this during the shutdown after the last GC when
* the background finalization is disabled.
*/
MOZ_ASSERT(backgroundFinalizeState[i] == BFS_DONE);
ReleaseArenaList(arenaLists[i].head());
}
ReleaseArenaList(incrementalSweptArenas.head());
for (size_t i = 0; i < FINALIZE_OBJECT_LIMIT; i++)
ReleaseArenaList(savedObjectArenas[i].head());
ReleaseArenaList(savedEmptyObjectArenas);
}
~ArenaLists();
static uintptr_t getFreeListOffset(AllocKind thingKind) {
uintptr_t offset = offsetof(ArenaLists, freeLists);

Просмотреть файл

@ -526,7 +526,7 @@ CheckAllocatorState(ThreadSafeContext *cx, AllocKind kind)
rt->gc.runDebugGC();
#endif
if (rt->interrupt) {
if (rt->hasPendingInterrupt()) {
// Invoking the interrupt callback can fail and we can't usefully
// handle that here. Just check in case we need to collect instead.
ncx->gcIfNeeded();

Просмотреть файл

@ -18,6 +18,7 @@ inline uintptr_t
GetNativeStackBase()
{
uintptr_t stackBase = reinterpret_cast<uintptr_t>(GetNativeStackBaseImpl());
MOZ_ASSERT(stackBase != 0);
MOZ_ASSERT(stackBase % sizeof(void *) == 0);
return stackBase;
}

Просмотреть файл

@ -1440,7 +1440,7 @@ ForkJoinShared::execute()
// Sometimes a GC request occurs *just before* we enter into the
// parallel section. Rather than enter into the parallel section
// and then abort, we just check here and abort early.
if (cx_->runtime()->interruptPar)
if (cx_->runtime()->hasPendingInterruptPar())
return TP_RETRY_SEQUENTIALLY;
AutoLockMonitor lock(*this);
@ -1518,7 +1518,7 @@ ForkJoinShared::executeFromWorker(ThreadPoolWorker *worker, uintptr_t stackLimit
// Don't use setIonStackLimit() because that acquires the ionStackLimitLock, and the
// lock has not been initialized in these cases.
thisThread.jitStackLimit = stackLimit;
thisThread.initJitStackLimitPar(stackLimit);
executePortion(&thisThread, worker);
TlsPerThreadData.set(nullptr);
@ -1551,7 +1551,7 @@ ForkJoinShared::executeFromMainThread(ThreadPoolWorker *worker)
//
// Thus, use GetNativeStackLimit instead of just propagating the
// main thread's.
thisThread.jitStackLimit = GetNativeStackLimit(cx_);
thisThread.initJitStackLimitPar(GetNativeStackLimit(cx_));
executePortion(&thisThread, worker);
TlsPerThreadData.set(oldData);
@ -1647,7 +1647,7 @@ ForkJoinShared::executePortion(PerThreadData *perThread, ThreadPoolWorker *worke
void
ForkJoinShared::setAbortFlagDueToInterrupt(ForkJoinContext &cx)
{
MOZ_ASSERT(cx_->runtime()->interruptPar);
MOZ_ASSERT(cx_->runtime()->hasPendingInterruptPar());
// The GC Needed flag should not be set during parallel
// execution. Instead, one of the requestGC() or
// requestZoneGC() methods should be invoked.
@ -1826,7 +1826,7 @@ ForkJoinContext::hasAcquiredJSContext() const
bool
ForkJoinContext::check()
{
if (runtime()->interruptPar) {
if (runtime()->hasPendingInterruptPar()) {
shared_->setAbortFlagDueToInterrupt(*this);
return false;
}
@ -2273,13 +2273,6 @@ js::ParallelTestsShouldPass(JSContext *cx)
cx->runtime()->gcZeal() == 0;
}
void
js::RequestInterruptForForkJoin(JSRuntime *rt, JSRuntime::InterruptMode mode)
{
if (mode != JSRuntime::RequestInterruptAnyThreadDontStopIon)
rt->interruptPar = true;
}
bool
js::intrinsic_SetForkJoinTargetRegion(JSContext *cx, unsigned argc, Value *vp)
{

Просмотреть файл

@ -546,8 +546,6 @@ bool InExclusiveParallelSection();
bool ParallelTestsShouldPass(JSContext *cx);
void RequestInterruptForForkJoin(JSRuntime *rt, JSRuntime::InterruptMode mode);
bool intrinsic_SetForkJoinTargetRegion(JSContext *cx, unsigned argc, Value *vp);
extern const JSJitInfo intrinsic_SetForkJoinTargetRegionInfo;

Просмотреть файл

@ -621,14 +621,8 @@ RegExpShared::execute(JSContext *cx, HandleLinearString input, size_t start,
// in the bytecode interpreter, which can execute while tolerating
// future interrupts. Otherwise, if we keep getting interrupted we
// will never finish executing the regexp.
bool interrupted;
{
JSRuntime::AutoLockForInterrupt lock(cx->runtime());
interrupted = cx->runtime()->interrupt;
}
if (interrupted) {
if (!InvokeInterruptCallback(cx))
if (cx->runtime()->hasPendingInterrupt()) {
if (!cx->runtime()->handleInterrupt(cx))
return RegExpRunStatus_Error;
break;
}

Просмотреть файл

@ -36,6 +36,7 @@
#include "jit/PcScriptCache.h"
#include "js/MemoryMetrics.h"
#include "js/SliceBudget.h"
#include "vm/Debugger.h"
#include "jscntxtinlines.h"
#include "jsgcinlines.h"
@ -73,7 +74,7 @@ PerThreadData::PerThreadData(JSRuntime *runtime)
runtime_(runtime),
jitTop(nullptr),
jitJSContext(nullptr),
jitStackLimit(0),
jitStackLimit_(0xbad),
#ifdef JS_TRACE_LOGGING
traceLogger(nullptr),
#endif
@ -135,8 +136,8 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime)
),
mainThread(this),
parentRuntime(parentRuntime),
interrupt(false),
interruptPar(false),
interrupt_(false),
interruptPar_(false),
handlingSignal(false),
interruptCallback(nullptr),
interruptLock(nullptr),
@ -155,7 +156,7 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime)
execAlloc_(nullptr),
jitRuntime_(nullptr),
selfHostingGlobal_(nullptr),
nativeStackBase(0),
nativeStackBase(GetNativeStackBase()),
cxCallback(nullptr),
destroyCompartmentCallback(nullptr),
destroyZoneCallback(nullptr),
@ -321,8 +322,6 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes)
return false;
#endif
nativeStackBase = GetNativeStackBase();
jitSupportsFloatingPoint = js::jit::JitSupportsFloatingPoint();
jitSupportsSimd = js::jit::JitSupportsSimd();
@ -464,17 +463,6 @@ NewObjectCache::clearNurseryObjects(JSRuntime *rt)
#endif
}
void
JSRuntime::resetJitStackLimit()
{
AutoLockForInterrupt lock(this);
mainThread.setJitStackLimit(mainThread.nativeStackLimit[js::StackForUntrustedScript]);
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
mainThread.setJitStackLimit(js::jit::Simulator::StackLimit());
#endif
}
void
JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes *rtSizes)
{
@ -529,33 +517,120 @@ JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Runtim
#endif
}
static bool
InvokeInterruptCallback(JSContext *cx)
{
MOZ_ASSERT(cx->runtime()->requestDepth >= 1);
cx->gcIfNeeded();
// A worker thread may have requested an interrupt after finishing an Ion
// compilation.
jit::AttachFinishedCompilations(cx);
// Important: Additional callbacks can occur inside the callback handler
// if it re-enters the JS engine. The embedding must ensure that the
// callback is disconnected before attempting such re-entry.
JSInterruptCallback cb = cx->runtime()->interruptCallback;
if (!cb)
return true;
if (cb(cx)) {
// Debugger treats invoking the interrupt callback as a "step", so
// invoke the onStep handler.
if (cx->compartment()->debugMode()) {
ScriptFrameIter iter(cx);
if (iter.script()->stepModeEnabled()) {
RootedValue rval(cx);
switch (Debugger::onSingleStep(cx, &rval)) {
case JSTRAP_ERROR:
return false;
case JSTRAP_CONTINUE:
return true;
case JSTRAP_RETURN:
// See note in Debugger::propagateForcedReturn.
Debugger::propagateForcedReturn(cx, iter.abstractFramePtr(), rval);
return false;
case JSTRAP_THROW:
cx->setPendingException(rval);
return false;
default:;
}
}
}
return true;
}
// No need to set aside any pending exception here: ComputeStackString
// already does that.
JSString *stack = ComputeStackString(cx);
JSFlatString *flat = stack ? stack->ensureFlat(cx) : nullptr;
const char16_t *chars;
AutoStableStringChars stableChars(cx);
if (flat && stableChars.initTwoByte(cx, flat))
chars = stableChars.twoByteRange().start().get();
else
chars = MOZ_UTF16("(stack not available)");
JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_WARNING, js_GetErrorMessage, nullptr,
JSMSG_TERMINATED, chars);
return false;
}
void
PerThreadData::resetJitStackLimit()
{
// Note that, for now, we use the untrusted limit for ion. This is fine,
// because it's the most conservative limit, and if we hit it, we'll bail
// out of ion into the interpeter, which will do a proper recursion check.
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
jitStackLimit_ = jit::Simulator::StackLimit();
#else
jitStackLimit_ = nativeStackLimit[StackForUntrustedScript];
#endif
}
void
PerThreadData::initJitStackLimit()
{
resetJitStackLimit();
}
void
PerThreadData::initJitStackLimitPar(uintptr_t limit)
{
jitStackLimit_ = limit;
}
void
JSRuntime::requestInterrupt(InterruptMode mode)
{
AutoLockForInterrupt lock(this);
interrupt_ = true;
interruptPar_ = true;
mainThread.jitStackLimit_ = UINTPTR_MAX;
/*
* Invalidate ionTop to trigger its over-recursion check. Note this must be
* set before interrupt, to avoid racing with js::InvokeInterruptCallback,
* into a weird state where interrupt is stuck at 0 but jitStackLimit is
* MAXADDR.
*/
mainThread.setJitStackLimit(-1);
interrupt = true;
RequestInterruptForForkJoin(this, mode);
/*
* asm.js and normal Ion code optionally use memory protection and signal
* handlers to halt running code.
*/
if (canUseSignalHandlers()) {
AutoLockForInterrupt lock(this);
RequestInterruptForAsmJSCode(this, mode);
jit::RequestInterruptForIonCode(this, mode);
}
}
bool
JSRuntime::handleInterrupt(JSContext *cx)
{
MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
if (interrupt_ || mainThread.jitStackLimit_ == UINTPTR_MAX) {
interrupt_ = false;
interruptPar_ = false;
mainThread.resetJitStackLimit();
return InvokeInterruptCallback(cx);
}
return true;
}
jit::ExecutableAllocator *
JSRuntime::createExecutableAllocator(JSContext *cx)
{

Просмотреть файл

@ -519,13 +519,20 @@ class PerThreadData : public PerThreadDataFriendFields
*/
JSContext *jitJSContext;
/*
* The stack limit checked by JIT code. This stack limit may be temporarily
* set to null to force JIT code to exit (e.g., for the operation callback).
*/
uintptr_t jitStackLimit;
/* See comment for JSRuntime::interrupt_. */
private:
mozilla::Atomic<uintptr_t, mozilla::Relaxed> jitStackLimit_;
void resetJitStackLimit();
friend struct ::JSRuntime;
public:
void initJitStackLimit();
void initJitStackLimitPar(uintptr_t limit);
inline void setJitStackLimit(uintptr_t limit);
uintptr_t jitStackLimit() const { return jitStackLimit_; }
// For read-only JIT use:
void *addressOfJitStackLimit() { return &jitStackLimit_; }
static size_t offsetOfJitStackLimit() { return offsetof(PerThreadData, jitStackLimit_); }
// Information about the heap allocated backtrack stack used by RegExp JIT code.
irregexp::RegExpStack regexpStack;
@ -678,8 +685,6 @@ class PerThreadData : public PerThreadDataFriendFields
class AutoLockForExclusiveAccess;
void RecomputeStackLimit(JSRuntime *rt, StackKind kind);
} // namespace js
struct JSRuntime : public JS::shadow::Runtime,
@ -703,18 +708,56 @@ struct JSRuntime : public JS::shadow::Runtime,
*/
JSRuntime *parentRuntime;
/*
* If true, we've been asked to call the interrupt callback as soon as
* possible.
*/
mozilla::Atomic<bool, mozilla::Relaxed> interrupt;
private:
mozilla::Atomic<uint32_t, mozilla::Relaxed> interrupt_;
mozilla::Atomic<uint32_t, mozilla::Relaxed> interruptPar_;
public:
/*
* If non-zero, ForkJoin should service an interrupt. This is a separate
* flag from |interrupt| because we cannot use the mprotect trick with PJS
* code and ignore the TriggerCallbackAnyThreadDontStopIon trigger.
*/
mozilla::Atomic<bool, mozilla::Relaxed> interruptPar;
enum InterruptMode {
RequestInterruptMainThread,
RequestInterruptAnyThread,
RequestInterruptAnyThreadDontStopIon,
RequestInterruptAnyThreadForkJoin
};
// Any thread can call requestInterrupt() to request that the main JS thread
// stop running and call the interrupt callback (allowing the interrupt
// callback to halt execution). To stop the main JS thread, requestInterrupt
// sets two fields: interrupt_ (set to true) and jitStackLimit_ (set to
// UINTPTR_MAX). The JS engine must continually poll one of these fields
// and call handleInterrupt if either field has the interrupt value. (The
// point of setting jitStackLimit_ to UINTPTR_MAX is that JIT code already
// needs to guard on jitStackLimit_ in every function prologue to avoid
// stack overflow, so we avoid a second branch on interrupt_ by setting
// jitStackLimit_ to a value that is guaranteed to fail the guard.)
//
// Note that the writes to interrupt_ and jitStackLimit_ use a Relaxed
// Atomic so, while the writes are guaranteed to eventually be visible to
// the main thread, it can happen in any order. handleInterrupt calls the
// interrupt callback if either is set, so it really doesn't matter as long
// as the JS engine is continually polling at least one field. In corner
// cases, this relaxed ordering could lead to an interrupt handler being
// called twice in succession after a single requestInterrupt call, but
// that's fine.
void requestInterrupt(InterruptMode mode);
bool handleInterrupt(JSContext *cx);
MOZ_ALWAYS_INLINE bool hasPendingInterrupt() const {
return interrupt_;
}
MOZ_ALWAYS_INLINE bool hasPendingInterruptPar() const {
return interruptPar_;
}
// For read-only JIT use:
void *addressOfInterruptUint32() {
static_assert(sizeof(interrupt_) == sizeof(uint32_t), "Assumed by JIT callers");
return &interrupt_;
}
void *addressOfInterruptParUint32() {
static_assert(sizeof(interruptPar_) == sizeof(uint32_t), "Assumed by JIT callers");
return &interruptPar_;
}
/* Set when handling a signal for a thread associated with this runtime. */
bool handlingSignal;
@ -900,7 +943,7 @@ struct JSRuntime : public JS::shadow::Runtime,
void setDefaultVersion(JSVersion v) { defaultVersion_ = v; }
/* Base address of the native stack for the current thread. */
uintptr_t nativeStackBase;
const uintptr_t nativeStackBase;
/* The native stack size limit that runtime should not exceed. */
size_t nativeStackQuota[js::StackKindCount];
@ -1266,10 +1309,6 @@ struct JSRuntime : public JS::shadow::Runtime,
bool jitSupportsFloatingPoint;
bool jitSupportsSimd;
// Used to reset stack limit after a signaled interrupt (i.e. jitStackLimit_ = -1)
// has been noticed by Ion/Baseline.
void resetJitStackLimit();
// Cache for jit::GetPcScript().
js::jit::PcScriptCache *ionPcScriptCache;
@ -1330,17 +1369,6 @@ struct JSRuntime : public JS::shadow::Runtime,
/* onOutOfMemory but can call the largeAllocationFailureCallback. */
JS_FRIEND_API(void *) onOutOfMemoryCanGC(void *p, size_t bytes);
// Ways in which the interrupt callback on the runtime can be triggered,
// varying based on which thread is triggering the callback.
enum InterruptMode {
RequestInterruptMainThread,
RequestInterruptAnyThread,
RequestInterruptAnyThreadDontStopIon,
RequestInterruptAnyThreadForkJoin
};
void requestInterrupt(InterruptMode mode);
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes *runtime);
private:
@ -1564,13 +1592,6 @@ class MOZ_STACK_CLASS AutoKeepAtoms
}
};
inline void
PerThreadData::setJitStackLimit(uintptr_t limit)
{
MOZ_ASSERT(runtime_->currentThreadOwnsInterruptLock());
jitStackLimit = limit;
}
inline JSRuntime *
PerThreadData::runtimeFromMainThread()
{

Просмотреть файл

@ -12,6 +12,7 @@
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/PathHelpers.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/Move.h"
#include "nsCOMPtr.h"
#include "nsFontMetrics.h"
#include "nsGkAtoms.h"
@ -51,20 +52,14 @@ NS_QUERYFRAME_TAIL_INHERITING(nsFrame)
nsBulletFrame::~nsBulletFrame()
{
NS_ASSERTION(!mBlockingOnload, "Still blocking onload in destructor?");
}
void
nsBulletFrame::DestroyFrom(nsIFrame* aDestructRoot)
{
// Stop image loading first
if (mImageRequest) {
// Deregister our image request from the refresh driver
nsLayoutUtils::DeregisterImageRequest(PresContext(),
mImageRequest,
&mRequestRegistered);
mImageRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
mImageRequest = nullptr;
}
// Stop image loading first.
DeregisterAndCancelImageRequest();
if (mListener) {
mListener->SetFrame(nullptr);
@ -132,35 +127,21 @@ nsBulletFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
}
if (needNewRequest) {
nsRefPtr<imgRequestProxy> oldRequest = mImageRequest;
newRequest->Clone(mListener, getter_AddRefs(mImageRequest));
nsRefPtr<imgRequestProxy> newRequestClone;
newRequest->Clone(mListener, getter_AddRefs(newRequestClone));
// Deregister the old request. We wait until after Clone is done in case
// the old request and the new request are the same underlying image
// accessed via different URLs.
if (oldRequest) {
nsLayoutUtils::DeregisterImageRequest(PresContext(), oldRequest,
&mRequestRegistered);
oldRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
oldRequest = nullptr;
}
DeregisterAndCancelImageRequest();
// Register the new request.
if (mImageRequest) {
nsLayoutUtils::RegisterImageRequestIfAnimated(PresContext(),
mImageRequest,
&mRequestRegistered);
}
mImageRequest = Move(newRequestClone);
RegisterImageRequest(/* aKnownToBeAnimated = */ false);
}
} else {
// No image request on the new style context
if (mImageRequest) {
nsLayoutUtils::DeregisterImageRequest(PresContext(), mImageRequest,
&mRequestRegistered);
mImageRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
mImageRequest = nullptr;
}
// No image request on the new style context.
DeregisterAndCancelImageRequest();
}
#ifdef ACCESSIBILITY
@ -692,14 +673,67 @@ nsBulletFrame::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aDa
// Register the image request with the refresh driver now that we know it's
// animated.
if (aRequest == mImageRequest) {
nsLayoutUtils::RegisterImageRequest(PresContext(), mImageRequest,
&mRequestRegistered);
RegisterImageRequest(/* aKnownToBeAnimated = */ true);
}
}
if (aType == imgINotificationObserver::LOAD_COMPLETE) {
// Unconditionally start decoding for now.
// XXX(seth): We eventually want to decide whether to do this based on
// visibility. We should get that for free from bug 1091236.
if (aRequest == mImageRequest) {
mImageRequest->RequestDecode();
}
InvalidateFrame();
}
return NS_OK;
}
NS_IMETHODIMP
nsBulletFrame::BlockOnload(imgIRequest* aRequest)
{
if (aRequest != mImageRequest) {
return NS_OK;
}
NS_ASSERTION(!mBlockingOnload, "Double BlockOnload for an nsBulletFrame?");
nsIDocument* doc = GetOurCurrentDoc();
if (doc) {
mBlockingOnload = true;
doc->BlockOnload();
}
return NS_OK;
}
NS_IMETHODIMP
nsBulletFrame::UnblockOnload(imgIRequest* aRequest)
{
if (aRequest != mImageRequest) {
return NS_OK;
}
NS_ASSERTION(!mBlockingOnload, "Double UnblockOnload for an nsBulletFrame?");
nsIDocument* doc = GetOurCurrentDoc();
if (doc) {
doc->UnblockOnload(false);
}
mBlockingOnload = false;
return NS_OK;
}
nsIDocument*
nsBulletFrame::GetOurCurrentDoc() const
{
nsIContent* parentContent = GetParent()->GetContent();
return parentContent ? parentContent->GetComposedDoc()
: nullptr;
}
nsresult nsBulletFrame::OnStartContainer(imgIRequest *aRequest,
imgIContainer *aImage)
{
@ -873,7 +907,57 @@ nsBulletFrame::GetSpokenText(nsAString& aText)
}
}
void
nsBulletFrame::RegisterImageRequest(bool aKnownToBeAnimated)
{
if (mImageRequest) {
// mRequestRegistered is a bitfield; unpack it temporarily so we can take
// the address.
bool isRequestRegistered = mRequestRegistered;
if (aKnownToBeAnimated) {
nsLayoutUtils::RegisterImageRequest(PresContext(), mImageRequest,
&isRequestRegistered);
} else {
nsLayoutUtils::RegisterImageRequestIfAnimated(PresContext(),
mImageRequest,
&isRequestRegistered);
}
isRequestRegistered = mRequestRegistered;
}
}
void
nsBulletFrame::DeregisterAndCancelImageRequest()
{
if (mImageRequest) {
// mRequestRegistered is a bitfield; unpack it temporarily so we can take
// the address.
bool isRequestRegistered = mRequestRegistered;
// Deregister our image request from the refresh driver.
nsLayoutUtils::DeregisterImageRequest(PresContext(),
mImageRequest,
&isRequestRegistered);
isRequestRegistered = mRequestRegistered;
// Unblock onload if we blocked it.
if (mBlockingOnload) {
nsIDocument* doc = GetOurCurrentDoc();
if (doc) {
doc->UnblockOnload(false);
}
mBlockingOnload = false;
}
// Cancel the image request and forget about it.
mImageRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
mImageRequest = nullptr;
}
}
@ -894,7 +978,26 @@ nsBulletListener::~nsBulletListener()
NS_IMETHODIMP
nsBulletListener::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
{
if (!mFrame)
if (!mFrame) {
return NS_ERROR_FAILURE;
}
return mFrame->Notify(aRequest, aType, aData);
}
NS_IMETHODIMP
nsBulletListener::BlockOnload(imgIRequest* aRequest)
{
if (!mFrame) {
return NS_ERROR_FAILURE;
}
return mFrame->BlockOnload(aRequest);
}
NS_IMETHODIMP
nsBulletListener::UnblockOnload(imgIRequest* aRequest)
{
if (!mFrame) {
return NS_ERROR_FAILURE;
}
return mFrame->UnblockOnload(aRequest);
}

Просмотреть файл

@ -12,19 +12,22 @@
#include "nsFrame.h"
#include "imgINotificationObserver.h"
#include "imgIOnloadBlocker.h"
class imgIContainer;
class imgRequestProxy;
class nsBulletFrame;
class nsBulletListener MOZ_FINAL : public imgINotificationObserver
class nsBulletListener MOZ_FINAL : public imgINotificationObserver,
public imgIOnloadBlocker
{
public:
nsBulletListener();
NS_DECL_ISUPPORTS
NS_DECL_IMGINOTIFICATIONOBSERVER
NS_DECL_IMGIONLOADBLOCKER
void SetFrame(nsBulletFrame *frame) { mFrame = frame; }
@ -50,11 +53,14 @@ public:
: nsFrame(aContext)
, mPadding(GetWritingMode())
, mIntrinsicSize(GetWritingMode())
{
}
, mRequestRegistered(false)
, mBlockingOnload(false)
{ }
virtual ~nsBulletFrame();
NS_IMETHOD Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData);
NS_IMETHOD Notify(imgIRequest* aRequest, int32_t aType, const nsIntRect* aData);
NS_IMETHOD BlockOnload(imgIRequest* aRequest);
NS_IMETHOD UnblockOnload(imgIRequest* aRequest);
// nsIFrame
virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE;
@ -111,6 +117,7 @@ protected:
float aFontSizeInflation);
void GetLoadGroup(nsPresContext *aPresContext, nsILoadGroup **aLoadGroup);
nsIDocument* GetOurCurrentDoc() const;
mozilla::LogicalMargin mPadding;
nsRefPtr<imgRequestProxy> mImageRequest;
@ -120,10 +127,15 @@ protected:
int32_t mOrdinal;
private:
void RegisterImageRequest(bool aKnownToBeAnimated);
void DeregisterAndCancelImageRequest();
// This is a boolean flag indicating whether or not the current image request
// has been registered with the refresh driver.
bool mRequestRegistered;
bool mRequestRegistered : 1;
// Whether we're currently blocking onload.
bool mBlockingOnload : 1;
};
#endif /* nsBulletFrame_h___ */

Просмотреть файл

@ -127,7 +127,7 @@ skip-if(B2G) == img-fragment-2a.html img-fragment-2-ref.html # bug 773482
skip-if(B2G) == img-fragment-2b.html img-fragment-2-ref.html # bug 773482
skip-if(B2G) == img-fragment-2c.html img-fragment-2-ref.html # bug 773482
skip-if(B2G) == list-simple-1.html list-simple-1-ref.html # bug 773482
fuzzy-if(B2G,68,4) == list-simple-1.html list-simple-1-ref.html
== svg-image-simple-1.svg lime100x100.svg
== svg-image-simple-2.svg lime100x100.svg

Просмотреть файл

@ -226,7 +226,10 @@ FontFace::FontFace(nsISupports* aParent, nsPresContext* aPresContext)
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aParent);
if (global) {
// If the pref is not set, don't create the Promise (which the page wouldn't
// be able to get to anyway) as it causes the window.FontFace constructor
// to be created.
if (global && FontFaceSet::PrefEnabled()) {
ErrorResult rv;
mLoaded = Promise::Create(global, rv);
}

Просмотреть файл

@ -39,6 +39,8 @@ using namespace mozilla::dom;
#define LOG_ENABLED() PR_LOG_TEST(gfxUserFontSet::GetUserFontsLog(), \
PR_LOG_DEBUG)
#define FONT_LOADING_API_ENABLED_PREF "layout.css.font-loading-api.enabled"
NS_IMPL_CYCLE_COLLECTION_CLASS(FontFaceSet)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FontFaceSet, DOMEventTargetHelper)
@ -83,7 +85,10 @@ FontFaceSet::FontFaceSet(nsPIDOMWindow* aWindow, nsPresContext* aPresContext)
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aWindow);
if (global) {
// If the pref is not set, don't create the Promise (which the page wouldn't
// be able to get to anyway) as it causes the window.FontFaceSet constructor
// to be created.
if (global && PrefEnabled()) {
ErrorResult rv;
mReady = Promise::Create(global, rv);
}
@ -1337,7 +1342,7 @@ FontFaceSet::CheckLoadingStarted()
false))->RunDOMEventWhenSafe();
}
if (mReadyIsResolved) {
if (mReadyIsResolved && PrefEnabled()) {
nsRefPtr<Promise> ready;
if (GetParentObject()) {
ErrorResult rv;
@ -1496,6 +1501,18 @@ FontFaceSet::HandleEvent(nsIDOMEvent* aEvent)
return NS_OK;
}
/* static */ bool
FontFaceSet::PrefEnabled()
{
static bool initialized = false;
static bool enabled;
if (!initialized) {
initialized = true;
Preferences::AddBoolVarCache(&enabled, FONT_LOADING_API_ENABLED_PREF);
}
return enabled;
}
// nsICSSLoaderObserver
NS_IMETHODIMP

Просмотреть файл

@ -157,6 +157,11 @@ public:
*/
void DidRefresh();
/**
* Returns whether the "layout.css.font-loading-api.enabled" pref is true.
*/
static bool PrefEnabled();
// nsICSSLoaderObserver
NS_IMETHOD StyleSheetLoaded(mozilla::CSSStyleSheet* aSheet,
bool aWasAlternate,

Просмотреть файл

@ -1,6 +1,9 @@
#ifdef _WIN32
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#if !defined(INT64_MAX)
#define INT64_MAX 9223372036854775807LL
#endif
#else
#include <stdint.h>
#endif

Просмотреть файл

@ -2106,6 +2106,9 @@ nestegg_offset_seek(nestegg * ctx, uint64_t offset)
{
int r;
if (offset > INT64_MAX)
return -1;
/* Seek and set up parser state for segment-level element (Cluster). */
r = ne_io_seek(ctx->io, offset, NESTEGG_SEEK_SET);
if (r != 0)

Просмотреть файл

@ -2482,8 +2482,9 @@ var NativeWindow = {
return;
}
// Use the highlighted element for the context menu target.
this._target = BrowserEventHandler._highlightElement;
// Use the highlighted element for the context menu target. When accessibility is
// enabled, elements may not be highlighted so use the event target instead.
this._target = BrowserEventHandler._highlightElement || event.target;
if (!this._target) {
return;
}

Просмотреть файл

@ -450,30 +450,4 @@ operator!=( NSCAP_Zero* lhs, const nsHtml5RefPtr<T>& rhs )
return reinterpret_cast<const void*>(lhs) != static_cast<const void*>(rhs.get());
}
#ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO
// We need to explicitly define comparison operators for `int'
// because the compiler is lame.
template <class T>
inline
bool
operator==( const nsHtml5RefPtr<T>& lhs, int rhs )
// specifically to allow |smartPtr == 0|
{
return static_cast<const void*>(lhs.get()) == reinterpret_cast<const void*>(rhs);
}
template <class T>
inline
bool
operator==( int lhs, const nsHtml5RefPtr<T>& rhs )
// specifically to allow |0 == smartPtr|
{
return reinterpret_cast<const void*>(lhs) == static_cast<const void*>(rhs.get());
}
#endif // !defined(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO)
#endif // !defined(nsHtml5RefPtr_h)

Просмотреть файл

@ -80,7 +80,7 @@ pageInfo_EncryptionWithBitsAndProtocol=Connection Encrypted (%1$S, %2$S bit keys
pageInfo_Privacy_Encrypted1=The page you are viewing was encrypted before being transmitted over the Internet.
pageInfo_Privacy_Encrypted2=Encryption makes it difficult for unauthorized people to view information traveling between computers. It is therefore unlikely that anyone read this page as it traveled across the network.
pageInfo_MixedContent=Connection Partially Encrypted
pageInfo_Privacy_Mixed1=Parts of the page you are viewing were not encrypted before being transmitted over the Internet.
pageInfo_Privacy_Broken1=Parts of the page you are viewing were not encrypted or the encryption is not strong enough before being transmitted over the Internet.
#Cert Viewer
certDetails=Certificate Viewer:

Просмотреть файл

@ -1172,6 +1172,92 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
infoObject->GetPort(),
versions.max);
bool weakEncryption = false;
SSLChannelInfo channelInfo;
rv = SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo));
MOZ_ASSERT(rv == SECSuccess);
if (rv == SECSuccess) {
// Get the protocol version for telemetry
// 0=ssl3, 1=tls1, 2=tls1.1, 3=tls1.2
unsigned int versionEnum = channelInfo.protocolVersion & 0xFF;
Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_VERSION, versionEnum);
AccumulateCipherSuite(
infoObject->IsFullHandshake() ? Telemetry::SSL_CIPHER_SUITE_FULL
: Telemetry::SSL_CIPHER_SUITE_RESUMED,
channelInfo);
SSLCipherSuiteInfo cipherInfo;
rv = SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
sizeof cipherInfo);
MOZ_ASSERT(rv == SECSuccess);
if (rv == SECSuccess) {
weakEncryption =
(channelInfo.protocolVersion <= SSL_LIBRARY_VERSION_3_0) ||
(cipherInfo.symCipher == ssl_calg_rc4);
// keyExchange null=0, rsa=1, dh=2, fortezza=3, ecdh=4
Telemetry::Accumulate(
infoObject->IsFullHandshake()
? Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_FULL
: Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_RESUMED,
cipherInfo.keaType);
DebugOnly<int16_t> KEAUsed;
MOZ_ASSERT(NS_SUCCEEDED(infoObject->GetKEAUsed(&KEAUsed)) &&
(KEAUsed == cipherInfo.keaType));
if (infoObject->IsFullHandshake()) {
switch (cipherInfo.keaType) {
case ssl_kea_rsa:
AccumulateNonECCKeySize(Telemetry::SSL_KEA_RSA_KEY_SIZE_FULL,
channelInfo.keaKeyBits);
break;
case ssl_kea_dh:
AccumulateNonECCKeySize(Telemetry::SSL_KEA_DHE_KEY_SIZE_FULL,
channelInfo.keaKeyBits);
break;
case ssl_kea_ecdh:
AccumulateECCCurve(Telemetry::SSL_KEA_ECDHE_CURVE_FULL,
channelInfo.keaKeyBits);
break;
default:
MOZ_CRASH("impossible KEA");
break;
}
Telemetry::Accumulate(Telemetry::SSL_AUTH_ALGORITHM_FULL,
cipherInfo.authAlgorithm);
// RSA key exchange doesn't use a signature for auth.
if (cipherInfo.keaType != ssl_kea_rsa) {
switch (cipherInfo.authAlgorithm) {
case ssl_auth_rsa:
AccumulateNonECCKeySize(Telemetry::SSL_AUTH_RSA_KEY_SIZE_FULL,
channelInfo.authKeyBits);
break;
case ssl_auth_dsa:
AccumulateNonECCKeySize(Telemetry::SSL_AUTH_DSA_KEY_SIZE_FULL,
channelInfo.authKeyBits);
break;
case ssl_auth_ecdsa:
AccumulateECCCurve(Telemetry::SSL_AUTH_ECDSA_CURVE_FULL,
channelInfo.authKeyBits);
break;
default:
MOZ_CRASH("impossible auth algorithm");
break;
}
}
}
Telemetry::Accumulate(
infoObject->IsFullHandshake()
? Telemetry::SSL_SYMMETRIC_CIPHER_FULL
: Telemetry::SSL_SYMMETRIC_CIPHER_RESUMED,
cipherInfo.symCipher);
}
}
PRBool siteSupportsSafeRenego;
rv = SSL_HandshakeNegotiatedExtension(fd, ssl_renegotiation_info_xtn,
&siteSupportsSafeRenego);
@ -1180,8 +1266,9 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
siteSupportsSafeRenego = false;
}
if (siteSupportsSafeRenego ||
!ioLayerHelpers.treatUnsafeNegotiationAsBroken()) {
if (!weakEncryption &&
(siteSupportsSafeRenego ||
!ioLayerHelpers.treatUnsafeNegotiationAsBroken())) {
infoObject->SetSecurityState(nsIWebProgressListener::STATE_IS_SECURE |
nsIWebProgressListener::STATE_SECURE_HIGH);
} else {
@ -1246,87 +1333,6 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
}
}
SSLChannelInfo channelInfo;
rv = SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo));
MOZ_ASSERT(rv == SECSuccess);
if (rv == SECSuccess) {
// Get the protocol version for telemetry
// 0=ssl3, 1=tls1, 2=tls1.1, 3=tls1.2
unsigned int versionEnum = channelInfo.protocolVersion & 0xFF;
Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_VERSION, versionEnum);
AccumulateCipherSuite(
infoObject->IsFullHandshake() ? Telemetry::SSL_CIPHER_SUITE_FULL
: Telemetry::SSL_CIPHER_SUITE_RESUMED,
channelInfo);
SSLCipherSuiteInfo cipherInfo;
rv = SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
sizeof cipherInfo);
MOZ_ASSERT(rv == SECSuccess);
if (rv == SECSuccess) {
// keyExchange null=0, rsa=1, dh=2, fortezza=3, ecdh=4
Telemetry::Accumulate(
infoObject->IsFullHandshake()
? Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_FULL
: Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_RESUMED,
cipherInfo.keaType);
DebugOnly<int16_t> KEAUsed;
MOZ_ASSERT(NS_SUCCEEDED(infoObject->GetKEAUsed(&KEAUsed)) &&
(KEAUsed == cipherInfo.keaType));
if (infoObject->IsFullHandshake()) {
switch (cipherInfo.keaType) {
case ssl_kea_rsa:
AccumulateNonECCKeySize(Telemetry::SSL_KEA_RSA_KEY_SIZE_FULL,
channelInfo.keaKeyBits);
break;
case ssl_kea_dh:
AccumulateNonECCKeySize(Telemetry::SSL_KEA_DHE_KEY_SIZE_FULL,
channelInfo.keaKeyBits);
break;
case ssl_kea_ecdh:
AccumulateECCCurve(Telemetry::SSL_KEA_ECDHE_CURVE_FULL,
channelInfo.keaKeyBits);
break;
default:
MOZ_CRASH("impossible KEA");
break;
}
Telemetry::Accumulate(Telemetry::SSL_AUTH_ALGORITHM_FULL,
cipherInfo.authAlgorithm);
// RSA key exchange doesn't use a signature for auth.
if (cipherInfo.keaType != ssl_kea_rsa) {
switch (cipherInfo.authAlgorithm) {
case ssl_auth_rsa:
AccumulateNonECCKeySize(Telemetry::SSL_AUTH_RSA_KEY_SIZE_FULL,
channelInfo.authKeyBits);
break;
case ssl_auth_dsa:
AccumulateNonECCKeySize(Telemetry::SSL_AUTH_DSA_KEY_SIZE_FULL,
channelInfo.authKeyBits);
break;
case ssl_auth_ecdsa:
AccumulateECCCurve(Telemetry::SSL_AUTH_ECDSA_CURVE_FULL,
channelInfo.authKeyBits);
break;
default:
MOZ_CRASH("impossible auth algorithm");
break;
}
}
}
Telemetry::Accumulate(
infoObject->IsFullHandshake()
? Telemetry::SSL_SYMMETRIC_CIPHER_FULL
: Telemetry::SSL_SYMMETRIC_CIPHER_RESUMED,
cipherInfo.symCipher);
}
}
infoObject->NoteTimeUntilReady();
infoObject->SetHandshakeCompleted();
}

Просмотреть файл

@ -407,29 +407,6 @@ operator!=(NSCAP_Zero* aLhs, const nsAutoPtr<T>& aRhs)
}
#ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO
// We need to explicitly define comparison operators for `int'
// because the compiler is lame.
template <class T>
inline bool
operator==(const nsAutoPtr<T>& aLhs, int aRhs)
// specifically to allow |smartPtr == 0|
{
return static_cast<const void*>(aLhs.get()) == reinterpret_cast<const void*>(aRhs);
}
template <class T>
inline bool
operator==(int aLhs, const nsAutoPtr<T>& aRhs)
// specifically to allow |0 == smartPtr|
{
return reinterpret_cast<const void*>(aLhs) == static_cast<const void*>(aRhs.get());
}
#endif // !defined(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO)
/*****************************************************************************/
// template <class T> class nsAutoArrayPtrGetterTransfers;
@ -782,29 +759,6 @@ operator!=(NSCAP_Zero* aLhs, const nsAutoArrayPtr<T>& aRhs)
}
#ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO
// We need to explicitly define comparison operators for `int'
// because the compiler is lame.
template <class T>
inline bool
operator==(const nsAutoArrayPtr<T>& aLhs, int aRhs)
// specifically to allow |smartPtr == 0|
{
return static_cast<const void*>(aLhs.get()) == reinterpret_cast<const void*>(aRhs);
}
template <class T>
inline bool
operator==(int aLhs, const nsAutoArrayPtr<T>& aRhs)
// specifically to allow |0 == smartPtr|
{
return reinterpret_cast<const void*>(aLhs) == static_cast<const void*>(aRhs.get());
}
#endif // !defined(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO)
/*****************************************************************************/
template<class T>

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше