Merge m-c to b2g-inbound. a=merge

This commit is contained in:
Ryan VanderMeulen 2014-06-10 00:45:53 -04:00
commit 0289206652
149 changed files with 2634 additions and 913 deletions

View File

@ -272,7 +272,14 @@ Target.prototype = {
},
_send: function target_send(data) {
shell.sendEvent(this.frame, 'developer-hud-update', Cu.cloneInto(data, this.frame));
let frame = this.frame;
let systemapp = document.querySelector('#systemapp');
if (this.frame === systemapp) {
frame = getContentWindow();
}
shell.sendEvent(frame, 'developer-hud-update', Cu.cloneInto(data, frame));
}
};

View File

@ -1363,6 +1363,11 @@ pref("devtools.gcli.hideIntro", false);
// How eager are we to show help: never=1, sometimes=2, always=3
pref("devtools.gcli.eagerHelper", 2);
// Alias to the script URLs for inject command.
pref("devtools.gcli.jquerySrc", "http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js");
pref("devtools.gcli.lodashSrc", "http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js");
pref("devtools.gcli.underscoreSrc", "http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js");
// Remember the Web Console filters
pref("devtools.webconsole.filter.network", true);
pref("devtools.webconsole.filter.networkinfo", false);

View File

@ -14,6 +14,7 @@ const commandModules = [
"gcli/commands/cmd",
"gcli/commands/cookie",
"gcli/commands/csscoverage",
"gcli/commands/inject",
"gcli/commands/jsb",
"gcli/commands/listen",
"gcli/commands/media",

View File

@ -50,6 +50,9 @@ support-files =
browser_cmd_csscoverage_sheetB.css
browser_cmd_csscoverage_sheetC.css
browser_cmd_csscoverage_sheetD.css
[browser_cmd_inject.js]
support-files =
browser_cmd_inject.html
[browser_cmd_csscoverage_util.js]
[browser_cmd_jsb.js]
support-files =

View File

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<head>
<body>
</body>
</html>

View File

@ -0,0 +1,98 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that the inject commands works as they should
const TEST_URI = 'http://example.com/browser/browser/devtools/commandline/'+
'test/browser_cmd_inject.html';
function test() {
helpers.addTabWithToolbar(TEST_URI, function(options) {
return helpers.audit(options, [
{
setup: 'inject',
check: {
input: 'inject',
hints: ' <library>',
markup: 'VVVVVV',
status: 'ERROR'
},
},
{
setup: 'inject j',
check: {
input: 'inject j',
hints: 'Query',
markup: 'VVVVVVVI',
status: 'ERROR'
},
},
{
setup: 'inject http://example.com/browser/browser/devtools/commandline/test/browser_cmd_inject.js',
check: {
input: 'inject http://example.com/browser/browser/devtools/commandline/test/browser_cmd_inject.js',
hints: '',
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
status: 'VALID',
args: {
library: {
value: function(library) {
is(library.type, 'string', 'inject type name');
is(library.string, 'http://example.com/browser/browser/devtools/commandline/test/browser_cmd_inject.js',
'inject uri data');
},
status: 'VALID'
}
}
},
exec: {
output: [ /http:\/\/example.com\/browser\/browser\/devtools\/commandline\/test\/browser_cmd_inject.js loaded/ ]
}
},
{
setup: 'inject notauri',
check: {
input: 'inject notauri',
hints: '',
markup: 'VVVVVVVVVVVVVV',
status: 'VALID',
args: {
library: {
value: function(library) {
is(library.type, 'string', 'inject type name');
is(library.string, 'notauri', 'inject notauri data');
},
status: 'VALID'
}
}
},
exec: {
output: [ /Failed to load notauri - Invalid URI/ ]
}
},
{
setup: 'inject jQuery',
check: {
input: 'inject jQuery',
hints: '',
markup: 'VVVVVVVVVVVVV',
status: 'VALID',
args: {
library: {
value: function(library) {
is(library.type, 'selection', 'inject type name');
is(library.selection.name, 'jQuery', 'inject jquery name');
is(library.selection.src, 'http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js',
'inject jquery src');
},
status: 'VALID'
}
}
},
exec: {
output: [ /jQuery loaded/ ]
}
},
]);
}).then(finish, helpers.handleError);
}

View File

@ -76,6 +76,9 @@ function forEachType(options, typeSpec, callback) {
else if (name === 'remote') {
return;
}
else if (name === 'union') {
typeSpec.types = [{ name: "string" }];
}
var type = types.createType(typeSpec);
var reply = callback(type);
@ -86,6 +89,7 @@ function forEachType(options, typeSpec, callback) {
delete typeSpec.data;
delete typeSpec.delegateType;
delete typeSpec.subtype;
delete typeSpec.types;
return value;
});

View File

@ -177,6 +177,10 @@ helpIntro=GCLI is an experiment to create a highly usable command line for web d
# sub-commands.
subCommands=Sub-Commands
# LOCALIZATION NOTE: This error message is displayed when the command line is
# cannot find a match for the parse types.
commandParseError=Command line parsing error
# LOCALIZATION NOTE (contextDesc, contextManual, contextPrefixDesc): These
# strings are used to describe the 'context' command and its 'prefix'
# parameter. See localization comment for 'connect' for an explanation about

View File

@ -1391,3 +1391,12 @@ mediaEmulateDesc=Emulate a specified CSS media type
mediaEmulateManual=View the document as if rendered on a device supporting the given media type, with the relevant CSS rules applied.
mediaEmulateType=The media type to emulate
mediaResetDesc=Stop emulating a CSS media type
# LOCALIZATION NOTE (injectDesc, injectManual, injectLibraryDesc, injectLoaded,
# injectFailed) These strings describe the 'inject' commands and all available
# parameters.
injectDesc=Inject common libraries into the page
injectManual=Inject common libraries into the content of the page which can also be accessed from the Firefox console.
injectLibraryDesc=Select the library to inject or enter a valid script URI to inject
injectLoaded=%1$S loaded
injectFailed=Failed to load %1$S - Invalid URI

View File

@ -318,6 +318,7 @@ browser.jar:
skin/classic/browser/devtools/font-inspector.css (../shared/devtools/font-inspector.css)
skin/classic/browser/devtools/computedview.css (../shared/devtools/computedview.css)
skin/classic/browser/devtools/arrow-e.png (../shared/devtools/images/arrow-e.png)
skin/classic/browser/devtools/arrow-e@2x.png (../shared/devtools/images/arrow-e@2x.png)
skin/classic/browser/devtools/projecteditor/projecteditor.css (../shared/devtools/projecteditor/projecteditor.css)
skin/classic/browser/devtools/projecteditor/file-icons-sheet@2x.png (../shared/devtools/projecteditor/file-icons-sheet@2x.png)
skin/classic/browser/devtools/app-manager/connection-footer.css (../shared/devtools/app-manager/connection-footer.css)

View File

@ -436,6 +436,7 @@ browser.jar:
skin/classic/browser/devtools/font-inspector.css (../shared/devtools/font-inspector.css)
skin/classic/browser/devtools/computedview.css (../shared/devtools/computedview.css)
skin/classic/browser/devtools/arrow-e.png (../shared/devtools/images/arrow-e.png)
skin/classic/browser/devtools/arrow-e@2x.png (../shared/devtools/images/arrow-e@2x.png)
skin/classic/browser/devtools/projecteditor/projecteditor.css (../shared/devtools/projecteditor/projecteditor.css)
skin/classic/browser/devtools/projecteditor/file-icons-sheet@2x.png (../shared/devtools/projecteditor/file-icons-sheet@2x.png)
skin/classic/browser/devtools/app-manager/connection-footer.css (../shared/devtools/app-manager/connection-footer.css)

View File

@ -29,6 +29,13 @@ menulist:not([editable="true"]) > .menulist-dropmarker {
margin-bottom: 1px;
}
menulist > menupopup menu,
menulist > menupopup menuitem,
button[type="menu"] > menupopup menu,
button[type="menu"] > menupopup menuitem {
-moz-padding-end: 34px;
}
.help-button > .button-box > .button-icon {
-moz-margin-start: 0;
}

View File

@ -51,23 +51,29 @@ body {
outline: 0;
}
.property-value, .other-property-value {
background-image: url(arrow-e.png);
background-repeat: no-repeat;
background-size: 5px 8px;
}
@media (min-resolution: 2dppx) {
.property-value, .other-property-value {
background-image: url(arrow-e@2x.png);
}
}
.property-value {
width: 100%;
overflow-x: hidden;
text-overflow: ellipsis;
white-space: nowrap;
background-image: url(arrow-e.png);
background-repeat: no-repeat;
background-size: 5px 8px;
background-position: 2px center;
padding-left: 10px;
outline: 0;
}
.other-property-value {
background-image: url(arrow-e.png);
background-repeat: no-repeat;
background-size: 5px 8px;
background-position: left center;
padding-left: 8px;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 B

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 B

View File

@ -66,27 +66,29 @@
.stylesheet-sidebar {
width: 230px;
-moz-border-start: 1px solid;
}
.theme-light .stylesheet-sidebar {
border-left: 1px solid #A6A6A6;
border-color: #aaa; /* Splitters */
}
.theme-dark .stylesheet-sidebar {
border-left: 1px solid #606C75;
border-color: #000; /* Splitters */
}
.theme-light .media-rule-label {
border-bottom: 1px solid #CCC;
border-bottom-color: #cddae5; /* Grey */
}
.theme-dark .media-rule-label {
border-bottom: 1px solid #343C45;
border-bottom-color: #303b47; /* Grey */
}
.media-rule-label {
padding: 4px;
cursor: pointer;
border-bottom: 1px solid;
}
.theme-light .media-condition-unmatched {

View File

@ -355,6 +355,7 @@ browser.jar:
skin/classic/browser/devtools/font-inspector.css (../shared/devtools/font-inspector.css)
skin/classic/browser/devtools/computedview.css (../shared/devtools/computedview.css)
skin/classic/browser/devtools/arrow-e.png (../shared/devtools/images/arrow-e.png)
skin/classic/browser/devtools/arrow-e@2x.png (../shared/devtools/images/arrow-e@2x.png)
skin/classic/browser/devtools/projecteditor/projecteditor.css (../shared/devtools/projecteditor/projecteditor.css)
skin/classic/browser/devtools/projecteditor/file-icons-sheet@2x.png (../shared/devtools/projecteditor/file-icons-sheet@2x.png)
skin/classic/browser/devtools/app-manager/connection-footer.css (../shared/devtools/app-manager/connection-footer.css)
@ -758,6 +759,7 @@ browser.jar:
skin/classic/aero/browser/devtools/font-inspector.css (../shared/devtools/font-inspector.css)
skin/classic/aero/browser/devtools/computedview.css (../shared/devtools/computedview.css)
skin/classic/aero/browser/devtools/arrow-e.png (../shared/devtools/images/arrow-e.png)
skin/classic/aero/browser/devtools/arrow-e.png (../shared/devtools/images/arrow-e@2x.png)
skin/classic/aero/browser/devtools/projecteditor/projecteditor.css (../shared/devtools/projecteditor/projecteditor.css)
skin/classic/aero/browser/devtools/projecteditor/file-icons-sheet@2x.png (../shared/devtools/projecteditor/file-icons-sheet@2x.png)
skin/classic/aero/browser/devtools/app-manager/connection-footer.css (../shared/devtools/app-manager/connection-footer.css)

View File

@ -13630,6 +13630,11 @@ nsGlobalWindow::GetDialogArguments(JSContext* aCx, ErrorResult& aError)
MOZ_ASSERT(IsModalContentWindow(),
"This should only be called on modal windows!");
if (!mDialogArguments) {
MOZ_ASSERT(mIsClosed, "This window should be closed!");
return JS::UndefinedValue();
}
// This does an internal origin check, and returns undefined if the subject
// does not subsumes the origin of the arguments.
JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());

View File

@ -350,9 +350,7 @@ public:
// nsWrapperCache
virtual JSObject *WrapObject(JSContext *cx) MOZ_OVERRIDE
{
NS_ASSERTION(IsOuterWindow(),
"Inner window supports nsWrapperCache, fix WrapObject!");
return EnsureInnerWindow() ? GetWrapper() : nullptr;
return IsInnerWindow() || EnsureInnerWindow() ? GetWrapper() : nullptr;
}
// nsIGlobalJSObjectHolder

View File

@ -8,7 +8,6 @@ support-files =
file_empty.html
iframe_postMessage_solidus.html
[test_Image_constructor.html]
[test_appname_override.html]
[test_audioWindowUtils.html]
[test_audioNotification.html]
@ -22,6 +21,8 @@ support-files =
[test_consoleEmptyStack.html]
[test_constructor-assignment.html]
[test_constructor.html]
[test_dialogArguments.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s
[test_document.all_unqualified.html]
[test_domcursor.html]
[test_domrequest.html]
@ -37,6 +38,7 @@ support-files =
[test_getFeature_without_perm.html]
[test_history_document_open.html]
[test_history_state_null.html]
[test_Image_constructor.html]
[test_innersize_scrollport.html]
[test_messageChannel.html]
[test_messageChannel_cloning.html]

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<title>Test for Bug 1019761</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body>
<script type="application/javascript">
/*
Tests whether Firefox crashes when accessing the dialogArguments property
of a modal window that has been closed.
*/
SimpleTest.waitForExplicitFinish();
function openModal() {
showModalDialog("javascript:opener.winRef = window; \
window.opener.setTimeout(\'winRef.dialogArguments;\', 0);\
window.close();");
ok(true, "dialogArguments did not cause a crash.");
SimpleTest.finish();
}
window.onload = openModal;
</script>
</body>
</html>

View File

@ -45,14 +45,13 @@
#include "MediaEngineDefault.h"
#if defined(MOZ_WEBRTC)
#include "MediaEngineWebRTC.h"
#include "browser_logging/WebRtcLog.h"
#endif
#ifdef MOZ_B2G
#include "MediaPermissionGonk.h"
#endif
#include "browser_logging/WebRtcLog.h"
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
// GetTickCount() and conflicts with MediaStream::GetCurrentTime.
#ifdef GetCurrentTime
@ -1577,7 +1576,9 @@ MediaManager::GetUserMedia(bool aPrivileged,
obs->NotifyObservers(req, "getUserMedia:request", nullptr);
}
#ifdef MOZ_WEBRTC
EnableWebRtcLog();
#endif
return NS_OK;
}

View File

@ -1 +1 @@
skip load 408431-1.html # bug 1022509 - renable when the cause of that is backed out
load 408431-1.html

View File

@ -9,19 +9,27 @@ const Ci = Components.interfaces;
const Cc = Components.classes;
const POSITION_UNAVAILABLE = Ci.nsIDOMGeoPositionError.POSITION_UNAVAILABLE;
const SETTING_DEBUG_ENABLED = "geolocation.debugging.enabled";
const SETTING_CHANGED_TOPIC = "mozsettings-changed";
const SETTINGS_DEBUG_ENABLED = "geolocation.debugging.enabled";
const SETTINGS_CHANGED_TOPIC = "mozsettings-changed";
const SETTINGS_WIFI_ENABLED = "wifi.enabled";
let gLoggingEnabled = false;
// if we don't see any wifi responses in 5 seconds, send the request.
let gTimeToWaitBeforeSending = 5000; //ms
/*
The gLocationRequestTimeout controls how long we wait on receiving an update
from the Wifi subsystem. If this timer fires, we believe the Wifi scan has
had a problem and we no longer can use Wifi to position the user this time
around (we will continue to be hopeful that Wifi will recover).
This timeout value is also used when Wifi scanning is disabled (see
gWifiScanningEnabled). In this case, we use this timer to collect cell/ip
data and xhr it to the location server.
*/
let gLocationRequestTimeout = 5000;
let gWifiScanningEnabled = true;
let gWifiResults;
let gCellScanningEnabled = false;
let gCellResults;
function LOG(aMsg) {
if (gLoggingEnabled) {
@ -59,7 +67,7 @@ function WifiGeoPositionProvider() {
} catch (e) {}
try {
gTimeToWaitBeforeSending = Services.prefs.getIntPref("geo.wifi.timeToWaitBeforeSending");
gLocationRequestTimeout = Services.prefs.getIntPref("geo.wifi.timeToWaitBeforeSending");
} catch (e) {}
try {
@ -71,7 +79,7 @@ function WifiGeoPositionProvider() {
} catch (e) {}
this.wifiService = null;
this.timeoutTimer = null;
this.timer = null;
this.started = false;
}
@ -84,28 +92,53 @@ WifiGeoPositionProvider.prototype = {
listener: null,
observe: function(aSubject, aTopic, aData) {
if (aTopic != SETTING_CHANGED_TOPIC) {
if (aTopic != SETTINGS_CHANGED_TOPIC) {
return;
}
try {
let setting = JSON.parse(aData);
if (setting.key != SETTING_DEBUG_ENABLED) {
return;
if (setting.key == SETTINGS_DEBUG_ENABLED) {
gLoggingEnabled = setting.value;
} else if (setting.key == SETTINGS_WIFI_ENABLED) {
gWifiScanningEnabled = setting.value;
}
gLoggingEnabled = setting.value;
} catch (e) {
}
},
resetTimer: function() {
if (this.timer) {
this.timer.cancel();
this.timer = null;
}
// wifi thread triggers WifiGeoPositionProvider to proceed, with no wifi, do manual timeout
this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this.timer.initWithCallback(this,
gLocationRequestTimeout,
this.timer.TYPE_REPEATING_SLACK);
},
startup: function() {
if (this.started)
return;
this.started = true;
let self = this;
let settingsCallback = {
handle: function(name, result) {
gLoggingEnabled = result && result.value === true ? true : false;
if (name == SETTINGS_DEBUG_ENABLED) {
gLoggingEnabled = result;
} else if (name == SETTINGS_WIFI_ENABLED) {
gWifiScanningEnabled = result;
if (self.wifiService) {
self.wifiService.stopWatching(self);
}
if (gWifiScanningEnabled) {
self.wifiService = Cc["@mozilla.org/wifi/monitor;1"].getService(Ci.nsIWifiMonitor);
self.wifiService.startWatching(self);
}
}
},
handleError: function(message) {
@ -115,21 +148,23 @@ WifiGeoPositionProvider.prototype = {
};
try {
Services.obs.addObserver(this, SETTING_CHANGED_TOPIC, false);
Services.obs.addObserver(this, SETTINGS_CHANGED_TOPIC, false);
let settings = Cc["@mozilla.org/settingsService;1"].getService(Ci.nsISettingsService);
settings.createLock().get(SETTING_DEBUG_ENABLED, settingsCallback);
settings.createLock().get(SETTINGS_WIFI_ENABLED, settingsCallback);
settings.createLock().get(SETTINGS_DEBUG_ENABLED, settingsCallback);
} catch(ex) {
// This platform doesn't have the settings interface, and that is just peachy
}
if (gWifiScanningEnabled && Cc["@mozilla.org/wifi/monitor;1"]) {
this.wifiService = Cc["@mozilla.org/wifi/monitor;1"].getService(Components.interfaces.nsIWifiMonitor);
if (this.wifiService) {
this.wifiService.stopWatching(this);
}
this.wifiService = Cc["@mozilla.org/wifi/monitor;1"].getService(Ci.nsIWifiMonitor);
this.wifiService.startWatching(this);
}
this.timeoutTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this.timeoutTimer.initWithCallback(this,
gTimeToWaitBeforeSending,
this.timeoutTimer.TYPE_REPEATING_SLACK);
this.resetTimer();
LOG("startup called.");
},
@ -143,9 +178,9 @@ WifiGeoPositionProvider.prototype = {
return;
}
if (this.timeoutTimer) {
this.timeoutTimer.cancel();
this.timeoutTimer = null;
if (this.timer) {
this.timer.cancel();
this.timer = null;
}
if(this.wifiService) {
@ -153,7 +188,7 @@ WifiGeoPositionProvider.prototype = {
this.wifiService = null;
}
Services.obs.removeObserver(this, SETTING_CHANGED_TOPIC);
Services.obs.removeObserver(this, SETTINGS_CHANGED_TOPIC);
this.listener = null;
this.started = false;
@ -164,6 +199,9 @@ WifiGeoPositionProvider.prototype = {
onChange: function(accessPoints) {
// we got some wifi data, rearm the timer.
this.resetTimer();
function isPublic(ap) {
let mask = "_nomap"
let result = ap.ssid.indexOf(mask, ap.ssid.length - mask.length);
@ -181,18 +219,19 @@ WifiGeoPositionProvider.prototype = {
return { 'macAddress': ap.mac, 'signalStrength': ap.signal };
};
let wifiData = null;
if (accessPoints) {
gWifiResults = accessPoints.filter(isPublic).sort(sort).map(encode);
} else {
gWifiResults = null;
wifiData = accessPoints.filter(isPublic).sort(sort).map(encode);
}
this.sendLocationRequest(wifiData);
},
onError: function (code) {
LOG("wifi error: " + code);
this.sendLocationRequest(null);
},
updateMobileInfo: function() {
getMobileInfo: function() {
LOG("updateMobileInfo called");
try {
let radioService = Cc["@mozilla.org/ril;1"]
@ -216,11 +255,15 @@ WifiGeoPositionProvider.prototype = {
}
return result;
} catch (e) {
gCellResults = null;
return null;
}
},
notify: function (timeoutTimer) {
notify: function (timer) {
this.sendLocationRequest(null);
},
sendLocationRequest: function (wifiData) {
let url = Services.urlFormatter.formatURLPref("geo.wifi.uri");
let listener = this.listener;
LOG("Sending request: " + url + "\n");
@ -258,19 +301,19 @@ WifiGeoPositionProvider.prototype = {
listener.update(newLocation);
};
if (gCellScanningEnabled) {
this.updateMobileInfo();
let data = {};
if (wifiData) {
data.wifiAccessPoints = wifiData;
}
let data = {};
if (gWifiResults) {
data.wifiAccessPoints = gWifiResults;
}
if (gCellResults) {
data.cellTowers = gCellResults;
if (gCellScanningEnabled) {
let cellData = this.getMobileInfo();
if (cellData) {
data.cellTowers = cellData;
}
}
data = JSON.stringify(data);
gWifiResults = gCellResults = null;
LOG("sending " + data);
xhr.send(data);
},

View File

@ -703,10 +703,11 @@ GonkGPSGeolocationProvider::NetworkLocationUpdate::Update(nsIDOMGeoPosition *pos
// assume the MLS coord is unchanged, and stick with the GPS location
const double kMinMLSCoordChangeInMeters = 10;
// if we haven't seen anything from the GPS device for 1s,
// if we haven't seen anything from the GPS device for 10s,
// use this network derived location.
const int kMaxGPSDelayBeforeConsideringMLS = 10000;
int64_t diff = PR_Now() - provider->mLastGPSDerivedLocationTime;
if (provider->mLocationCallback && diff > kDefaultPeriod
if (provider->mLocationCallback && diff > kMaxGPSDelayBeforeConsideringMLS
&& delta > kMinMLSCoordChangeInMeters)
{
provider->mLocationCallback->Update(position);

View File

@ -118,6 +118,7 @@ AppendToString(nsACString& s, const FrameMetrics& m,
{
s += pfx;
AppendToString(s, m.mViewport, "{ viewport=");
AppendToString(s, m.mCompositionBounds, " cb=");
AppendToString(s, m.GetScrollOffset(), " viewportScroll=");
AppendToString(s, m.mDisplayPort, " displayport=");
AppendToString(s, m.mCriticalDisplayPort, " critdp=");

View File

@ -16,7 +16,6 @@
#include "nsRegion.h" // for nsIntRegion
#include "nscore.h" // for nsACString, etc
class gfx3DMatrix;
struct gfxRGBA;
struct nsIntPoint;
struct nsIntRect;
@ -46,10 +45,6 @@ nsACString&
AppendToString(nsACString& s, const gfxRGBA& c,
const char* pfx="", const char* sfx="");
nsACString&
AppendToString(nsACString& s, const gfx3DMatrix& m,
const char* pfx="", const char* sfx="");
nsACString&
AppendToString(nsACString& s, const nsIntPoint& p,
const char* pfx="", const char* sfx="");
@ -80,6 +75,18 @@ AppendToString(nsACString& s, const mozilla::gfx::RectTyped<T>& r,
return s += sfx;
}
template<class T>
nsACString&
AppendToString(nsACString& s, const mozilla::gfx::IntRectTyped<T>& r,
const char* pfx="", const char* sfx="")
{
s += pfx;
s.AppendPrintf(
"(x=%d, y=%d, w=%d, h=%d)",
r.x, r.y, r.width, r.height);
return s += sfx;
}
nsACString&
AppendToString(nsACString& s, const nsIntRegion& r,
const char* pfx="", const char* sfx="");

View File

@ -17,6 +17,7 @@
#include "nsRect.h" // for nsIntRect
#include "nsRegion.h" // for nsIntRegion
#include "nsTArray.h" // for nsTArray
#include "prlog.h" // for PR_LOG
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
#include <ui/Fence.h>
@ -25,6 +26,24 @@
namespace mozilla {
namespace layers {
// To get this logging, you need PR logging enabled (either by
// doing a debug build, or #define'ing FORCE_PR_LOG at the top
// of a .cpp file), and then run with NSPR_LOG_MODULES=tiling:5
// in your environment at runtime.
#ifdef PR_LOGGING
# define TILING_PRLOG(_args) PR_LOG(gTilingLog, PR_LOG_DEBUG, _args)
# define TILING_PRLOG_OBJ(_args, obj) \
{ \
nsAutoCString tmpstr; \
AppendToString(tmpstr, obj); \
PR_LOG(gTilingLog, PR_LOG_DEBUG, _args); \
}
extern PRLogModuleInfo* gTilingLog;
#else
# define TILING_PRLOG(_args)
# define TILING_PRLOG_OBJ(_args, obj)
#endif
// An abstract implementation of a tile buffer. This code covers the logic of
// moving and reusing tiles and leaves the validation up to the implementor. To
// avoid the overhead of virtual dispatch, we employ the curiously recurring

View File

@ -9,6 +9,7 @@
#include "CrossProcessMutex.h"
#include "mozilla/layers/GeckoContentController.h"
#include "mozilla/layers/APZCTreeManager.h"
#include "mozilla/Attributes.h"
#include "mozilla/EventForwards.h"
#include "mozilla/Monitor.h"
@ -38,7 +39,6 @@ class GestureEventListener;
class ContainerLayer;
class PCompositorParent;
class ViewTransform;
class APZCTreeManager;
class AsyncPanZoomAnimation;
class FlingAnimation;

View File

@ -28,6 +28,8 @@
namespace mozilla {
namespace layers {
PRLogModuleInfo* gTilingLog;
using namespace mozilla::gfx;
void
@ -143,6 +145,9 @@ ClientLayerManager::CreateThebesLayerWithHint(ThebesLayerCreationHint aHint)
(AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_OPENGL ||
AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_D3D9 ||
AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_D3D11)) {
if (!gTilingLog) {
gTilingLog = PR_NewLogModule("tiling");
}
if (gfxPrefs::LayersUseSimpleTiles()) {
nsRefPtr<SimpleClientTiledThebesLayer> layer =
new SimpleClientTiledThebesLayer(this);

View File

@ -2,6 +2,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/. */
// Uncomment this to enable the TILING_PRLOG stuff in this file
// for release builds. To get the output you need to have
// NSPR_LOG_MODULES=tiling:5 in your environment at runtime.
// #define FORCE_PR_LOG
#include "ClientTiledThebesLayer.h"
#include "FrameMetrics.h" // for FrameMetrics
#include "Units.h" // for ScreenIntRect, CSSPoint, etc
@ -18,6 +23,7 @@
#include "mozilla/mozalloc.h" // for operator delete, etc
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
#include "nsRect.h" // for nsIntRect
#include "LayersLogging.h"
namespace mozilla {
namespace layers {
@ -52,10 +58,10 @@ ClientTiledThebesLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
aAttrs = ThebesLayerAttributes(GetValidRegion());
}
static LayoutDeviceRect
ApplyParentLayerToLayoutTransform(const gfx3DMatrix& aTransform, const ParentLayerRect& aParentLayerRect)
static LayerRect
ApplyParentLayerToLayerTransform(const gfx3DMatrix& aTransform, const ParentLayerRect& aParentLayerRect)
{
return TransformTo<LayoutDevicePixel>(aTransform, aParentLayerRect);
return TransformTo<LayerPixel>(aTransform, aParentLayerRect);
}
static gfx3DMatrix
@ -64,6 +70,12 @@ GetTransformToAncestorsParentLayer(Layer* aStart, Layer* aAncestor)
gfx::Matrix4x4 transform;
Layer* ancestorParent = aAncestor->GetParent();
for (Layer* iter = aStart; iter != ancestorParent; iter = iter->GetParent()) {
if (iter->AsContainerLayer()) {
// If the layer has a non-transient async transform then we need to apply it here
// because it will get applied by the APZ in the compositor as well
const FrameMetrics& metrics = iter->AsContainerLayer()->GetFrameMetrics();
transform = transform * gfx::Matrix4x4().Scale(metrics.mResolution.scale, metrics.mResolution.scale, 1.f);
}
transform = transform * iter->GetTransform();
}
gfx3DMatrix ret;
@ -117,49 +129,58 @@ ClientTiledThebesLayer::BeginPaint()
return;
}
TILING_PRLOG(("TILING 0x%p: Found scrollAncestor 0x%p and displayPortAncestor 0x%p\n", this,
scrollAncestor, displayPortAncestor));
const FrameMetrics& scrollMetrics = scrollAncestor->GetFrameMetrics();
const FrameMetrics& displayportMetrics = displayPortAncestor->GetFrameMetrics();
// Calculate the transform required to convert ParentLayer space of our
// display port ancestor to the LayoutDevice space of this layer.
gfx3DMatrix layoutDeviceToDisplayPort =
// display port ancestor to the Layer space of this layer.
gfx3DMatrix transformToDisplayPort =
GetTransformToAncestorsParentLayer(this, displayPortAncestor);
layoutDeviceToDisplayPort.ScalePost(scrollMetrics.mCumulativeResolution.scale,
scrollMetrics.mCumulativeResolution.scale,
1.f);
mPaintData.mTransformDisplayPortToLayoutDevice = layoutDeviceToDisplayPort.Inverse();
mPaintData.mTransformDisplayPortToLayer = transformToDisplayPort.Inverse();
// Note that below we use GetZoomToParent() in a number of places. Because this
// code runs on the client side, the mTransformScale field of the FrameMetrics
// will not have been set. This can result in incorrect values being returned
// by GetZoomToParent() when we have CSS transforms set on some of these layers.
// This code should be audited and updated as part of fixing bug 993525.
// Compute the critical display port that applies to this layer in the
// LayoutDevice space of this layer.
ParentLayerRect criticalDisplayPort =
(displayportMetrics.mCriticalDisplayPort * displayportMetrics.GetZoomToParent())
+ displayportMetrics.mCompositionBounds.TopLeft();
mPaintData.mCriticalDisplayPort = LayoutDeviceIntRect::ToUntyped(RoundedOut(
ApplyParentLayerToLayoutTransform(mPaintData.mTransformDisplayPortToLayoutDevice,
criticalDisplayPort)));
mPaintData.mCriticalDisplayPort = RoundedOut(
ApplyParentLayerToLayerTransform(mPaintData.mTransformDisplayPortToLayer, criticalDisplayPort));
TILING_PRLOG_OBJ(("TILING 0x%p: Critical displayport %s\n", this, tmpstr.get()), mPaintData.mCriticalDisplayPort);
// Compute the viewport that applies to this layer in the LayoutDevice
// space of this layer.
ParentLayerRect viewport =
(displayportMetrics.mViewport * displayportMetrics.GetZoomToParent())
+ displayportMetrics.mCompositionBounds.TopLeft();
mPaintData.mViewport = ApplyParentLayerToLayoutTransform(
mPaintData.mTransformDisplayPortToLayoutDevice, viewport);
mPaintData.mViewport = ApplyParentLayerToLayerTransform(
mPaintData.mTransformDisplayPortToLayer, viewport);
TILING_PRLOG_OBJ(("TILING 0x%p: Viewport %s\n", this, tmpstr.get()), mPaintData.mViewport);
// Store the resolution from the displayport ancestor layer. Because this is Gecko-side,
// before any async transforms have occurred, we can use the zoom for this.
mPaintData.mResolution = displayportMetrics.GetZoomToParent();
TILING_PRLOG(("TILING 0x%p: Resolution %f\n", this, mPaintData.mResolution.scale));
// Store the applicable composition bounds in this layer's LayoutDevice units.
gfx3DMatrix layoutDeviceToCompBounds =
// Store the applicable composition bounds in this layer's Layer units.
gfx3DMatrix transformToCompBounds =
GetTransformToAncestorsParentLayer(this, scrollAncestor);
mPaintData.mCompositionBounds = TransformTo<LayoutDevicePixel>(
layoutDeviceToCompBounds.Inverse(),
scrollMetrics.mCompositionBounds / scrollMetrics.GetParentResolution());
mPaintData.mCompositionBounds = ApplyParentLayerToLayerTransform(
transformToCompBounds.Inverse(), ParentLayerRect(scrollMetrics.mCompositionBounds));
TILING_PRLOG_OBJ(("TILING 0x%p: Composition bounds %s\n", this, tmpstr.get()), mPaintData.mCompositionBounds);
// Calculate the scroll offset since the last transaction
mPaintData.mScrollOffset = displayportMetrics.GetScrollOffset() * displayportMetrics.GetZoomToParent();
TILING_PRLOG_OBJ(("TILING 0x%p: Scroll offset %s\n", this, tmpstr.get()), mPaintData.mScrollOffset);
}
void
@ -172,6 +193,7 @@ ClientTiledThebesLayer::EndPaint(bool aFinish)
mPaintData.mLastScrollOffset = mPaintData.mScrollOffset;
mPaintData.mPaintFinished = true;
mPaintData.mFirstPaint = false;
TILING_PRLOG(("TILING 0x%p: Paint finished\n", this));
}
void
@ -197,6 +219,9 @@ ClientTiledThebesLayer::RenderLayer()
mValidRegion = nsIntRegion();
}
TILING_PRLOG_OBJ(("TILING 0x%p: Initial visible region %s\n", this, tmpstr.get()), mVisibleRegion);
TILING_PRLOG_OBJ(("TILING 0x%p: Initial valid region %s\n", this, tmpstr.get()), mValidRegion);
nsIntRegion invalidRegion = mVisibleRegion;
invalidRegion.Sub(invalidRegion, mValidRegion);
if (invalidRegion.IsEmpty()) {
@ -239,6 +264,9 @@ ClientTiledThebesLayer::RenderLayer()
return;
}
TILING_PRLOG_OBJ(("TILING 0x%p: Valid region %s\n", this, tmpstr.get()), mValidRegion);
TILING_PRLOG_OBJ(("TILING 0x%p: Visible region %s\n", this, tmpstr.get()), mVisibleRegion);
// Make sure that tiles that fall outside of the visible region are
// discarded on the first update.
if (!ClientManager()->IsRepeatTransaction()) {
@ -246,7 +274,7 @@ ClientTiledThebesLayer::RenderLayer()
if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
// Make sure that tiles that fall outside of the critical displayport are
// discarded on the first update.
mValidRegion.And(mValidRegion, mPaintData.mCriticalDisplayPort);
mValidRegion.And(mValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
}
}
@ -262,13 +290,15 @@ ClientTiledThebesLayer::RenderLayer()
}
// Clip the invalid region to the critical display-port
invalidRegion.And(invalidRegion, mPaintData.mCriticalDisplayPort);
invalidRegion.And(invalidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
if (invalidRegion.IsEmpty() && lowPrecisionInvalidRegion.IsEmpty()) {
EndPaint(true);
return;
}
}
TILING_PRLOG_OBJ(("TILING 0x%p: Invalid region %s\n", this, tmpstr.get()), invalidRegion);
if (!invalidRegion.IsEmpty() && mPaintData.mLowPrecisionPaintCount == 0) {
bool updatedBuffer = false;
// Only draw progressively when the resolution is unchanged.
@ -281,9 +311,11 @@ ClientTiledThebesLayer::RenderLayer()
nsIntRegion oldValidRegion = mContentClient->mTiledBuffer.GetValidRegion();
oldValidRegion.And(oldValidRegion, mVisibleRegion);
if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
oldValidRegion.And(oldValidRegion, mPaintData.mCriticalDisplayPort);
oldValidRegion.And(oldValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
}
TILING_PRLOG_OBJ(("TILING 0x%p: Progressive update with old valid region %s\n", this, tmpstr.get()), oldValidRegion);
updatedBuffer =
mContentClient->mTiledBuffer.ProgressiveUpdate(mValidRegion, invalidRegion,
oldValidRegion, &mPaintData,
@ -292,8 +324,12 @@ ClientTiledThebesLayer::RenderLayer()
updatedBuffer = true;
mValidRegion = mVisibleRegion;
if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
mValidRegion.And(mValidRegion, mPaintData.mCriticalDisplayPort);
mValidRegion.And(mValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
}
TILING_PRLOG_OBJ(("TILING 0x%p: Painting: valid region %s\n", this, tmpstr.get()), mValidRegion);
TILING_PRLOG_OBJ(("TILING 0x%p: and invalid region %s\n", this, tmpstr.get()), invalidRegion);
mContentClient->mTiledBuffer.SetFrameResolution(mPaintData.mResolution);
mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion,
callback, data);
@ -318,11 +354,14 @@ ClientTiledThebesLayer::RenderLayer()
}
}
TILING_PRLOG_OBJ(("TILING 0x%p: Low-precision valid region is %s\n", this, tmpstr.get()), mLowPrecisionValidRegion);
TILING_PRLOG_OBJ(("TILING 0x%p: Low-precision invalid region is %s\n", this, tmpstr.get()), lowPrecisionInvalidRegion);
// Render the low precision buffer, if there's area to invalidate and the
// visible region is larger than the critical display port.
bool updatedLowPrecision = false;
if (!lowPrecisionInvalidRegion.IsEmpty() &&
!nsIntRegion(mPaintData.mCriticalDisplayPort).Contains(mVisibleRegion)) {
!nsIntRegion(LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort)).Contains(mVisibleRegion)) {
nsIntRegion oldValidRegion =
mContentClient->mLowPrecisionTiledBuffer.GetValidRegion();
oldValidRegion.And(oldValidRegion, mVisibleRegion);

View File

@ -929,6 +929,7 @@ ContentClientIncremental::GetUpdateSurface(BufferType aType,
mContentType,
&desc)) {
NS_WARNING("creating SurfaceDescriptor failed!");
Clear();
return nullptr;
}

View File

@ -889,29 +889,29 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
return aTile;
}
static LayoutDeviceRect
static LayerRect
TransformCompositionBounds(const ParentLayerRect& aCompositionBounds,
const CSSToParentLayerScale& aZoom,
const ParentLayerPoint& aScrollOffset,
const CSSToParentLayerScale& aResolution,
const gfx3DMatrix& aTransformDisplayPortToLayoutDevice)
const gfx3DMatrix& aTransformDisplayPortToLayer)
{
// Transform the composition bounds from the space of the displayport ancestor
// layer into the LayoutDevice space of this layer. Do this by
// layer into the Layer space of this layer. Do this by
// compensating for the difference in resolution and subtracting the
// old composition bounds origin.
ParentLayerRect offsetViewportRect = (aCompositionBounds / aZoom) * aResolution;
offsetViewportRect.MoveBy(-aScrollOffset);
gfxRect transformedViewport =
aTransformDisplayPortToLayoutDevice.TransformBounds(
aTransformDisplayPortToLayer.TransformBounds(
gfxRect(offsetViewportRect.x, offsetViewportRect.y,
offsetViewportRect.width, offsetViewportRect.height));
return LayoutDeviceRect(transformedViewport.x,
transformedViewport.y,
transformedViewport.width,
transformedViewport.height);
return LayerRect(transformedViewport.x,
transformedViewport.y,
transformedViewport.width,
transformedViewport.height);
}
bool
@ -976,26 +976,27 @@ ClientTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInval
}
}
LayoutDeviceRect transformedCompositionBounds =
LayerRect transformedCompositionBounds =
TransformCompositionBounds(compositionBounds, zoom, aPaintData->mScrollOffset,
aPaintData->mResolution, aPaintData->mTransformDisplayPortToLayoutDevice);
aPaintData->mResolution, aPaintData->mTransformDisplayPortToLayer);
// Paint tiles that have stale content or that intersected with the screen
// at the time of issuing the draw command in a single transaction first.
// This is to avoid rendering glitches on animated page content, and when
// layers change size/shape.
LayoutDeviceRect typedCoherentUpdateRect =
LayerRect typedCoherentUpdateRect =
transformedCompositionBounds.Intersect(aPaintData->mCompositionBounds);
// Offset by the viewport origin, as the composition bounds are stored in
// Layer space and not LayoutDevice space.
// TODO(kats): does this make sense?
typedCoherentUpdateRect.MoveBy(aPaintData->mViewport.TopLeft());
// Convert to untyped to intersect with the invalid region.
nsIntRect roundedCoherentUpdateRect =
LayoutDeviceIntRect::ToUntyped(RoundedOut(typedCoherentUpdateRect));
nsIntRect untypedCoherentUpdateRect(LayerIntRect::ToUntyped(
RoundedOut(typedCoherentUpdateRect)));
aRegionToPaint.And(aInvalidRegion, roundedCoherentUpdateRect);
aRegionToPaint.And(aInvalidRegion, untypedCoherentUpdateRect);
aRegionToPaint.Or(aRegionToPaint, staleRegion);
bool drawingStale = !aRegionToPaint.IsEmpty();
if (!drawingStale) {
@ -1004,8 +1005,8 @@ ClientTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInval
// Prioritise tiles that are currently visible on the screen.
bool paintVisible = false;
if (aRegionToPaint.Intersects(roundedCoherentUpdateRect)) {
aRegionToPaint.And(aRegionToPaint, roundedCoherentUpdateRect);
if (aRegionToPaint.Intersects(untypedCoherentUpdateRect)) {
aRegionToPaint.And(aRegionToPaint, untypedCoherentUpdateRect);
paintVisible = true;
}

View File

@ -255,26 +255,23 @@ struct BasicTiledLayerPaintData {
/*
* The transform matrix to go from the display port layer's ParentLayer
* units to this layer's LayoutDevice units. The "display port layer" is
* units to this layer's Layer units. The "display port layer" is
* the closest ancestor layer with a displayport.
*/
gfx3DMatrix mTransformDisplayPortToLayoutDevice;
gfx3DMatrix mTransformDisplayPortToLayer;
/*
* The critical displayport of the content from the nearest ancestor layer
* that represents scrollable content with a display port set. Empty if a
* critical displayport is not set.
*
* This is in LayoutDevice coordinates, but is stored as an nsIntRect for
* convenience when intersecting with the layer's mValidRegion.
*/
nsIntRect mCriticalDisplayPort;
LayerIntRect mCriticalDisplayPort;
/*
* The viewport of the content from the nearest ancestor layer that
* represents scrollable content with a display port set.
*/
LayoutDeviceRect mViewport;
LayerRect mViewport;
/*
* The render resolution of the document that the content this layer
@ -283,11 +280,11 @@ struct BasicTiledLayerPaintData {
CSSToParentLayerScale mResolution;
/*
* The composition bounds of the layer, in LayoutDevice coordinates. This is
* The composition bounds of the layer, in Layer coordinates. This is
* used to make sure that tiled updates to regions that are visible to the
* user are grouped coherently.
*/
LayoutDeviceRect mCompositionBounds;
LayerRect mCompositionBounds;
/*
* Low precision updates are always executed a tile at a time in repeated

View File

@ -406,14 +406,6 @@ ContentHostIncremental::~ContentHostIncremental()
{
}
void
ContentHostIncremental::DestroyTextures()
{
mSource = nullptr;
mSourceOnWhite = nullptr;
mUpdateList.Clear();
}
bool
ContentHostIncremental::CreatedIncrementalTexture(ISurfaceAllocator* aAllocator,
const TextureInfo& aTextureInfo,
@ -501,6 +493,8 @@ ContentHostIncremental::TextureCreationRequest::Execute(ContentHostIncremental*
}
if (mTextureInfo.mDeprecatedTextureHostFlags & DeprecatedTextureHostFlags::COPY_PREVIOUS) {
MOZ_ASSERT(aHost->mSource);
MOZ_ASSERT(aHost->mSource->IsValid());
nsIntRect bufferRect = aHost->mBufferRect;
nsIntPoint bufferRotation = aHost->mBufferRotation;
nsIntRect overlap;

View File

@ -281,8 +281,6 @@ public:
virtual void PrintInfo(nsACString& aTo, const char* aPrefix) MOZ_OVERRIDE;
virtual void DestroyTextures();
virtual bool Lock() {
MOZ_ASSERT(!mLocked);
ProcessTextureUpdates();

View File

@ -385,8 +385,11 @@ TextureImageTextureSourceOGL::GetSize() const
gfx::SurfaceFormat
TextureImageTextureSourceOGL::GetFormat() const
{
MOZ_ASSERT(mTexImage);
return mTexImage->GetTextureFormat();
if (mTexImage) {
return mTexImage->GetTextureFormat();
}
NS_WARNING("Trying to query the format of an empty TextureSource.");
return gfx::SurfaceFormat::UNKNOWN;
}
nsIntRect TextureImageTextureSourceOGL::GetTileRect()

View File

@ -2,9 +2,10 @@ This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/.
Our reference repository is https://github.com/khaledhosny/ots/.
Current revision: d7d831edd171054c7974f5e0dec2fc19bf869574
Current revision: d6018b62bf41f6b419aeae6d2795725a55715481
Applied local patches:
ots-visibility.patch - make Process function externally visible for Windows DLL (bug 711079)
Upstream files included: LICENSE, src/, include/
ots-woff2 - disable WOFF2 support (bug 941019)
Additional files: README.mozilla, src/moz.build
Additional patch: ots-visibility.patch (bug 711079).

View File

@ -199,16 +199,6 @@ class OTSStream {
unsigned chksum_buffer_offset_;
};
// -----------------------------------------------------------------------------
// Process a given OpenType file and write out a sanitised version
// output: a pointer to an object implementing the OTSStream interface. The
// sanitisied output will be written to this. In the even of a failure,
// partial output may have been written.
// input: the OpenType file
// length: the size, in bytes, of |input|
// -----------------------------------------------------------------------------
bool OTS_API Process(OTSStream *output, const uint8_t *input, size_t length);
// Signature of the function to be provided by the client in order to report errors.
// The return type is a boolean so that it can be used within an expression,
// but the actual value is ignored. (Suggested convention is to always return 'false'.)
@ -219,9 +209,6 @@ bool OTS_API Process(OTSStream *output, const uint8_t *input, size_t length);
#endif
typedef bool (*MessageFunc)(void *user_data, const char *format, ...) MSGFUNC_FMT_ATTR;
// Set a callback function that will be called when OTS is reporting an error.
void OTS_API SetMessageCallback(MessageFunc func, void *user_data);
enum TableAction {
TABLE_ACTION_DEFAULT, // Use OTS's default action for that table
TABLE_ACTION_SANITIZE, // Sanitize the table, potentially droping it
@ -231,20 +218,56 @@ enum TableAction {
// Signature of the function to be provided by the client to decide what action
// to do for a given table.
// tag: table tag as an integer in big-endian byte order, independent of platform endianness
// user_data: user defined data that are passed to SetTableActionCallback()
typedef TableAction (*TableActionFunc)(uint32_t tag, void *user_data);
// Set a callback function that will be called when OTS needs to decide what to
// do for a font table.
void OTS_API SetTableActionCallback(TableActionFunc func, void *user_data);
class OTS_API OTSContext {
public:
OTSContext()
: message_func(0),
message_user_data(0),
table_action_func(0),
table_action_user_data(0)
{}
~OTSContext() {}
// Process a given OpenType file and write out a sanitised version
// output: a pointer to an object implementing the OTSStream interface. The
// sanitisied output will be written to this. In the even of a failure,
// partial output may have been written.
// input: the OpenType file
// length: the size, in bytes, of |input|
// context: optional context that holds various OTS settings like user callbacks
bool Process(OTSStream *output, const uint8_t *input, size_t length);
// Set a callback function that will be called when OTS is reporting an error.
void SetMessageCallback(MessageFunc func, void *user_data) {
message_func = func;
message_user_data = user_data;
}
// Set a callback function that will be called when OTS needs to decide what to
// do for a font table.
void SetTableActionCallback(TableActionFunc func, void *user_data) {
table_action_func = func;
table_action_user_data = user_data;
}
private:
MessageFunc message_func;
void *message_user_data;
TableActionFunc table_action_func;
void *table_action_user_data;
};
// Force to disable debug output even when the library is compiled with
// -DOTS_DEBUG.
void DisableDebugOutput();
#ifdef MOZ_OTS_WOFF2
// Enable WOFF2 support(experimental).
void EnableWOFF2();
#endif
} // namespace ots

View File

@ -37,52 +37,22 @@ diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-san
typedef unsigned short uint16_t;
typedef int int32_t;
typedef unsigned int uint32_t;
@@ -182,45 +202,45 @@ class OTSStream {
// -----------------------------------------------------------------------------
// Process a given OpenType file and write out a sanitised version
// output: a pointer to an object implementing the OTSStream interface. The
// sanitisied output will be written to this. In the even of a failure,
// partial output may have been written.
// input: the OpenType file
// length: the size, in bytes, of |input|
// -----------------------------------------------------------------------------
-bool Process(OTSStream *output, const uint8_t *input, size_t length);
+bool OTS_API Process(OTSStream *output, const uint8_t *input, size_t length);
// Signature of the function to be provided by the client in order to report errors.
// The return type is a boolean so that it can be used within an expression,
// but the actual value is ignored. (Suggested convention is to always return 'false'.)
#ifdef __GCC__
#define MSGFUNC_FMT_ATTR __attribute__((format(printf, 2, 3)))
#else
#define MSGFUNC_FMT_ATTR
#endif
typedef bool (*MessageFunc)(void *user_data, const char *format, ...) MSGFUNC_FMT_ATTR;
// Set a callback function that will be called when OTS is reporting an error.
-void SetMessageCallback(MessageFunc func, void *user_data);
+void OTS_API SetMessageCallback(MessageFunc func, void *user_data);
enum TableAction {
TABLE_ACTION_DEFAULT, // Use OTS's default action for that table
TABLE_ACTION_SANITIZE, // Sanitize the table, potentially droping it
TABLE_ACTION_PASSTHRU, // Serialize the table unchanged
TABLE_ACTION_DROP // Drop the table
@@ -197,17 +217,17 @@ enum TableAction {
};
// Signature of the function to be provided by the client to decide what action
// to do for a given table.
// tag: table tag as an integer in big-endian byte order, independent of platform endianness
// user_data: user defined data that are passed to SetTableActionCallback()
typedef TableAction (*TableActionFunc)(uint32_t tag, void *user_data);
// Set a callback function that will be called when OTS needs to decide what to
// do for a font table.
-void SetTableActionCallback(TableActionFunc func, void *user_data);
+void OTS_API SetTableActionCallback(TableActionFunc func, void *user_data);
// Force to disable debug output even when the library is compiled with
// -DOTS_DEBUG.
void DisableDebugOutput();
// Enable WOFF2 support(experimental).
void EnableWOFF2();
-class OTSContext {
+class OTS_API OTSContext {
public:
OTSContext()
: message_func(0),
message_user_data(0),
table_action_func(0),
table_action_user_data(0)
{}

View File

@ -1,134 +0,0 @@
diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-sanitiser.h
--- a/gfx/ots/include/opentype-sanitiser.h
+++ b/gfx/ots/include/opentype-sanitiser.h
@@ -236,14 +236,16 @@ typedef TableAction (*TableActionFunc)(u
// Set a callback function that will be called when OTS needs to decide what to
// do for a font table.
void OTS_API SetTableActionCallback(TableActionFunc func, void *user_data);
// Force to disable debug output even when the library is compiled with
// -DOTS_DEBUG.
void DisableDebugOutput();
+#ifdef MOZ_OTS_WOFF2
// Enable WOFF2 support(experimental).
void EnableWOFF2();
+#endif
} // namespace ots
#endif // OPENTYPE_SANITISER_H_
diff --git a/gfx/ots/src/ots.cc b/gfx/ots/src/ots.cc
--- a/gfx/ots/src/ots.cc
+++ b/gfx/ots/src/ots.cc
@@ -9,25 +9,29 @@
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <limits>
#include <map>
#include <vector>
+#ifdef MOZ_OTS_WOFF2
#include "woff2.h"
+#endif
// The OpenType Font File
// http://www.microsoft.com/typography/otspec/cmap.htm
namespace {
bool g_debug_output = true;
+#ifdef MOZ_OTS_WOFF2
bool g_enable_woff2 = false;
+#endif
ots::MessageFunc g_message_func = NULL;
void *g_message_user_data = NULL;
ots::TableActionFunc g_table_action_func = NULL;
void *g_table_action_user_data = NULL;
// Generate a message with or without a table tag, when 'header' is the OpenTypeFile pointer
@@ -395,16 +399,17 @@ bool ProcessWOFF(ots::OpenTypeFile *head
}
if (block_end != ots::Round4(length)) {
return OTS_FAILURE_MSG_HDR("file length mismatch (trailing junk?)");
}
return ProcessGeneric(header, woff_tag, output, data, length, tables, file);
}
+#ifdef MOZ_OTS_WOFF2
bool ProcessWOFF2(ots::OpenTypeFile *header,
ots::OTSStream *output, const uint8_t *data, size_t length) {
size_t decompressed_size = ots::ComputeWOFF2FinalSize(data, length);
if (decompressed_size == 0) {
return OTS_FAILURE();
}
// decompressed font must be <= 30MB
if (decompressed_size > 30 * 1024 * 1024) {
@@ -413,16 +418,17 @@ bool ProcessWOFF2(ots::OpenTypeFile *hea
std::vector<uint8_t> decompressed_buffer(decompressed_size);
if (!ots::ConvertWOFF2ToTTF(&decompressed_buffer[0], decompressed_size,
data, length)) {
return OTS_FAILURE();
}
return ProcessTTF(header, output, &decompressed_buffer[0], decompressed_size);
}
+#endif
ots::TableAction GetTableAction(uint32_t tag) {
ots::TableAction action = ots::TABLE_ACTION_DEFAULT;
if (g_table_action_func != NULL) {
action = g_table_action_func(htonl(tag), g_table_action_user_data);
}
@@ -795,19 +801,21 @@ bool IsValidVersionTag(uint32_t tag) {
tag == Tag("true") ||
tag == Tag("typ1");
}
void DisableDebugOutput() {
g_debug_output = false;
}
+#ifdef MOZ_OTS_WOFF2
void EnableWOFF2() {
g_enable_woff2 = true;
}
+#endif
void SetMessageCallback(MessageFunc func, void *user_data) {
g_message_func = func;
g_message_user_data = user_data;
}
void SetTableActionCallback(TableActionFunc func, void *user_data) {
g_table_action_func = func;
@@ -822,20 +830,22 @@ bool Process(OTSStream *output, const ui
if (length < 4) {
return OTS_FAILURE_MSG_(&header, "file less than 4 bytes");
}
bool result;
if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') {
result = ProcessWOFF(&header, output, data, length);
+#ifdef MOZ_OTS_WOFF2
} else if (g_enable_woff2 &&
data[0] == 'w' && data[1] == 'O' && data[2] == 'F' &&
data[3] == '2') {
result = ProcessWOFF2(&header, output, data, length);
+#endif
} else {
result = ProcessTTF(&header, output, data, length);
}
for (unsigned i = 0; ; ++i) {
if (table_parsers[i].parse == NULL) break;
table_parsers[i].free(&header);
}

View File

@ -1028,3 +1028,5 @@ void ots_cff_free(OpenTypeFile *file) {
}
} // namespace ots
#undef TABLE_NAME

View File

@ -360,8 +360,8 @@ bool Parse31013(ots::OpenTypeFile *file,
if (!subtable.Skip(8)) {
return OTS_FAILURE_MSG("Bad cmap subtable length");
}
uint16_t language = 0;
if (!subtable.ReadU16(&language)) {
uint32_t language = 0;
if (!subtable.ReadU32(&language)) {
return OTS_FAILURE_MSG("Can't read cmap subtable language");
}
if (language) {
@ -876,7 +876,7 @@ bool ots_cmap_serialise(OTSStream *out, OpenTypeFile *file) {
// Some fonts don't have 3-0-4 MS Symbol nor 3-1-4 Unicode BMP tables
// (e.g., old fonts for Mac). We don't support them.
if (!have_304 && !have_314 && !have_034) {
if (!have_304 && !have_314 && !have_034 && !have_31012 && !have_31013) {
return OTS_FAILURE();
}
@ -1005,7 +1005,7 @@ bool ots_cmap_serialise(OTSStream *out, OpenTypeFile *file) {
= file->cmap->subtable_3_10_13;
const unsigned num_groups = groups.size();
if (!out->WriteU16(13) ||
!out->WriteU16(0) ||
!out->WriteU32(0) ||
!out->WriteU32(num_groups * 12 + 14) ||
!out->WriteU32(0) ||
!out->WriteU32(num_groups)) {
@ -1101,3 +1101,5 @@ void ots_cmap_free(OpenTypeFile *file) {
}
} // namespace ots
#undef TABLE_NAME

View File

@ -56,3 +56,5 @@ void ots_cvt_free(OpenTypeFile *file) {
}
} // namespace ots
#undef TABLE_NAME

View File

@ -50,3 +50,5 @@ void ots_fpgm_free(OpenTypeFile *file) {
}
} // namespace ots
#undef TABLE_NAME

View File

@ -110,3 +110,6 @@ void ots_gasp_free(OpenTypeFile *file) {
}
} // namespace ots
#undef TABLE_NAME
#undef DROP_THIS_TABLE

View File

@ -384,3 +384,5 @@ void ots_gdef_free(OpenTypeFile *file) {
} // namespace ots
#undef TABLE_NAME
#undef DROP_THIS_TABLE

View File

@ -307,3 +307,5 @@ void ots_glyf_free(OpenTypeFile *file) {
}
} // namespace ots
#undef TABLE_NAME

View File

@ -757,36 +757,48 @@ bool ots_gpos_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
DROP_THIS_TABLE("Bad version");
return true;
}
if ((offset_script_list < kGposHeaderSize ||
offset_script_list >= length) ||
(offset_feature_list < kGposHeaderSize ||
offset_feature_list >= length) ||
(offset_lookup_list < kGposHeaderSize ||
offset_lookup_list >= length)) {
DROP_THIS_TABLE("Bad offset in table header");
return true;
}
if (!ParseLookupListTable(file, data + offset_lookup_list,
length - offset_lookup_list,
&kGposLookupSubtableParser,
&gpos->num_lookups)) {
DROP_THIS_TABLE("Failed to parse lookup list table");
return true;
if (offset_lookup_list) {
if (offset_lookup_list < kGposHeaderSize || offset_lookup_list >= length) {
DROP_THIS_TABLE("Bad lookup list offset in table header");
return true;
}
if (!ParseLookupListTable(file, data + offset_lookup_list,
length - offset_lookup_list,
&kGposLookupSubtableParser,
&gpos->num_lookups)) {
DROP_THIS_TABLE("Failed to parse lookup list table");
return true;
}
}
uint16_t num_features = 0;
if (!ParseFeatureListTable(file, data + offset_feature_list,
length - offset_feature_list, gpos->num_lookups,
&num_features)) {
DROP_THIS_TABLE("Failed to parse feature list table");
return true;
if (offset_feature_list) {
if (offset_feature_list < kGposHeaderSize || offset_feature_list >= length) {
DROP_THIS_TABLE("Bad feature list offset in table header");
return true;
}
if (!ParseFeatureListTable(file, data + offset_feature_list,
length - offset_feature_list, gpos->num_lookups,
&num_features)) {
DROP_THIS_TABLE("Failed to parse feature list table");
return true;
}
}
if (!ParseScriptListTable(file, data + offset_script_list,
length - offset_script_list, num_features)) {
DROP_THIS_TABLE("Failed to parse script list table");
return true;
if (offset_script_list) {
if (offset_script_list < kGposHeaderSize || offset_script_list >= length) {
DROP_THIS_TABLE("Bad script list offset in table header");
return true;
}
if (!ParseScriptListTable(file, data + offset_script_list,
length - offset_script_list, num_features)) {
DROP_THIS_TABLE("Failed to parse script list table");
return true;
}
}
gpos->data = data;
@ -812,3 +824,5 @@ void ots_gpos_free(OpenTypeFile *file) {
} // namespace ots
#undef TABLE_NAME
#undef DROP_THIS_TABLE

View File

@ -614,36 +614,48 @@ bool ots_gsub_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
DROP_THIS_TABLE("Bad version");
return true;
}
if ((offset_script_list < kGsubHeaderSize ||
offset_script_list >= length) ||
(offset_feature_list < kGsubHeaderSize ||
offset_feature_list >= length) ||
(offset_lookup_list < kGsubHeaderSize ||
offset_lookup_list >= length)) {
DROP_THIS_TABLE("Bad offset in table header");
return true;
}
if (!ParseLookupListTable(file, data + offset_lookup_list,
length - offset_lookup_list,
&kGsubLookupSubtableParser,
&gsub->num_lookups)) {
DROP_THIS_TABLE("Failed to parse lookup list table");
return true;
if (offset_lookup_list) {
if (offset_lookup_list < kGsubHeaderSize || offset_lookup_list >= length) {
DROP_THIS_TABLE("Bad lookup list offset in table header");
return true;
}
if (!ParseLookupListTable(file, data + offset_lookup_list,
length - offset_lookup_list,
&kGsubLookupSubtableParser,
&gsub->num_lookups)) {
DROP_THIS_TABLE("Failed to parse lookup list table");
return true;
}
}
uint16_t num_features = 0;
if (!ParseFeatureListTable(file, data + offset_feature_list,
length - offset_feature_list, gsub->num_lookups,
&num_features)) {
DROP_THIS_TABLE("Failed to parse feature list table");
return true;
if (offset_feature_list) {
if (offset_feature_list < kGsubHeaderSize || offset_feature_list >= length) {
DROP_THIS_TABLE("Bad feature list offset in table header");
return true;
}
if (!ParseFeatureListTable(file, data + offset_feature_list,
length - offset_feature_list, gsub->num_lookups,
&num_features)) {
DROP_THIS_TABLE("Failed to parse feature list table");
return true;
}
}
if (!ParseScriptListTable(file, data + offset_script_list,
length - offset_script_list, num_features)) {
DROP_THIS_TABLE("Failed to parse script list table");
return true;
if (offset_script_list) {
if (offset_script_list < kGsubHeaderSize || offset_script_list >= length) {
DROP_THIS_TABLE("Bad script list offset in table header");
return true;
}
if (!ParseScriptListTable(file, data + offset_script_list,
length - offset_script_list, num_features)) {
DROP_THIS_TABLE("Failed to parse script list table");
return true;
}
}
gsub->data = data;
@ -669,3 +681,5 @@ void ots_gsub_free(OpenTypeFile *file) {
} // namespace ots
#undef TABLE_NAME
#undef DROP_THIS_TABLE

View File

@ -138,3 +138,6 @@ void ots_hdmx_free(OpenTypeFile *file) {
}
} // namespace ots
#undef TABLE_NAME
#undef DROP_THIS_TABLE

View File

@ -149,3 +149,5 @@ void ots_head_free(OpenTypeFile *file) {
}
} // namespace
#undef TABLE_NAME

View File

@ -49,3 +49,5 @@ void ots_hhea_free(OpenTypeFile *file) {
}
} // namespace ots
#undef TABLE_NAME

View File

@ -47,3 +47,5 @@ void ots_hmtx_free(OpenTypeFile *file) {
}
} // namespace ots
#undef TABLE_NAME

View File

@ -200,3 +200,6 @@ void ots_kern_free(OpenTypeFile *file) {
}
} // namespace ots
#undef TABLE_NAME
#undef DROP_THIS_TABLE

View File

@ -1510,3 +1510,4 @@ bool ParseExtensionSubtable(const OpenTypeFile *file,
} // namespace ots
#undef TABLE_NAME

View File

@ -98,3 +98,5 @@ void ots_loca_free(OpenTypeFile *file) {
}
} // namespace ots
#undef TABLE_NAME

View File

@ -86,3 +86,6 @@ void ots_ltsh_free(OpenTypeFile *file) {
}
} // namespace ots
#undef TABLE_NAME
#undef DROP_THIS_TABLE

View File

@ -606,3 +606,5 @@ void ots_math_free(OpenTypeFile *file) {
} // namespace ots
#undef TABLE_NAME
#undef DROP_THIS_TABLE

View File

@ -128,3 +128,5 @@ void ots_maxp_free(OpenTypeFile *file) {
}
} // namespace ots
#undef TABLE_NAME

View File

@ -184,3 +184,4 @@ bool SerialiseMetricsTable(const ots::OpenTypeFile *file,
} // namespace ots
#undef TABLE_NAME

View File

@ -60,3 +60,6 @@ DEFINES['NOMINMAX'] = True
if CONFIG['OS_TARGET'] == 'WINNT':
DEFINES['OTS_DLL'] = True
DEFINES['OTS_DLL_EXPORTS'] = True
# Disable WOFF2 support.
DEFINES['OTS_DISABLE_WOFF2'] = True;

View File

@ -332,3 +332,5 @@ void ots_name_free(OpenTypeFile* file) {
}
} // namespace
#undef TABLE_NAME

View File

@ -290,3 +290,5 @@ void ots_os2_free(OpenTypeFile *file) {
}
} // namespace ots
#undef TABLE_NAME

View File

@ -14,7 +14,7 @@
#include <map>
#include <vector>
#ifdef MOZ_OTS_WOFF2
#ifndef OTS_DISABLE_WOFF2
#include "woff2.h"
#endif
@ -24,15 +24,7 @@
namespace {
bool g_debug_output = true;
#ifdef MOZ_OTS_WOFF2
bool g_enable_woff2 = false;
#endif
ots::MessageFunc g_message_func = NULL;
void *g_message_user_data = NULL;
ots::TableActionFunc g_table_action_func = NULL;
void *g_table_action_user_data = NULL;
// Generate a message with or without a table tag, when 'header' is the OpenTypeFile pointer
#define OTS_FAILURE_MSG_TAG(msg_,tag_) OTS_FAILURE_MSG_TAG_(header, msg_, tag_)
@ -404,7 +396,7 @@ bool ProcessWOFF(ots::OpenTypeFile *header,
return ProcessGeneric(header, woff_tag, output, data, length, tables, file);
}
#ifdef MOZ_OTS_WOFF2
#ifndef OTS_DISABLE_WOFF2
bool ProcessWOFF2(ots::OpenTypeFile *header,
ots::OTSStream *output, const uint8_t *data, size_t length) {
size_t decompressed_size = ots::ComputeWOFF2FinalSize(data, length);
@ -425,11 +417,11 @@ bool ProcessWOFF2(ots::OpenTypeFile *header,
}
#endif
ots::TableAction GetTableAction(uint32_t tag) {
ots::TableAction GetTableAction(ots::OpenTypeFile *header, uint32_t tag) {
ots::TableAction action = ots::TABLE_ACTION_DEFAULT;
if (g_table_action_func != NULL) {
action = g_table_action_func(htonl(tag), g_table_action_user_data);
if (header->table_action_func != NULL) {
action = header->table_action_func(htonl(tag), header->table_action_user_data);
}
if (action == ots::TABLE_ACTION_DEFAULT) {
@ -578,10 +570,10 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
for (unsigned i = 0; ; ++i) {
if (table_parsers[i].parse == NULL) break;
const std::map<uint32_t, OpenTypeTable>::const_iterator it
= table_map.find(Tag(table_parsers[i].tag));
uint32_t tag = Tag(table_parsers[i].tag);
const std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.find(tag);
ots::TableAction action = GetTableAction(Tag(table_parsers[i].tag));
ots::TableAction action = GetTableAction(header, tag);
if (it == table_map.end()) {
if (table_parsers[i].required && action == ots::TABLE_ACTION_SANITIZE) {
return OTS_FAILURE_MSG_TAG("missing required table", table_parsers[i].tag);
@ -634,7 +626,7 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
for (std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.begin();
it != table_map.end(); ++it) {
ots::TableAction action = GetTableAction(it->first);
ots::TableAction action = GetTableAction(header, it->first);
if (action == ots::TABLE_ACTION_PASSTHRU) {
num_output_tables++;
}
@ -706,7 +698,7 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
for (std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.begin();
it != table_map.end(); ++it) {
ots::TableAction action = GetTableAction(it->first);
ots::TableAction action = GetTableAction(header, it->first);
if (action == ots::TABLE_ACTION_PASSTHRU) {
OutputTable out;
out.tag = it->second.tag;
@ -806,27 +798,19 @@ void DisableDebugOutput() {
g_debug_output = false;
}
#ifdef MOZ_OTS_WOFF2
void EnableWOFF2() {
g_enable_woff2 = true;
}
#endif
void SetMessageCallback(MessageFunc func, void *user_data) {
g_message_func = func;
g_message_user_data = user_data;
}
void SetTableActionCallback(TableActionFunc func, void *user_data) {
g_table_action_func = func;
g_table_action_user_data = user_data;
}
bool Process(OTSStream *output, const uint8_t *data, size_t length) {
bool OTSContext::Process(OTSStream *output,
const uint8_t *data,
size_t length) {
OpenTypeFile header;
header.message_func = g_message_func;
header.user_data = g_message_user_data;
header.message_func = message_func;
header.message_user_data = message_user_data;
header.table_action_func = table_action_func;
header.table_action_user_data = table_action_user_data;
if (length < 4) {
return OTS_FAILURE_MSG_(&header, "file less than 4 bytes");
@ -835,7 +819,7 @@ bool Process(OTSStream *output, const uint8_t *data, size_t length) {
bool result;
if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') {
result = ProcessWOFF(&header, output, data, length);
#ifdef MOZ_OTS_WOFF2
#ifndef OTS_DISABLE_WOFF2
} else if (g_enable_woff2 &&
data[0] == 'w' && data[1] == 'O' && data[2] == 'F' &&
data[3] == '2') {

View File

@ -53,13 +53,13 @@ void Warning(const char *f, int l, const char *format, ...)
// Generate a simple message
#define OTS_FAILURE_MSG_(otf_,...) \
((otf_)->message_func && \
(*(otf_)->message_func)((otf_)->user_data, __VA_ARGS__) && \
(*(otf_)->message_func)((otf_)->message_user_data, __VA_ARGS__) && \
false)
// Generate a message with an associated table tag
#define OTS_FAILURE_MSG_TAG_(otf_,msg_,tag_) \
((otf_)->message_func && \
(*(otf_)->message_func)((otf_)->user_data, "%4.4s: %s", tag_, msg_) && \
(*(otf_)->message_func)((otf_)->message_user_data, "%4.4s: %s", tag_, msg_) && \
false)
// Convenience macro for use in files that only handle a single table tag,
@ -250,8 +250,11 @@ struct OpenTypeFile {
uint16_t entry_selector;
uint16_t range_shift;
MessageFunc message_func;
void *user_data;
MessageFunc message_func;
void *message_user_data;
TableActionFunc table_action_func;
void *table_action_user_data;
#define F(name, capname) OpenType##capname *name;
FOR_EACH_TABLE_TYPE

View File

@ -180,3 +180,5 @@ void ots_post_free(OpenTypeFile *file) {
}
} // namespace ots
#undef TABLE_NAME

View File

@ -50,3 +50,5 @@ void ots_prep_free(OpenTypeFile *file) {
}
} // namespace ots
#undef TABLE_NAME

View File

@ -181,3 +181,6 @@ void ots_vdmx_free(OpenTypeFile *file) {
}
} // namespace ots
#undef TABLE_NAME
#undef DROP_THIS_TABLE

View File

@ -56,3 +56,4 @@ void ots_vhea_free(OpenTypeFile *file) {
} // namespace ots
#undef TABLE_NAME

View File

@ -52,3 +52,4 @@ void ots_vmtx_free(OpenTypeFile *file) {
} // namespace ots
#undef TABLE_NAME

View File

@ -101,3 +101,6 @@ void ots_vorg_free(OpenTypeFile *file) {
}
} // namespace ots
#undef TABLE_NAME
#undef DROP_THIS_TABLE

1022
gfx/ots/src/woff2.cc Normal file

File diff suppressed because it is too large Load Diff

20
gfx/ots/src/woff2.h Normal file
View File

@ -0,0 +1,20 @@
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef OTS_WOFF2_H_
#define OTS_WOFF2_H_
namespace ots {
// Compute the size of the final uncompressed font, or 0 on error.
size_t ComputeWOFF2FinalSize(const uint8_t *data, size_t length);
// Decompresses the font into the target buffer. The result_length should
// be the same as determined by ComputeFinalSize(). Returns true on successful
// decompression.
bool ConvertWOFF2ToTTF(uint8_t *result, size_t result_length,
const uint8_t *data, size_t length);
}
#endif // OTS_WOFF2_H_

View File

@ -388,10 +388,11 @@ gfxUserFontSet::SanitizeOpenTypeData(gfxMixedFontFamily *aFamily,
userData.mFamily = aFamily;
userData.mProxy = aProxy;
ots::SetTableActionCallback(&OTSTableAction, nullptr);
ots::SetMessageCallback(&gfxUserFontSet::OTSMessage, &userData);
ots::OTSContext otsContext;
otsContext.SetTableActionCallback(&OTSTableAction, nullptr);
otsContext.SetMessageCallback(&gfxUserFontSet::OTSMessage, &userData);
if (ots::Process(&output, aData, aLength)) {
if (otsContext.Process(&output, aData, aLength)) {
aSaneLength = output.Tell();
return static_cast<uint8_t*>(output.forget());
} else {

View File

@ -45,7 +45,7 @@ namespace JS {
D(TOO_MUCH_MALLOC) \
D(ALLOC_TRIGGER) \
D(DEBUG_GC) \
D(COMPARTMENT_REVIVED) \
D(TRANSPLANT) \
D(RESET) \
D(OUT_OF_NURSERY) \
D(EVICT_NURSERY) \

View File

@ -32,7 +32,6 @@ class AutoValueVector;
class AutoIdArray;
class JS_PUBLIC_API(AutoGCRooter);
template <typename T> class AutoVectorRooter;
template<typename K, typename V> class AutoHashMapRooter;
template<typename T> class AutoHashSetRooter;
@ -42,8 +41,6 @@ class MOZ_STACK_CLASS SourceBufferHolder;
class HandleValueArray;
class AutoCheckCannotGC;
}
// Do the importing.
@ -80,7 +77,6 @@ using JS::AutoValueVector;
using JS::AutoIdArray;
using JS::AutoGCRooter;
using JS::AutoHashMapRooter;
using JS::AutoHashSetRooter;
using JS::AutoVectorRooter;
@ -135,8 +131,6 @@ using JS::HandleValueArray;
using JS::Zone;
using JS::AutoCheckCannotGC;
} /* namespace js */
#endif /* NamespaceImports_h */

View File

@ -42,12 +42,12 @@ class HashableValue {
Value get() const { return value.get(); }
};
class AutoHashableValueRooter : private AutoGCRooter
class AutoHashableValueRooter : private JS::AutoGCRooter
{
public:
explicit AutoHashableValueRooter(JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoGCRooter(cx, HASHABLEVALUE)
: JS::AutoGCRooter(cx, HASHABLEVALUE)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
@ -62,7 +62,7 @@ class AutoHashableValueRooter : private AutoGCRooter
Value get() const { return value.get(); }
friend void AutoGCRooter::trace(JSTracer *trc);
friend void JS::AutoGCRooter::trace(JSTracer *trc);
void trace(JSTracer *trc);
private:

View File

@ -68,7 +68,7 @@ IsKeyword(JSLinearString *str);
/* GC marking. Defined in Parser.cpp. */
void
MarkParser(JSTracer *trc, AutoGCRooter *parser);
MarkParser(JSTracer *trc, JS::AutoGCRooter *parser);
} /* namespace frontend */
} /* namespace js */

View File

@ -42,8 +42,11 @@
using namespace js;
using namespace js::gc;
using mozilla::Maybe;
using JS::AutoGCRooter;
namespace js {
namespace frontend {

View File

@ -313,7 +313,7 @@ enum VarContext { HoistVars, DontHoistVars };
enum FunctionType { Getter, Setter, Normal };
template <typename ParseHandler>
class Parser : private AutoGCRooter, public StrictModeGetter
class Parser : private JS::AutoGCRooter, public StrictModeGetter
{
public:
ExclusiveContext *const context;
@ -392,7 +392,7 @@ class Parser : private AutoGCRooter, public StrictModeGetter
traceListHead = m.traceListHead;
}
friend void js::frontend::MarkParser(JSTracer *trc, AutoGCRooter *parser);
friend void js::frontend::MarkParser(JSTracer *trc, JS::AutoGCRooter *parser);
const char *getFilename() const { return tokenStream.getFilename(); }
JSVersion versionNumber() const { return tokenStream.versionNumber(); }

View File

@ -188,6 +188,9 @@ CheckMarkedThing(JSTracer *trc, T **thingp)
DebugOnly<JSRuntime *> rt = trc->runtime();
JS_ASSERT_IF(IS_GC_MARKING_TRACER(trc) && rt->gc.manipulatingDeadZones,
!thing->zone()->scheduledForDestruction);
JS_ASSERT(CurrentThreadCanAccessRuntime(rt));
JS_ASSERT_IF(thing->zone()->requireGCTracer(),
@ -218,33 +221,6 @@ CheckMarkedThing(JSTracer *trc, T **thingp)
}
/*
* We only set the maybeAlive flag for objects and scripts. It's assumed that,
* if a compartment is alive, then it will have at least some live object or
* script it in. Even if we get this wrong, the worst that will happen is that
* scheduledForDestruction will be set on the compartment, which will cause some
* extra GC activity to try to free the compartment.
*/
template<typename T>
static inline void
SetMaybeAliveFlag(T *thing)
{
}
template<>
void
SetMaybeAliveFlag(JSObject *thing)
{
thing->compartment()->maybeAlive = true;
}
template<>
void
SetMaybeAliveFlag(JSScript *thing)
{
thing->compartment()->maybeAlive = true;
}
template<typename T>
static void
MarkInternal(JSTracer *trc, T **thingp)
@ -278,7 +254,7 @@ MarkInternal(JSTracer *trc, T **thingp)
return;
PushMarkStack(AsGCMarker(trc), thing);
SetMaybeAliveFlag(thing);
thing->zone()->maybeAlive = true;
} else {
trc->callback(trc, (void **)thingp, MapTypeToTraceKind<T>::kind);
trc->unsetTracingLocation();

View File

@ -244,7 +244,7 @@ js::Nursery::reallocateSlots(JSContext *cx, JSObject *obj, HeapSlot *oldSlots,
if (!isInside(oldSlots)) {
HeapSlot *newSlots = static_cast<HeapSlot *>(cx->realloc_(oldSlots, oldSize, newSize));
if (oldSlots != newSlots) {
if (newSlots && oldSlots != newSlots) {
hugeSlots.remove(oldSlots);
/* If this put fails, we will only leak the slots. */
(void)hugeSlots.put(newSlots);
@ -257,7 +257,8 @@ js::Nursery::reallocateSlots(JSContext *cx, JSObject *obj, HeapSlot *oldSlots,
return oldSlots;
HeapSlot *newSlots = allocateSlots(cx, obj, newCount);
PodCopy(newSlots, oldSlots, oldCount);
if (newSlots)
PodCopy(newSlots, oldSlots, oldCount);
return newSlots;
}
@ -284,7 +285,8 @@ js::Nursery::allocateHugeSlots(JSContext *cx, size_t nslots)
{
HeapSlot *slots = cx->pod_malloc<HeapSlot>(nslots);
/* If this put fails, we will only leak the slots. */
(void)hugeSlots.put(slots);
if (slots)
(void)hugeSlots.put(slots);
return slots;
}

View File

@ -36,6 +36,8 @@ using namespace js::gc;
using mozilla::ArrayEnd;
using JS::AutoGCRooter;
typedef RootedValueMap::Range RootRange;
typedef RootedValueMap::Entry RootEntry;
typedef RootedValueMap::Enum RootEnum;
@ -582,7 +584,7 @@ AutoGCRooter::trace(JSTracer *trc)
AutoGCRooter::traceAll(JSTracer *trc)
{
for (ContextIter cx(trc->runtime()); !cx.done(); cx.next()) {
for (js::AutoGCRooter *gcr = cx->autoGCRooters; gcr; gcr = gcr->down)
for (AutoGCRooter *gcr = cx->autoGCRooters; gcr; gcr = gcr->down)
gcr->trace(trc);
}
}
@ -591,7 +593,7 @@ AutoGCRooter::traceAll(JSTracer *trc)
AutoGCRooter::traceAllWrappers(JSTracer *trc)
{
for (ContextIter cx(trc->runtime()); !cx.done(); cx.next()) {
for (js::AutoGCRooter *gcr = cx->autoGCRooters; gcr; gcr = gcr->down) {
for (AutoGCRooter *gcr = cx->autoGCRooters; gcr; gcr = gcr->down) {
if (gcr->tag_ == WRAPVECTOR || gcr->tag_ == WRAPPER)
gcr->trace(trc);
}

View File

@ -638,20 +638,7 @@ GCMarker::appendGrayRoot(void *thing, JSGCTraceKind kind)
Zone *zone = static_cast<Cell *>(thing)->tenuredZone();
if (zone->isCollecting()) {
// See the comment on SetMaybeAliveFlag to see why we only do this for
// objects and scripts. We rely on gray root buffering for this to work,
// but we only need to worry about uncollected dead compartments during
// incremental GCs (when we do gray root buffering).
switch (kind) {
case JSTRACE_OBJECT:
static_cast<JSObject *>(thing)->compartment()->maybeAlive = true;
break;
case JSTRACE_SCRIPT:
static_cast<JSScript *>(thing)->compartment()->maybeAlive = true;
break;
default:
break;
}
zone->maybeAlive = true;
if (!zone->gcGrayRoots.append(root)) {
resetBufferedGrayRoots();
grayBufferState = GRAY_BUFFER_FAILED;

View File

@ -35,6 +35,8 @@ JS::Zone::Zone(JSRuntime *rt)
data(nullptr),
isSystem(false),
usedByExclusiveThread(false),
scheduledForDestruction(false),
maybeAlive(true),
active(false),
jitZone_(nullptr),
gcState_(NoGC),

View File

@ -258,6 +258,11 @@ struct Zone : public JS::shadow::Zone,
bool usedByExclusiveThread;
// These flags help us to discover if a compartment that shouldn't be alive
// manages to outlive a GC.
bool scheduledForDestruction;
bool maybeAlive;
// True when there are active frames.
bool active;

View File

@ -1,20 +0,0 @@
assertEq(Number.toInteger(4), 4);
assertEq(Number.toInteger(4.), 4);
assertEq(Number.toInteger(4.3), 4);
assertEq(Number.toInteger(-4), -4);
assertEq(Number.toInteger(-4.), -4);
assertEq(Number.toInteger(-4.3), -4);
assertEq(Number.toInteger(0.), 0.);
assertEq(Number.toInteger(-0.), -0.);
assertEq(Number.toInteger(Infinity), Infinity);
assertEq(Number.toInteger(-Infinity), -Infinity);
assertEq(Number.toInteger(NaN), 0);
assertEq(Number.toInteger(null), 0);
assertEq(Number.toInteger(undefined), 0);
assertEq(Number.toInteger(true), 1);
assertEq(Number.toInteger(false), 0);
assertEq(Number.toInteger({valueOf : function () { return 4; }}), 4);
assertEq(Number.toInteger({valueOf : function () { return 4.3; }}), 4);
assertEq(Number.toInteger({valueOf : function () { return "4"; }}), 4);
assertEq(Number.toInteger({valueOf : function () { return {};}}), 0);
assertEq(Number.toInteger(), 0);

View File

@ -74,17 +74,17 @@ class TempAllocator
};
// Stack allocated rooter for all roots associated with a TempAllocator
class AutoTempAllocatorRooter : private AutoGCRooter
class AutoTempAllocatorRooter : private JS::AutoGCRooter
{
public:
explicit AutoTempAllocatorRooter(JSContext *cx, TempAllocator *temp
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoGCRooter(cx, IONALLOC), temp(temp)
: JS::AutoGCRooter(cx, IONALLOC), temp(temp)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
friend void AutoGCRooter::trace(JSTracer *trc);
friend void JS::AutoGCRooter::trace(JSTracer *trc);
void trace(JSTracer *trc);
private:

View File

@ -548,6 +548,13 @@ MacroAssembler::allocateObject(Register result, Register slots, gc::AllocKind al
{
JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
#ifdef JS_CODEGEN_ARM
// Bug 1011474: Always take the ool path when allocating malloc slots on
// ARM to work around a top-crasher while we investigate.
if (nDynamicSlots)
return jump(fail);
#endif
checkAllocatorState(fail);
if (shouldNurseryAllocate(allocKind, initialHeap))

View File

@ -41,13 +41,13 @@ class MacroAssembler : public MacroAssemblerSpecific
}
public:
class AutoRooter : public AutoGCRooter
class AutoRooter : public JS::AutoGCRooter
{
MacroAssembler *masm_;
public:
AutoRooter(JSContext *cx, MacroAssembler *masm)
: AutoGCRooter(cx, IONMASM),
: JS::AutoGCRooter(cx, IONMASM),
masm_(masm)
{ }

View File

@ -17,6 +17,8 @@
using namespace js;
using namespace jit;
using JS::AutoCheckCannotGC;
using parallel::Spew;
using parallel::SpewOps;
using parallel::SpewBailouts;

View File

@ -98,6 +98,8 @@ using mozilla::Maybe;
using mozilla::PodCopy;
using mozilla::PodZero;
using JS::AutoGCRooter;
using js::frontend::Parser;
#ifdef HAVE_VA_LIST_AS_ARRAY
@ -1088,6 +1090,7 @@ JS_TransplantObject(JSContext *cx, HandleObject origobj, HandleObject target)
JS_ASSERT(!origobj->is<CrossCompartmentWrapperObject>());
JS_ASSERT(!target->is<CrossCompartmentWrapperObject>());
AutoMaybeTouchDeadZones agc(cx);
AutoDisableProxyCheck adpc(cx->runtime());
JSCompartment *destination = target->compartment();

View File

@ -74,66 +74,6 @@ inline void AssertArgumentsAreSane(JSContext *cx, JS::HandleValue v) {
}
#endif /* JS_DEBUG */
class JS_PUBLIC_API(AutoGCRooter) {
public:
AutoGCRooter(JSContext *cx, ptrdiff_t tag);
AutoGCRooter(js::ContextFriendFields *cx, ptrdiff_t tag);
~AutoGCRooter() {
JS_ASSERT(this == *stackTop);
*stackTop = down;
}
/* Implemented in gc/RootMarking.cpp. */
inline void trace(JSTracer *trc);
static void traceAll(JSTracer *trc);
static void traceAllWrappers(JSTracer *trc);
protected:
AutoGCRooter * const down;
/*
* Discriminates actual subclass of this being used. If non-negative, the
* subclass roots an array of values of the length stored in this field.
* If negative, meaning is indicated by the corresponding value in the enum
* below. Any other negative value indicates some deeper problem such as
* memory corruption.
*/
ptrdiff_t tag_;
enum {
VALARRAY = -2, /* js::AutoValueArray */
PARSER = -3, /* js::frontend::Parser */
SHAPEVECTOR = -4, /* js::AutoShapeVector */
IDARRAY = -6, /* js::AutoIdArray */
DESCVECTOR = -7, /* js::AutoPropDescVector */
VALVECTOR = -10, /* js::AutoValueVector */
IDVECTOR = -13, /* js::AutoIdVector */
OBJVECTOR = -14, /* js::AutoObjectVector */
STRINGVECTOR =-15, /* js::AutoStringVector */
SCRIPTVECTOR =-16, /* js::AutoScriptVector */
NAMEVECTOR = -17, /* js::AutoNameVector */
HASHABLEVALUE=-18, /* js::HashableValue */
IONMASM = -19, /* js::jit::MacroAssembler */
IONALLOC = -20, /* js::jit::AutoTempAllocatorRooter */
WRAPVECTOR = -21, /* js::AutoWrapperVector */
WRAPPER = -22, /* js::AutoWrapperRooter */
OBJOBJHASHMAP=-23, /* js::AutoObjectObjectHashMap */
OBJU32HASHMAP=-24, /* js::AutoObjectUnsigned32HashMap */
OBJHASHSET = -25, /* js::AutoObjectHashSet */
JSONPARSER = -26, /* js::JSONParser */
CUSTOM = -27, /* js::CustomAutoRooter */
FUNVECTOR = -28 /* js::AutoFunctionVector */
};
private:
AutoGCRooter ** const stackTop;
/* No copy or assignment semantics. */
AutoGCRooter(AutoGCRooter &ida) MOZ_DELETE;
void operator=(AutoGCRooter &ida) MOZ_DELETE;
};
/* AutoValueArray roots an internal fixed-size array of Values. */
template <size_t N>
class AutoValueArray : public AutoGCRooter

View File

@ -49,6 +49,8 @@ using mozilla::DebugOnly;
using mozilla::IsNaN;
using mozilla::PointerRangeSize;
using JS::AutoCheckCannotGC;
bool
js::GetLengthProperty(JSContext *cx, HandleObject obj, uint32_t *lengthp)
{

View File

@ -914,12 +914,12 @@ class AutoObjectHashSet : public AutoHashSetRooter<JSObject *>
};
/* AutoArrayRooter roots an external array of Values. */
class AutoArrayRooter : private AutoGCRooter
class AutoArrayRooter : private JS::AutoGCRooter
{
public:
AutoArrayRooter(JSContext *cx, size_t len, Value *vec
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoGCRooter(cx, len), array(vec)
: JS::AutoGCRooter(cx, len), array(vec)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
JS_ASSERT(tag_ >= 0);
@ -961,7 +961,7 @@ class AutoArrayRooter : private AutoGCRooter
return HandleValue::fromMarkedLocation(&array[i]);
}
friend void AutoGCRooter::trace(JSTracer *trc);
friend void JS::AutoGCRooter::trace(JSTracer *trc);
private:
Value *array;

View File

@ -65,9 +65,7 @@ JSCompartment::JSCompartment(Zone *zone, const JS::CompartmentOptions &options =
debugScriptMap(nullptr),
debugScopes(nullptr),
enumerators(nullptr),
compartmentStats(nullptr),
scheduledForDestruction(false),
maybeAlive(true)
compartmentStats(nullptr)
#ifdef JS_ION
, jitCompartment_(nullptr)
#endif

View File

@ -448,11 +448,6 @@ struct JSCompartment
/* Used by memory reporters and invalid otherwise. */
void *compartmentStats;
// These flags help us to discover if a compartment that shouldn't be alive
// manages to outlive a GC.
bool scheduledForDestruction;
bool maybeAlive;
#ifdef JS_ION
private:
js::jit::JitCompartment *jitCompartment_;
@ -656,11 +651,11 @@ class AutoWrapperVector : public AutoVectorRooter<WrapperValue>
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
class AutoWrapperRooter : private AutoGCRooter {
class AutoWrapperRooter : private JS::AutoGCRooter {
public:
AutoWrapperRooter(JSContext *cx, WrapperValue v
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoGCRooter(cx, WRAPPER), value(v)
: JS::AutoGCRooter(cx, WRAPPER), value(v)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
@ -669,7 +664,7 @@ class AutoWrapperRooter : private AutoGCRooter {
return value.get().toObjectOrNull();
}
friend void AutoGCRooter::trace(JSTracer *trc);
friend void JS::AutoGCRooter::trace(JSTracer *trc);
private:
WrapperValue value;

View File

@ -978,6 +978,8 @@ JS::IncrementalObjectBarrier(JSObject *obj)
JS_ASSERT(!obj->zone()->runtimeFromMainThread()->isHeapMajorCollecting());
AutoMarkInDeadZone amn(obj->zone());
JSObject::writeBarrierPre(obj);
}
@ -988,13 +990,13 @@ JS::IncrementalReferenceBarrier(void *ptr, JSGCTraceKind kind)
return;
gc::Cell *cell = static_cast<gc::Cell *>(ptr);
#ifdef DEBUG
Zone *zone = kind == JSTRACE_OBJECT
? static_cast<JSObject *>(cell)->zone()
: cell->tenuredZone();
JS_ASSERT(!zone->runtimeFromMainThread()->isHeapMajorCollecting());
#endif
AutoMarkInDeadZone amn(zone);
if (kind == JSTRACE_OBJECT)
JSObject::writeBarrierPre(static_cast<JSObject*>(cell));

View File

@ -230,6 +230,8 @@ using mozilla::DebugOnly;
using mozilla::Maybe;
using mozilla::Swap;
using JS::AutoGCRooter;
/* Perform a Full GC every 20 seconds if MaybeGC is called */
static const uint64_t GC_IDLE_FULL_SPAN = 20 * 1000 * 1000;
@ -2982,14 +2984,14 @@ GCRuntime::beginMarkPhase()
isFull = false;
}
zone->scheduledForDestruction = false;
zone->maybeAlive = false;
zone->setPreservingCode(false);
}
for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next()) {
JS_ASSERT(c->gcLiveArrayBuffers.empty());
c->marked = false;
c->scheduledForDestruction = false;
c->maybeAlive = false;
if (shouldPreserveJITCode(c, currentTime))
c->zone()->setPreservingCode(true);
}
@ -3090,50 +3092,40 @@ GCRuntime::beginMarkPhase()
bufferGrayRoots();
/*
* This code ensures that if a compartment is "dead", then it will be
* collected in this GC. A compartment is considered dead if its maybeAlive
* This code ensures that if a zone is "dead", then it will be
* collected in this GC. A zone is considered dead if its maybeAlive
* flag is false. The maybeAlive flag is set if:
* (1) the compartment has incoming cross-compartment edges, or
* (2) an object in the compartment was marked during root marking, either
* (1) the zone has incoming cross-compartment edges, or
* (2) an object in the zone was marked during root marking, either
* as a black root or a gray root.
* If the maybeAlive is false, then we set the scheduledForDestruction flag.
* At the end of the GC, we look for compartments where
* scheduledForDestruction is true. These are compartments that were somehow
* "revived" during the incremental GC. If any are found, we do a special,
* non-incremental GC of those compartments to try to collect them.
* At any time later in the GC, if we try to mark an object whose
* zone is scheduled for destruction, we will assert.
* NOTE: Due to bug 811587, we only assert if gcManipulatingDeadCompartments
* is true (e.g., if we're doing a brain transplant).
*
* Compartments can be revived for a variety of reasons. On reason is bug
* 811587, where a reflector that was dead can be revived by DOM code that
* still refers to the underlying DOM node.
* The purpose of this check is to ensure that a zone that we would
* normally destroy is not resurrected by a read barrier or an
* allocation. This might happen during a function like JS_TransplantObject,
* which iterates over all compartments, live or dead, and operates on their
* objects. See bug 803376 for details on this problem. To avoid the
* problem, we are very careful to avoid allocation and read barriers during
* JS_TransplantObject and the like. The code here ensures that we don't
* regress.
*
* Read barriers and allocations can also cause revival. This might happen
* during a function like JS_TransplantObject, which iterates over all
* compartments, live or dead, and operates on their objects. See bug 803376
* for details on this problem. To avoid the problem, we try to avoid
* allocation and read barriers during JS_TransplantObject and the like.
* Note that there are certain cases where allocations or read barriers in
* dead zone are difficult to avoid. We detect such cases (via the
* gcObjectsMarkedInDeadCompartment counter) and redo any ongoing GCs after
* the JS_TransplantObject function has finished. This ensures that the dead
* zones will be cleaned up. See AutoMarkInDeadZone and
* AutoMaybeTouchDeadZones for details.
*/
/* Set the maybeAlive flag based on cross-compartment edges. */
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
const CrossCompartmentKey &key = e.front().key();
JSCompartment *dest;
switch (key.kind) {
case CrossCompartmentKey::ObjectWrapper:
case CrossCompartmentKey::DebuggerObject:
case CrossCompartmentKey::DebuggerSource:
case CrossCompartmentKey::DebuggerEnvironment:
dest = static_cast<JSObject *>(key.wrapped)->compartment();
break;
case CrossCompartmentKey::DebuggerScript:
dest = static_cast<JSScript *>(key.wrapped)->compartment();
break;
default:
dest = nullptr;
break;
}
if (dest)
dest->maybeAlive = true;
Cell *dst = e.front().key().wrapped;
dst->tenuredZone()->maybeAlive = true;
}
}
@ -3142,9 +3134,9 @@ GCRuntime::beginMarkPhase()
* during MarkRuntime.
*/
for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
if (!c->maybeAlive && !rt->isAtomsCompartment(c))
c->scheduledForDestruction = true;
for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
if (!zone->maybeAlive && !rt->isAtomsZone(zone))
zone->scheduledForDestruction = true;
}
foundBlackGrayEdges = false;
@ -4520,8 +4512,8 @@ GCRuntime::resetIncrementalGC(const char *reason)
case SWEEP:
marker.reset();
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
c->scheduledForDestruction = false;
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
zone->scheduledForDestruction = false;
/* Finish sweeping the current zone group, then abort. */
abortSweepAfterCurrentGroup = true;
@ -4999,30 +4991,13 @@ GCRuntime::collect(bool incremental, int64_t budget, JSGCInvocationKind gckind,
if (poked && shouldCleanUpEverything)
JS::PrepareForFullGC(rt);
/*
* This code makes an extra effort to collect compartments that we
* thought were dead at the start of the GC. See the large comment in
* beginMarkPhase.
*/
bool repeatForDeadZone = false;
if (incremental && incrementalState == NO_INCREMENTAL) {
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
if (c->scheduledForDestruction) {
incremental = false;
repeatForDeadZone = true;
reason = JS::gcreason::COMPARTMENT_REVIVED;
c->zone()->scheduleGC();
}
}
}
/*
* If we reset an existing GC, we need to start a new one. Also, we
* repeat GCs that happen during shutdown (the gcShouldCleanUpEverything
* case) until we can be sure that no additional garbage is created
* (which typically happens if roots are dropped during finalizers).
*/
repeat = (poked && shouldCleanUpEverything) || wasReset || repeatForDeadZone;
repeat = (poked && shouldCleanUpEverything) || wasReset;
} while (repeat);
if (incrementalState == NO_INCREMENTAL) {
@ -5559,6 +5534,34 @@ ArenaLists::containsArena(JSRuntime *rt, ArenaHeader *needle)
}
AutoMaybeTouchDeadZones::AutoMaybeTouchDeadZones(JSContext *cx)
: runtime(cx->runtime()),
markCount(runtime->gc.objectsMarkedInDeadZones),
inIncremental(JS::IsIncrementalGCInProgress(runtime)),
manipulatingDeadZones(runtime->gc.manipulatingDeadZones)
{
runtime->gc.manipulatingDeadZones = true;
}
AutoMaybeTouchDeadZones::AutoMaybeTouchDeadZones(JSObject *obj)
: runtime(obj->compartment()->runtimeFromMainThread()),
markCount(runtime->gc.objectsMarkedInDeadZones),
inIncremental(JS::IsIncrementalGCInProgress(runtime)),
manipulatingDeadZones(runtime->gc.manipulatingDeadZones)
{
runtime->gc.manipulatingDeadZones = true;
}
AutoMaybeTouchDeadZones::~AutoMaybeTouchDeadZones()
{
runtime->gc.manipulatingDeadZones = manipulatingDeadZones;
if (inIncremental && runtime->gc.objectsMarkedInDeadZones != markCount) {
JS::PrepareForFullGC(runtime);
js::GC(runtime, GC_NORMAL, JS::gcreason::TRANSPLANT);
}
}
AutoSuppressGC::AutoSuppressGC(ExclusiveContext *cx)
: suppressGC_(cx->perThreadData->suppressGC)
{

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