mirror of
https://github.com/roytam1/mozilla45esr.git
synced 2026-05-26 06:25:03 +00:00
partly import changes from https://github.com/classilla/tenfourfox/commit/c9b2922b70d0052b78a1a9bc6069cefe5a119124 , with ppc-only changes excluded
This commit is contained in:
@@ -77,7 +77,8 @@ pref("extensions.systemAddon.update.url", "https://aus5.mozilla.org/update/3/Sys
|
||||
pref("extensions.autoDisableScopes", 15);
|
||||
|
||||
// Require signed add-ons by default
|
||||
pref("xpinstall.signatures.required", true);
|
||||
// ... except on TenFourFox
|
||||
pref("xpinstall.signatures.required", false);
|
||||
pref("xpinstall.signatures.devInfoURL", "https://wiki.mozilla.org/Addons/Extension_Signing");
|
||||
|
||||
// Dictionary download preference
|
||||
@@ -129,7 +130,7 @@ pref("app.update.enabled", true);
|
||||
pref("app.update.auto", true);
|
||||
|
||||
// See chart in nsUpdateService.js source for more details
|
||||
pref("app.update.mode", 1);
|
||||
pref("app.update.mode", 2);
|
||||
|
||||
// If set to true, the Update Service will present no UI for any event.
|
||||
pref("app.update.silent", false);
|
||||
@@ -144,7 +145,7 @@ pref("app.update.badge", false);
|
||||
|
||||
// If set to true, the Update Service will apply updates in the background
|
||||
// when it finishes downloading them.
|
||||
pref("app.update.staging.enabled", true);
|
||||
pref("app.update.staging.enabled", false);
|
||||
|
||||
// Update service URL:
|
||||
pref("app.update.url", "https://aus5.mozilla.org/update/6/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%SYSTEM_CAPABILITIES%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml");
|
||||
@@ -222,7 +223,8 @@ pref("browser.fixup.domainwhitelist.localhost", true);
|
||||
pref("general.useragent.locale", "@AB_CD@");
|
||||
pref("general.skins.selectedSkin", "classic/1.0");
|
||||
|
||||
pref("general.smoothScroll", true);
|
||||
// too slow on TenFourFox
|
||||
pref("general.smoothScroll", false);
|
||||
#ifdef UNIX_BUT_NOT_MAC
|
||||
pref("general.autoScroll", false);
|
||||
#else
|
||||
@@ -241,7 +243,7 @@ pref("browser.shell.defaultBrowserCheckCount", 0);
|
||||
pref("browser.startup.page", 1);
|
||||
pref("browser.startup.homepage", "chrome://branding/locale/browserconfig.properties");
|
||||
|
||||
pref("browser.slowStartup.notificationDisabled", false);
|
||||
pref("browser.slowStartup.notificationDisabled", true); // STFU!
|
||||
pref("browser.slowStartup.timeThreshold", 40000);
|
||||
pref("browser.slowStartup.maxSamples", 5);
|
||||
|
||||
@@ -1011,15 +1013,15 @@ pref("browser.sessionstore.resume_from_crash", true);
|
||||
pref("browser.sessionstore.resume_session_once", false);
|
||||
|
||||
// minimal interval between two save operations in milliseconds
|
||||
pref("browser.sessionstore.interval", 15000);
|
||||
pref("browser.sessionstore.interval", 25000);
|
||||
// on which sites to save text data, POSTDATA and cookies
|
||||
// 0 = everywhere, 1 = unencrypted sites, 2 = nowhere
|
||||
pref("browser.sessionstore.privacy_level", 0);
|
||||
// how many tabs can be reopened (per window)
|
||||
pref("browser.sessionstore.max_tabs_undo", 10);
|
||||
pref("browser.sessionstore.max_tabs_undo", 4);
|
||||
// how many windows can be reopened (per session) - on non-OS X platforms this
|
||||
// pref may be ignored when dealing with pop-up windows to ensure proper startup
|
||||
pref("browser.sessionstore.max_windows_undo", 3);
|
||||
pref("browser.sessionstore.max_windows_undo", 2);
|
||||
// number of crashes that can occur before the about:sessionrestore page is displayed
|
||||
// (this pref has no effect if more than 6 hours have passed since the last crash)
|
||||
pref("browser.sessionstore.max_resumed_crashes", 1);
|
||||
@@ -1149,7 +1151,7 @@ pref("dom.ipc.shims.enabledWarnings", false);
|
||||
|
||||
// Start the browser in e10s mode
|
||||
pref("browser.tabs.remote.autostart", false);
|
||||
pref("browser.tabs.remote.desktopbehavior", true);
|
||||
pref("browser.tabs.remote.desktopbehavior", false);
|
||||
|
||||
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
|
||||
// When this pref is true the Windows process sandbox will set up dummy
|
||||
@@ -1427,11 +1429,7 @@ pref("plain_text.wrap_long_lines", true);
|
||||
pref("dom.debug.propagate_gesture_events_through_content", false);
|
||||
|
||||
// The request URL of the GeoLocation backend.
|
||||
#ifdef RELEASE_BUILD
|
||||
pref("geo.wifi.uri", "https://www.googleapis.com/geolocation/v1/geolocate?key=%GOOGLE_API_KEY%");
|
||||
#else
|
||||
pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%");
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#ifdef RELEASE_BUILD
|
||||
@@ -1617,7 +1615,7 @@ pref("reader.parse-node-limit", 0);
|
||||
// and because (normally) these errors are not persisted anywhere.
|
||||
pref("reader.errors.includeURLs", true);
|
||||
|
||||
pref("browser.pocket.enabled", true);
|
||||
pref("browser.pocket.enabled", false);
|
||||
pref("browser.pocket.api", "api.getpocket.com");
|
||||
pref("browser.pocket.site", "getpocket.com");
|
||||
pref("browser.pocket.oAuthConsumerKey", "40249-e88c401e1b1f2242d9e441c4");
|
||||
|
||||
@@ -1222,7 +1222,7 @@ var gBrowserInit = {
|
||||
PanelUI.init();
|
||||
LightweightThemeListener.init();
|
||||
|
||||
Services.telemetry.getHistogramById("E10S_WINDOW").add(gMultiProcessBrowser);
|
||||
//Services.telemetry.getHistogramById("E10S_WINDOW").add(gMultiProcessBrowser);
|
||||
|
||||
SidebarUI.startDelayedLoad();
|
||||
|
||||
@@ -1354,6 +1354,7 @@ var gBrowserInit = {
|
||||
Cu.reportError("Could not end startup crash tracking: " + ex);
|
||||
}
|
||||
|
||||
/*
|
||||
// Delay this a minute because there's no rush
|
||||
setTimeout(() => {
|
||||
this.gmpInstallManager = new GMPInstallManager();
|
||||
@@ -1375,6 +1376,7 @@ var gBrowserInit = {
|
||||
let h264Works = v.canPlayType("video/mp4") != "";
|
||||
Services.telemetry.getHistogramById("VIDEO_CAN_CREATE_H264_DECODER").add(h264Works);
|
||||
}, 90 * 1000);
|
||||
*/
|
||||
|
||||
SessionStore.promiseInitialized.then(() => {
|
||||
// Bail out if the window has been closed in the meantime.
|
||||
@@ -1389,6 +1391,7 @@ var gBrowserInit = {
|
||||
|
||||
// Telemetry for master-password - we do this after 5 seconds as it
|
||||
// can cause IO if NSS/PSM has not already initialized.
|
||||
/*
|
||||
setTimeout(() => {
|
||||
if (window.closed) {
|
||||
return;
|
||||
@@ -1403,13 +1406,14 @@ var gBrowserInit = {
|
||||
Services.telemetry.getHistogramById("MASTER_PASSWORD_ENABLED").add(mpEnabled);
|
||||
}
|
||||
}, 5000);
|
||||
*/
|
||||
|
||||
PanicButtonNotifier.init();
|
||||
});
|
||||
this.delayedStartupFinished = true;
|
||||
|
||||
Services.obs.notifyObservers(window, "browser-delayed-startup-finished", "");
|
||||
TelemetryTimestamps.add("delayedStartupFinished");
|
||||
//TelemetryTimestamps.add("delayedStartupFinished");
|
||||
},
|
||||
|
||||
// Returns the URI(s) to load at startup.
|
||||
@@ -2784,16 +2788,20 @@ var BrowserOnClick = {
|
||||
break;
|
||||
case "Browser:SetSSLErrorReportAuto":
|
||||
Services.prefs.setBoolPref("security.ssl.errorReporting.automatic", msg.json.automatic);
|
||||
/*
|
||||
let bin = TLS_ERROR_REPORT_TELEMETRY_AUTO_UNCHECKED;
|
||||
if (msg.json.automatic) {
|
||||
bin = TLS_ERROR_REPORT_TELEMETRY_AUTO_CHECKED;
|
||||
}
|
||||
Services.telemetry.getHistogramById("TLS_ERROR_REPORT_UI").add(bin);
|
||||
*/
|
||||
break;
|
||||
case "Browser:SSLErrorReportTelemetry":
|
||||
/*
|
||||
let reportStatus = msg.data.reportStatus;
|
||||
Services.telemetry.getHistogramById("TLS_ERROR_REPORT_UI")
|
||||
.add(reportStatus);
|
||||
*/
|
||||
break;
|
||||
case "Browser:OverrideWeakCrypto":
|
||||
let weakCryptoOverride = Cc["@mozilla.org/security/weakcryptooverride;1"]
|
||||
@@ -2825,11 +2833,13 @@ var BrowserOnClick = {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
let bin = TLS_ERROR_REPORT_TELEMETRY_MANUAL_SEND;
|
||||
if (Services.prefs.getBoolPref("security.ssl.errorReporting.automatic")) {
|
||||
bin = TLS_ERROR_REPORT_TELEMETRY_AUTO_SEND;
|
||||
}
|
||||
Services.telemetry.getHistogramById("TLS_ERROR_REPORT_UI").add(bin);
|
||||
*/
|
||||
|
||||
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
@@ -2906,13 +2916,15 @@ var BrowserOnClick = {
|
||||
},
|
||||
|
||||
onAboutCertError: function (browser, elementId, isTopFrame, location, securityInfoAsString) {
|
||||
let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
|
||||
//let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
|
||||
|
||||
switch (elementId) {
|
||||
case "exceptionDialogButton":
|
||||
/*
|
||||
if (isTopFrame) {
|
||||
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_CLICK_ADD_EXCEPTION);
|
||||
}
|
||||
*/
|
||||
|
||||
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
@@ -2943,16 +2955,20 @@ var BrowserOnClick = {
|
||||
break;
|
||||
|
||||
case "returnButton":
|
||||
/*
|
||||
if (isTopFrame) {
|
||||
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_GET_ME_OUT_OF_HERE);
|
||||
}
|
||||
*/
|
||||
goBackFromErrorPage();
|
||||
break;
|
||||
|
||||
case "advancedButton":
|
||||
/*
|
||||
if (isTopFrame) {
|
||||
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_UNDERSTAND_RISKS);
|
||||
}
|
||||
*/
|
||||
|
||||
let errorInfo = getDetailedCertErrorInfo(location,
|
||||
securityInfoAsString);
|
||||
@@ -2974,6 +2990,7 @@ var BrowserOnClick = {
|
||||
onAboutBlocked: function (elementId, reason, isTopFrame, location) {
|
||||
// Depending on what page we are displaying here (malware/phishing/unwanted)
|
||||
// use the right strings and links for each.
|
||||
/*
|
||||
let bucketName = "";
|
||||
let sendTelemetry = false;
|
||||
if (reason === 'malware') {
|
||||
@@ -2989,11 +3006,14 @@ var BrowserOnClick = {
|
||||
let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
|
||||
let nsISecTel = Ci.nsISecurityUITelemetry;
|
||||
bucketName += isTopFrame ? "TOP_" : "FRAME_";
|
||||
*/
|
||||
switch (elementId) {
|
||||
case "getMeOutButton":
|
||||
/*
|
||||
if (sendTelemetry) {
|
||||
secHistogram.add(nsISecTel[bucketName + "GET_ME_OUT_OF_HERE"]);
|
||||
}
|
||||
*/
|
||||
getMeOutOfHere();
|
||||
break;
|
||||
|
||||
@@ -3003,17 +3023,21 @@ var BrowserOnClick = {
|
||||
|
||||
// We log even if malware/phishing/unwanted info URL couldn't be found:
|
||||
// the measurement is for how many users clicked the WHY BLOCKED button
|
||||
/*
|
||||
if (sendTelemetry) {
|
||||
secHistogram.add(nsISecTel[bucketName + "WHY_BLOCKED"]);
|
||||
}
|
||||
*/
|
||||
openHelpLink("phishing-malware", false, "current");
|
||||
break;
|
||||
|
||||
case "ignoreWarningButton":
|
||||
if (gPrefService.getBoolPref("browser.safebrowsing.allowOverride")) {
|
||||
/*
|
||||
if (sendTelemetry) {
|
||||
secHistogram.add(nsISecTel[bucketName + "IGNORE_WARNING"]);
|
||||
}
|
||||
*/
|
||||
this.ignoreWarningButton(reason);
|
||||
}
|
||||
break;
|
||||
@@ -3808,6 +3832,7 @@ const BrowserSearch = {
|
||||
},
|
||||
|
||||
recordSearchInTelemetry: function (engine, source) {
|
||||
/*
|
||||
const SOURCES = [
|
||||
"abouthome",
|
||||
"contextmenu",
|
||||
@@ -3825,11 +3850,14 @@ const BrowserSearch = {
|
||||
|
||||
let count = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS");
|
||||
count.add(countId);
|
||||
*/
|
||||
},
|
||||
|
||||
recordOneoffSearchInTelemetry: function (engine, source, type, where) {
|
||||
/*
|
||||
let id = this._getSearchEngineId(engine) + "." + source;
|
||||
BrowserUITelemetry.countOneoffSearchEvent(id, type, where);
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3992,6 +4020,7 @@ function toOpenWindowByType(inType, uri, features)
|
||||
|
||||
function OpenBrowserWindow(options)
|
||||
{
|
||||
/*
|
||||
var telemetryObj = {};
|
||||
TelemetryStopwatch.start("FX_NEW_WINDOW_MS", telemetryObj);
|
||||
|
||||
@@ -4016,6 +4045,7 @@ function OpenBrowserWindow(options)
|
||||
// is being closed right after it was opened to avoid leaking.
|
||||
Services.obs.addObserver(newDocumentShown, "document-shown", false);
|
||||
Services.obs.addObserver(windowClosed, "domwindowclosed", false);
|
||||
*/
|
||||
|
||||
var charsetArg = new String();
|
||||
var handler = Components.classes["@mozilla.org/browser/clh;1"]
|
||||
@@ -4813,6 +4843,7 @@ var CombinedStopReload = {
|
||||
|
||||
var TabsProgressListener = {
|
||||
onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||
/*
|
||||
// Collect telemetry data about tab load times.
|
||||
if (aWebProgress.isTopLevel) {
|
||||
if (aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) {
|
||||
@@ -4827,6 +4858,7 @@ var TabsProgressListener = {
|
||||
TelemetryStopwatch.cancel("FX_PAGE_LOAD_MS", aBrowser);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Attach a listener to watch for "click" events bubbling up from error
|
||||
// pages and other similar pages (like about:newtab). This lets us fix bugs
|
||||
@@ -5278,11 +5310,13 @@ var gTabletModePageCounter = {
|
||||
},
|
||||
|
||||
finish() {
|
||||
/*
|
||||
if (this.enabled) {
|
||||
let histogram = Services.telemetry.getKeyedHistogramById("FX_TABLETMODE_PAGE_LOAD");
|
||||
histogram.add("tablet", this._tabletCount);
|
||||
histogram.add("desktop", this._desktopCount);
|
||||
}
|
||||
*/
|
||||
},
|
||||
};
|
||||
|
||||
@@ -6851,10 +6885,12 @@ var gIdentityHandler = {
|
||||
disableMixedContentProtection() {
|
||||
// Use telemetry to measure how often unblocking happens
|
||||
const kMIXED_CONTENT_UNBLOCK_EVENT = 2;
|
||||
/*
|
||||
let histogram =
|
||||
Services.telemetry.getHistogramById(
|
||||
"MIXED_CONTENT_UNBLOCK_COUNTER");
|
||||
histogram.add(kMIXED_CONTENT_UNBLOCK_EVENT);
|
||||
*/
|
||||
// Reload the page with the content unblocked
|
||||
BrowserReloadWithFlags(
|
||||
Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_MIXED_CONTENT);
|
||||
|
||||
@@ -1947,7 +1947,7 @@
|
||||
|
||||
if (animate) {
|
||||
requestAnimationFrame(function () {
|
||||
this.tabContainer._handleTabTelemetryStart(t, aURI);
|
||||
//this.tabContainer._handleTabTelemetryStart(t, aURI);
|
||||
|
||||
// kick the animation off
|
||||
t.setAttribute("fadein", "true");
|
||||
@@ -2132,7 +2132,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
this.tabContainer._handleTabTelemetryStart(aTab);
|
||||
//this.tabContainer._handleTabTelemetryStart(aTab);
|
||||
|
||||
this._blurTab(aTab);
|
||||
aTab.style.maxWidth = ""; // ensure that fade-out transition happens
|
||||
@@ -4608,7 +4608,7 @@
|
||||
} catch (ex) {
|
||||
this._tabAnimationLoggingEnabled = false;
|
||||
}
|
||||
this._browserNewtabpageEnabled = Services.prefs.getBoolPref("browser.newtabpage.enabled");
|
||||
this._browserNewtabpageEnabled = false; //Services.prefs.getBoolPref("browser.newtabpage.enabled");
|
||||
]]>
|
||||
</constructor>
|
||||
|
||||
@@ -5263,6 +5263,7 @@
|
||||
<parameter name="aURI"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
/*
|
||||
// Animation-smoothness telemetry/logging
|
||||
if (Services.telemetry.canRecordExtended || this._tabAnimationLoggingEnabled) {
|
||||
if (aURI == "about:newtab" && (aTab._tPos == 1 || aTab._tPos == 2)) {
|
||||
@@ -5277,6 +5278,7 @@
|
||||
|
||||
// Overall animation duration
|
||||
aTab._animStartTime = Date.now();
|
||||
*/
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
@@ -5285,6 +5287,7 @@
|
||||
<parameter name="aTab"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
/*
|
||||
if (!aTab._animStartTime) {
|
||||
return;
|
||||
}
|
||||
@@ -5333,6 +5336,7 @@
|
||||
Services.telemetry.getHistogramById("FX_TAB_ANIM_OPEN" + preview + "_FRAME_INTERVAL_MS").add(averageInterval);
|
||||
}
|
||||
}
|
||||
*/
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
@@ -5351,7 +5355,7 @@
|
||||
|
||||
var tab = event.target;
|
||||
|
||||
this._handleTabTelemetryEnd(tab);
|
||||
//this._handleTabTelemetryEnd(tab);
|
||||
|
||||
if (tab.getAttribute("fadein") == "true") {
|
||||
if (tab._fullyOpen)
|
||||
|
||||
@@ -86,7 +86,7 @@ static RedirEntry kRedirMap[] = {
|
||||
nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
|
||||
nsIAboutModule::ALLOW_SCRIPT |
|
||||
nsIAboutModule::ENABLE_INDEXED_DB },
|
||||
{ "newtab", "chrome://browser/content/newtab/newTab.xhtml",
|
||||
{ "newtab", "about:blank",
|
||||
nsIAboutModule::ALLOW_SCRIPT },
|
||||
#ifndef RELEASE_BUILD
|
||||
{ "remote-newtab", "chrome://browser/content/remote-newtab/newTab.xhtml",
|
||||
|
||||
@@ -509,6 +509,7 @@ BrowserGlue.prototype = {
|
||||
},
|
||||
|
||||
_handleURLBarTelemetry(input) {
|
||||
/*
|
||||
if (!input ||
|
||||
input.id != "urlbar" ||
|
||||
input.inPrivateContext ||
|
||||
@@ -563,6 +564,7 @@ BrowserGlue.prototype = {
|
||||
Cu.reportError("Unknown FX_URLBAR_SELECTED_RESULT_TYPE type: " +
|
||||
actionType);
|
||||
}
|
||||
*/
|
||||
},
|
||||
|
||||
_syncSearchEngines: function () {
|
||||
@@ -706,7 +708,7 @@ BrowserGlue.prototype = {
|
||||
const STATE_USER_CLOSED_NOTIFICATION = 4;
|
||||
|
||||
let update = function(response) {
|
||||
Services.telemetry.getHistogramById("SLOW_ADDON_WARNING_STATES").add(response);
|
||||
//Services.telemetry.getHistogramById("SLOW_ADDON_WARNING_STATES").add(response);
|
||||
}
|
||||
|
||||
let complete = false;
|
||||
@@ -718,7 +720,7 @@ BrowserGlue.prototype = {
|
||||
}
|
||||
complete = true;
|
||||
update(response);
|
||||
Services.telemetry.getHistogramById("SLOW_ADDON_WARNING_RESPONSE_TIME").add(Date.now() - start);
|
||||
//Services.telemetry.getHistogramById("SLOW_ADDON_WARNING_RESPONSE_TIME").add(Date.now() - start);
|
||||
};
|
||||
|
||||
update(STATE_WARNING_DISPLAYED);
|
||||
@@ -1049,6 +1051,7 @@ BrowserGlue.prototype = {
|
||||
},
|
||||
|
||||
_firstWindowTelemetry: function(aWindow) {
|
||||
/*
|
||||
#ifdef XP_WIN
|
||||
let SCALING_PROBE_NAME = "DISPLAY_SCALING_MSWIN";
|
||||
#elifdef XP_MACOSX
|
||||
@@ -1062,6 +1065,7 @@ BrowserGlue.prototype = {
|
||||
let scaling = aWindow.devicePixelRatio * 100;
|
||||
Services.telemetry.getHistogramById(SCALING_PROBE_NAME).add(scaling);
|
||||
}
|
||||
*/
|
||||
},
|
||||
|
||||
// the first browser window has finished initializing
|
||||
@@ -1324,6 +1328,7 @@ BrowserGlue.prototype = {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef I_LOVE_TELE_AND_I_CANNOT_LIE
|
||||
try {
|
||||
// Report default browser status on startup to telemetry
|
||||
// so we can track whether we are the default.
|
||||
@@ -1337,6 +1342,7 @@ BrowserGlue.prototype = {
|
||||
.add(promptCount);
|
||||
}
|
||||
catch (ex) { /* Don't break the default prompt if telemetry is broken. */ }
|
||||
#endif
|
||||
|
||||
if (willPrompt) {
|
||||
Services.tm.mainThread.dispatch(function() {
|
||||
@@ -1815,6 +1821,7 @@ BrowserGlue.prototype = {
|
||||
// available backup compared to that session.
|
||||
if (profileLastUse > lastBackupTime) {
|
||||
let backupAge = Math.round((profileLastUse - lastBackupTime) / 86400000);
|
||||
/*
|
||||
// Report the age of the last available backup.
|
||||
try {
|
||||
Services.telemetry
|
||||
@@ -1823,6 +1830,7 @@ BrowserGlue.prototype = {
|
||||
} catch (ex) {
|
||||
Cu.reportError("Unable to report telemetry.");
|
||||
}
|
||||
*/
|
||||
|
||||
if (backupAge > BOOKMARKS_BACKUP_MAX_INTERVAL_DAYS)
|
||||
this._bookmarksBackupIdleTime /= 2;
|
||||
@@ -2687,7 +2695,7 @@ ContentPermissionPrompt.prototype = {
|
||||
},
|
||||
|
||||
_promptGeo : function(aRequest) {
|
||||
var secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
|
||||
//var secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
|
||||
|
||||
var message;
|
||||
|
||||
@@ -2697,7 +2705,7 @@ ContentPermissionPrompt.prototype = {
|
||||
action: null,
|
||||
expireType: null,
|
||||
callback: function() {
|
||||
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST_SHARE_LOCATION);
|
||||
//secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST_SHARE_LOCATION);
|
||||
},
|
||||
}];
|
||||
|
||||
@@ -2715,7 +2723,7 @@ ContentPermissionPrompt.prototype = {
|
||||
action: Ci.nsIPermissionManager.ALLOW_ACTION,
|
||||
expireType: null,
|
||||
callback: function() {
|
||||
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST_ALWAYS_SHARE);
|
||||
//secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST_ALWAYS_SHARE);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -2725,12 +2733,12 @@ ContentPermissionPrompt.prototype = {
|
||||
action: Ci.nsIPermissionManager.DENY_ACTION,
|
||||
expireType: null,
|
||||
callback: function() {
|
||||
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST_NEVER_SHARE);
|
||||
//secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST_NEVER_SHARE);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST);
|
||||
//secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST);
|
||||
|
||||
this._showPrompt(aRequest, message, "geo", actions, "geolocation",
|
||||
"geo-notification-icon", options);
|
||||
@@ -2950,11 +2958,15 @@ var DefaultBrowserCheck = {
|
||||
if (isDefault || runTime > 600) {
|
||||
this._setAsDefaultTimer.cancel();
|
||||
this._setAsDefaultTimer = null;
|
||||
/*
|
||||
Services.telemetry.getHistogramById("BROWSER_SET_DEFAULT_TIME_TO_COMPLETION_SECONDS")
|
||||
.add(runTime);
|
||||
*/
|
||||
}
|
||||
/*
|
||||
Services.telemetry.getHistogramById("BROWSER_IS_USER_DEFAULT_ERROR")
|
||||
.add(isDefaultError);
|
||||
*/
|
||||
}, 1000, Ci.nsITimer.TYPE_REPEATING_SLACK);
|
||||
} catch (ex) {
|
||||
setAsDefaultError = true;
|
||||
@@ -2964,10 +2976,12 @@ var DefaultBrowserCheck = {
|
||||
// to be inverse of each other, but that is only because this function is
|
||||
// called when the browser is set as the default. During startup we record
|
||||
// the BROWSER_IS_USER_DEFAULT value without recording BROWSER_SET_USER_DEFAULT_ERROR.
|
||||
/*
|
||||
Services.telemetry.getHistogramById("BROWSER_IS_USER_DEFAULT")
|
||||
.add(!setAsDefaultError);
|
||||
Services.telemetry.getHistogramById("BROWSER_SET_DEFAULT_ERROR")
|
||||
.add(setAsDefaultError);
|
||||
*/
|
||||
},
|
||||
|
||||
_createPopup: function(win, notNowStrings, neverStrings) {
|
||||
@@ -3080,11 +3094,13 @@ var DefaultBrowserCheck = {
|
||||
ShellService.shouldCheckDefaultBrowser = false;
|
||||
}
|
||||
|
||||
#ifdef I_LOVE_TELE_AND_I_CANNOT_LIE
|
||||
try {
|
||||
let resultEnum = rv * 2 + shouldAsk.value;
|
||||
Services.telemetry.getHistogramById("BROWSER_SET_DEFAULT_RESULT")
|
||||
.add(resultEnum);
|
||||
} catch (ex) { /* Don't break if Telemetry is acting up. */ }
|
||||
#endif
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -305,6 +305,8 @@ class SectionFinder(object):
|
||||
|
||||
def print_command(out, args):
|
||||
print >>out, "Executing: " + " ".join(args)
|
||||
if not hasattr(args, 'tmp'):
|
||||
return
|
||||
for tmp in [f for f in args.tmp if os.path.isfile(f)]:
|
||||
print >>out, tmp + ":"
|
||||
with open(tmp) as file:
|
||||
|
||||
@@ -377,8 +377,8 @@ nsContentIterator::Init(nsIDOMRange* aDOMRange)
|
||||
// Does mFirst node really intersect the range? The range could be
|
||||
// 'degenerate', i.e., not collapsed but still contain no content.
|
||||
if (mFirst &&
|
||||
NS_WARN_IF(!NodeIsInTraversalRange(mFirst, mPre, startNode,
|
||||
startIndx, endNode, endIndx))) {
|
||||
!NodeIsInTraversalRange(mFirst, mPre, startNode, startIndx,
|
||||
endNode, endIndx)) {
|
||||
mFirst = nullptr;
|
||||
}
|
||||
} else {
|
||||
@@ -405,8 +405,8 @@ nsContentIterator::Init(nsIDOMRange* aDOMRange)
|
||||
// 'degenerate', i.e., not collapsed but still contain no content.
|
||||
|
||||
if (mFirst &&
|
||||
NS_WARN_IF(!NodeIsInTraversalRange(mFirst, mPre, startNode, startIndx,
|
||||
endNode, endIndx))) {
|
||||
!NodeIsInTraversalRange(mFirst, mPre, startNode, startIndx,
|
||||
endNode, endIndx)) {
|
||||
mFirst = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -448,9 +448,9 @@ nsContentIterator::Init(nsIDOMRange* aDOMRange)
|
||||
mLast = GetPrevSibling(endNode);
|
||||
NS_WARN_IF(!mLast);
|
||||
|
||||
if (NS_WARN_IF(!NodeIsInTraversalRange(mLast, mPre,
|
||||
startNode, startIndx,
|
||||
endNode, endIndx))) {
|
||||
if (!NodeIsInTraversalRange(mLast, mPre,
|
||||
startNode, startIndx,
|
||||
endNode, endIndx)) {
|
||||
mLast = nullptr;
|
||||
}
|
||||
} else {
|
||||
@@ -485,7 +485,7 @@ nsContentIterator::Init(nsIDOMRange* aDOMRange)
|
||||
|
||||
// If either first or last is null, they both have to be null!
|
||||
|
||||
if (NS_WARN_IF(!mFirst) || NS_WARN_IF(!mLast)) {
|
||||
if (!mFirst || !mLast) {
|
||||
mFirst = nullptr;
|
||||
mLast = nullptr;
|
||||
}
|
||||
|
||||
@@ -178,6 +178,7 @@ static uint32_t sForgetSkippableBeforeCC = 0;
|
||||
static uint32_t sPreviousSuspectedCount = 0;
|
||||
static uint32_t sCleanupsSinceLastGC = UINT32_MAX;
|
||||
static bool sNeedsFullCC = false;
|
||||
static bool sNeedsFullGC = false;
|
||||
static bool sNeedsGCAfterCC = false;
|
||||
static bool sIncrementalCC = false;
|
||||
static bool sDidPaintAfterPreviousICCSlice = false;
|
||||
@@ -1312,7 +1313,14 @@ nsJSContext::GarbageCollectNow(JS::gcreason::Reason aReason,
|
||||
}
|
||||
|
||||
JSGCInvocationKind gckind = aShrinking == ShrinkingGC ? GC_SHRINK : GC_NORMAL;
|
||||
JS::PrepareForFullGC(sRuntime);
|
||||
|
||||
if (sNeedsFullGC || aReason != JS::gcreason::CC_WAITING) {
|
||||
sNeedsFullGC = false;
|
||||
JS::PrepareForFullGC(sRuntime);
|
||||
} else {
|
||||
CycleCollectedJSRuntime::Get()->PrepareWaitingZonesForGC();
|
||||
}
|
||||
|
||||
if (aIncremental == IncrementalGC) {
|
||||
JS::StartIncrementalGC(sRuntime, gckind, aReason, aSliceMillis);
|
||||
} else {
|
||||
@@ -2009,6 +2017,8 @@ nsJSContext::RunNextCollectorTimer()
|
||||
void
|
||||
nsJSContext::PokeGC(JS::gcreason::Reason aReason, int aDelay)
|
||||
{
|
||||
sNeedsFullGC = sNeedsFullGC || aReason != JS::gcreason::CC_WAITING;
|
||||
|
||||
if (sGCTimer || sInterSliceGCTimer || sShuttingDown) {
|
||||
// There's already a timer for GC'ing, just return
|
||||
return;
|
||||
@@ -2279,13 +2289,20 @@ DOMGCSliceCallback(JSRuntime *aRt, JS::GCProgress aProgress, const JS::GCDescrip
|
||||
} else {
|
||||
nsJSContext::KillFullGCTimer();
|
||||
|
||||
// bug 1052793
|
||||
#if(1)
|
||||
}
|
||||
#else
|
||||
// Avoid shrinking during heavy activity, which is suggested by
|
||||
// compartment GC. We don't need to shrink after a shrinking GC as this
|
||||
// happens automatically in this case.
|
||||
#endif
|
||||
if (aDesc.invocationKind_ == GC_NORMAL) {
|
||||
nsJSContext::PokeShrinkGCBuffers();
|
||||
}
|
||||
#if(0)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
|
||||
nsCycleCollector_dispatchDeferredDeletion();
|
||||
@@ -2380,6 +2397,7 @@ mozilla::dom::StartupJSEnvironment()
|
||||
sLikelyShortLivingObjectsNeedingGC = 0;
|
||||
sPostGCEventsToConsole = false;
|
||||
sNeedsFullCC = false;
|
||||
sNeedsFullGC = false;
|
||||
sNeedsGCAfterCC = false;
|
||||
gNameSpaceManager = nullptr;
|
||||
sRuntime = nullptr;
|
||||
|
||||
@@ -205,10 +205,10 @@ public:
|
||||
return str && init(aContext, str);
|
||||
}
|
||||
|
||||
bool init(JSContext* aContext, jsid id)
|
||||
bool init(JSContext* aContext, jsid jid)
|
||||
{
|
||||
JS::Rooted<JS::Value> v(aContext);
|
||||
return JS_IdToValue(aContext, id, &v) && init(aContext, v);
|
||||
return JS_IdToValue(aContext, jid, &v) && init(aContext, v);
|
||||
}
|
||||
|
||||
bool init(const JS::Value &v);
|
||||
|
||||
@@ -1783,11 +1783,12 @@ GetCallbackFromCallbackObject(T& aObj)
|
||||
return GetCallbackFromCallbackObjectHelper<T>::Get(aObj);
|
||||
}
|
||||
|
||||
// id is a reserved word to our gcc.
|
||||
static inline bool
|
||||
AtomizeAndPinJSString(JSContext* cx, jsid& id, const char* chars)
|
||||
AtomizeAndPinJSString(JSContext* cx, jsid& jid, const char* chars)
|
||||
{
|
||||
if (JSString *str = ::JS_AtomizeAndPinString(cx, chars)) {
|
||||
id = INTERNED_STRING_TO_JSID(cx, str);
|
||||
jid = INTERNED_STRING_TO_JSID(cx, str);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -3106,26 +3107,26 @@ CreateGlobal(JSContext* aCx, T* aNative, nsWrapperCache* aCache,
|
||||
*/
|
||||
class PinnedStringId
|
||||
{
|
||||
jsid id;
|
||||
jsid jid;
|
||||
|
||||
public:
|
||||
PinnedStringId() : id(JSID_VOID) {}
|
||||
PinnedStringId() : jid(JSID_VOID) {}
|
||||
|
||||
bool init(JSContext *cx, const char *string) {
|
||||
JSString* str = JS_AtomizeAndPinString(cx, string);
|
||||
if (!str)
|
||||
return false;
|
||||
id = INTERNED_STRING_TO_JSID(cx, str);
|
||||
jid = INTERNED_STRING_TO_JSID(cx, str);
|
||||
return true;
|
||||
}
|
||||
|
||||
operator const jsid& () {
|
||||
return id;
|
||||
return jid;
|
||||
}
|
||||
|
||||
operator JS::Handle<jsid> () {
|
||||
/* This is safe because we have pinned the string. */
|
||||
return JS::Handle<jsid>::fromMarkedLocation(&id);
|
||||
return JS::Handle<jsid>::fromMarkedLocation(&jid);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -3893,9 +3893,25 @@ void HTMLMediaElement::ChangeReadyState(nsMediaReadyState aState)
|
||||
UpdateAudioChannelPlayingState();
|
||||
|
||||
// Handle raising of "waiting" event during seek (see 4.8.10.9)
|
||||
// or
|
||||
// 4.8.12.7 Ready states:
|
||||
// "If the previous ready state was HAVE_FUTURE_DATA or more, and the new
|
||||
// ready state is HAVE_CURRENT_DATA or less
|
||||
// If the media element was potentially playing before its readyState
|
||||
// attribute changed to a value lower than HAVE_FUTURE_DATA, and the element
|
||||
// has not ended playback, and playback has not stopped due to errors,
|
||||
// paused for user interaction, or paused for in-band content, the user agent
|
||||
// must queue a task to fire a simple event named timeupdate at the element,
|
||||
// and queue a task to fire a simple event named waiting at the element."
|
||||
// (bug 1298594)
|
||||
if (mPlayingBeforeSeek &&
|
||||
mReadyState < nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA) {
|
||||
DispatchAsyncEvent(NS_LITERAL_STRING("waiting"));
|
||||
} else if (oldState >= nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA &&
|
||||
mReadyState < nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA &&
|
||||
!Paused() && !Ended() && !mError) {
|
||||
FireTimeUpdate(false);
|
||||
DispatchAsyncEvent(NS_LITERAL_STRING("waiting"));
|
||||
}
|
||||
|
||||
if (oldState < nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA &&
|
||||
@@ -3905,9 +3921,12 @@ void HTMLMediaElement::ChangeReadyState(nsMediaReadyState aState)
|
||||
mLoadedDataFired = true;
|
||||
}
|
||||
|
||||
// bug 1298594
|
||||
#if(0)
|
||||
if (mReadyState == nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA) {
|
||||
mWaitingFired = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (oldState < nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA &&
|
||||
mReadyState >= nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA) {
|
||||
|
||||
@@ -410,9 +410,9 @@ public:
|
||||
return SetTokenList(nsGkAtoms::itemtype, aType);
|
||||
}
|
||||
NS_IMETHOD GetItemId(nsAString& aId) final override {
|
||||
nsString id;
|
||||
GetItemId(id);
|
||||
aId.Assign(id);
|
||||
nsString hid;
|
||||
GetItemId(hid);
|
||||
aId.Assign(hid);
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD SetItemId(const nsAString& aId) final override {
|
||||
|
||||
@@ -303,6 +303,10 @@ public:
|
||||
|
||||
bool mSentToCompositor;
|
||||
|
||||
// True if this video frame is reported as dropped
|
||||
// for missing the compositor deadline. (bug 1299018)
|
||||
bool mIsDropped = false;
|
||||
|
||||
VideoData(int64_t aOffset,
|
||||
int64_t aTime,
|
||||
int64_t aDuration,
|
||||
|
||||
@@ -85,13 +85,13 @@ namespace detail {
|
||||
// trying to decode the video, we'll skip decoding video up to the next
|
||||
// keyframe. We may increase this value for an individual decoder if we
|
||||
// encounter video frames which take a long time to decode.
|
||||
static const uint32_t LOW_AUDIO_USECS = 300000;
|
||||
static const uint32_t LOW_AUDIO_USECS = 1000000;
|
||||
|
||||
// If more than this many usecs of decoded audio is queued, we'll hold off
|
||||
// decoding more audio. If we increase the low audio threshold (see
|
||||
// LOW_AUDIO_USECS above) we'll also increase this value to ensure it's not
|
||||
// less than the low audio threshold.
|
||||
const int64_t AMPLE_AUDIO_USECS = 1000000;
|
||||
const int64_t AMPLE_AUDIO_USECS = 2000000;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -105,13 +105,13 @@ const int64_t NO_VIDEO_AMPLE_AUDIO_DIVISOR = 8;
|
||||
// If we have fewer than LOW_VIDEO_FRAMES decoded frames, and
|
||||
// we're not "prerolling video", we'll skip the video up to the next keyframe
|
||||
// which is at or after the current playback position.
|
||||
static const uint32_t LOW_VIDEO_FRAMES = 2;
|
||||
static const uint32_t LOW_VIDEO_FRAMES = 8;
|
||||
|
||||
// Threshold in usecs that used to check if we are low on decoded video.
|
||||
// If the last video frame's end time |mDecodedVideoEndTime| is more than
|
||||
// |LOW_VIDEO_THRESHOLD_USECS*mPlaybackRate| after the current clock in
|
||||
// Advanceframe(), the video decode is lagging, and we skip to next keyframe.
|
||||
static const int32_t LOW_VIDEO_THRESHOLD_USECS = 60000;
|
||||
static const int32_t LOW_VIDEO_THRESHOLD_USECS = 16000;
|
||||
|
||||
// Arbitrary "frame duration" when playing only audio.
|
||||
static const int AUDIO_DURATION_USECS = 40000;
|
||||
@@ -128,7 +128,7 @@ namespace detail {
|
||||
// ourselves to be running low on undecoded data. We determine how much
|
||||
// undecoded data we have remaining using the reader's GetBuffered()
|
||||
// implementation.
|
||||
static const int64_t LOW_DATA_THRESHOLD_USECS = 5000000;
|
||||
static const int64_t LOW_DATA_THRESHOLD_USECS = 20000000;
|
||||
|
||||
// LOW_DATA_THRESHOLD_USECS needs to be greater than AMPLE_AUDIO_USECS, otherwise
|
||||
// the skip-to-keyframe logic can activate when we're running low on data.
|
||||
@@ -174,8 +174,8 @@ static int64_t DurationToUsecs(TimeDuration aDuration) {
|
||||
return static_cast<int64_t>(aDuration.ToSeconds() * USECS_PER_S);
|
||||
}
|
||||
|
||||
static const uint32_t MIN_VIDEO_QUEUE_SIZE = 3;
|
||||
static const uint32_t MAX_VIDEO_QUEUE_SIZE = 10;
|
||||
static const uint32_t MIN_VIDEO_QUEUE_SIZE = 30;
|
||||
static const uint32_t MAX_VIDEO_QUEUE_SIZE = 30;
|
||||
static const uint32_t VIDEO_QUEUE_SEND_TO_COMPOSITOR_SIZE = 9999;
|
||||
|
||||
static uint32_t sVideoQueueDefaultSize = MAX_VIDEO_QUEUE_SIZE;
|
||||
@@ -456,6 +456,19 @@ void MediaDecoderStateMachine::DiscardStreamData()
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// TenFourFox. Don't try to push video frames that are already past.
|
||||
// This just wastes time in the compositor.
|
||||
while(true) {
|
||||
const MediaData* v = VideoQueue().PeekFront();
|
||||
FrameStatistics& frameStats = *mFrameStats;
|
||||
if (v && v->mTime < clockTime) {
|
||||
RefPtr<MediaData> releaseMe = VideoQueue().PopFront();
|
||||
frameStats.NotifyDecodedFrames(0, 0, 1); // Frame dropped
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool MediaDecoderStateMachine::HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs)
|
||||
@@ -532,6 +545,30 @@ MediaDecoderStateMachine::NeedToSkipToNextKeyframe()
|
||||
return false;
|
||||
}
|
||||
|
||||
// TenFourFox. On our slower systems the audio decode thread can run
|
||||
// wildly ahead of the video decode thread, which can cause a situation
|
||||
// where we get more than one keyframe behind and never catch up. In
|
||||
// that situation we should just dump the queued frames if we separate by
|
||||
// more than a certain interval because there's no point in displaying
|
||||
// them; they'll just hog the compositor which obviously can't keep up.
|
||||
// (This situation is mitigated by our extra code in DiscardStreamData(),
|
||||
// so this code here mostly runs as an emergency backup.)
|
||||
const MediaData* a = AudioQueue().PeekFront();
|
||||
const MediaData* v = VideoQueue().PeekFront();
|
||||
int64_t videoTime = 0;
|
||||
// Use the original AMPLE_AUDIO_USECS, since this is the minimum needed
|
||||
// to keep something approaching synchronized and we may well have the
|
||||
// audio that far ahead even if we're actually keeping up.
|
||||
if (a && v && (a->mTime > ((videoTime = v->mTime) + mozilla::detail::AMPLE_AUDIO_USECS))) {
|
||||
//if (mMediaSink && ((videoTime >> 20) & 1)) mMediaSink->Redraw();
|
||||
//fprintf(stderr, "TenFourFox detected loss of video sync @a=%lld v=%lld; resetting.\n", a->mTime, videoTime);
|
||||
FrameStatistics& frameStats = *mFrameStats;
|
||||
frameStats.NotifyDecodedFrames(0, 0, VideoQueue().GetSize());
|
||||
VideoQueue().Reset();
|
||||
StartBuffering(); // resync, see if we can get more data
|
||||
return true;
|
||||
}
|
||||
|
||||
// We'll skip the video decode to the next keyframe if we're low on
|
||||
// audio, or if we're low on video, provided we're not running low on
|
||||
// data to decode. If we're running low on downloaded data to decode,
|
||||
@@ -873,7 +910,7 @@ MediaDecoderStateMachine::MaybeFinishDecodeFirstFrame()
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideoSample)
|
||||
MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideoSample, TimeStamp aDecodeStartTime)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
RefPtr<MediaData> video(aVideoSample);
|
||||
@@ -917,7 +954,7 @@ MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideoSample)
|
||||
if (mReader->IsAsync()) {
|
||||
return;
|
||||
}
|
||||
TimeDuration decodeTime = TimeStamp::Now() - mVideoDecodeStartTime;
|
||||
TimeDuration decodeTime = TimeStamp::Now() - aDecodeStartTime;
|
||||
if (!IsDecodingFirstFrame() &&
|
||||
THRESHOLD_FACTOR * DurationToUsecs(decodeTime) > mLowAudioThresholdUsecs &&
|
||||
!HasLowUndecodedData())
|
||||
@@ -1757,24 +1794,31 @@ MediaDecoderStateMachine::RequestVideoData()
|
||||
// Time the video decode, so that if it's slow, we can increase our low
|
||||
// audio threshold to reduce the chance of an audio underrun while we're
|
||||
// waiting for a video decode to complete.
|
||||
mVideoDecodeStartTime = TimeStamp::Now();
|
||||
TimeStamp videoDecodeStartTime = TimeStamp::Now();
|
||||
|
||||
bool skipToNextKeyFrame = mSentFirstFrameLoadedEvent &&
|
||||
NeedToSkipToNextKeyframe();
|
||||
int64_t currentTime = mState == DECODER_STATE_SEEKING ? 0 : GetMediaTime();
|
||||
int64_t currentTime =
|
||||
mState == DECODER_STATE_SEEKING || !mSentFirstFrameLoadedEvent
|
||||
? 0 : GetMediaTime() + StartTime();
|
||||
|
||||
SAMPLE_LOG("Queueing video task - queued=%i, decoder-queued=%o, skip=%i, time=%lld",
|
||||
VideoQueue().GetSize(), mReader->SizeOfVideoQueueInFrames(), skipToNextKeyFrame,
|
||||
currentTime);
|
||||
|
||||
RefPtr<MediaDecoderStateMachine> self = this;
|
||||
if (mSentFirstFrameLoadedEvent) {
|
||||
mVideoDataRequest.Begin(
|
||||
InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
|
||||
&MediaDecoderReader::RequestVideoData,
|
||||
skipToNextKeyFrame, currentTime)
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnVideoDecoded,
|
||||
&MediaDecoderStateMachine::OnVideoNotDecoded));
|
||||
->Then(OwnerThread(), __func__,
|
||||
[self, videoDecodeStartTime] (MediaData* aVideoSample) {
|
||||
self->OnVideoDecoded(aVideoSample, videoDecodeStartTime);
|
||||
},
|
||||
[self] (MediaDecoderReader::NotDecodedReason aReason) {
|
||||
self->OnVideoNotDecoded(aReason);
|
||||
}));
|
||||
} else {
|
||||
mVideoDataRequest.Begin(
|
||||
InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
|
||||
@@ -1784,9 +1828,13 @@ MediaDecoderStateMachine::RequestVideoData()
|
||||
&StartTimeRendezvous::ProcessFirstSample<VideoDataPromise, MediaData::VIDEO_DATA>,
|
||||
&StartTimeRendezvous::FirstSampleRejected<MediaData::VIDEO_DATA>)
|
||||
->CompletionPromise()
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnVideoDecoded,
|
||||
&MediaDecoderStateMachine::OnVideoNotDecoded));
|
||||
->Then(OwnerThread(), __func__,
|
||||
[self, videoDecodeStartTime] (MediaData* aVideoSample) {
|
||||
self->OnVideoDecoded(aVideoSample, videoDecodeStartTime);
|
||||
},
|
||||
[self] (MediaDecoderReader::NotDecodedReason aReason) {
|
||||
self->OnVideoNotDecoded(aReason);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2661,6 +2709,13 @@ void MediaDecoderStateMachine::UpdateNextFrameStatus()
|
||||
|
||||
if (status != mNextFrameStatus) {
|
||||
DECODER_LOG("Changed mNextFrameStatus to %s", statusString);
|
||||
// bug 1298594
|
||||
if(status == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING ||
|
||||
status == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE) {
|
||||
// Ensure currentTime is up to date prior updating mNextFrameStatus so that
|
||||
// the MediaDecoderOwner fire events at correct currentTime.
|
||||
UpdatePlaybackPositionPeriodically();
|
||||
}
|
||||
}
|
||||
|
||||
mNextFrameStatus = status;
|
||||
|
||||
@@ -378,7 +378,7 @@ private:
|
||||
// TODO: Those callback function may receive demuxed-only data.
|
||||
// Need to figure out a suitable API name for this case.
|
||||
void OnAudioDecoded(MediaData* aAudioSample);
|
||||
void OnVideoDecoded(MediaData* aVideoSample);
|
||||
void OnVideoDecoded(MediaData* aVideoSample, TimeStamp aDecodeStartTime);
|
||||
void OnNotDecoded(MediaData::Type aType, MediaDecoderReader::NotDecodedReason aReason);
|
||||
void OnAudioNotDecoded(MediaDecoderReader::NotDecodedReason aReason)
|
||||
{
|
||||
@@ -813,11 +813,6 @@ private:
|
||||
bool HaveStartTime() { return mStartTimeRendezvous && mStartTimeRendezvous->HaveStartTime(); }
|
||||
int64_t StartTime() { return mStartTimeRendezvous->StartTime(); }
|
||||
|
||||
// Time at which the last video sample was requested. If it takes too long
|
||||
// before the sample arrives, we will increase the amount of audio we buffer.
|
||||
// This is necessary for legacy synchronous decoders to prevent underruns.
|
||||
TimeStamp mVideoDecodeStartTime;
|
||||
|
||||
// Queue of audio frames. This queue is threadsafe, and is accessed from
|
||||
// the audio, decoder, state machine, and main threads.
|
||||
MediaQueue<MediaData> mAudioQueue;
|
||||
|
||||
@@ -290,6 +290,11 @@ VideoSink::RenderVideoFrames(int32_t aMaxFrames,
|
||||
VideoData* frame = frames[i]->As<VideoData>();
|
||||
|
||||
frame->mSentToCompositor = true;
|
||||
// This frame is behind the current time. Let's report it as dropped.
|
||||
// bug 1299018
|
||||
if (aClockTime >= frame->GetEndTime()) {
|
||||
frame->mIsDropped = true;
|
||||
}
|
||||
|
||||
if (!frame->mImage || !frame->mImage->IsValid()) {
|
||||
continue;
|
||||
@@ -342,6 +347,7 @@ VideoSink::UpdateRenderedVideoFrames()
|
||||
// the current frame.
|
||||
NS_ASSERTION(clockTime >= 0, "Should have positive clock time.");
|
||||
|
||||
#if(0)
|
||||
int64_t remainingTime = -1;
|
||||
if (VideoQueue().GetSize() > 0) {
|
||||
RefPtr<MediaData> currentFrame = VideoQueue().PopFront();
|
||||
@@ -353,7 +359,8 @@ VideoSink::UpdateRenderedVideoFrames()
|
||||
break;
|
||||
}
|
||||
++framesRemoved;
|
||||
if (!currentFrame->As<VideoData>()->mSentToCompositor) {
|
||||
if (!currentFrame->As<VideoData>()->mSentToCompositor ||
|
||||
currentFrame->As<VideoData>()->mIsDropped /* bug 1299018 */) {
|
||||
mFrameStats.NotifyDecodedFrames(0, 0, 1);
|
||||
VSINK_LOG_V("discarding video frame mTime=%lld clock_time=%lld",
|
||||
currentFrame->mTime, clockTime);
|
||||
@@ -378,6 +385,45 @@ VideoSink::UpdateRenderedVideoFrames()
|
||||
TimeStamp target = nowTime + TimeDuration::FromMicroseconds(
|
||||
remainingTime / mAudioSink->GetPlaybackParams().mPlaybackRate);
|
||||
|
||||
#else
|
||||
// bug 1258870
|
||||
// Skip frames up to the playback position.
|
||||
int64_t lastDisplayedFrameEndTime = 0;
|
||||
while (VideoQueue().GetSize() > 0 &&
|
||||
clockTime >= VideoQueue().PeekFront()->GetEndTime()) { // bug 1298594
|
||||
RefPtr<MediaData> frame = VideoQueue().PopFront();
|
||||
if ( frame->As<VideoData>()->mSentToCompositor &&
|
||||
!frame->As<VideoData>()->mIsDropped /* bug 1299018 */) {
|
||||
lastDisplayedFrameEndTime = frame->GetEndTime();
|
||||
mFrameStats.NotifyPresentedFrame();
|
||||
} else {
|
||||
mFrameStats.NotifyDecodedFrames(0, 0, 1);
|
||||
VSINK_LOG_V("discarding video frame mTime=%lld clock_time=%lld",
|
||||
frame->mTime, clockTime);
|
||||
}
|
||||
}
|
||||
|
||||
// The presentation end time of the last video frame displayed is either
|
||||
// the end time of the current frame, or if we dropped all frames in the
|
||||
// queue, the end time of the last frame we removed from the queue.
|
||||
RefPtr<MediaData> currentFrame = VideoQueue().PeekFront();
|
||||
mVideoFrameEndTime = currentFrame ? currentFrame->GetEndTime() : lastDisplayedFrameEndTime;
|
||||
|
||||
RenderVideoFrames(mVideoQueueSendToCompositorSize, clockTime, nowTime);
|
||||
|
||||
// Get the timestamp of the next frame. Schedule the next update at
|
||||
// the start time of the next frame. If we don't have a next frame,
|
||||
// we will run render loops again upon incoming frames.
|
||||
nsTArray<RefPtr<MediaData>> frames;
|
||||
VideoQueue().GetFirstElements(2, &frames);
|
||||
if (frames.Length() < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t nextFrameTime = frames[1]->mTime;
|
||||
TimeStamp target = nowTime + TimeDuration::FromMicroseconds((nextFrameTime - clockTime) / mAudioSink->GetPlaybackParams().mPlaybackRate);
|
||||
#endif
|
||||
|
||||
RefPtr<VideoSink> self = this;
|
||||
mUpdateScheduler.Ensure(target, [self] () {
|
||||
self->UpdateRenderedVideoFramesByTimer();
|
||||
|
||||
@@ -1232,6 +1232,9 @@ TrackBuffersManager::CompleteCodedFrameProcessing()
|
||||
if (HasVideo()) {
|
||||
const auto& track = mVideoTracks.mBuffers.LastElement();
|
||||
MOZ_ASSERT(track.IsEmpty() || track[0]->mKeyframe);
|
||||
fprintf(stderr, "track %i timecode %lld /// track %i timecode %lld\n",
|
||||
track.Length()-2, track[(track.Length()-2)]->mTimecode,
|
||||
track.Length()-1, track[track.Length()-1]->mTimecode);
|
||||
for (uint32_t i = 1; i < track.Length(); i++) {
|
||||
MOZ_ASSERT((track[i-1]->mTrackInfo->GetID() == track[i]->mTrackInfo->GetID() && track[i-1]->mTimecode <= track[i]->mTimecode) ||
|
||||
track[i]->mKeyframe);
|
||||
@@ -1610,7 +1613,17 @@ TrackBuffersManager::InsertFrames(TrackBuffer& aSamples,
|
||||
intersection.Intersection(aIntervals);
|
||||
|
||||
if (intersection.Length()) {
|
||||
RemoveFrames(aIntervals, trackBuffer, trackBuffer.mNextInsertionIndex.refOr(0));
|
||||
if (aSamples[0]->mKeyframe) {
|
||||
// We are starting a new GOP, we do not have to worry about breaking an
|
||||
// existing current coded frame group. Reset the next insertion index
|
||||
// so the search for when to start our frames removal can be exhaustive.
|
||||
trackBuffer.mNextInsertionIndex.reset();
|
||||
}
|
||||
size_t index =
|
||||
RemoveFrames(aIntervals, trackBuffer, trackBuffer.mNextInsertionIndex.refOr(0));
|
||||
if (index) {
|
||||
trackBuffer.mNextInsertionIndex = Some(index);
|
||||
}
|
||||
}
|
||||
|
||||
// 16. Add the coded frame with the presentation timestamp, decode timestamp, and frame duration to the track buffer.
|
||||
@@ -1645,7 +1658,7 @@ TrackBuffersManager::InsertFrames(TrackBuffer& aSamples,
|
||||
trackBuffer.mSanitizedBufferedRanges += range;
|
||||
}
|
||||
|
||||
void
|
||||
size_t
|
||||
TrackBuffersManager::RemoveFrames(const TimeIntervals& aIntervals,
|
||||
TrackData& aTrackData,
|
||||
uint32_t aStartIndex)
|
||||
@@ -1664,7 +1677,7 @@ TrackBuffersManager::RemoveFrames(const TimeIntervals& aIntervals,
|
||||
// If highest end timestamp for track buffer is set and less than or equal to presentation timestamp:
|
||||
// Remove all coded frames from track buffer that have a presentation timestamp greater than or equal to highest end timestamp and less than frame end timestamp"
|
||||
for (uint32_t i = aStartIndex; i < data.Length(); i++) {
|
||||
MediaRawData* sample = data[i].get();
|
||||
const RefPtr<MediaRawData> sample = data[i];
|
||||
TimeInterval sampleInterval =
|
||||
TimeInterval(TimeUnit::FromMicroseconds(sample->mTime),
|
||||
TimeUnit::FromMicroseconds(sample->GetEndTime()));
|
||||
@@ -1677,13 +1690,13 @@ TrackBuffersManager::RemoveFrames(const TimeIntervals& aIntervals,
|
||||
}
|
||||
|
||||
if (firstRemovedIndex.isNothing()) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Remove decoding dependencies of the coded frames removed in the previous step:
|
||||
// Remove all coded frames between the coded frames removed in the previous step and the next random access point after those removed frames.
|
||||
for (uint32_t i = lastRemovedIndex + 1; i < data.Length(); i++) {
|
||||
MediaRawData* sample = data[i].get();
|
||||
const RefPtr<MediaRawData>& sample = data[i];
|
||||
if (sample->mKeyframe) {
|
||||
break;
|
||||
}
|
||||
@@ -1693,7 +1706,7 @@ TrackBuffersManager::RemoveFrames(const TimeIntervals& aIntervals,
|
||||
int64_t maxSampleDuration = 0;
|
||||
TimeIntervals removedIntervals;
|
||||
for (uint32_t i = firstRemovedIndex.ref(); i <= lastRemovedIndex; i++) {
|
||||
MediaRawData* sample = data[i].get();
|
||||
const RefPtr<MediaRawData> sample = data[i];
|
||||
TimeInterval sampleInterval =
|
||||
TimeInterval(TimeUnit::FromMicroseconds(sample->mTime),
|
||||
TimeUnit::FromMicroseconds(sample->GetEndTime()));
|
||||
@@ -1741,6 +1754,8 @@ TrackBuffersManager::RemoveFrames(const TimeIntervals& aIntervals,
|
||||
|
||||
data.RemoveElementsAt(firstRemovedIndex.ref(),
|
||||
lastRemovedIndex - firstRemovedIndex.ref() + 1);
|
||||
|
||||
return firstRemovedIndex.ref();
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -291,9 +291,12 @@ private:
|
||||
void InsertFrames(TrackBuffer& aSamples,
|
||||
const media::TimeIntervals& aIntervals,
|
||||
TrackData& aTrackData);
|
||||
void RemoveFrames(const media::TimeIntervals& aIntervals,
|
||||
TrackData& aTrackData,
|
||||
uint32_t aStartIndex);
|
||||
// Remove all frames and their dependencies contained in aIntervals.
|
||||
// Return the index at which frames were first removed or 0 if no frames
|
||||
// removed.
|
||||
size_t RemoveFrames(const media::TimeIntervals& aIntervals,
|
||||
TrackData& aTrackData,
|
||||
uint32_t aStartIndex);
|
||||
// Find index of sample. Return a negative value if not found.
|
||||
uint32_t FindSampleIndex(const TrackBuffer& aTrackBuffer,
|
||||
const media::TimeInterval& aInterval);
|
||||
|
||||
@@ -424,8 +424,13 @@ nsSMILAnimationFunction::InterpolateResult(const nsSMILValueArray& aValues,
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
MOZ_ASSERT(from, "NULL from-value during interpolation");
|
||||
MOZ_ASSERT(to, "NULL to-value during interpolation");
|
||||
#if(0)
|
||||
// Bogus assertion that keeps firing. intervalProgress is always within
|
||||
// this range even when it does fire, usually some critically small value
|
||||
// like -6.1679056923618572e-18.
|
||||
MOZ_ASSERT(0.0f <= intervalProgress && intervalProgress < 1.0f,
|
||||
"Interval progress should be in the range [0, 1)");
|
||||
#endif
|
||||
rv = from->Interpolate(*to, intervalProgress, aResult);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,6 +317,8 @@ nsSMILTimeContainer::NotifyTimeChange()
|
||||
// milestone elements. This is because any timed element with dependents and
|
||||
// with significant transitions yet to fire should have their next milestone
|
||||
// registered. Other timed elements don't matter.
|
||||
// bug 1321357
|
||||
#if(0)
|
||||
AutoRestore<bool> saveHolding(mHoldingEntries);
|
||||
mHoldingEntries = true;
|
||||
const MilestoneEntry* p = mMilestoneEntries.Elements();
|
||||
@@ -331,4 +333,24 @@ nsSMILTimeContainer::NotifyTimeChange()
|
||||
"queue of milestones");
|
||||
++p;
|
||||
}
|
||||
#else
|
||||
// Copy the timed elements to a separate array before calling
|
||||
// HandleContainerTimeChange on each of them in case doing so mutates
|
||||
// mMilestoneEntries.
|
||||
nsTArray<RefPtr<mozilla::dom::SVGAnimationElement>> elems;
|
||||
|
||||
{
|
||||
AutoRestore<bool> saveHolding(mHoldingEntries);
|
||||
mHoldingEntries = true;
|
||||
for (const MilestoneEntry* p = mMilestoneEntries.Elements();
|
||||
p < mMilestoneEntries.Elements() + mMilestoneEntries.Length();
|
||||
++p) {
|
||||
elems.AppendElement(p->mTimebase.get());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& elem : elems) {
|
||||
elem->TimedElement().HandleContainerTimeChange();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -94,7 +94,8 @@ using mozilla::dom::indexedDB::IndexedDatabaseManager;
|
||||
#define WORKER_DEFAULT_ALLOCATION_THRESHOLD 30
|
||||
|
||||
// Half the size of the actual C stack, to be safe.
|
||||
#define WORKER_CONTEXT_NATIVE_STACK_LIMIT 128 * sizeof(size_t) * 1024
|
||||
// We need a little larger than regular Firefox.
|
||||
#define WORKER_CONTEXT_NATIVE_STACK_LIMIT 512 * sizeof(size_t) * 1024
|
||||
|
||||
// The maximum number of threads to use for workers, overridable via pref.
|
||||
#define MAX_WORKERS_PER_DOMAIN 10
|
||||
|
||||
@@ -391,7 +391,7 @@ nsXULPrototypeCache::GetOutputStream(nsIURI* uri, nsIObjectOutputStream** stream
|
||||
nsCOMPtr<nsIStorageStream> storageStream;
|
||||
bool found = mOutputStreamTable.Get(uri, getter_AddRefs(storageStream));
|
||||
if (found) {
|
||||
objectOutput = do_CreateInstance("mozilla.org/binaryoutputstream;1");
|
||||
objectOutput = do_CreateInstance("@mozilla.org/binaryoutputstream;1");
|
||||
if (!objectOutput) return NS_ERROR_OUT_OF_MEMORY;
|
||||
nsCOMPtr<nsIOutputStream> outputStream
|
||||
= do_QueryInterface(storageStream);
|
||||
|
||||
@@ -12,10 +12,17 @@
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
#if defined WORDS_BIGENDIAN || defined IS_BIG_ENDIAN || defined __BIG_ENDIAN__
|
||||
const ptrdiff_t B8G8R8A8_COMPONENT_BYTEOFFSET_B = 3;
|
||||
const ptrdiff_t B8G8R8A8_COMPONENT_BYTEOFFSET_G = 2;
|
||||
const ptrdiff_t B8G8R8A8_COMPONENT_BYTEOFFSET_R = 1;
|
||||
const ptrdiff_t B8G8R8A8_COMPONENT_BYTEOFFSET_A = 0;
|
||||
#else
|
||||
const ptrdiff_t B8G8R8A8_COMPONENT_BYTEOFFSET_B = 0;
|
||||
const ptrdiff_t B8G8R8A8_COMPONENT_BYTEOFFSET_G = 1;
|
||||
const ptrdiff_t B8G8R8A8_COMPONENT_BYTEOFFSET_R = 2;
|
||||
const ptrdiff_t B8G8R8A8_COMPONENT_BYTEOFFSET_A = 3;
|
||||
#endif
|
||||
|
||||
class FilterProcessing
|
||||
{
|
||||
|
||||
@@ -328,6 +328,7 @@ hb_blob_is_immutable (hb_blob_t *blob)
|
||||
unsigned int
|
||||
hb_blob_get_length (hb_blob_t *blob)
|
||||
{
|
||||
if (!blob) return 0; // wallpaper TenFourFox issue 309
|
||||
return blob->length;
|
||||
}
|
||||
|
||||
|
||||
@@ -743,6 +743,8 @@ nsIntRegion nsRegion::ScaleToNearestPixels (float aScaleX, float aScaleY,
|
||||
nsIntRegion nsRegion::ScaleToOutsidePixels (float aScaleX, float aScaleY,
|
||||
nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
// bug 1247979
|
||||
#if(0)
|
||||
nsIntRegion result;
|
||||
nsRegionRectIterator rgnIter(*this);
|
||||
const nsRect* currentRect;
|
||||
@@ -752,6 +754,27 @@ nsIntRegion nsRegion::ScaleToOutsidePixels (float aScaleX, float aScaleY,
|
||||
result.Or(result, deviceRect);
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
// make a copy of the region so that we can mutate it inplace
|
||||
nsRegion region = *this;
|
||||
int n;
|
||||
pixman_box32_t *boxes = pixman_region32_rectangles(®ion.mImpl, &n);
|
||||
boxes = pixman_region32_rectangles(®ion.mImpl, &n);
|
||||
for (int i=0; i<n; i++) {
|
||||
nsRect rect = BoxToRect(boxes[i]);
|
||||
mozilla::gfx::IntRect irect = rect.ScaleToOutsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
|
||||
boxes[i] = RectToBox(irect);
|
||||
}
|
||||
|
||||
pixman_region32_t pixmanRegion;
|
||||
// This will union all of the rectangles and runs in about O(n lg(n))
|
||||
pixman_region32_init_rects(&pixmanRegion, boxes, n);
|
||||
|
||||
nsIntRegion iRegion;
|
||||
pixman_region32_fini(&iRegion.mImpl.mImpl);
|
||||
iRegion.mImpl.mImpl = pixmanRegion;
|
||||
return iRegion;
|
||||
#endif
|
||||
}
|
||||
|
||||
nsIntRegion nsRegion::ScaleToInsidePixels (float aScaleX, float aScaleY,
|
||||
|
||||
@@ -1320,6 +1320,8 @@ gfxFontFamily::FindAllFontsForStyle(const gfxFontStyle& aFontStyle,
|
||||
uint8_t faceIndex = (wantItalic ? kItalicMask : 0) |
|
||||
(wantBold ? kBoldMask : 0);
|
||||
|
||||
// Paranoia checks here
|
||||
if (faceIndex < mAvailableFonts.Length()) {
|
||||
// if the desired style is available, return it directly
|
||||
fe = mAvailableFonts[faceIndex];
|
||||
if (fe) {
|
||||
@@ -1327,6 +1329,7 @@ gfxFontFamily::FindAllFontsForStyle(const gfxFontStyle& aFontStyle,
|
||||
aFontEntryList.AppendElement(fe);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// order to check fallback faces in a simple family, depending on requested style
|
||||
static const uint8_t simpleFallbacks[4][3] = {
|
||||
@@ -1339,6 +1342,7 @@ gfxFontFamily::FindAllFontsForStyle(const gfxFontStyle& aFontStyle,
|
||||
|
||||
for (uint8_t trial = 0; trial < 3; ++trial) {
|
||||
// check remaining faces in order of preference to find the first that actually exists
|
||||
if (order[trial] < mAvailableFonts.Length())
|
||||
fe = mAvailableFonts[order[trial]];
|
||||
if (fe) {
|
||||
aNeedsSyntheticBold =
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
#include "opentype-sanitiser.h"
|
||||
#include "ots-memory-stream.h"
|
||||
|
||||
#include "nsICryptoHash.h"
|
||||
#include "nsNetCID.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
mozilla::LogModule*
|
||||
@@ -51,11 +54,11 @@ public:
|
||||
free(mPtr);
|
||||
}
|
||||
|
||||
// return the buffer, and give up ownership of it
|
||||
// so the caller becomes responsible to call free
|
||||
// when finished with it
|
||||
// Return the buffer, resized to fit its contents (as it may have been
|
||||
// over-allocated during growth), and give up ownership of it so the
|
||||
// caller becomes responsible to call free() when finished with it.
|
||||
void* forget() {
|
||||
void* p = mPtr;
|
||||
void* p = moz_xrealloc(mPtr, mOff);
|
||||
mPtr = nullptr;
|
||||
return p;
|
||||
}
|
||||
@@ -176,7 +179,7 @@ public:
|
||||
virtual ots::TableAction GetTableAction(uint32_t aTag) override {
|
||||
// Preserve Graphite, color glyph and SVG tables
|
||||
if (
|
||||
#ifdef RELEASE_BUILD // For Beta/Release, also allow OT Layout tables through
|
||||
#if(1) // def RELEASE_BUILD // For Beta/Release, also allow OT Layout tables through
|
||||
// unchecked, and rely on harfbuzz to handle them safely.
|
||||
aTag == TRUETYPE_TAG('G', 'D', 'E', 'F') ||
|
||||
aTag == TRUETYPE_TAG('G', 'P', 'O', 'S') ||
|
||||
@@ -246,14 +249,14 @@ gfxUserFontEntry::SanitizeOpenTypeData(const uint8_t* aData,
|
||||
ExpandingMemoryStream output(lengthHint, 1024 * 1024 * 256);
|
||||
|
||||
gfxOTSContext otsContext(this);
|
||||
|
||||
if (otsContext.Process(&output, aData, aLength)) {
|
||||
aSaneLength = output.Tell();
|
||||
return static_cast<uint8_t*>(output.forget());
|
||||
} else {
|
||||
if (!otsContext.Process(&output, aData, aLength)) {
|
||||
// Failed to decode/sanitize the font, so discard it.
|
||||
aSaneLength = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aSaneLength = output.Tell();
|
||||
return static_cast<const uint8_t*>(output.forget());
|
||||
}
|
||||
|
||||
void
|
||||
@@ -376,6 +379,47 @@ CopyWOFFMetadata(const uint8_t* aFontData,
|
||||
*aMetaOrigLen = woff->metaOrigLen;
|
||||
}
|
||||
|
||||
// TenFourFox issue 311: check for bad data: fonts.
|
||||
static nsresult
|
||||
HashDataFontURL(nsIURI *aFontURI)
|
||||
{
|
||||
nsCString spec;
|
||||
nsresult rv = aFontURI->GetAsciiSpec(spec);
|
||||
if (NS_FAILED(rv) || spec.Length() < 8)
|
||||
return NS_ERROR_FAILURE; // can't be valid
|
||||
|
||||
// Hash the data URL.
|
||||
nsAutoCString fullHash;
|
||||
nsCOMPtr<nsICryptoHash> crypto = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = crypto->Init(nsICryptoHash::SHA1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = crypto->Update(reinterpret_cast<const uint8_t*>(spec.BeginReading()),
|
||||
spec.Length());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = crypto->Finish(true, fullHash);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
#if(0)
|
||||
fprintf(stderr, "URL: %s -> hash: %s\n", spec.get(), fullHash.get());
|
||||
#endif
|
||||
if (0 ||
|
||||
fullHash.Equals("7bEdowSouswJQEDqXZ1HyJ/nAVU=") ||
|
||||
fullHash.Equals("5L3jz1VLjOoygPOTw9UX/2M+Wh4=") ||
|
||||
fullHash.Equals("ViO/mt90XnXJm7kgYJNIa4w2u7M=") ||
|
||||
fullHash.Equals("s3Hh0b18aP3UvzzEIuczok5AKOQ=") ||
|
||||
fullHash.Equals("bw95WsPe1C3i6ywQkwLd7tZUVT4=") ||
|
||||
fullHash.Equals("YFKGFitMqlw1z0z+kITI2oiGjUM=") ||
|
||||
fullHash.Equals("d0fwa3E00upl5Vj+C8K+NFhfiNQ=") ||
|
||||
0) {
|
||||
fprintf(stderr, "Warning: TenFourFox blocking ATSUI-incompatible data: font (with SHA-1 URL hash of %s).\n", fullHash.get());
|
||||
return NS_ERROR_FAILURE; // bad font
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
fprintf(stderr, "hash failed: %08x\n", (uint32_t)rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
gfxUserFontEntry::LoadNextSrc()
|
||||
{
|
||||
@@ -494,6 +538,8 @@ gfxUserFontEntry::LoadNextSrc()
|
||||
uint32_t bufferLength = 0;
|
||||
|
||||
// sync load font immediately
|
||||
rv = HashDataFontURL(currSrc.mURI);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = mFontSet->SyncLoadFontData(this, &currSrc, buffer,
|
||||
bufferLength);
|
||||
|
||||
@@ -682,6 +728,7 @@ gfxUserFontEntry::LoadPlatformFont(const uint8_t* aFontData, uint32_t& aLength)
|
||||
NS_ConvertUTF16toUTF8(mFamilyName).get(),
|
||||
this, uint32_t(mFontSet->mGeneration), fontCompressionRatio));
|
||||
}
|
||||
fe->AddRef(); // BADFIX???
|
||||
mPlatformFontEntry = fe;
|
||||
SetLoadState(STATUS_LOADED);
|
||||
gfxUserFontSet::UserFontCache::CacheFont(fe);
|
||||
@@ -775,6 +822,7 @@ gfxUserFontEntry::GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult)
|
||||
gfxUserFontSet::gfxUserFontSet()
|
||||
: mFontFamilies(4),
|
||||
mLocalRulesUsed(false),
|
||||
mRebuildLocalRules(false),
|
||||
mDownloadCount(0),
|
||||
mDownloadSize(0)
|
||||
{
|
||||
@@ -944,6 +992,7 @@ void
|
||||
gfxUserFontSet::RebuildLocalRules()
|
||||
{
|
||||
if (mLocalRulesUsed) {
|
||||
mRebuildLocalRules = true;
|
||||
DoRebuildUserFontSet();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,6 +523,9 @@ protected:
|
||||
// true when local names have been looked up, false otherwise
|
||||
bool mLocalRulesUsed;
|
||||
|
||||
// true when rules using local names need to be redone
|
||||
bool mRebuildLocalRules;
|
||||
|
||||
// performance stats
|
||||
uint32_t mDownloadCount;
|
||||
uint64_t mDownloadSize;
|
||||
|
||||
@@ -31,7 +31,7 @@ nsresult nsUnicodeDecodeHelper::ConvertByTable(
|
||||
while ((srcLen > 0) && (dest < destEnd)) {
|
||||
bool charFound;
|
||||
if (aScanClass == uMultibytesCharset) {
|
||||
NS_ASSERTION(aShiftInTable, "shift table missing");
|
||||
//NS_ASSERTION(aShiftInTable, "shift table missing");
|
||||
charFound = uScanShift(aShiftInTable, nullptr, (uint8_t *)src,
|
||||
reinterpret_cast<uint16_t*>(&med), srcLen,
|
||||
(uint32_t *)&bcr);
|
||||
|
||||
@@ -54,13 +54,13 @@ class IDMap {
|
||||
// the list. The caller either must generate all unique IDs itself and use
|
||||
// this function, or allow this object to generate IDs and call Add. These
|
||||
// two methods may not be mixed, or duplicate IDs may be generated
|
||||
void AddWithID(T* data, int32_t id) {
|
||||
DCHECK(data_.find(id) == data_.end()) << "Inserting duplicate item";
|
||||
data_[id] = data;
|
||||
void AddWithID(T* data, int32_t cid) {
|
||||
DCHECK(data_.find(cid) == data_.end()) << "Inserting duplicate item";
|
||||
data_[cid] = data;
|
||||
}
|
||||
|
||||
void Remove(int32_t id) {
|
||||
iterator i = data_.find(id);
|
||||
void Remove(int32_t cid) {
|
||||
iterator i = data_.find(cid);
|
||||
if (i == data_.end()) {
|
||||
NOTREACHED() << "Attempting to remove an item not in the list";
|
||||
return;
|
||||
@@ -84,8 +84,8 @@ class IDMap {
|
||||
return false;
|
||||
}
|
||||
|
||||
T* Lookup(int32_t id) const {
|
||||
const_iterator i = data_.find(id);
|
||||
T* Lookup(int32_t cid) const {
|
||||
const_iterator i = data_.find(cid);
|
||||
if (i == data_.end())
|
||||
return NULL;
|
||||
return i->second;
|
||||
|
||||
+8
-1
@@ -2551,7 +2551,14 @@ insert_common_timeout_inorder(struct common_timeout_list *ctl,
|
||||
* there's some wacky threading issue going on, we do a search from
|
||||
* the end of 'ev' to find the right insertion point.
|
||||
*/
|
||||
TAILQ_FOREACH_REVERSE(e, &ctl->events,
|
||||
|
||||
// 10.4's queue.h is wrong here.
|
||||
#define SM_TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||
for((var) = TAILQ_LAST(head, headname); \
|
||||
(var) != NULL ; \
|
||||
(var) = TAILQ_PREV(var, headname, field))
|
||||
|
||||
SM_TAILQ_FOREACH_REVERSE(e, &ctl->events,
|
||||
event_list, ev_timeout_pos.ev_next_with_common_timeout) {
|
||||
/* This timercmp is a little sneaky, since both ev and e have
|
||||
* magic values in tv_usec. Fortunately, they ought to have
|
||||
|
||||
+19
@@ -137,6 +137,25 @@ kq_init(struct event_base *base)
|
||||
goto err;
|
||||
kqueueop->events_size = kqueueop->changes_size = NEVENT;
|
||||
|
||||
/* Check for Mac OS X kqueue bug. */
|
||||
/* This reverts M1304266 and Chromium bug 626534. */
|
||||
memset(&kqueueop->changes[0], 0, sizeof kqueueop->changes[0]);
|
||||
kqueueop->changes[0].ident = -1;
|
||||
kqueueop->changes[0].filter = EVFILT_READ;
|
||||
kqueueop->changes[0].flags = EV_ADD;
|
||||
/*
|
||||
* If kqueue works, then kevent will succeed, and it will
|
||||
* stick an error in events[0]. If kqueue is broken, then
|
||||
* kevent will fail.
|
||||
*/
|
||||
if (kevent(kq,
|
||||
kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 ||
|
||||
(int)kqueueop->events[0].ident != -1 ||
|
||||
kqueueop->events[0].flags != EV_ERROR) {
|
||||
event_warn("%s: detected broken kqueue; not using.", __func__);
|
||||
goto err;
|
||||
}
|
||||
|
||||
base->evsigsel = &kqsigops;
|
||||
|
||||
return (kqueueop);
|
||||
|
||||
@@ -71,7 +71,7 @@ private:
|
||||
};
|
||||
|
||||
inline XPCShellEnvironment*
|
||||
Environment(Handle<JSObject*> global)
|
||||
Environment(JS::Handle<JSObject*> global)
|
||||
{
|
||||
AutoSafeJSContext cx;
|
||||
JSAutoCompartment ac(cx, global);
|
||||
|
||||
@@ -144,6 +144,7 @@ namespace JS {
|
||||
\
|
||||
_(ICNameStub_ReadSlot) \
|
||||
_(ICNameStub_CallGetter) \
|
||||
_(ICNameStub_TypeOfNoProperty) \
|
||||
\
|
||||
_(CantInlineGeneric) \
|
||||
_(CantInlineNoTarget) \
|
||||
|
||||
@@ -412,6 +412,11 @@ a scope chain object.
|
||||
An inline cache element which loads a bare variable name by calling a
|
||||
getter function on the global object.
|
||||
|
||||
### ICNameStub_TypeOfNoProperty
|
||||
|
||||
An inline cache element which loads undefined for the type
|
||||
of a missing property.
|
||||
|
||||
## Call Inlining Outcomes
|
||||
|
||||
Optimization outcomes of attempts to inline function calls.
|
||||
|
||||
@@ -102,6 +102,7 @@ js::Nursery::init(uint32_t maxNurseryBytes)
|
||||
setCurrentChunk(0);
|
||||
updateDecommittedRegion();
|
||||
|
||||
#if DEBUG
|
||||
char* env = getenv("JS_GC_PROFILE_NURSERY");
|
||||
if (env) {
|
||||
if (0 == strcmp(env, "help")) {
|
||||
@@ -112,6 +113,7 @@ js::Nursery::init(uint32_t maxNurseryBytes)
|
||||
enableProfiling_ = true;
|
||||
profileThreshold_ = atoi(env);
|
||||
}
|
||||
#endif
|
||||
|
||||
MOZ_ASSERT(isEnabled());
|
||||
return true;
|
||||
@@ -407,9 +409,15 @@ js::TenuringTracer::TenuringTracer(JSRuntime* rt, Nursery* nursery)
|
||||
{
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
#define TIME_START(name) int64_t timestampStart_##name = enableProfiling_ ? PRMJ_Now() : 0
|
||||
#define TIME_END(name) int64_t timestampEnd_##name = enableProfiling_ ? PRMJ_Now() : 0
|
||||
#define TIME_TOTAL(name) (timestampEnd_##name - timestampStart_##name)
|
||||
#else
|
||||
#define TIME_START(name)
|
||||
#define TIME_END(name)
|
||||
#define TIME_TOTAL(name)
|
||||
#endif
|
||||
|
||||
void
|
||||
js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList* pretenureGroups)
|
||||
@@ -437,7 +445,9 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList
|
||||
|
||||
TraceMinorGCStart();
|
||||
|
||||
#if DEBUG
|
||||
int64_t timestampStart_total = PRMJ_Now();
|
||||
#endif
|
||||
|
||||
AutoTraceSession session(rt, JS::HeapState::MinorCollecting);
|
||||
AutoStopVerifyingBarriers av(rt, false);
|
||||
@@ -568,6 +578,9 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList
|
||||
if (rt->gc.usage.gcBytes() >= rt->gc.tunables.gcMaxBytes())
|
||||
disable();
|
||||
|
||||
#ifndef DEBUG
|
||||
TraceMinorGCEnd();
|
||||
#else
|
||||
int64_t totalTime = PRMJ_Now() - timestampStart_total;
|
||||
rt->addTelemetry(JS_TELEMETRY_GC_MINOR_US, totalTime);
|
||||
rt->addTelemetry(JS_TELEMETRY_GC_MINOR_REASON, reason);
|
||||
@@ -618,6 +631,7 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList
|
||||
fprintf(stderr, "\n");
|
||||
#undef FMT
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef TIME_START
|
||||
|
||||
@@ -911,6 +911,7 @@ Statistics::endGC()
|
||||
for (int i = 0; i < PHASE_LIMIT; i++)
|
||||
phaseTotals[j][i] += phaseTimes[j][i];
|
||||
|
||||
#if DEBUG
|
||||
int64_t total, longest;
|
||||
gcDuration(&total, &longest);
|
||||
|
||||
@@ -938,6 +939,7 @@ Statistics::endGC()
|
||||
|
||||
if (fp)
|
||||
printStats();
|
||||
#endif
|
||||
|
||||
// Clear the timers at the end of a GC because we accumulate time in
|
||||
// between GCs for some (which come before PHASE_GC_BEGIN in the list.)
|
||||
@@ -968,7 +970,7 @@ Statistics::beginSlice(const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
|
||||
return;
|
||||
}
|
||||
|
||||
runtime->addTelemetry(JS_TELEMETRY_GC_REASON, reason);
|
||||
//runtime->addTelemetry(JS_TELEMETRY_GC_REASON, reason);
|
||||
|
||||
// Slice callbacks should only fire for the outermost level.
|
||||
if (gcDepth == 1) {
|
||||
@@ -987,6 +989,7 @@ Statistics::endSlice()
|
||||
slices.back().endTimestamp = JS_GetCurrentEmbedderTime();
|
||||
slices.back().endFaults = GetPageFaultCount();
|
||||
|
||||
#if DEBUG
|
||||
int64_t sliceTime = slices.back().end - slices.back().start;
|
||||
runtime->addTelemetry(JS_TELEMETRY_GC_SLICE_MS, t(sliceTime));
|
||||
runtime->addTelemetry(JS_TELEMETRY_GC_RESET, !!slices.back().resetReason);
|
||||
@@ -1003,6 +1006,7 @@ Statistics::endSlice()
|
||||
runtime->addTelemetry(JS_TELEMETRY_GC_SLOW_PHASE, phases[longest].telemetryBucket);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool last = !runtime->gc.isIncrementalGCInProgress();
|
||||
|
||||
@@ -91,8 +91,19 @@ BaselineCompiler::compile()
|
||||
AutoTraceLog logScript(logger, scriptEvent);
|
||||
AutoTraceLog logCompile(logger, TraceLogger_BaselineCompilation);
|
||||
|
||||
#if(0)
|
||||
if (!script->ensureHasTypes(cx) || !script->ensureHasAnalyzedArgsUsage(cx))
|
||||
return Method_Error;
|
||||
#else
|
||||
// This makes a non-trivial difference in Baseline-heavy code.
|
||||
if (!script->ensureHasTypes(cx))
|
||||
return Method_Error;
|
||||
|
||||
if (script->argumentsHasVarBinding()) {
|
||||
if (!script->ensureHasAnalyzedArgsUsage(cx))
|
||||
return Method_Error;
|
||||
}
|
||||
#endif
|
||||
|
||||
// When a Debugger set the collectCoverageInfo flag, we recompile baseline
|
||||
// scripts without entering the interpreter again. We have to create the
|
||||
|
||||
@@ -8703,6 +8703,7 @@ IonBuilder::pushScalarLoadFromTypedObject(MDefinition* obj,
|
||||
elemType,
|
||||
DoesNotRequireMemoryBarrier,
|
||||
adjustment);
|
||||
load->setTarget(MLoadUnboxedScalar::TypedArrayTarget);
|
||||
current->add(load);
|
||||
current->push(load);
|
||||
|
||||
@@ -9549,6 +9550,7 @@ IonBuilder::jsop_getelem_typed(MDefinition* obj, MDefinition* index,
|
||||
|
||||
// Load the element.
|
||||
MLoadUnboxedScalar* load = MLoadUnboxedScalar::New(alloc(), elements, index, arrayType);
|
||||
load->setTarget(MLoadUnboxedScalar::TypedArrayTarget);
|
||||
current->add(load);
|
||||
current->push(load);
|
||||
|
||||
@@ -10094,6 +10096,7 @@ IonBuilder::jsop_setelem_typed(Scalar::Type arrayType,
|
||||
MStoreUnboxedScalar* store =
|
||||
MStoreUnboxedScalar::New(alloc(), elements, id, toWrite, arrayType,
|
||||
MStoreUnboxedScalar::TruncateInput);
|
||||
store->setTarget(MStoreUnboxedScalar::TypedArrayTarget);
|
||||
ins = store;
|
||||
}
|
||||
|
||||
|
||||
@@ -4103,7 +4103,7 @@ GenerateGetTypedOrUnboxedArrayElement(JSContext* cx, MacroAssembler& masm,
|
||||
|
||||
if (IsAnyTypedArray(array)) {
|
||||
// Guard on the initialized length.
|
||||
Address length(object, TypedArrayObject::lengthOffset());
|
||||
Address length(object, TypedArrayObject::lengthOffset() + NUNBOX32_PAYLOAD_OFFSET);
|
||||
masm.branch32(Assembler::BelowOrEqual, length, indexReg, &failures);
|
||||
|
||||
// Save the object register on the stack in case of failure.
|
||||
@@ -4927,6 +4927,62 @@ IsCacheableNameCallGetter(HandleObject scopeChain, HandleObject obj, HandleObjec
|
||||
IsCacheableGetPropCallScripted(obj, holder, shape);
|
||||
}
|
||||
|
||||
bool
|
||||
NameIC::attachTypeOfNoProperty(JSContext* cx, HandleScript outerScript, IonScript* ion,
|
||||
HandleObject scopeChain)
|
||||
{
|
||||
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
|
||||
Label failures;
|
||||
StubAttacher attacher(*this);
|
||||
|
||||
Register scratchReg = outputReg().valueReg().scratchReg();
|
||||
|
||||
masm.movePtr(scopeChainReg(), scratchReg);
|
||||
|
||||
// Generate scope chain guards.
|
||||
// Since the property was not defined on any object, iterate until reaching the global.
|
||||
JSObject* tobj = scopeChain;
|
||||
while (true) {
|
||||
GenerateScopeChainGuard(masm, tobj, scratchReg, nullptr, &failures);
|
||||
|
||||
if (tobj->is<GlobalObject>())
|
||||
break;
|
||||
|
||||
// Load the next link.
|
||||
tobj = &tobj->as<ScopeObject>().enclosingScope();
|
||||
masm.extractObject(Address(scratchReg, ScopeObject::offsetOfEnclosingScope()), scratchReg);
|
||||
}
|
||||
|
||||
masm.moveValue(UndefinedValue(), outputReg().valueReg());
|
||||
attacher.jumpRejoin(masm);
|
||||
|
||||
masm.bind(&failures);
|
||||
attacher.jumpNextStub(masm);
|
||||
|
||||
return linkAndAttachStub(cx, masm, attacher, ion, "generic",
|
||||
JS::TrackedOutcome::ICNameStub_TypeOfNoProperty);
|
||||
}
|
||||
|
||||
static bool
|
||||
IsCacheableNameNoProperty(HandleObject scopeChain, HandleObject obj,
|
||||
HandleObject holder, HandleShape shape, jsbytecode* pc,
|
||||
NameIC& cache)
|
||||
{
|
||||
if (cache.isTypeOf() && !shape) {
|
||||
MOZ_ASSERT(!obj);
|
||||
MOZ_ASSERT(!holder);
|
||||
MOZ_ASSERT(scopeChain);
|
||||
|
||||
// Assert those extra things checked by IsCacheableNoProperty().
|
||||
MOZ_ASSERT(cache.outputReg().hasValue());
|
||||
MOZ_ASSERT(pc != nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
NameIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex, HandleObject scopeChain,
|
||||
MutableHandleValue vp)
|
||||
@@ -4969,6 +5025,9 @@ NameIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex, Handl
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else if (IsCacheableNameNoProperty(scopeChain, obj, holder, shape, pc, cache)) {
|
||||
if (!cache.attachTypeOfNoProperty(cx, outerScript, ion, scopeChain))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -791,6 +791,9 @@ class NameIC : public IonCache
|
||||
HandleObject scopeChain, HandleObject obj, HandleObject holder,
|
||||
HandleShape shape, void* returnAddr);
|
||||
|
||||
bool attachTypeOfNoProperty(JSContext* cx, HandleScript outerScript, IonScript* ion,
|
||||
HandleObject scopeChain);
|
||||
|
||||
static bool
|
||||
update(JSContext* cx, HandleScript outerScript, size_t cacheIndex, HandleObject scopeChain,
|
||||
MutableHandleValue vp);
|
||||
|
||||
@@ -46,7 +46,7 @@ OptimizationInfo::initNormalOptimizationInfo()
|
||||
inliningMaxCallerBytecodeLength_ = 1500;
|
||||
maxInlineDepth_ = 3;
|
||||
scalarReplacement_ = true;
|
||||
smallFunctionMaxInlineDepth_ = 10;
|
||||
smallFunctionMaxInlineDepth_ = 13;
|
||||
compilerWarmUpThreshold_ = CompilerWarmupThreshold;
|
||||
inliningWarmUpThresholdFactor_ = 0.125;
|
||||
inliningRecompileThresholdFactor_ = 4;
|
||||
|
||||
@@ -490,6 +490,8 @@ jit::CheckLogging()
|
||||
EnableIonDebugSyncLogging();
|
||||
if (ContainsFlag(env, "profiling"))
|
||||
EnableChannel(JitSpew_Profiling);
|
||||
if (ContainsFlag(env, "irregexp"))
|
||||
EnableChannel(JitSpew_Irregexp);
|
||||
if (ContainsFlag(env, "trackopts"))
|
||||
EnableChannel(JitSpew_OptimizationTracking);
|
||||
if (ContainsFlag(env, "all"))
|
||||
|
||||
@@ -92,7 +92,8 @@ namespace jit {
|
||||
/* Debug info about snapshots */ \
|
||||
_(IonSnapshots) \
|
||||
/* Generated inline cache stubs */ \
|
||||
_(IonIC)
|
||||
_(IonIC) \
|
||||
_(Irregexp)
|
||||
|
||||
enum JitSpewChannel {
|
||||
#define JITSPEW_CHANNEL(name) JitSpew_##name,
|
||||
|
||||
@@ -4823,6 +4823,20 @@ MTableSwitch::foldsTo(TempAllocator& alloc)
|
||||
if (numSuccessors() == 1 || (op->type() != MIRType_Value && !IsNumberType(op->type())))
|
||||
return MGoto::New(alloc, getDefault());
|
||||
|
||||
if (op->isConstantValue()) {
|
||||
Value v = op->constantValue();
|
||||
if (v.isInt32()) {
|
||||
int32_t i = v.toInt32() - low_;
|
||||
MBasicBlock* target;
|
||||
if (size_t(i) < numCases())
|
||||
target = getCase(size_t(i));
|
||||
else
|
||||
target = getDefault();
|
||||
MOZ_ASSERT(target);
|
||||
return MGoto::New(alloc, target);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -9545,6 +9545,13 @@ class MLoadUnboxedScalar
|
||||
bool requiresBarrier_;
|
||||
int32_t offsetAdjustment_;
|
||||
bool canonicalizeDoubles_;
|
||||
public:
|
||||
enum TargetKind {
|
||||
ScalarTarget = 0,
|
||||
TypedArrayTarget
|
||||
};
|
||||
private:
|
||||
TargetKind target_;
|
||||
|
||||
MLoadUnboxedScalar(MDefinition* elements, MDefinition* index,
|
||||
Scalar::Type storageType, MemoryBarrierRequirement requiresBarrier,
|
||||
@@ -9562,6 +9569,7 @@ class MLoadUnboxedScalar
|
||||
setGuard(); // Not removable or movable
|
||||
else
|
||||
setMovable();
|
||||
target_ = ScalarTarget;
|
||||
MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
|
||||
MOZ_ASSERT(index->type() == MIRType_Int32);
|
||||
MOZ_ASSERT(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType);
|
||||
@@ -9582,6 +9590,12 @@ class MLoadUnboxedScalar
|
||||
canonicalizeDoubles);
|
||||
}
|
||||
|
||||
TargetKind target() {
|
||||
return target_;
|
||||
}
|
||||
void setTarget(TargetKind t) {
|
||||
target_ = t;
|
||||
}
|
||||
void setSimdRead(Scalar::Type type, unsigned numElems) {
|
||||
readType_ = type;
|
||||
numElems_ = numElems;
|
||||
@@ -9832,6 +9846,10 @@ class MStoreUnboxedScalar
|
||||
DontTruncateInput,
|
||||
TruncateInput
|
||||
};
|
||||
enum TargetKind {
|
||||
ScalarTarget = 0,
|
||||
TypedArrayTarget
|
||||
};
|
||||
|
||||
private:
|
||||
Scalar::Type storageType_;
|
||||
@@ -9842,6 +9860,8 @@ class MStoreUnboxedScalar
|
||||
bool requiresBarrier_;
|
||||
int32_t offsetAdjustment_;
|
||||
unsigned numElems_; // used only for SIMD
|
||||
|
||||
TargetKind target_;
|
||||
|
||||
MStoreUnboxedScalar(MDefinition* elements, MDefinition* index, MDefinition* value,
|
||||
Scalar::Type storageType, TruncateInputKind truncateInput,
|
||||
@@ -9858,6 +9878,7 @@ class MStoreUnboxedScalar
|
||||
setGuard(); // Not removable or movable
|
||||
else
|
||||
setMovable();
|
||||
target_ = ScalarTarget;
|
||||
MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
|
||||
MOZ_ASSERT(index->type() == MIRType_Int32);
|
||||
MOZ_ASSERT(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType);
|
||||
@@ -9910,6 +9931,12 @@ class MStoreUnboxedScalar
|
||||
int32_t offsetAdjustment() const {
|
||||
return offsetAdjustment_;
|
||||
}
|
||||
TargetKind target() {
|
||||
return target_;
|
||||
}
|
||||
void setTarget(TargetKind t) {
|
||||
target_ = t;
|
||||
}
|
||||
TruncateKind operandTruncateKind(size_t index) const override;
|
||||
|
||||
bool canConsumeFloat32(MUse* use) const override {
|
||||
|
||||
@@ -2564,7 +2564,8 @@ TryAttachNativeGetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecod
|
||||
|
||||
bool isScripted = false;
|
||||
bool cacheableCall = IsCacheableGetPropCall(cx, obj, holder, shape, &isScripted,
|
||||
isTemporarilyUnoptimizable);
|
||||
isTemporarilyUnoptimizable,
|
||||
isDOMProxy);
|
||||
|
||||
// Try handling scripted getters.
|
||||
if (cacheableCall && isScripted && !isDOMProxy && engine == ICStubCompiler::Engine::Baseline) {
|
||||
|
||||
+3
-3
@@ -4341,10 +4341,10 @@ extern JS_PUBLIC_API(const char16_t*)
|
||||
JS_GetTwoByteFlatStringChars(const JS::AutoCheckCannotGC& nogc, JSFlatString* str);
|
||||
|
||||
static MOZ_ALWAYS_INLINE JSFlatString*
|
||||
JSID_TO_FLAT_STRING(jsid id)
|
||||
JSID_TO_FLAT_STRING(jsid jid)
|
||||
{
|
||||
MOZ_ASSERT(JSID_IS_STRING(id));
|
||||
return (JSFlatString*)(JSID_BITS(id));
|
||||
MOZ_ASSERT(JSID_IS_STRING(jid));
|
||||
return (JSFlatString*)(JSID_BITS(jid));
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE JSFlatString*
|
||||
|
||||
+23
-23
@@ -219,7 +219,7 @@ extern JS_FRIEND_API(void)
|
||||
DumpValue(const JS::Value& val);
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
DumpId(jsid id);
|
||||
DumpId(jsid jid);
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
DumpInterpreterFrame(JSContext* cx, InterpreterFrame* start = nullptr);
|
||||
@@ -715,7 +715,7 @@ NewFunctionWithReserved(JSContext* cx, JSNative call, unsigned nargs, unsigned f
|
||||
|
||||
JS_FRIEND_API(JSFunction*)
|
||||
NewFunctionByIdWithReserved(JSContext* cx, JSNative native, unsigned nargs, unsigned flags,
|
||||
jsid id);
|
||||
jsid jid);
|
||||
|
||||
JS_FRIEND_API(const JS::Value&)
|
||||
GetFunctionNativeReserved(JSObject* fun, size_t which);
|
||||
@@ -2495,14 +2495,14 @@ SET_JITINFO(JSFunction * func, const JSJitInfo* info)
|
||||
static MOZ_ALWAYS_INLINE jsid
|
||||
JSID_FROM_BITS(size_t bits)
|
||||
{
|
||||
jsid id;
|
||||
JSID_BITS(id) = bits;
|
||||
return id;
|
||||
jsid jid;
|
||||
JSID_BITS(jid) = bits;
|
||||
return jid;
|
||||
}
|
||||
|
||||
namespace js {
|
||||
namespace detail {
|
||||
bool IdMatchesAtom(jsid id, JSAtom* atom);
|
||||
bool IdMatchesAtom(jsid jid, JSAtom* atom);
|
||||
} // namespace detail
|
||||
} // namespace js
|
||||
|
||||
@@ -2531,28 +2531,28 @@ static MOZ_ALWAYS_INLINE jsid
|
||||
NON_INTEGER_ATOM_TO_JSID(JSAtom* atom)
|
||||
{
|
||||
MOZ_ASSERT(((size_t)atom & 0x7) == 0);
|
||||
jsid id = JSID_FROM_BITS((size_t)atom);
|
||||
MOZ_ASSERT(js::detail::IdMatchesAtom(id, atom));
|
||||
return id;
|
||||
jsid jid = JSID_FROM_BITS((size_t)atom);
|
||||
MOZ_ASSERT(js::detail::IdMatchesAtom(jid, atom));
|
||||
return jid;
|
||||
}
|
||||
|
||||
/* All strings stored in jsids are atomized, but are not necessarily property names. */
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
JSID_IS_ATOM(jsid id)
|
||||
JSID_IS_ATOM(jsid jid)
|
||||
{
|
||||
return JSID_IS_STRING(id);
|
||||
return JSID_IS_STRING(jid);
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
JSID_IS_ATOM(jsid id, JSAtom* atom)
|
||||
JSID_IS_ATOM(jsid jid, JSAtom* atom)
|
||||
{
|
||||
return id == JSID_FROM_BITS((size_t)atom);
|
||||
return jid == JSID_FROM_BITS((size_t)atom);
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE JSAtom*
|
||||
JSID_TO_ATOM(jsid id)
|
||||
JSID_TO_ATOM(jsid jid)
|
||||
{
|
||||
return (JSAtom*)JSID_TO_STRING(id);
|
||||
return (JSAtom*)JSID_TO_STRING(jid);
|
||||
}
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(jsid) == sizeof(void*));
|
||||
@@ -2560,15 +2560,15 @@ JS_STATIC_ASSERT(sizeof(jsid) == sizeof(void*));
|
||||
namespace js {
|
||||
|
||||
static MOZ_ALWAYS_INLINE JS::Value
|
||||
IdToValue(jsid id)
|
||||
IdToValue(jsid jid)
|
||||
{
|
||||
if (JSID_IS_STRING(id))
|
||||
return JS::StringValue(JSID_TO_STRING(id));
|
||||
if (JSID_IS_INT(id))
|
||||
return JS::Int32Value(JSID_TO_INT(id));
|
||||
if (JSID_IS_SYMBOL(id))
|
||||
return JS::SymbolValue(JSID_TO_SYMBOL(id));
|
||||
MOZ_ASSERT(JSID_IS_VOID(id));
|
||||
if (JSID_IS_STRING(jid))
|
||||
return JS::StringValue(JSID_TO_STRING(jid));
|
||||
if (JSID_IS_INT(jid))
|
||||
return JS::Int32Value(JSID_TO_INT(jid));
|
||||
if (JSID_IS_SYMBOL(jid))
|
||||
return JS::SymbolValue(JSID_TO_SYMBOL(jid));
|
||||
MOZ_ASSERT(JSID_IS_VOID(jid));
|
||||
return JS::UndefinedValue();
|
||||
}
|
||||
|
||||
|
||||
@@ -375,6 +375,10 @@ JO(JSContext* cx, HandleObject obj, StringifyContext* scx)
|
||||
bool wroteMember = false;
|
||||
RootedId id(cx);
|
||||
for (size_t i = 0, len = propertyList.length(); i < len; i++) {
|
||||
// bug 1257164
|
||||
if (!CheckForInterrupt(cx))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Steps 8a-8b. Note that the call to Str is broken up into 1) getting
|
||||
* the property; 2) processing for toJSON, calling the replacer, and
|
||||
@@ -454,6 +458,10 @@ JA(JSContext* cx, HandleObject obj, StringifyContext* scx)
|
||||
/* Steps 7-10. */
|
||||
RootedValue outputValue(cx);
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
// bug 1257164
|
||||
if (!CheckForInterrupt(cx))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Steps 8a-8c. Again note how the call to the spec's Str method
|
||||
* is broken up into getting the property, running it past toJSON
|
||||
@@ -731,6 +739,10 @@ Walk(JSContext* cx, HandleObject holder, HandleId name, HandleValue reviver, Mut
|
||||
RootedId id(cx);
|
||||
RootedValue newElement(cx);
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
// bug 1257164
|
||||
if (!CheckForInterrupt(cx))
|
||||
return false;
|
||||
|
||||
if (!IndexToId(cx, i, &id))
|
||||
return false;
|
||||
|
||||
@@ -761,6 +773,10 @@ Walk(JSContext* cx, HandleObject holder, HandleId name, HandleValue reviver, Mut
|
||||
RootedId id(cx);
|
||||
RootedValue newElement(cx);
|
||||
for (size_t i = 0, len = keys.length(); i < len; i++) {
|
||||
// bug 1257164
|
||||
if (!CheckForInterrupt(cx))
|
||||
return false;
|
||||
|
||||
/* Step 2b(ii)(1). */
|
||||
id = keys[i];
|
||||
if (!Walk(cx, obj, id, reviver, &newElement))
|
||||
|
||||
+1
-1
@@ -3522,7 +3522,7 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri
|
||||
/* RegExps */
|
||||
|
||||
AutoObjectVector regexps(cx);
|
||||
for (unsigned i = 0; i < nregexps; i++) {
|
||||
if (nregexps != 0) {
|
||||
HeapPtrObject* vector = src->regexps()->vector;
|
||||
for (unsigned i = 0; i < nregexps; i++) {
|
||||
JSObject* clone = CloneScriptRegExpObject(cx, vector[i]->as<RegExpObject>());
|
||||
|
||||
@@ -539,7 +539,7 @@ ObjectGroup::defaultNewGroup(ExclusiveContext* cx, const Class* clasp,
|
||||
}
|
||||
|
||||
ObjectGroupFlags initialFlags = 0;
|
||||
if (!proto.isObject() || proto.toObject()->isNewGroupUnknown())
|
||||
if (proto.isLazy() || (proto.isObject() && proto.toObject()->isNewGroupUnknown()))
|
||||
initialFlags = OBJECT_FLAG_DYNAMIC_MASK;
|
||||
|
||||
Rooted<TaggedProto> protoRoot(cx, proto);
|
||||
|
||||
@@ -344,6 +344,11 @@ UnboxedPlainObject::ensureExpando(JSContext* cx, Handle<UnboxedPlainObject*> obj
|
||||
if (!expando)
|
||||
return nullptr;
|
||||
|
||||
// Don't track property types for expando objects. This allows Baseline
|
||||
// and Ion AddSlot ICs to guard on the unboxed group without guarding on
|
||||
// the expando group.
|
||||
MarkObjectGroupUnknownProperties(cx, expando->group());
|
||||
|
||||
// If the expando is tenured then the original object must also be tenured.
|
||||
// Otherwise barriers triggered on the original object for writes to the
|
||||
// expando (as can happen in the JIT) won't see the tenured->nursery edge.
|
||||
|
||||
@@ -636,8 +636,8 @@ JSXrayTraits::delete_(JSContext* cx, HandleObject wrapper, HandleId id, ObjectOp
|
||||
|
||||
bool
|
||||
JSXrayTraits::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
|
||||
Handle<JSPropertyDescriptor> desc,
|
||||
Handle<JSPropertyDescriptor> existingDesc,
|
||||
JS::Handle<JSPropertyDescriptor> desc,
|
||||
JS::Handle<JSPropertyDescriptor> existingDesc,
|
||||
ObjectOpResult& result,
|
||||
bool* defined)
|
||||
{
|
||||
@@ -1473,8 +1473,8 @@ XPCWrappedNativeXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsW
|
||||
|
||||
bool
|
||||
XPCWrappedNativeXrayTraits::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
|
||||
Handle<JSPropertyDescriptor> desc,
|
||||
Handle<JSPropertyDescriptor> existingDesc,
|
||||
JS::Handle<JSPropertyDescriptor> desc,
|
||||
JS::Handle<JSPropertyDescriptor> existingDesc,
|
||||
JS::ObjectOpResult& result, bool* defined)
|
||||
{
|
||||
*defined = false;
|
||||
@@ -1633,8 +1633,8 @@ DOMXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, Handl
|
||||
|
||||
bool
|
||||
DOMXrayTraits::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
|
||||
Handle<JSPropertyDescriptor> desc,
|
||||
Handle<JSPropertyDescriptor> existingDesc,
|
||||
JS::Handle<JSPropertyDescriptor> desc,
|
||||
JS::Handle<JSPropertyDescriptor> existingDesc,
|
||||
JS::ObjectOpResult& result, bool* defined)
|
||||
{
|
||||
// Check for an indexed property on a Window. If that's happening, do
|
||||
@@ -2032,7 +2032,7 @@ RecreateLostWaivers(JSContext* cx, const JSPropertyDescriptor* orig,
|
||||
template <typename Base, typename Traits>
|
||||
bool
|
||||
XrayWrapper<Base, Traits>::defineProperty(JSContext* cx, HandleObject wrapper,
|
||||
HandleId id, Handle<JSPropertyDescriptor> desc,
|
||||
HandleId id, JS::Handle<JSPropertyDescriptor> desc,
|
||||
ObjectOpResult& result) const
|
||||
{
|
||||
assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::SET);
|
||||
|
||||
@@ -460,7 +460,8 @@ public:
|
||||
* Add the given hit regions to the hit regions to the hit retions for this
|
||||
* PaintedLayer.
|
||||
*/
|
||||
void AccumulateEventRegions(ContainerState* aState, nsDisplayLayerEventRegions* aEventRegions);
|
||||
// bug 1247979
|
||||
void AccumulateEventRegions(ContainerState* aState, nsDisplayLayerEventRegions* aEventRegions, nsRegion &tmp);
|
||||
|
||||
/**
|
||||
* If this represents only a nsDisplayImage, and the image type supports being
|
||||
@@ -3319,6 +3320,8 @@ void ContainerState::FinishPaintedLayerData(PaintedLayerData& aData, FindOpaqueB
|
||||
containingPaintedLayerData->mReferenceFrame);
|
||||
containingPaintedLayerData->mMaybeHitRegion.Or(
|
||||
containingPaintedLayerData->mMaybeHitRegion, rect);
|
||||
// bug 1256373
|
||||
containingPaintedLayerData->mMaybeHitRegion.SimplifyOutward(8);
|
||||
}
|
||||
nsLayoutUtils::TransformToAncestorAndCombineRegions(
|
||||
data->mHitRegion.GetBounds(),
|
||||
@@ -3540,16 +3543,28 @@ PaintedLayerData::Accumulate(ContainerState* aState,
|
||||
}
|
||||
|
||||
void
|
||||
PaintedLayerData::AccumulateEventRegions(ContainerState* aState, nsDisplayLayerEventRegions* aEventRegions)
|
||||
PaintedLayerData::AccumulateEventRegions(ContainerState* aState, nsDisplayLayerEventRegions* aEventRegions, nsRegion &tmp)
|
||||
{
|
||||
FLB_LOG_PAINTED_LAYER_DECISION(this, "Accumulating event regions %p against pld=%p\n", aEventRegions, this);
|
||||
|
||||
/* tmp from bug 1247979 */
|
||||
#if(0)
|
||||
mHitRegion.Or(mHitRegion, aEventRegions->HitRegion());
|
||||
mMaybeHitRegion.Or(mMaybeHitRegion, aEventRegions->MaybeHitRegion());
|
||||
mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, aEventRegions->DispatchToContentHitRegion());
|
||||
mNoActionRegion.Or(mNoActionRegion, aEventRegions->NoActionRegion());
|
||||
mHorizontalPanRegion.Or(mHorizontalPanRegion, aEventRegions->HorizontalPanRegion());
|
||||
mVerticalPanRegion.Or(mVerticalPanRegion, aEventRegions->VerticalPanRegion());
|
||||
#else
|
||||
// we use a tmp region to avoid modifying the regions in place which is gauranteed to do a new allocation.
|
||||
//
|
||||
tmp.Or(mHitRegion, aEventRegions->HitRegion()); mHitRegion = tmp;
|
||||
tmp.Or(mMaybeHitRegion, aEventRegions->MaybeHitRegion()); mMaybeHitRegion = tmp;
|
||||
tmp.Or(mDispatchToContentHitRegion, aEventRegions->DispatchToContentHitRegion()); mDispatchToContentHitRegion = tmp;
|
||||
tmp.Or(mNoActionRegion, aEventRegions->NoActionRegion()); mNoActionRegion = tmp;
|
||||
tmp.Or(mHorizontalPanRegion, aEventRegions->HorizontalPanRegion()); mHorizontalPanRegion = tmp;
|
||||
tmp.Or(mVerticalPanRegion, aEventRegions->VerticalPanRegion()); mVerticalPanRegion = tmp;
|
||||
#endif
|
||||
|
||||
// Calculate scaled versions of the bounds of mHitRegion and mMaybeHitRegion
|
||||
// for quick access in FindPaintedLayerFor().
|
||||
@@ -3699,8 +3714,12 @@ ContainerState::ComputeOpaqueRect(nsDisplayItem* aItem,
|
||||
{
|
||||
bool snapOpaque;
|
||||
nsRegion opaque = aItem->GetOpaqueRegion(mBuilder, &snapOpaque);
|
||||
if (opaque.IsEmpty()) {
|
||||
return nsIntRegion();
|
||||
} // bug 1220466
|
||||
|
||||
nsIntRegion opaquePixels;
|
||||
if (!opaque.IsEmpty()) {
|
||||
// if (!opaque.IsEmpty()) {
|
||||
nsRegion opaqueClipped;
|
||||
nsRegionRectIterator iter(opaque);
|
||||
for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
|
||||
@@ -3737,7 +3756,7 @@ ContainerState::ComputeOpaqueRect(nsDisplayItem* aItem,
|
||||
*aOpaqueForAnimatedGeometryRootParent = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// }
|
||||
return opaquePixels;
|
||||
}
|
||||
|
||||
@@ -3815,6 +3834,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
|
||||
|
||||
nsDisplayList savedItems;
|
||||
nsDisplayItem* item;
|
||||
nsRegion tmpRegion;
|
||||
while ((item = aList->RemoveBottom()) != nullptr) {
|
||||
// Peek ahead to the next item and try merging with it or swapping with it
|
||||
// if necessary.
|
||||
@@ -4001,7 +4021,10 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
|
||||
// So we'll do a little hand holding and pass the clip instead of the
|
||||
// visible rect for the two important cases.
|
||||
nscolor uniformColor = NS_RGBA(0,0,0,0);
|
||||
nscolor* uniformColorPtr = !mayDrawOutOfOrder ? &uniformColor : nullptr;
|
||||
// bug 1220466 and comments
|
||||
//nscolor* uniformColorPtr = !mayDrawOutOfOrder ? &uniformColor : nullptr;
|
||||
nscolor* uniformColorPtr = (!mayDrawOutOfOrder && !IsInInactiveLayer())
|
||||
? &uniformColor : nullptr;
|
||||
nsIntRect clipRectUntyped;
|
||||
const DisplayItemClip& layerClip = shouldFixToViewport ? fixedToViewportClip : itemClip;
|
||||
ParentLayerIntRect layerClipRect;
|
||||
@@ -4162,7 +4185,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
|
||||
if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) {
|
||||
nsDisplayLayerEventRegions* eventRegions =
|
||||
static_cast<nsDisplayLayerEventRegions*>(item);
|
||||
paintedLayerData->AccumulateEventRegions(this, eventRegions);
|
||||
paintedLayerData->AccumulateEventRegions(this, eventRegions, tmpRegion);
|
||||
} else {
|
||||
// check to see if the new item has rounded rect clips in common with
|
||||
// other items in the layer
|
||||
|
||||
@@ -748,6 +748,27 @@ nsLayoutUtils::FindContentFor(ViewID aId)
|
||||
}
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
GetScrollFrameFromContent(nsIContent* aContent)
|
||||
{
|
||||
nsIFrame* frame = aContent->GetPrimaryFrame();
|
||||
if (aContent->OwnerDoc()->GetRootElement() == aContent) {
|
||||
nsIPresShell* presShell = frame ? frame->PresContext()->PresShell() :
|
||||
nullptr;
|
||||
if (!presShell) {
|
||||
presShell = aContent->OwnerDoc()->GetShell();
|
||||
}
|
||||
// We want the scroll frame, the root scroll frame differs from all
|
||||
// others in that the primary frame is not the scroll frame.
|
||||
nsIFrame* rootScrollFrame = presShell ? presShell->GetRootScrollFrame() :
|
||||
nullptr;
|
||||
if (rootScrollFrame) {
|
||||
frame = rootScrollFrame;
|
||||
}
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
nsIScrollableFrame*
|
||||
nsLayoutUtils::FindScrollableFrameFor(ViewID aId)
|
||||
{
|
||||
@@ -756,6 +777,7 @@ nsLayoutUtils::FindScrollableFrameFor(ViewID aId)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if(0) // backbugs from whatever the hell it was
|
||||
nsIFrame* scrolledFrame = content->GetPrimaryFrame();
|
||||
if (scrolledFrame && content->OwnerDoc()->GetRootElement() == content) {
|
||||
// The content is the root element of a subdocument, so return the root scrollable
|
||||
@@ -763,6 +785,10 @@ nsLayoutUtils::FindScrollableFrameFor(ViewID aId)
|
||||
scrolledFrame = scrolledFrame->PresContext()->PresShell()->GetRootScrollFrame();
|
||||
}
|
||||
return scrolledFrame ? scrolledFrame->GetScrollTargetFrame() : nullptr;
|
||||
#else
|
||||
nsIFrame* scrollFrame = GetScrollFrameFromContent(content);
|
||||
return scrollFrame ? scrollFrame->GetScrollTargetFrame() : nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
static nsRect
|
||||
@@ -1140,8 +1166,51 @@ nsLayoutUtils::SetDisplayPortMargins(nsIContent* aContent,
|
||||
}
|
||||
|
||||
// Display port margins changing means that the set of visible images may
|
||||
// have drastically changed. Schedule an update.
|
||||
aPresShell->ScheduleImageVisibilityUpdate();
|
||||
// have drastically changed. Check if we should schedule an update.
|
||||
nsIFrame* frame = GetScrollFrameFromContent(aContent);
|
||||
nsIScrollableFrame* scrollableFrame = frame ? frame->GetScrollTargetFrame() : nullptr;
|
||||
if (!scrollableFrame) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsRect oldDisplayPort;
|
||||
bool hadDisplayPort =
|
||||
scrollableFrame->GetDisplayPortAtLastImageVisibilityUpdate(&oldDisplayPort);
|
||||
|
||||
nsRect newDisplayPort;
|
||||
Unused << GetDisplayPort(aContent, &newDisplayPort);
|
||||
|
||||
bool needImageVisibilityUpdate = !hadDisplayPort;
|
||||
// Check if the width or height was or is going to be 0, mostly
|
||||
// just so we don't divide by zero in the next check.
|
||||
if (newDisplayPort.width == 0 || oldDisplayPort.width == 0 ||
|
||||
newDisplayPort.height == 0 || oldDisplayPort.height == 0) {
|
||||
needImageVisibilityUpdate = true;
|
||||
}
|
||||
// Check if the total size has changed by a large factor.
|
||||
if (!needImageVisibilityUpdate) {
|
||||
if ((newDisplayPort.width/((float)oldDisplayPort.width) > 2.f) ||
|
||||
(oldDisplayPort.width/((float)newDisplayPort.width) > 2.f) ||
|
||||
(newDisplayPort.height/((float)oldDisplayPort.height) > 2.f) ||
|
||||
(oldDisplayPort.height/((float)newDisplayPort.height) > 2.f)) {
|
||||
needImageVisibilityUpdate = true;
|
||||
}
|
||||
}
|
||||
// Check if it's moved by a significant amount.
|
||||
if (!needImageVisibilityUpdate) {
|
||||
if (nsRect* baseData = static_cast<nsRect*>(aContent->GetProperty(nsGkAtoms::DisplayPortBase))) {
|
||||
nsRect base = *baseData;
|
||||
if ((std::abs(newDisplayPort.X() - oldDisplayPort.X()) > base.width) ||
|
||||
(std::abs(newDisplayPort.XMost() - oldDisplayPort.XMost()) > base.width) ||
|
||||
(std::abs(newDisplayPort.Y() - oldDisplayPort.Y()) > base.height) ||
|
||||
(std::abs(newDisplayPort.YMost() - oldDisplayPort.YMost()) > base.height)) {
|
||||
needImageVisibilityUpdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (needImageVisibilityUpdate) {
|
||||
aPresShell->ScheduleImageVisibilityUpdate();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5710,6 +5710,7 @@ PresShell::MarkImagesInSubtreeVisible(nsIFrame* aFrame, const nsRect& aRect)
|
||||
|
||||
nsIScrollableFrame* scrollFrame = do_QueryFrame(aFrame);
|
||||
if (scrollFrame) {
|
||||
scrollFrame->NotifyImageVisibilityUpdate();
|
||||
nsRect displayPort;
|
||||
bool usingDisplayport =
|
||||
nsLayoutUtils::GetDisplayPortForVisibilityTesting(aFrame->GetContent(),
|
||||
|
||||
@@ -55,9 +55,9 @@ class CSSStyleSheet;
|
||||
class EventDispatchingCallback;
|
||||
} // namespace mozilla
|
||||
|
||||
// 250ms. This is actually pref-controlled, but we use this value if we fail
|
||||
// This is actually pref-controlled, but we use this value if we fail
|
||||
// to get the pref for any reason.
|
||||
#define PAINTLOCK_EVENT_DELAY 250
|
||||
#define PAINTLOCK_EVENT_DELAY 100
|
||||
|
||||
class PresShell final : public nsIPresShell,
|
||||
public nsStubDocumentObserver,
|
||||
|
||||
@@ -2542,11 +2542,31 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
|
||||
child->MarkAbsoluteFramesForDisplayList(aBuilder, dirty);
|
||||
|
||||
// moved here from below
|
||||
if (aBuilder->IsBuildingLayerEventRegions()) {
|
||||
// If this frame has a different animated geometry root than its parent,
|
||||
// make sure we accumulate event regions for its layer.
|
||||
if (buildingForChild.IsAnimatedGeometryRoot()) {
|
||||
nsDisplayLayerEventRegions* eventRegions =
|
||||
new (aBuilder) nsDisplayLayerEventRegions(aBuilder, child);
|
||||
eventRegions->AddFrame(aBuilder, child);
|
||||
aBuilder->SetLayerEventRegions(eventRegions);
|
||||
aLists.BorderBackground()->AppendNewToTop(eventRegions);
|
||||
}
|
||||
}
|
||||
|
||||
nsDisplayLayerEventRegions* eventRegions = aBuilder->GetLayerEventRegions();
|
||||
if (eventRegions) {
|
||||
eventRegions->AddFrame(aBuilder, child);
|
||||
}
|
||||
|
||||
if (!pseudoStackingContext) {
|
||||
// THIS IS THE COMMON CASE.
|
||||
// Not a pseudo or real stacking context. Do the simple thing and
|
||||
// return early.
|
||||
|
||||
// bug 1220466 moves this above.
|
||||
#if(0)
|
||||
if (aBuilder->IsBuildingLayerEventRegions()) {
|
||||
// If this frame has a different animated geometry root than its parent,
|
||||
// make sure we accumulate event regions for its layer.
|
||||
@@ -2563,6 +2583,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
if (eventRegions) {
|
||||
eventRegions->AddFrame(aBuilder, child);
|
||||
}
|
||||
#endif
|
||||
aBuilder->AdjustWindowDraggingRegion(child);
|
||||
child->BuildDisplayList(aBuilder, dirty, aLists);
|
||||
aBuilder->DisplayCaret(child, dirty, aLists.Content());
|
||||
@@ -2577,6 +2598,8 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
// stacking context's positioned descendant list, because they might be
|
||||
// z-index:non-auto
|
||||
nsDisplayListCollection pseudoStack;
|
||||
// bug 1220466
|
||||
#if(0)
|
||||
if (aBuilder->IsBuildingLayerEventRegions()) {
|
||||
nsDisplayLayerEventRegions* eventRegions =
|
||||
new (aBuilder) nsDisplayLayerEventRegions(aBuilder, child);
|
||||
@@ -2584,6 +2607,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
aBuilder->SetLayerEventRegions(eventRegions);
|
||||
pseudoStack.BorderBackground()->AppendNewToTop(eventRegions);
|
||||
}
|
||||
#endif
|
||||
aBuilder->AdjustWindowDraggingRegion(child);
|
||||
child->BuildDisplayList(aBuilder, dirty, pseudoStack);
|
||||
aBuilder->DisplayCaret(child, dirty, pseudoStack.Content());
|
||||
|
||||
@@ -1837,6 +1837,8 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter,
|
||||
, mLastPos(-1, -1)
|
||||
, mScrollPosForLayerPixelAlignment(-1, -1)
|
||||
, mLastUpdateImagesPos(-1, -1)
|
||||
, mHadDisplayPortAtLastImageUpdate(false)
|
||||
, mDisplayPortAtLastImageUpdate()
|
||||
, mNeverHasVerticalScrollbar(false)
|
||||
, mNeverHasHorizontalScrollbar(false)
|
||||
, mHasVerticalScrollbar(false)
|
||||
@@ -2476,6 +2478,23 @@ ScrollFrameHelper::ScheduleSyntheticMouseMove()
|
||||
ScrollActivityCallback, this, 100, nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
void
|
||||
ScrollFrameHelper::NotifyImageVisibilityUpdate()
|
||||
{
|
||||
mLastUpdateImagesPos = GetScrollPosition();
|
||||
mHadDisplayPortAtLastImageUpdate =
|
||||
nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &mDisplayPortAtLastImageUpdate);
|
||||
}
|
||||
|
||||
bool
|
||||
ScrollFrameHelper::GetDisplayPortAtLastImageVisibilityUpdate(nsRect* aDisplayPort)
|
||||
{
|
||||
if (mHadDisplayPortAtLastImageUpdate) {
|
||||
*aDisplayPort = mDisplayPortAtLastImageUpdate;
|
||||
}
|
||||
return mHadDisplayPortAtLastImageUpdate;
|
||||
}
|
||||
|
||||
void
|
||||
ScrollFrameHelper::ScrollToImpl(nsPoint aPt, const nsRect& aRange, nsIAtom* aOrigin)
|
||||
{
|
||||
@@ -2528,10 +2547,6 @@ ScrollFrameHelper::ScrollToImpl(nsPoint aPt, const nsRect& aRange, nsIAtom* aOri
|
||||
needImageVisibilityUpdate = true;
|
||||
}
|
||||
|
||||
if (needImageVisibilityUpdate) {
|
||||
presContext->PresShell()->ScheduleImageVisibilityUpdate();
|
||||
}
|
||||
|
||||
// notify the listeners.
|
||||
for (uint32_t i = 0; i < mListeners.Length(); i++) {
|
||||
mListeners[i]->ScrollPositionWillChange(pt.x, pt.y);
|
||||
@@ -2549,6 +2564,7 @@ ScrollFrameHelper::ScrollToImpl(nsPoint aPt, const nsRect& aRange, nsIAtom* aOri
|
||||
|
||||
ScrollVisual();
|
||||
|
||||
#if(0) // this won't ever happen
|
||||
if (LastScrollOrigin() == nsGkAtoms::apz) {
|
||||
// If this was an apz scroll and the displayport (relative to the
|
||||
// scrolled frame) hasn't changed, then this won't trigger
|
||||
@@ -2562,10 +2578,19 @@ ScrollFrameHelper::ScrollToImpl(nsPoint aPt, const nsRect& aRange, nsIAtom* aOri
|
||||
|
||||
if (!displayPort.IsEqualEdges(oldDisplayPort)) {
|
||||
mOuter->SchedulePaint();
|
||||
|
||||
if (needImageVisibilityUpdate) {
|
||||
presContext->PresShell()->ScheduleImageVisibilityUpdate();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
mOuter->SchedulePaint();
|
||||
}
|
||||
|
||||
if (needImageVisibilityUpdate) {
|
||||
presContext->PresShell()->ScheduleImageVisibilityUpdate();
|
||||
}
|
||||
// }
|
||||
|
||||
if (mOuter->ChildrenHavePerspective()) {
|
||||
// The overflow areas of descendants may depend on the scroll position,
|
||||
@@ -2884,7 +2909,7 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsDisplayListSet& aLists)
|
||||
{
|
||||
if (aBuilder->IsForImageVisibility()) {
|
||||
mLastUpdateImagesPos = GetScrollPosition();
|
||||
NotifyImageVisibilityUpdate();
|
||||
}
|
||||
|
||||
mOuter->DisplayBorderBackgroundOutline(aBuilder, aLists);
|
||||
|
||||
@@ -366,6 +366,8 @@ public:
|
||||
bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
|
||||
nsRect* aDirtyRect,
|
||||
bool aAllowCreateDisplayPort);
|
||||
void NotifyImageVisibilityUpdate();
|
||||
bool GetDisplayPortAtLastImageVisibilityUpdate(nsRect* aDisplayPort);
|
||||
|
||||
void ScheduleSyntheticMouseMove();
|
||||
static void ScrollActivityCallback(nsITimer *aTimer, void* anInstance);
|
||||
@@ -459,6 +461,8 @@ public:
|
||||
|
||||
// The scroll position where we last updated image visibility.
|
||||
nsPoint mLastUpdateImagesPos;
|
||||
bool mHadDisplayPortAtLastImageUpdate;
|
||||
nsRect mDisplayPortAtLastImageUpdate;
|
||||
|
||||
nsRect mPrevScrolledRect;
|
||||
|
||||
@@ -857,6 +861,12 @@ public:
|
||||
bool aAllowCreateDisplayPort) override {
|
||||
return mHelper.DecideScrollableLayer(aBuilder, aDirtyRect, aAllowCreateDisplayPort);
|
||||
}
|
||||
virtual void NotifyImageVisibilityUpdate() override {
|
||||
mHelper.NotifyImageVisibilityUpdate();
|
||||
}
|
||||
virtual bool GetDisplayPortAtLastImageVisibilityUpdate(nsRect* aDisplayPort) override {
|
||||
return mHelper.GetDisplayPortAtLastImageVisibilityUpdate(aDisplayPort);
|
||||
}
|
||||
|
||||
// nsIStatefulFrame
|
||||
NS_IMETHOD SaveState(nsPresState** aState) override {
|
||||
@@ -1328,7 +1338,12 @@ public:
|
||||
bool aAllowCreateDisplayPort) override {
|
||||
return mHelper.DecideScrollableLayer(aBuilder, aDirtyRect, aAllowCreateDisplayPort);
|
||||
}
|
||||
|
||||
virtual void NotifyImageVisibilityUpdate() override {
|
||||
mHelper.NotifyImageVisibilityUpdate();
|
||||
}
|
||||
virtual bool GetDisplayPortAtLastImageVisibilityUpdate(nsRect* aDisplayPort) override {
|
||||
return mHelper.GetDisplayPortAtLastImageVisibilityUpdate(aDisplayPort);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
virtual nsresult GetFrameName(nsAString& aResult) const override;
|
||||
|
||||
@@ -450,6 +450,18 @@ public:
|
||||
virtual bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
|
||||
nsRect* aDirtyRect,
|
||||
bool aAllowCreateDisplayPort) = 0;
|
||||
|
||||
/**
|
||||
* Notification that this scroll frame is getting its image visibility updated.
|
||||
*/
|
||||
virtual void NotifyImageVisibilityUpdate() = 0;
|
||||
|
||||
/**
|
||||
* Returns true if this scroll frame had a display port at the last image
|
||||
* visibility update and fills in aDisplayPort with that displayport. Returns
|
||||
* false otherwise, and doesn't touch aDisplayPort.
|
||||
*/
|
||||
virtual bool GetDisplayPortAtLastImageVisibilityUpdate(nsRect* aDisplayPort) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -788,8 +788,11 @@ FontFaceSet::UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules)
|
||||
CheckLoadingFinished();
|
||||
}
|
||||
|
||||
// local rules have been rebuilt, so clear the flag
|
||||
mUserFontSet->mLocalRulesUsed = false;
|
||||
// if local rules needed to be rebuilt, they have been rebuilt at this point
|
||||
if (mUserFontSet->mRebuildLocalRules) {
|
||||
mUserFontSet->mLocalRulesUsed = false;
|
||||
mUserFontSet->mRebuildLocalRules = false;
|
||||
}
|
||||
|
||||
if (LOG_ENABLED() && !mRuleFaces.IsEmpty()) {
|
||||
LOG(("userfonts (%p) userfont rules update (%s) rule count: %d",
|
||||
@@ -874,7 +877,8 @@ FontFaceSet::InsertRuleFontFace(FontFace* aFontFace, SheetType aSheetType,
|
||||
|
||||
// if local rules were used, don't use the old font entry
|
||||
// for rules containing src local usage
|
||||
if (mUserFontSet->mLocalRulesUsed) {
|
||||
if (mUserFontSet->mLocalRulesUsed &&
|
||||
mUserFontSet->mRebuildLocalRules) {
|
||||
nsCSSValue val;
|
||||
aFontFace->GetDesc(eCSSFontDesc_Src, val);
|
||||
nsCSSUnit unit = val.GetUnit();
|
||||
|
||||
@@ -49,4 +49,22 @@
|
||||
# define PRIXPTR "X" /* uintptr_t */
|
||||
#endif
|
||||
|
||||
/* Fix issues with the 10.4 SDK using weird printf macros but not working
|
||||
properly with gcc-4.8. This causes failures in tests/coverage/simple.js
|
||||
and other less visible places (i.e., using %qu instead of %llu). */
|
||||
|
||||
#define __104PRI_64_LENGTH_MODIFIER__ "ll"
|
||||
#undef PRId64
|
||||
# define PRId64 __104PRI_64_LENGTH_MODIFIER__ "d"
|
||||
#undef PRIi64
|
||||
# define PRIi64 __104PRI_64_LENGTH_MODIFIER__ "i"
|
||||
#undef PRIo64
|
||||
# define PRIo64 __104PRI_64_LENGTH_MODIFIER__ "o"
|
||||
#undef PRIu64
|
||||
# define PRIu64 __104PRI_64_LENGTH_MODIFIER__ "u"
|
||||
#undef PRIx64
|
||||
# define PRIx64 __104PRI_64_LENGTH_MODIFIER__ "x"
|
||||
#undef PRIX64
|
||||
# define PRIX64 __104PRI_64_LENGTH_MODIFIER__ "X"
|
||||
|
||||
#endif /* mozilla_IntegerPrintfMacros_h_ */
|
||||
|
||||
+2
-2
@@ -198,7 +198,7 @@ struct MOZ_NON_TEMPORARY_CLASS name : public mozilla::Scoped<Traits<Type> > \
|
||||
} \
|
||||
name& operator=(name&& aRhs) \
|
||||
{ \
|
||||
Super::operator=(Move(aRhs)); \
|
||||
Super::operator=(mozilla::Move(aRhs)); \
|
||||
return *this; \
|
||||
} \
|
||||
explicit name(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) \
|
||||
@@ -211,7 +211,7 @@ struct MOZ_NON_TEMPORARY_CLASS name : public mozilla::Scoped<Traits<Type> > \
|
||||
{} \
|
||||
name(name&& aRhs \
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM) \
|
||||
: Super(Move(aRhs) \
|
||||
: Super(mozilla::Move(aRhs) \
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) \
|
||||
{} \
|
||||
private: \
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
// Incorporate our local patches for inttypes.h.
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace non_crypto {
|
||||
|
||||
@@ -4,7 +4,7 @@ include ../shared.mk
|
||||
|
||||
CFLAGS += -Wall
|
||||
|
||||
OBJS = bit_reader.o decode.o dictionary.o huffman.o state.o streams.o
|
||||
OBJS = bit_reader.o decode.o dictionary.o huffman.o state.o
|
||||
|
||||
all : $(OBJS)
|
||||
|
||||
|
||||
@@ -1,38 +1,23 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Bit reading helpers */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "./bit_reader.h"
|
||||
|
||||
#include "./port.h"
|
||||
#include "./types.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void BrotliInitBitReader(BrotliBitReader* const br, BrotliInput input) {
|
||||
BROTLI_DCHECK(br != NULL);
|
||||
|
||||
br->input_ = input;
|
||||
void BrotliInitBitReader(BrotliBitReader* const br) {
|
||||
br->val_ = 0;
|
||||
br->bit_pos_ = sizeof(br->val_) << 3;
|
||||
br->avail_in = 0;
|
||||
br->eos_ = 0;
|
||||
br->next_in = br->buf_;
|
||||
}
|
||||
|
||||
int BrotliWarmupBitReader(BrotliBitReader* const br) {
|
||||
@@ -43,16 +28,21 @@ int BrotliWarmupBitReader(BrotliBitReader* const br) {
|
||||
if (!BROTLI_ALIGNED_READ) {
|
||||
aligned_read_mask = 0;
|
||||
}
|
||||
while (br->bit_pos_ == (sizeof(br->val_) << 3) ||
|
||||
(((size_t)br->next_in) & aligned_read_mask) != 0) {
|
||||
if (!br->avail_in) {
|
||||
if (BrotliGetAvailableBits(br) == 0) {
|
||||
if (!BrotliPullByte(br)) {
|
||||
return 0;
|
||||
}
|
||||
BrotliPullByte(br);
|
||||
}
|
||||
|
||||
while ((((size_t)br->next_in) & aligned_read_mask) != 0) {
|
||||
if (!BrotliPullByte(br)) {
|
||||
/* If we consumed all the input, we don't care about the alignment. */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
+212
-160
@@ -1,16 +1,7 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Bit reading helpers */
|
||||
@@ -18,129 +9,169 @@
|
||||
#ifndef BROTLI_DEC_BIT_READER_H_
|
||||
#define BROTLI_DEC_BIT_READER_H_
|
||||
|
||||
#include <string.h>
|
||||
#include <string.h> /* memcpy */
|
||||
|
||||
#include "./port.h"
|
||||
#include "./streams.h"
|
||||
#include "./types.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BROTLI_READ_SIZE 1024
|
||||
/* 128 bytes, plus 8 bytes slack for valid 128-byte BrotliCheckInputAmount with
|
||||
some bytes read in val_ of bit reader. */
|
||||
#define BROTLI_IMPLICIT_ZEROES 136
|
||||
#define BROTLI_IBUF_SIZE (BROTLI_READ_SIZE + BROTLI_IMPLICIT_ZEROES)
|
||||
#define BROTLI_IBUF_MASK (BROTLI_READ_SIZE - 1)
|
||||
#if (BROTLI_64_BITS)
|
||||
#define BROTLI_SHORT_FILL_BIT_WINDOW_READ 4
|
||||
typedef uint64_t reg_t;
|
||||
#else
|
||||
#define BROTLI_SHORT_FILL_BIT_WINDOW_READ 2
|
||||
typedef uint32_t reg_t;
|
||||
#endif
|
||||
|
||||
/* Masking with this expression turns to a single "Unsigned Bit Field Extract"
|
||||
UBFX instruction on ARM. */
|
||||
static BROTLI_INLINE uint32_t BitMask(int n) { return ~((0xffffffff) << n); }
|
||||
static const uint32_t kBitMask[33] = { 0x0000,
|
||||
0x00000001, 0x00000003, 0x00000007, 0x0000000F,
|
||||
0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
|
||||
0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
|
||||
0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
|
||||
0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
|
||||
0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
|
||||
0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
|
||||
0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
|
||||
};
|
||||
|
||||
static BROTLI_INLINE uint32_t BitMask(uint32_t n) {
|
||||
if (IS_CONSTANT(n) || BROTLI_HAS_UBFX) {
|
||||
/* Masking with this expression turns to a single
|
||||
"Unsigned Bit Field Extract" UBFX instruction on ARM. */
|
||||
return ~((0xffffffffU) << n);
|
||||
} else {
|
||||
return kBitMask[n];
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
#if (BROTLI_64_BITS_LITTLE_ENDIAN)
|
||||
uint64_t val_; /* pre-fetched bits */
|
||||
#else
|
||||
uint32_t val_; /* pre-fetched bits */
|
||||
#endif
|
||||
uint32_t bit_pos_; /* current bit-reading position in val_ */
|
||||
uint8_t* next_in; /* the byte we're reading from */
|
||||
uint32_t avail_in;
|
||||
int eos_; /* input stream is finished */
|
||||
BrotliInput input_; /* input callback */
|
||||
|
||||
/* Input byte buffer, consist of a ringbuffer and a "slack" region where */
|
||||
/* bytes from the start of the ringbuffer are copied. */
|
||||
uint8_t buf_[BROTLI_IBUF_SIZE];
|
||||
reg_t val_; /* pre-fetched bits */
|
||||
uint32_t bit_pos_; /* current bit-reading position in val_ */
|
||||
const uint8_t* next_in; /* the byte we're reading from */
|
||||
size_t avail_in;
|
||||
} BrotliBitReader;
|
||||
|
||||
typedef struct {
|
||||
reg_t val_;
|
||||
uint32_t bit_pos_;
|
||||
const uint8_t* next_in;
|
||||
size_t avail_in;
|
||||
} BrotliBitReaderState;
|
||||
|
||||
/* Initializes the bitreader fields. */
|
||||
void BrotliInitBitReader(BrotliBitReader* const br, BrotliInput input);
|
||||
BROTLI_INTERNAL void BrotliInitBitReader(BrotliBitReader* const br);
|
||||
|
||||
/* Ensures that accumulator is not empty. May consume one byte of input.
|
||||
Returns 0 if data is required but there is no input available.
|
||||
For BROTLI_BUILD_PORTABLE this function also prepares bit reader for aligned
|
||||
For BROTLI_ALIGNED_READ this function also prepares bit reader for aligned
|
||||
reading. */
|
||||
int BrotliWarmupBitReader(BrotliBitReader* const br);
|
||||
static BROTLI_INLINE void BrotliPullByte(BrotliBitReader* const br);
|
||||
/* Pulls data from the input to the the read buffer.
|
||||
BROTLI_INTERNAL int BrotliWarmupBitReader(BrotliBitReader* const br);
|
||||
|
||||
Returns 0 if one of:
|
||||
- the input callback returned an error, or
|
||||
- there is no more input and the position is past the end of the stream.
|
||||
- finish is false and less than BROTLI_READ_SIZE are available - a next call
|
||||
when more data is available makes it continue including the partially read
|
||||
data
|
||||
static BROTLI_INLINE void BrotliBitReaderSaveState(
|
||||
BrotliBitReader* const from, BrotliBitReaderState* to) {
|
||||
to->val_ = from->val_;
|
||||
to->bit_pos_ = from->bit_pos_;
|
||||
to->next_in = from->next_in;
|
||||
to->avail_in = from->avail_in;
|
||||
}
|
||||
|
||||
If finish is true and the end of the stream is reached,
|
||||
BROTLI_IMPLICIT_ZEROES additional zero bytes are copied to the ringbuffer.
|
||||
*/
|
||||
static BROTLI_INLINE int BrotliReadInput(
|
||||
BrotliBitReader* const br, int finish) {
|
||||
if (PREDICT_FALSE(br->eos_)) {
|
||||
return 0;
|
||||
} else {
|
||||
size_t i;
|
||||
int bytes_read;
|
||||
if (br->next_in != br->buf_) {
|
||||
for (i = 0; i < br->avail_in; i++) {
|
||||
br->buf_[i] = br->next_in[i];
|
||||
}
|
||||
br->next_in = br->buf_;
|
||||
}
|
||||
bytes_read = BrotliRead(br->input_, br->next_in + br->avail_in,
|
||||
(size_t)(BROTLI_READ_SIZE - br->avail_in));
|
||||
if (bytes_read < 0) {
|
||||
return 0;
|
||||
}
|
||||
br->avail_in += (uint32_t)bytes_read;
|
||||
if (br->avail_in < BROTLI_READ_SIZE) {
|
||||
if (!finish) {
|
||||
return 0;
|
||||
}
|
||||
br->eos_ = 1;
|
||||
/* Store BROTLI_IMPLICIT_ZEROES bytes of zero after the stream end. */
|
||||
memset(br->next_in + br->avail_in, 0, BROTLI_IMPLICIT_ZEROES);
|
||||
br->avail_in += BROTLI_IMPLICIT_ZEROES;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
static BROTLI_INLINE void BrotliBitReaderRestoreState(
|
||||
BrotliBitReader* const to, BrotliBitReaderState* from) {
|
||||
to->val_ = from->val_;
|
||||
to->bit_pos_ = from->bit_pos_;
|
||||
to->next_in = from->next_in;
|
||||
to->avail_in = from->avail_in;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t BrotliGetAvailableBits(
|
||||
const BrotliBitReader* br) {
|
||||
return (BROTLI_64_BITS ? 64 : 32) - br->bit_pos_;
|
||||
}
|
||||
|
||||
/* Returns amount of unread bytes the bit reader still has buffered from the
|
||||
BrotliInput, including whole bytes in br->val_. */
|
||||
static BROTLI_INLINE size_t BrotliGetRemainingBytes(BrotliBitReader* br) {
|
||||
size_t result = br->avail_in + sizeof(br->val_) - (br->bit_pos_ >> 3);
|
||||
if (!br->eos_) {
|
||||
return result;
|
||||
}
|
||||
if (result <= BROTLI_IMPLICIT_ZEROES) {
|
||||
return 0;
|
||||
}
|
||||
return result - BROTLI_IMPLICIT_ZEROES;
|
||||
return br->avail_in + (BrotliGetAvailableBits(br) >> 3);
|
||||
}
|
||||
|
||||
/* Checks if there is at least num bytes left in the input ringbuffer (excluding
|
||||
the bits remaining in br->val_). The maximum value for num is
|
||||
BROTLI_IMPLICIT_ZEROES bytes. */
|
||||
the bits remaining in br->val_). */
|
||||
static BROTLI_INLINE int BrotliCheckInputAmount(
|
||||
BrotliBitReader* const br, size_t num) {
|
||||
return br->avail_in >= num;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint16_t BrotliLoad16LE(const uint8_t* in) {
|
||||
if (BROTLI_LITTLE_ENDIAN) {
|
||||
return *((const uint16_t*)in);
|
||||
} else if (BROTLI_BIG_ENDIAN) {
|
||||
uint16_t value = *((const uint16_t*)in);
|
||||
return (uint16_t)(((value & 0xFFU) << 8) | ((value & 0xFF00U) >> 8));
|
||||
} else {
|
||||
return (uint16_t)(in[0] | (in[1] << 8));
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t BrotliLoad32LE(const uint8_t* in) {
|
||||
if (BROTLI_LITTLE_ENDIAN) {
|
||||
return *((const uint32_t*)in);
|
||||
} else if (BROTLI_BIG_ENDIAN) {
|
||||
uint32_t value = *((const uint32_t*)in);
|
||||
return ((value & 0xFFU) << 24) | ((value & 0xFF00U) << 8) |
|
||||
((value & 0xFF0000U) >> 8) | ((value & 0xFF000000U) >> 24);
|
||||
} else {
|
||||
uint32_t value = (uint32_t)(*(in++));
|
||||
value |= (uint32_t)(*(in++)) << 8;
|
||||
value |= (uint32_t)(*(in++)) << 16;
|
||||
value |= (uint32_t)(*(in++)) << 24;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
#if (BROTLI_64_BITS)
|
||||
static BROTLI_INLINE uint64_t BrotliLoad64LE(const uint8_t* in) {
|
||||
if (BROTLI_LITTLE_ENDIAN) {
|
||||
return *((const uint64_t*)in);
|
||||
} else if (BROTLI_BIG_ENDIAN) {
|
||||
uint64_t value = *((const uint64_t*)in);
|
||||
return
|
||||
((value & 0xFFU) << 56) |
|
||||
((value & 0xFF00U) << 40) |
|
||||
((value & 0xFF0000U) << 24) |
|
||||
((value & 0xFF000000U) << 8) |
|
||||
((value & 0xFF00000000U) >> 8) |
|
||||
((value & 0xFF0000000000U) >> 24) |
|
||||
((value & 0xFF000000000000U) >> 40) |
|
||||
((value & 0xFF00000000000000U) >> 56);
|
||||
} else {
|
||||
uint64_t value = (uint64_t)(*(in++));
|
||||
value |= (uint64_t)(*(in++)) << 8;
|
||||
value |= (uint64_t)(*(in++)) << 16;
|
||||
value |= (uint64_t)(*(in++)) << 24;
|
||||
value |= (uint64_t)(*(in++)) << 32;
|
||||
value |= (uint64_t)(*(in++)) << 40;
|
||||
value |= (uint64_t)(*(in++)) << 48;
|
||||
value |= (uint64_t)(*(in++)) << 56;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Guarantees that there are at least n_bits + 1 bits in accumulator.
|
||||
Precondition: accumulator contains at least 1 bit.
|
||||
n_bits should be in the range [1..24] for regular build. For portable
|
||||
non-64-bit little endian build only 16 bits are safe to request. */
|
||||
static BROTLI_INLINE void BrotliFillBitWindow(
|
||||
BrotliBitReader* const br, int n_bits) {
|
||||
#if (BROTLI_64_BITS_LITTLE_ENDIAN)
|
||||
BrotliBitReader* const br, uint32_t n_bits) {
|
||||
#if (BROTLI_64_BITS)
|
||||
if (!BROTLI_ALIGNED_READ && IS_CONSTANT(n_bits) && (n_bits <= 8)) {
|
||||
if (br->bit_pos_ >= 56) {
|
||||
br->val_ >>= 56;
|
||||
br->bit_pos_ ^= 56; /* here same as -= 56 because of the if condition */
|
||||
br->val_ |= (*(const uint64_t*)(br->next_in)) << 8;
|
||||
br->val_ |= BrotliLoad64LE(br->next_in) << 8;
|
||||
br->avail_in -= 7;
|
||||
br->next_in += 7;
|
||||
}
|
||||
@@ -148,7 +179,7 @@ static BROTLI_INLINE void BrotliFillBitWindow(
|
||||
if (br->bit_pos_ >= 48) {
|
||||
br->val_ >>= 48;
|
||||
br->bit_pos_ ^= 48; /* here same as -= 48 because of the if condition */
|
||||
br->val_ |= (*(const uint64_t*)(br->next_in)) << 16;
|
||||
br->val_ |= BrotliLoad64LE(br->next_in) << 16;
|
||||
br->avail_in -= 6;
|
||||
br->next_in += 6;
|
||||
}
|
||||
@@ -156,17 +187,17 @@ static BROTLI_INLINE void BrotliFillBitWindow(
|
||||
if (br->bit_pos_ >= 32) {
|
||||
br->val_ >>= 32;
|
||||
br->bit_pos_ ^= 32; /* here same as -= 32 because of the if condition */
|
||||
br->val_ |= ((uint64_t)(*(const uint32_t*)(br->next_in))) << 32;
|
||||
br->avail_in -= 4;
|
||||
br->next_in += 4;
|
||||
br->val_ |= ((uint64_t)BrotliLoad32LE(br->next_in)) << 32;
|
||||
br->avail_in -= BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
||||
br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
||||
}
|
||||
}
|
||||
#elif (BROTLI_LITTLE_ENDIAN)
|
||||
#else
|
||||
if (!BROTLI_ALIGNED_READ && IS_CONSTANT(n_bits) && (n_bits <= 8)) {
|
||||
if (br->bit_pos_ >= 24) {
|
||||
br->val_ >>= 24;
|
||||
br->bit_pos_ ^= 24; /* here same as -= 24 because of the if condition */
|
||||
br->val_ |= (*(const uint32_t*)(br->next_in)) << 8;
|
||||
br->val_ |= BrotliLoad32LE(br->next_in) << 8;
|
||||
br->avail_in -= 3;
|
||||
br->next_in += 3;
|
||||
}
|
||||
@@ -174,69 +205,105 @@ static BROTLI_INLINE void BrotliFillBitWindow(
|
||||
if (br->bit_pos_ >= 16) {
|
||||
br->val_ >>= 16;
|
||||
br->bit_pos_ ^= 16; /* here same as -= 16 because of the if condition */
|
||||
br->val_ |= ((uint32_t)(*(const uint16_t*)(br->next_in))) << 16;
|
||||
br->avail_in -= 2;
|
||||
br->next_in += 2;
|
||||
br->val_ |= ((uint32_t)BrotliLoad16LE(br->next_in)) << 16;
|
||||
br->avail_in -= BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
||||
br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
||||
}
|
||||
}
|
||||
#else
|
||||
while (br->bit_pos_ >= 16) {
|
||||
BrotliPullByte(br);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Mosltly like BrotliFillBitWindow, but guarantees only 16 bits and reads no
|
||||
more than BROTLI_SHORT_FILL_BIT_WINDOW_READ bytes of input. */
|
||||
static BROTLI_INLINE void BrotliFillBitWindow16(BrotliBitReader* const br) {
|
||||
BrotliFillBitWindow(br, 17);
|
||||
}
|
||||
|
||||
/* Pulls one byte of input to accumulator. */
|
||||
static BROTLI_INLINE void BrotliPullByte(BrotliBitReader* const br) {
|
||||
static BROTLI_INLINE int BrotliPullByte(BrotliBitReader* const br) {
|
||||
if (br->avail_in == 0) {
|
||||
return 0;
|
||||
}
|
||||
br->val_ >>= 8;
|
||||
#if (BROTLI_64_BITS_LITTLE_ENDIAN)
|
||||
br->val_ |= ((uint64_t)*br->next_in) << 56;
|
||||
#if (BROTLI_64_BITS)
|
||||
br->val_ |= ((uint64_t)*br->next_in) << 56;
|
||||
#else
|
||||
br->val_ |= ((uint32_t)*br->next_in) << 24;
|
||||
br->val_ |= ((uint32_t)*br->next_in) << 24;
|
||||
#endif
|
||||
br->bit_pos_ -= 8;
|
||||
--br->avail_in;
|
||||
++br->next_in;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Like BrotliGetBits, but does not mask the result, it is only guaranteed
|
||||
that it has minimum n_bits. */
|
||||
static BROTLI_INLINE uint32_t BrotliGetBitsUnmasked(
|
||||
BrotliBitReader* const br, int n_bits) {
|
||||
BrotliFillBitWindow(br, n_bits);
|
||||
return (uint32_t)(br->val_ >> br->bit_pos_);
|
||||
/* Returns currently available bits.
|
||||
The number of valid bits could be calclulated by BrotliGetAvailableBits. */
|
||||
static BROTLI_INLINE reg_t BrotliGetBitsUnmasked(BrotliBitReader* const br) {
|
||||
return br->val_ >> br->bit_pos_;
|
||||
}
|
||||
|
||||
/* Like BrotliGetBits, but does not mask the result.
|
||||
The result contains at least 16 valid bits. */
|
||||
static BROTLI_INLINE uint32_t BrotliGet16BitsUnmasked(
|
||||
BrotliBitReader* const br) {
|
||||
BrotliFillBitWindow(br, 16);
|
||||
return (uint32_t)BrotliGetBitsUnmasked(br);
|
||||
}
|
||||
|
||||
/* Returns the specified number of bits from br without advancing bit pos. */
|
||||
static BROTLI_INLINE uint32_t BrotliGetBits(
|
||||
BrotliBitReader* const br, int n_bits) {
|
||||
BrotliBitReader* const br, uint32_t n_bits) {
|
||||
BrotliFillBitWindow(br, n_bits);
|
||||
return (uint32_t)(br->val_ >> br->bit_pos_) & BitMask(n_bits);
|
||||
return (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
|
||||
}
|
||||
|
||||
/* Tries to peek the specified amount of bits. Returns 0, if there is not
|
||||
enough input. */
|
||||
static BROTLI_INLINE int BrotliSafeGetBits(
|
||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||
while (BrotliGetAvailableBits(br) < n_bits) {
|
||||
if (!BrotliPullByte(br)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*val = (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Advances the bit pos by n_bits. */
|
||||
static BROTLI_INLINE void BrotliDropBits(
|
||||
BrotliBitReader* const br, int n_bits) {
|
||||
br->bit_pos_ += (uint32_t)n_bits;
|
||||
BrotliBitReader* const br, uint32_t n_bits) {
|
||||
br->bit_pos_ += n_bits;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void BrotliBitReaderUnload(BrotliBitReader* br) {
|
||||
uint32_t unused_bytes = BrotliGetAvailableBits(br) >> 3;
|
||||
uint32_t unused_bits = unused_bytes << 3;
|
||||
br->avail_in += unused_bytes;
|
||||
br->next_in -= unused_bytes;
|
||||
if (unused_bits == sizeof(br->val_) << 3) {
|
||||
br->val_ = 0;
|
||||
} else {
|
||||
br->val_ <<= unused_bits;
|
||||
}
|
||||
br->bit_pos_ += unused_bits;
|
||||
}
|
||||
|
||||
/* Reads the specified number of bits from br and advances the bit pos.
|
||||
Precondition: accumulator MUST contain at least n_bits. */
|
||||
static BROTLI_INLINE void BrotliTakeBits(
|
||||
BrotliBitReader* const br, int n_bits, uint32_t* val) {
|
||||
*val = (uint32_t)(br->val_ >> br->bit_pos_) & BitMask(n_bits);
|
||||
#ifdef BROTLI_DECODE_DEBUG
|
||||
printf("[BrotliReadBits] %d %d %d val: %6x\n",
|
||||
(int)br->avail_in, (int)br->bit_pos_, n_bits, (int)*val);
|
||||
#endif
|
||||
br->bit_pos_ += (uint32_t)n_bits;
|
||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||
*val = (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
|
||||
BROTLI_LOG(("[BrotliReadBits] %d %d %d val: %6x\n",
|
||||
(int)br->avail_in, (int)br->bit_pos_, n_bits, (int)*val));
|
||||
BrotliDropBits(br, n_bits);
|
||||
}
|
||||
|
||||
/* Reads the specified number of bits from br and advances the bit pos.
|
||||
Assumes that there is enough input to perform BrotliFillBitWindow. */
|
||||
static BROTLI_INLINE uint32_t BrotliReadBits(
|
||||
BrotliBitReader* const br, int n_bits) {
|
||||
if (BROTLI_64_BITS_LITTLE_ENDIAN || (n_bits <= 16)) {
|
||||
BrotliBitReader* const br, uint32_t n_bits) {
|
||||
if (BROTLI_64_BITS || (n_bits <= 16)) {
|
||||
uint32_t val;
|
||||
BrotliFillBitWindow(br, n_bits);
|
||||
BrotliTakeBits(br, n_bits, &val);
|
||||
@@ -253,14 +320,13 @@ static BROTLI_INLINE uint32_t BrotliReadBits(
|
||||
}
|
||||
|
||||
/* Tries to read the specified amount of bits. Returns 0, if there is not
|
||||
enough input. */
|
||||
enough input. n_bits MUST be positive. */
|
||||
static BROTLI_INLINE int BrotliSafeReadBits(
|
||||
BrotliBitReader* const br, int n_bits, uint32_t* val) {
|
||||
while (br->bit_pos_ + (uint32_t)n_bits > (sizeof(br->val_) << 3)) {
|
||||
if (br->avail_in == 0) {
|
||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||
while (BrotliGetAvailableBits(br) < n_bits) {
|
||||
if (!BrotliPullByte(br)) {
|
||||
return 0;
|
||||
}
|
||||
BrotliPullByte(br);
|
||||
}
|
||||
BrotliTakeBits(br, n_bits, val);
|
||||
return 1;
|
||||
@@ -269,7 +335,7 @@ static BROTLI_INLINE int BrotliSafeReadBits(
|
||||
/* Advances the bit reader position to the next byte boundary and verifies
|
||||
that any skipped bits are set to zero. */
|
||||
static BROTLI_INLINE int BrotliJumpToByteBoundary(BrotliBitReader* br) {
|
||||
int pad_bits_count = (64 - (int)br->bit_pos_) & 0x7;
|
||||
uint32_t pad_bits_count = BrotliGetAvailableBits(br) & 0x7;
|
||||
uint32_t pad_bits = 0;
|
||||
if (pad_bits_count != 0) {
|
||||
BrotliTakeBits(br, pad_bits_count, &pad_bits);
|
||||
@@ -280,16 +346,15 @@ static BROTLI_INLINE int BrotliJumpToByteBoundary(BrotliBitReader* br) {
|
||||
/* Peeks a byte at specified offset.
|
||||
Precondition: bit reader is parked to a byte boundary.
|
||||
Returns -1 if operation is not feasible. */
|
||||
static BROTLI_INLINE int BrotliPeekByte(BrotliBitReader* br, int offset) {
|
||||
int bytes_left = (int)(sizeof(br->val_) - (br->bit_pos_ >> 3));
|
||||
if (br->bit_pos_ & 7) {
|
||||
return -1;
|
||||
}
|
||||
static BROTLI_INLINE int BrotliPeekByte(BrotliBitReader* br, size_t offset) {
|
||||
uint32_t available_bits = BrotliGetAvailableBits(br);
|
||||
size_t bytes_left = available_bits >> 3;
|
||||
BROTLI_DCHECK((available_bits & 7) == 0);
|
||||
if (offset < bytes_left) {
|
||||
return (br->val_ >> (br->bit_pos_ + (unsigned)(offset << 3))) & 0xFF;
|
||||
return (BrotliGetBitsUnmasked(br) >> (unsigned)(offset << 3)) & 0xFF;
|
||||
}
|
||||
offset -= bytes_left;
|
||||
if (offset < (long)br->avail_in) {
|
||||
if (offset < br->avail_in) {
|
||||
return br->next_in[offset];
|
||||
}
|
||||
return -1;
|
||||
@@ -300,32 +365,19 @@ static BROTLI_INLINE int BrotliPeekByte(BrotliBitReader* br, int offset) {
|
||||
warmed up again after this. */
|
||||
static BROTLI_INLINE void BrotliCopyBytes(uint8_t* dest,
|
||||
BrotliBitReader* br, size_t num) {
|
||||
while (br->bit_pos_ + 8 <= (BROTLI_64_BITS_LITTLE_ENDIAN ? 64 : 32)
|
||||
&& num > 0) {
|
||||
*dest = (uint8_t)(br->val_ >> br->bit_pos_);
|
||||
br->bit_pos_ += 8;
|
||||
while (BrotliGetAvailableBits(br) >= 8 && num > 0) {
|
||||
*dest = (uint8_t)BrotliGetBitsUnmasked(br);
|
||||
BrotliDropBits(br, 8);
|
||||
++dest;
|
||||
--num;
|
||||
}
|
||||
memcpy(dest, br->next_in, num);
|
||||
br->avail_in -= (uint32_t)num;
|
||||
br->avail_in -= num;
|
||||
br->next_in += num;
|
||||
}
|
||||
|
||||
/* Checks that bit reader hasn't read after the end of input.
|
||||
Returns 0 if bit reader has used implicit zeroes after the end of input. */
|
||||
static BROTLI_INLINE int BrotliIsBitReaderOK(BrotliBitReader* br) {
|
||||
size_t remaining_bytes =
|
||||
br->avail_in + sizeof(br->val_) - (br->bit_pos_ >> 3);
|
||||
return !br->eos_ || (remaining_bytes >= BROTLI_IMPLICIT_ZEROES);
|
||||
}
|
||||
|
||||
#undef BROTLI_IMPLICIT_ZEROES
|
||||
#undef BROTLI_IBUF_SIZE
|
||||
#undef BROTLI_IBUF_MASK
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* BROTLI_DEC_BIT_READER_H_ */
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Lookup table to map the previous two bytes to a context id.
|
||||
@@ -111,10 +102,10 @@
|
||||
#include "./types.h"
|
||||
|
||||
enum ContextType {
|
||||
CONTEXT_LSB6 = 0,
|
||||
CONTEXT_MSB6 = 1,
|
||||
CONTEXT_UTF8 = 2,
|
||||
CONTEXT_SIGNED = 3
|
||||
CONTEXT_LSB6 = 0,
|
||||
CONTEXT_MSB6 = 1,
|
||||
CONTEXT_UTF8 = 2,
|
||||
CONTEXT_SIGNED = 3
|
||||
};
|
||||
|
||||
/* Common context lookup table for all context modes. */
|
||||
|
||||
+1583
-1029
File diff suppressed because it is too large
Load Diff
+112
-111
@@ -1,16 +1,7 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* API for Brotli decompression */
|
||||
@@ -18,141 +9,151 @@
|
||||
#ifndef BROTLI_DEC_DECODE_H_
|
||||
#define BROTLI_DEC_DECODE_H_
|
||||
|
||||
#include "./state.h"
|
||||
#include "./streams.h"
|
||||
#include "./types.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct BrotliStateStruct BrotliState;
|
||||
|
||||
typedef enum {
|
||||
/* Decoding error, e.g. corrupt input or no memory */
|
||||
/* Decoding error, e.g. corrupt input or memory allocation problem */
|
||||
BROTLI_RESULT_ERROR = 0,
|
||||
/* Successfully completely done */
|
||||
/* Decoding successfully completed */
|
||||
BROTLI_RESULT_SUCCESS = 1,
|
||||
/* Partially done, but must be called again with more input */
|
||||
/* Partially done; should be called again with more input */
|
||||
BROTLI_RESULT_NEEDS_MORE_INPUT = 2,
|
||||
/* Partially done, but must be called again with more output */
|
||||
/* Partially done; should be called again with more output */
|
||||
BROTLI_RESULT_NEEDS_MORE_OUTPUT = 3
|
||||
} BrotliResult;
|
||||
|
||||
/* BROTLI_FAILURE macro unwraps to BROTLI_RESULT_ERROR in non-debug build. */
|
||||
/* In debug build it dumps file name, line and pretty function name. */
|
||||
#if defined(_MSC_VER) || !defined(BROTLI_DEBUG)
|
||||
#define BROTLI_FAILURE() BROTLI_RESULT_ERROR
|
||||
#else
|
||||
#define BROTLI_FAILURE() \
|
||||
BrotliFailure(__FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
static inline BrotliResult BrotliFailure(const char *f, int l, const char *fn) {
|
||||
fprintf(stderr, "ERROR at %s:%d (%s)\n", f, l, fn);
|
||||
fflush(stderr);
|
||||
return BROTLI_RESULT_ERROR;
|
||||
}
|
||||
#endif
|
||||
#define BROTLI_ERROR_CODES_LIST(BROTLI_ERROR_CODE, SEPARATOR) \
|
||||
BROTLI_ERROR_CODE(_, NO_ERROR, 0) SEPARATOR \
|
||||
/* Same as BrotliResult values */ \
|
||||
BROTLI_ERROR_CODE(_, SUCCESS, 1) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(_, NEEDS_MORE_INPUT, 2) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(_, NEEDS_MORE_OUTPUT, 3) SEPARATOR \
|
||||
\
|
||||
/* Errors caused by invalid input */ \
|
||||
BROTLI_ERROR_CODE(_ERROR_FORMAT_, EXUBERANT_NIBBLE, -1) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(_ERROR_FORMAT_, RESERVED, -2) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(_ERROR_FORMAT_, EXUBERANT_META_NIBBLE, -3) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(_ERROR_FORMAT_, SIMPLE_HUFFMAN_ALPHABET, -4) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(_ERROR_FORMAT_, SIMPLE_HUFFMAN_SAME, -5) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(_ERROR_FORMAT_, CL_SPACE, -6) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(_ERROR_FORMAT_, HUFFMAN_SPACE, -7) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(_ERROR_FORMAT_, CONTEXT_MAP_REPEAT, -8) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(_ERROR_FORMAT_, BLOCK_LENGTH_1, -9) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(_ERROR_FORMAT_, BLOCK_LENGTH_2, -10) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(_ERROR_FORMAT_, TRANSFORM, -11) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(_ERROR_FORMAT_, DICTIONARY, -12) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(_ERROR_FORMAT_, WINDOW_BITS, -13) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(_ERROR_FORMAT_, PADDING_1, -14) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(_ERROR_FORMAT_, PADDING_2, -15) SEPARATOR \
|
||||
\
|
||||
/* -16..-20 codes are reserved */ \
|
||||
\
|
||||
/* Memory allocation problems */ \
|
||||
BROTLI_ERROR_CODE(_ERROR_ALLOC_, CONTEXT_MODES, -21) SEPARATOR \
|
||||
/* Literal, insert and distance trees together */ \
|
||||
BROTLI_ERROR_CODE(_ERROR_ALLOC_, TREE_GROUPS, -22) SEPARATOR \
|
||||
/* -23..-24 codes are reserved for distinct tree groups */ \
|
||||
BROTLI_ERROR_CODE(_ERROR_ALLOC_, CONTEXT_MAP, -25) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(_ERROR_ALLOC_, RING_BUFFER_1, -26) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(_ERROR_ALLOC_, RING_BUFFER_2, -27) SEPARATOR \
|
||||
/* -28..-29 codes are reserved for dynamic ringbuffer allocation */ \
|
||||
BROTLI_ERROR_CODE(_ERROR_ALLOC_, BLOCK_TYPE_TREES, -30) SEPARATOR \
|
||||
\
|
||||
/* "Impossible" states */ \
|
||||
BROTLI_ERROR_CODE(_ERROR_, UNREACHABLE, -31)
|
||||
|
||||
/* Sets *decoded_size to the decompressed size of the given encoded stream. */
|
||||
/* This function only works if the encoded buffer has a single meta block, */
|
||||
/* or if it has two meta-blocks, where the first is uncompressed and the */
|
||||
/* second is empty. */
|
||||
/* Returns 1 on success, 0 on failure. */
|
||||
typedef enum {
|
||||
#define _BROTLI_COMMA ,
|
||||
#define _BROTLI_ERROR_CODE_ENUM_ITEM(PREFIX, NAME, CODE) \
|
||||
BROTLI ## PREFIX ## NAME = CODE
|
||||
BROTLI_ERROR_CODES_LIST(_BROTLI_ERROR_CODE_ENUM_ITEM, _BROTLI_COMMA)
|
||||
#undef _BROTLI_ERROR_CODE_ENUM_ITEM
|
||||
#undef _BROTLI_COMMA
|
||||
} BrotliErrorCode;
|
||||
|
||||
#define BROTLI_LAST_ERROR_CODE BROTLI_ERROR_UNREACHABLE
|
||||
|
||||
/* Creates the instance of BrotliState and initializes it. |alloc_func| and
|
||||
|free_func| MUST be both zero or both non-zero. In the case they are both
|
||||
zero, default memory allocators are used. |opaque| is passed to |alloc_func|
|
||||
and |free_func| when they are called. */
|
||||
BrotliState* BrotliCreateState(
|
||||
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque);
|
||||
|
||||
/* Deinitializes and frees BrotliState instance. */
|
||||
void BrotliDestroyState(BrotliState* state);
|
||||
|
||||
/* Sets |*decoded_size| to the decompressed size of the given encoded stream.
|
||||
This function only works if the encoded buffer has a single meta block,
|
||||
or if it has two meta-blocks, where the first is uncompressed and the
|
||||
second is empty.
|
||||
Returns 1 on success, 0 on failure. */
|
||||
int BrotliDecompressedSize(size_t encoded_size,
|
||||
const uint8_t* encoded_buffer,
|
||||
size_t* decoded_size);
|
||||
|
||||
/* Decompresses the data in encoded_buffer into decoded_buffer, and sets */
|
||||
/* *decoded_size to the decompressed length. */
|
||||
/* Returns 0 if there was either a bit stream error or memory allocation */
|
||||
/* error, and 1 otherwise. */
|
||||
/* If decoded size is zero, returns 1 and keeps decoded_buffer unchanged. */
|
||||
/* Decompresses the data in |encoded_buffer| into |decoded_buffer|, and sets
|
||||
|*decoded_size| to the decompressed length. */
|
||||
BrotliResult BrotliDecompressBuffer(size_t encoded_size,
|
||||
const uint8_t* encoded_buffer,
|
||||
size_t* decoded_size,
|
||||
uint8_t* decoded_buffer);
|
||||
|
||||
/* Same as above, but uses the specified input and output callbacks instead */
|
||||
/* of reading from and writing to pre-allocated memory buffers. */
|
||||
BrotliResult BrotliDecompress(BrotliInput input, BrotliOutput output);
|
||||
/* Decompresses the data. Supports partial input and output.
|
||||
|
||||
/* Same as above, but supports the caller to call the decoder repeatedly with
|
||||
partial data to support streaming. The state must be initialized with
|
||||
BrotliStateInit and reused with every call for the same stream.
|
||||
Return values:
|
||||
0: failure.
|
||||
1: success, and done.
|
||||
2: success so far, end not reached so should call again with more input.
|
||||
The finish parameter is used as follows, for a series of calls with the
|
||||
same state:
|
||||
0: Every call except the last one must be called with finish set to 0. The
|
||||
last call may have finish set to either 0 or 1. Only if finish is 0, can
|
||||
the function return 2. It may also return 0 or 1, in that case no more
|
||||
calls (even with finish 1) may be made.
|
||||
1: Only the last call may have finish set to 1. It's ok to give empty input
|
||||
if all input was already given to previous calls. It is also ok to have
|
||||
only one single call in total, with finish 1, and with all input
|
||||
available immediately. That matches the non-streaming case. If finish is
|
||||
1, the function can only return 0 or 1, never 2. After a finish, no more
|
||||
calls may be done.
|
||||
After everything is done, the state must be cleaned with BrotliStateCleanup
|
||||
to free allocated resources.
|
||||
The given BrotliOutput must always accept all output and make enough space,
|
||||
it returning a smaller value than the amount of bytes to write always results
|
||||
in an error.
|
||||
*/
|
||||
BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
int finish, BrotliState* s);
|
||||
Must be called with an allocated input buffer in |*next_in| and an allocated
|
||||
output buffer in |*next_out|. The values |*available_in| and |*available_out|
|
||||
must specify the allocated size in |*next_in| and |*next_out| respectively.
|
||||
|
||||
/* Same as above, but with memory buffers.
|
||||
Must be called with an allocated input buffer in *next_in and an allocated
|
||||
output buffer in *next_out. The values *available_in and *available_out
|
||||
must specify the allocated size in *next_in and *next_out respectively.
|
||||
The value *total_out must be 0 initially, and will be summed with the
|
||||
amount of output bytes written after each call, so that at the end it
|
||||
gives the complete decoded size.
|
||||
After each call, *available_in will be decremented by the amount of input
|
||||
bytes consumed, and the *next_in pointer will be incremented by that amount.
|
||||
Similarly, *available_out will be decremented by the amount of output
|
||||
bytes written, and the *next_out pointer will be incremented by that
|
||||
amount.
|
||||
After each call, |*available_in| will be decremented by the amount of input
|
||||
bytes consumed, and the |*next_in| pointer will be incremented by that
|
||||
amount. Similarly, |*available_out| will be decremented by the amount of
|
||||
output bytes written, and the |*next_out| pointer will be incremented by that
|
||||
amount. |total_out|, if it is not a null-pointer, will be set to the number
|
||||
of bytes decompressed since the last state initialization.
|
||||
|
||||
The input may be partial. With each next function call, *next_in and
|
||||
*available_in must be updated to point to a next part of the compressed
|
||||
input. The current implementation will always consume all input unless
|
||||
an error occurs, so normally *available_in will always be 0 after
|
||||
calling this function and the next adjacent part of input is desired.
|
||||
|
||||
In the current implementation, the function requires that there is enough
|
||||
output buffer size to write all currently processed input, so
|
||||
*available_out must be large enough. Since the function updates *next_out
|
||||
each time, as long as the output buffer is large enough you can keep
|
||||
reusing this variable. It is also possible to update *next_out and
|
||||
*available_out yourself before a next call, e.g. to point to a new larger
|
||||
buffer.
|
||||
*/
|
||||
BrotliResult BrotliDecompressBufferStreaming(size_t* available_in,
|
||||
const uint8_t** next_in,
|
||||
int finish,
|
||||
size_t* available_out,
|
||||
uint8_t** next_out,
|
||||
size_t* total_out,
|
||||
BrotliState* s);
|
||||
Input is never overconsumed, so |next_in| and |available_in| could be passed
|
||||
to the next consumer after decoding is complete. */
|
||||
BrotliResult BrotliDecompressStream(size_t* available_in,
|
||||
const uint8_t** next_in,
|
||||
size_t* available_out,
|
||||
uint8_t** next_out,
|
||||
size_t* total_out,
|
||||
BrotliState* s);
|
||||
|
||||
/* Fills the new state with a dictionary for LZ77, warming up the ringbuffer,
|
||||
e.g. for custom static dictionaries for data formats.
|
||||
Not to be confused with the built-in transformable dictionary of Brotli.
|
||||
The dictionary must exist in memory until decoding is done and is owned by
|
||||
the caller. To use:
|
||||
-initialize state with BrotliStateInit
|
||||
-use BrotliSetCustomDictionary
|
||||
-use BrotliDecompressBufferStreaming
|
||||
-clean up with BrotliStateCleanup
|
||||
|size| should be less or equal to 2^24 (16MiB), otherwise the dictionary will
|
||||
be ignored. The dictionary must exist in memory until decoding is done and
|
||||
is owned by the caller. To use:
|
||||
1) Allocate and initialize state with BrotliCreateState
|
||||
2) Use BrotliSetCustomDictionary
|
||||
3) Use BrotliDecompressStream
|
||||
4) Clean up and free state with BrotliDestroyState
|
||||
*/
|
||||
void BrotliSetCustomDictionary(
|
||||
size_t size, const uint8_t* dict, BrotliState* s);
|
||||
|
||||
/* Returns 1, if s is in a state where we have not read any input bytes yet,
|
||||
and 0 otherwise */
|
||||
int BrotliStateIsStreamStart(const BrotliState* s);
|
||||
|
||||
/* Escalate internal functions visibility; for testing purposes only. */
|
||||
void InverseMoveToFrontTransformForTesting(uint8_t* v, int l, BrotliState* s);
|
||||
/* Returns 1, if s is in a state where we reached the end of the input and
|
||||
produced all of the output, and 0 otherwise. */
|
||||
int BrotliStateIsStreamEnd(const BrotliState* s);
|
||||
|
||||
/* Returns detailed error code after BrotliDecompressStream returns
|
||||
BROTLI_RESULT_ERROR. */
|
||||
BrotliErrorCode BrotliGetErrorCode(const BrotliState* s);
|
||||
|
||||
const char* BrotliErrorString(BrotliErrorCode c);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "./dictionary.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* In case of multiple definition linker error with dictionary.cc from the
|
||||
encoder: include only one of enc/dictionary.cc or dec/dictionary.c in a
|
||||
target using both enc and dec. */
|
||||
@@ -9465,3 +9460,7 @@ const uint8_t kBrotliDictionary[122784] = {
|
||||
0x88, 0xe0, 0xa4, 0xb8, 0xe0, 0xa4, 0x95, 0xe0, 0xa5, 0x8d, 0xe0, 0xa4, 0xb0,
|
||||
0xe0, 0xa4, 0xbf, 0xe0, 0xa4, 0xaf, 0xe0, 0xa4, 0xa4, 0xe0, 0xa4, 0xbe,
|
||||
};
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Collection of static dictionary words. */
|
||||
@@ -26,23 +17,22 @@ extern "C" {
|
||||
|
||||
extern const uint8_t kBrotliDictionary[122784];
|
||||
|
||||
static const int kBrotliDictionaryOffsetsByLength[] = {
|
||||
0, 0, 0, 0, 0, 4096, 9216, 21504, 35840, 44032,
|
||||
53248, 63488, 74752, 87040, 93696, 100864, 104704, 106752, 108928, 113536,
|
||||
115968, 118528, 119872, 121280, 122016,
|
||||
static const uint32_t kBrotliDictionaryOffsetsByLength[] = {
|
||||
0, 0, 0, 0, 0, 4096, 9216, 21504, 35840, 44032, 53248, 63488, 74752, 87040,
|
||||
93696, 100864, 104704, 106752, 108928, 113536, 115968, 118528, 119872, 121280,
|
||||
122016
|
||||
};
|
||||
|
||||
static const int8_t kBrotliDictionarySizeBitsByLength[] = {
|
||||
0, 0, 0, 0, 10, 10, 11, 11, 10, 10,
|
||||
10, 10, 10, 9, 9, 8, 7, 7, 8, 7,
|
||||
7, 6, 6, 5, 5,
|
||||
static const uint8_t kBrotliDictionarySizeBitsByLength[] = {
|
||||
0, 0, 0, 0, 10, 10, 11, 11, 10, 10, 10, 10, 10,
|
||||
9, 9, 8, 7, 7, 8, 7, 7, 6, 6, 5, 5,
|
||||
};
|
||||
|
||||
static const int kBrotliMinDictionaryWordLength = 4;
|
||||
static const int kBrotliMaxDictionaryWordLength = 24;
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* BROTLI_DEC_DICTIONARY_H_ */
|
||||
|
||||
+156
-126
@@ -1,41 +1,75 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Utilities for building Huffman decoding tables. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "./huffman.h"
|
||||
|
||||
#include <string.h> /* memcpy, memset */
|
||||
|
||||
#include "./port.h"
|
||||
#include "./types.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Returns reverse(reverse(key, len) + 1, len), where reverse(key, len) is the
|
||||
bit-wise reversal of the len least significant bits of key. */
|
||||
static BROTLI_INLINE uint32_t GetNextKey(uint32_t key, int len) {
|
||||
#define BROTLI_REVERSE_BITS_MAX 8
|
||||
|
||||
#ifdef BROTLI_RBIT
|
||||
return BROTLI_RBIT(BROTLI_RBIT(key) + (1 << (8 * sizeof(unsigned) - len)));
|
||||
#define BROTLI_REVERSE_BITS_BASE (32 - BROTLI_REVERSE_BITS_MAX)
|
||||
#else
|
||||
unsigned step = (unsigned)(1 << (len - 1));
|
||||
while (key & step) {
|
||||
step >>= 1;
|
||||
}
|
||||
return (key & (step - 1)) + step;
|
||||
#define BROTLI_REVERSE_BITS_BASE 0
|
||||
static uint8_t kReverseBits[1 << BROTLI_REVERSE_BITS_MAX] = {
|
||||
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
|
||||
0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
|
||||
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
|
||||
0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
|
||||
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
|
||||
0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
|
||||
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
|
||||
0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
|
||||
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
|
||||
0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
|
||||
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
|
||||
0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
|
||||
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
|
||||
0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
|
||||
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
|
||||
0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
|
||||
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
|
||||
0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
|
||||
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
|
||||
0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
|
||||
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
|
||||
0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
|
||||
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
|
||||
0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
|
||||
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
|
||||
0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
|
||||
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
|
||||
0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
|
||||
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
|
||||
0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
|
||||
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
|
||||
0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
|
||||
};
|
||||
#endif /* BROTLI_RBIT */
|
||||
|
||||
#define BROTLI_REVERSE_BITS_LOWEST \
|
||||
(1U << (BROTLI_REVERSE_BITS_MAX - 1 + BROTLI_REVERSE_BITS_BASE))
|
||||
|
||||
/* Returns reverse(num >> BROTLI_REVERSE_BITS_BASE, BROTLI_REVERSE_BITS_MAX),
|
||||
where reverse(value, len) is the bit-wise reversal of the len least
|
||||
significant bits of value. */
|
||||
static BROTLI_INLINE uint32_t BrotliReverseBits(uint32_t num) {
|
||||
#ifdef BROTLI_RBIT
|
||||
return BROTLI_RBIT(num);
|
||||
#else
|
||||
return kReverseBits[num];
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -65,20 +99,22 @@ static BROTLI_INLINE int NextTableBitSize(const uint16_t* const count,
|
||||
return len - root_bits;
|
||||
}
|
||||
|
||||
|
||||
void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
|
||||
const uint8_t* const code_lengths,
|
||||
uint16_t *count) {
|
||||
HuffmanCode code; /* current table entry */
|
||||
int symbol; /* symbol index in original or sorted table */
|
||||
unsigned key; /* reversed prefix code */
|
||||
int step; /* step size to replicate values in current table */
|
||||
int table_size; /* size of current table */
|
||||
int sorted[18]; /* symbols sorted by code length */
|
||||
uint16_t* count) {
|
||||
HuffmanCode code; /* current table entry */
|
||||
int symbol; /* symbol index in original or sorted table */
|
||||
uint32_t key; /* prefix code */
|
||||
uint32_t key_step; /* prefix code addend */
|
||||
int step; /* step size to replicate values in current table */
|
||||
int table_size; /* size of current table */
|
||||
int sorted[18]; /* symbols sorted by code length */
|
||||
/* offsets in sorted table for each length */
|
||||
int offset[BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH + 1];
|
||||
int bits;
|
||||
int bits_count;
|
||||
BROTLI_DCHECK(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH <=
|
||||
BROTLI_REVERSE_BITS_MAX);
|
||||
|
||||
/* generate offsets into sorted symbol table by code length */
|
||||
symbol = -1;
|
||||
@@ -106,7 +142,7 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
|
||||
if (offset[0] == 0) {
|
||||
code.bits = 0;
|
||||
code.value = (uint16_t)sorted[0];
|
||||
for (key = 0; key < table_size; ++key) {
|
||||
for (key = 0; key < (uint32_t)table_size; ++key) {
|
||||
table[key] = code;
|
||||
}
|
||||
return;
|
||||
@@ -114,6 +150,7 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
|
||||
|
||||
/* fill in table */
|
||||
key = 0;
|
||||
key_step = BROTLI_REVERSE_BITS_LOWEST;
|
||||
symbol = 0;
|
||||
bits = 1;
|
||||
step = 2;
|
||||
@@ -121,32 +158,38 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
|
||||
code.bits = (uint8_t)bits;
|
||||
for (bits_count = count[bits]; bits_count != 0; --bits_count) {
|
||||
code.value = (uint16_t)sorted[symbol++];
|
||||
ReplicateValue(&table[key], step, table_size, code);
|
||||
key = GetNextKey(key, bits);
|
||||
ReplicateValue(&table[BrotliReverseBits(key)], step, table_size, code);
|
||||
key += key_step;
|
||||
}
|
||||
step <<= 1;
|
||||
key_step >>= 1;
|
||||
} while (++bits <= BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH);
|
||||
}
|
||||
|
||||
int BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||
int root_bits,
|
||||
const uint16_t* const symbol_lists,
|
||||
uint16_t *count) {
|
||||
HuffmanCode code; /* current table entry */
|
||||
HuffmanCode* table; /* next available space in table */
|
||||
int len; /* current code length */
|
||||
int symbol; /* symbol index in original or sorted table */
|
||||
unsigned key; /* reversed prefix code */
|
||||
int step; /* step size to replicate values in current table */
|
||||
unsigned low; /* low bits for current root entry */
|
||||
unsigned mask; /* mask for low bits */
|
||||
int table_bits; /* key length of current table */
|
||||
int table_size; /* size of current table */
|
||||
int total_size; /* sum of root table size and 2nd level table sizes */
|
||||
uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||
int root_bits,
|
||||
const uint16_t* const symbol_lists,
|
||||
uint16_t* count) {
|
||||
HuffmanCode code; /* current table entry */
|
||||
HuffmanCode* table; /* next available space in table */
|
||||
int len; /* current code length */
|
||||
int symbol; /* symbol index in original or sorted table */
|
||||
uint32_t key; /* prefix code */
|
||||
uint32_t key_step; /* prefix code addend */
|
||||
uint32_t sub_key; /* 2nd level table prefix code */
|
||||
uint32_t sub_key_step; /* 2nd level table prefix code addend */
|
||||
int step; /* step size to replicate values in current table */
|
||||
int table_bits; /* key length of current table */
|
||||
int table_size; /* size of current table */
|
||||
int total_size; /* sum of root table size and 2nd level table sizes */
|
||||
int max_length = -1;
|
||||
int bits;
|
||||
int bits_count;
|
||||
|
||||
BROTLI_DCHECK(root_bits <= BROTLI_REVERSE_BITS_MAX);
|
||||
BROTLI_DCHECK(BROTLI_HUFFMAN_MAX_CODE_LENGTH - root_bits <=
|
||||
BROTLI_REVERSE_BITS_MAX);
|
||||
|
||||
while (symbol_lists[max_length] == 0xFFFF) max_length--;
|
||||
max_length += BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1;
|
||||
|
||||
@@ -163,6 +206,7 @@ int BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||
table_size = 1 << table_bits;
|
||||
}
|
||||
key = 0;
|
||||
key_step = BROTLI_REVERSE_BITS_LOWEST;
|
||||
bits = 1;
|
||||
step = 2;
|
||||
do {
|
||||
@@ -171,10 +215,11 @@ int BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||
for (bits_count = count[bits]; bits_count != 0; --bits_count) {
|
||||
symbol = symbol_lists[symbol];
|
||||
code.value = (uint16_t)symbol;
|
||||
ReplicateValue(&table[key], step, table_size, code);
|
||||
key = GetNextKey(key, bits);
|
||||
ReplicateValue(&table[BrotliReverseBits(key)], step, table_size, code);
|
||||
key += key_step;
|
||||
}
|
||||
step <<= 1;
|
||||
key_step >>= 1;
|
||||
} while (++bits <= table_bits);
|
||||
|
||||
/* if root_bits != table_bits we only created one fraction of the */
|
||||
@@ -186,37 +231,43 @@ int BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||
}
|
||||
|
||||
/* fill in 2nd level tables and add pointers to root table */
|
||||
mask = (unsigned)(total_size - 1);
|
||||
low = (unsigned)-1;
|
||||
for (len = root_bits + 1, step = 2; len <= max_length; ++len, step <<= 1) {
|
||||
key_step = BROTLI_REVERSE_BITS_LOWEST >> (root_bits - 1);
|
||||
sub_key = (BROTLI_REVERSE_BITS_LOWEST << 1);
|
||||
sub_key_step = BROTLI_REVERSE_BITS_LOWEST;
|
||||
for (len = root_bits + 1, step = 2; len <= max_length; ++len) {
|
||||
symbol = len - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
|
||||
for (; count[len] != 0; --count[len]) {
|
||||
if ((key & mask) != low) {
|
||||
if (sub_key == (BROTLI_REVERSE_BITS_LOWEST << 1U)) {
|
||||
table += table_size;
|
||||
table_bits = NextTableBitSize(count, len, root_bits);
|
||||
table_size = 1 << table_bits;
|
||||
total_size += table_size;
|
||||
low = key & mask;
|
||||
root_table[low].bits = (uint8_t)(table_bits + root_bits);
|
||||
root_table[low].value = (uint16_t)(
|
||||
((size_t)(table - root_table)) - low);
|
||||
sub_key = BrotliReverseBits(key);
|
||||
key += key_step;
|
||||
root_table[sub_key].bits = (uint8_t)(table_bits + root_bits);
|
||||
root_table[sub_key].value =
|
||||
(uint16_t)(((size_t)(table - root_table)) - sub_key);
|
||||
sub_key = 0;
|
||||
}
|
||||
code.bits = (uint8_t)(len - root_bits);
|
||||
symbol = symbol_lists[symbol];
|
||||
code.value = (uint16_t)symbol;
|
||||
ReplicateValue(&table[key >> root_bits], step, table_size, code);
|
||||
key = GetNextKey(key, len);
|
||||
ReplicateValue(
|
||||
&table[BrotliReverseBits(sub_key)], step, table_size, code);
|
||||
sub_key += sub_key_step;
|
||||
}
|
||||
step <<= 1;
|
||||
sub_key_step >>= 1;
|
||||
}
|
||||
return total_size;
|
||||
return (uint32_t)total_size;
|
||||
}
|
||||
|
||||
int BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
|
||||
int root_bits,
|
||||
uint16_t *val,
|
||||
uint32_t num_symbols) {
|
||||
int table_size = 1;
|
||||
const int goal_size = 1 << root_bits;
|
||||
uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
|
||||
int root_bits,
|
||||
uint16_t* val,
|
||||
uint32_t num_symbols) {
|
||||
uint32_t table_size = 1;
|
||||
const uint32_t goal_size = 1U << root_bits;
|
||||
switch (num_symbols) {
|
||||
case 0:
|
||||
table[0].bits = 0;
|
||||
@@ -250,49 +301,47 @@ int BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
|
||||
table[3].bits = 2;
|
||||
table_size = 4;
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
int i, k;
|
||||
for (i = 0; i < 3; ++i) {
|
||||
for (k = i + 1; k < 4; ++k) {
|
||||
if (val[k] < val[i]) {
|
||||
uint16_t t = val[k];
|
||||
val[k] = val[i];
|
||||
val[i] = t;
|
||||
}
|
||||
case 3: {
|
||||
int i, k;
|
||||
for (i = 0; i < 3; ++i) {
|
||||
for (k = i + 1; k < 4; ++k) {
|
||||
if (val[k] < val[i]) {
|
||||
uint16_t t = val[k];
|
||||
val[k] = val[i];
|
||||
val[i] = t;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 4; ++i) {
|
||||
table[i].bits = 2;
|
||||
}
|
||||
table[0].value = val[0];
|
||||
table[2].value = val[1];
|
||||
table[1].value = val[2];
|
||||
table[3].value = val[3];
|
||||
table_size = 4;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
int i;
|
||||
if (val[3] < val[2]) {
|
||||
uint16_t t = val[3];
|
||||
val[3] = val[2];
|
||||
val[2] = t;
|
||||
}
|
||||
for (i = 0; i < 7; ++i) {
|
||||
table[i].value = val[0];
|
||||
table[i].bits = (uint8_t)(1 + (i & 1));
|
||||
}
|
||||
table[1].value = val[1];
|
||||
table[3].value = val[2];
|
||||
table[5].value = val[1];
|
||||
table[7].value = val[3];
|
||||
table[3].bits = 3;
|
||||
table[7].bits = 3;
|
||||
table_size = 8;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
table[i].bits = 2;
|
||||
}
|
||||
table[0].value = val[0];
|
||||
table[2].value = val[1];
|
||||
table[1].value = val[2];
|
||||
table[3].value = val[3];
|
||||
table_size = 4;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
int i;
|
||||
if (val[3] < val[2]) {
|
||||
uint16_t t = val[3];
|
||||
val[3] = val[2];
|
||||
val[2] = t;
|
||||
}
|
||||
for (i = 0; i < 7; ++i) {
|
||||
table[i].value = val[0];
|
||||
table[i].bits = (uint8_t)(1 + (i & 1));
|
||||
}
|
||||
table[1].value = val[1];
|
||||
table[3].value = val[2];
|
||||
table[5].value = val[1];
|
||||
table[7].value = val[3];
|
||||
table[3].bits = 3;
|
||||
table[7].bits = 3;
|
||||
table_size = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (table_size != goal_size) {
|
||||
memcpy(&table[table_size], &table[0],
|
||||
@@ -302,25 +351,6 @@ int BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
|
||||
return goal_size;
|
||||
}
|
||||
|
||||
void BrotliHuffmanTreeGroupInit(HuffmanTreeGroup* group, int alphabet_size,
|
||||
int ntrees) {
|
||||
/* Pack two mallocs into one */
|
||||
const size_t code_size =
|
||||
sizeof(HuffmanCode) * (size_t)(ntrees * BROTLI_HUFFMAN_MAX_TABLE_SIZE);
|
||||
const size_t htree_size = sizeof(HuffmanCode*) * (size_t)ntrees;
|
||||
char *p = (char*)malloc(code_size + htree_size);
|
||||
group->alphabet_size = (int16_t)alphabet_size;
|
||||
group->num_htrees = (int16_t)ntrees;
|
||||
group->codes = (HuffmanCode*)p;
|
||||
group->htrees = (HuffmanCode**)(p + code_size);
|
||||
}
|
||||
|
||||
void BrotliHuffmanTreeGroupRelease(HuffmanTreeGroup* group) {
|
||||
if (group->codes) {
|
||||
free(group->codes);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Utilities for building Huffman decoding tables. */
|
||||
@@ -19,6 +10,7 @@
|
||||
#define BROTLI_DEC_HUFFMAN_H_
|
||||
|
||||
#include "./types.h"
|
||||
#include "./port.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -29,53 +21,48 @@ extern "C" {
|
||||
/* For current format this constant equals to kNumInsertAndCopyCodes */
|
||||
#define BROTLI_HUFFMAN_MAX_CODE_LENGTHS_SIZE 704
|
||||
|
||||
/* Maximum possible Huffman table size for an alphabet size of 704, max code
|
||||
* length 15 and root table bits 8. */
|
||||
#define BROTLI_HUFFMAN_MAX_TABLE_SIZE 1080
|
||||
/* Maximum possible Huffman table size for an alphabet size of (index * 32),
|
||||
* max code length 15 and root table bits 8. */
|
||||
static const uint16_t kMaxHuffmanTableSize[] = {
|
||||
256, 402, 436, 468, 500, 534, 566, 598, 630, 662, 694, 726, 758, 790, 822,
|
||||
854, 886, 920, 952, 984, 1016, 1048, 1080};
|
||||
#define BROTLI_HUFFMAN_MAX_SIZE_26 396
|
||||
#define BROTLI_HUFFMAN_MAX_SIZE_258 632
|
||||
#define BROTLI_HUFFMAN_MAX_SIZE_272 646
|
||||
|
||||
#define BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH 5
|
||||
|
||||
typedef struct {
|
||||
uint8_t bits; /* number of bits used for this symbol */
|
||||
uint16_t value; /* symbol value or table offset */
|
||||
uint8_t bits; /* number of bits used for this symbol */
|
||||
uint16_t value; /* symbol value or table offset */
|
||||
} HuffmanCode;
|
||||
|
||||
|
||||
/* Builds Huffman lookup table assuming code lengths are in symbol order. */
|
||||
void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* root_table,
|
||||
const uint8_t* const code_lengths,
|
||||
uint16_t *count);
|
||||
BROTLI_INTERNAL void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* root_table,
|
||||
const uint8_t* const code_lengths, uint16_t* count);
|
||||
|
||||
/* Builds Huffman lookup table assuming code lengths are in symbol order. */
|
||||
/* Returns size of resulting table. */
|
||||
int BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||
int root_bits,
|
||||
const uint16_t* const symbol_lists,
|
||||
uint16_t *count_arg);
|
||||
BROTLI_INTERNAL uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||
int root_bits, const uint16_t* const symbol_lists, uint16_t* count_arg);
|
||||
|
||||
/* Builds a simple Huffman table. The num_symbols parameter is to be */
|
||||
/* interpreted as follows: 0 means 1 symbol, 1 means 2 symbols, 2 means 3 */
|
||||
/* symbols, 3 means 4 symbols with lengths 2,2,2,2, 4 means 4 symbols with */
|
||||
/* lengths 1,2,3,3. */
|
||||
int BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
|
||||
int root_bits,
|
||||
uint16_t *symbols,
|
||||
uint32_t num_symbols);
|
||||
BROTLI_INTERNAL uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
|
||||
int root_bits, uint16_t* symbols, uint32_t num_symbols);
|
||||
|
||||
/* Contains a collection of Huffman trees with the same alphabet size. */
|
||||
typedef struct {
|
||||
HuffmanCode** htrees;
|
||||
HuffmanCode* codes;
|
||||
int16_t alphabet_size;
|
||||
int16_t num_htrees;
|
||||
uint16_t alphabet_size;
|
||||
uint16_t num_htrees;
|
||||
} HuffmanTreeGroup;
|
||||
|
||||
void BrotliHuffmanTreeGroupInit(HuffmanTreeGroup* group,
|
||||
int alphabet_size, int ntrees);
|
||||
void BrotliHuffmanTreeGroupRelease(HuffmanTreeGroup* group);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* BROTLI_DEC_HUFFMAN_H_ */
|
||||
|
||||
+142
-54
@@ -1,32 +1,33 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Macros for compiler / platform specific features and build options.
|
||||
|
||||
Build options are:
|
||||
* BROTLI_BUILD_32_BIT disables 64-bit optimizations
|
||||
* BROTLI_BUILD_64_BIT forces to use 64-bit optimizations
|
||||
* BROTLI_BUILD_BIG_ENDIAN forces to use big-endian optimizations
|
||||
* BROTLI_BUILD_ENDIAN_NEUTRAL disables endian-aware optimizations
|
||||
* BROTLI_BUILD_LITTLE_ENDIAN forces to use little-endian optimizations
|
||||
* BROTLI_BUILD_MODERN_COMPILER forces to use modern compilers built-ins,
|
||||
features and attributes
|
||||
* BROTLI_BUILD_PORTABLE disables dangerous optimizations, like unaligned
|
||||
read and overlapping memcpy; this reduces decompression speed by 5%
|
||||
* BROTLI_DEBUG dumps file name and line number when decoder detects stream
|
||||
or memory error
|
||||
* BROTLI_DECODE_DEBUG enables asserts and dumps various state information
|
||||
* BROTLI_ENABLE_LOG enables asserts and dumps various state information
|
||||
*/
|
||||
|
||||
#ifndef BROTLI_DEC_PORT_H_
|
||||
#define BROTLI_DEC_PORT_H_
|
||||
|
||||
#include<assert.h>
|
||||
#if defined(BROTLI_ENABLE_LOG) || defined(BROTLI_DEBUG)
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
/* Compatibility with non-clang compilers. */
|
||||
#ifndef __has_builtin
|
||||
@@ -41,15 +42,59 @@
|
||||
#define __has_feature(x) 0
|
||||
#endif
|
||||
|
||||
#ifdef BROTLI_BUILD_PORTABLE
|
||||
#define BROTLI_ALIGNED_READ 1
|
||||
#define BROTLI_SAFE_MEMMOVE 1
|
||||
#else
|
||||
#define BROTLI_ALIGNED_READ 0
|
||||
#define BROTLI_SAFE_MEMMOVE 0
|
||||
#if defined(__arm__) || defined(__thumb__) || \
|
||||
defined(_M_ARM) || defined(_M_ARMT)
|
||||
#define BROTLI_TARGET_ARM
|
||||
#if (defined(__ARM_ARCH) && (__ARM_ARCH >= 7)) || \
|
||||
(defined(M_ARM) && (M_ARM >= 7))
|
||||
#define BROTLI_TARGET_ARMV7
|
||||
#endif /* ARMv7 */
|
||||
#if defined(__aarch64__)
|
||||
#define BROTLI_TARGET_ARMV8
|
||||
#endif /* ARMv8 */
|
||||
#endif /* ARM */
|
||||
|
||||
#if defined(__i386) || defined(_M_IX86)
|
||||
#define BROTLI_TARGET_X86
|
||||
#endif
|
||||
|
||||
#define BROTLI_ASAN_BUILD __has_feature(address_sanitizer)
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
#define BROTLI_TARGET_X64
|
||||
#endif
|
||||
|
||||
#if defined(__PPC64__)
|
||||
#define BROTLI_TARGET_POWERPC64
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
|
||||
#define BROTLI_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
|
||||
#else
|
||||
#define BROTLI_GCC_VERSION 0
|
||||
#endif
|
||||
|
||||
#if defined(__ICC)
|
||||
#define BROTLI_ICC_VERSION __ICC
|
||||
#else
|
||||
#define BROTLI_ICC_VERSION 0
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_BUILD_MODERN_COMPILER)
|
||||
#define BROTLI_MODERN_COMPILER 1
|
||||
#elif (BROTLI_GCC_VERSION > 300) || (BROTLI_ICC_VERSION >= 1600)
|
||||
#define BROTLI_MODERN_COMPILER 1
|
||||
#else
|
||||
#define BROTLI_MODERN_COMPILER 0
|
||||
#endif
|
||||
|
||||
#ifdef BROTLI_BUILD_PORTABLE
|
||||
#define BROTLI_ALIGNED_READ (!!1)
|
||||
#elif defined(BROTLI_TARGET_X86) || defined(BROTLI_TARGET_X64) || \
|
||||
defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8)
|
||||
/* Allow unaligned read only for whitelisted CPUs. */
|
||||
#define BROTLI_ALIGNED_READ (!!0)
|
||||
#else
|
||||
#define BROTLI_ALIGNED_READ (!!1)
|
||||
#endif
|
||||
|
||||
/* Define "PREDICT_TRUE" and "PREDICT_FALSE" macros for capable compilers.
|
||||
|
||||
@@ -68,8 +113,7 @@ OR:
|
||||
}
|
||||
|
||||
*/
|
||||
#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ > 95) || \
|
||||
(defined(__llvm__) && __has_builtin(__builtin_expect))
|
||||
#if BROTLI_MODERN_COMPILER || __has_builtin(__builtin_expect)
|
||||
#define PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
|
||||
#define PREDICT_FALSE(x) (__builtin_expect(x, 0))
|
||||
#else
|
||||
@@ -78,23 +122,33 @@ OR:
|
||||
#endif
|
||||
|
||||
/* IS_CONSTANT macros returns true for compile-time constant expressions. */
|
||||
#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 0) || \
|
||||
(defined(__llvm__) && __has_builtin(__builtin_constant_p))
|
||||
#define IS_CONSTANT(x) __builtin_constant_p(x)
|
||||
#if BROTLI_MODERN_COMPILER || __has_builtin(__builtin_constant_p)
|
||||
#define IS_CONSTANT(x) (!!__builtin_constant_p(x))
|
||||
#else
|
||||
#define IS_CONSTANT(x) 0
|
||||
#define IS_CONSTANT(x) (!!0)
|
||||
#endif
|
||||
|
||||
#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 0) || \
|
||||
(defined(__llvm__) && __has_attribute(always_inline))
|
||||
#if BROTLI_MODERN_COMPILER || __has_attribute(always_inline)
|
||||
#define ATTRIBUTE_ALWAYS_INLINE __attribute__ ((always_inline))
|
||||
#else
|
||||
#define ATTRIBUTE_ALWAYS_INLINE
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#define ATTRIBUTE_VISIBILITY_HIDDEN
|
||||
#elif BROTLI_MODERN_COMPILER || __has_attribute(visibility)
|
||||
#define ATTRIBUTE_VISIBILITY_HIDDEN __attribute__ ((visibility ("hidden")))
|
||||
#else
|
||||
#define ATTRIBUTE_VISIBILITY_HIDDEN
|
||||
#endif
|
||||
|
||||
#ifndef BROTLI_INTERNAL
|
||||
#define BROTLI_INTERNAL ATTRIBUTE_VISIBILITY_HIDDEN
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#if defined(__cplusplus) || !defined(__STRICT_ANSI__) \
|
||||
|| __STDC_VERSION__ >= 199901L
|
||||
#if defined(__cplusplus) || !defined(__STRICT_ANSI__) || \
|
||||
__STDC_VERSION__ >= 199901L
|
||||
#define BROTLI_INLINE inline ATTRIBUTE_ALWAYS_INLINE
|
||||
#else
|
||||
#define BROTLI_INLINE
|
||||
@@ -103,55 +157,74 @@ OR:
|
||||
#define BROTLI_INLINE __forceinline
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#ifdef BROTLI_DECODE_DEBUG
|
||||
#ifdef BROTLI_ENABLE_LOG
|
||||
#define BROTLI_DCHECK(x) assert(x)
|
||||
#define BROTLI_LOG(x) printf x
|
||||
#else
|
||||
#define BROTLI_DCHECK(x)
|
||||
#define BROTLI_LOG(x)
|
||||
#endif
|
||||
|
||||
#if (defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) || \
|
||||
defined(__PPC64__))
|
||||
#if defined(BROTLI_DEBUG) || defined(BROTLI_ENABLE_LOG)
|
||||
static inline void BrotliDump(const char* f, int l, const char* fn) {
|
||||
fprintf(stderr, "%s:%d (%s)\n", f, l, fn);
|
||||
fflush(stderr);
|
||||
}
|
||||
#define BROTLI_DUMP() BrotliDump(__FILE__, __LINE__, __FUNCTION__)
|
||||
#else
|
||||
#define BROTLI_DUMP() (void)(0)
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_BUILD_64_BIT)
|
||||
#define BROTLI_64_BITS 1
|
||||
#elif defined(BROTLI_BUILD_32_BIT)
|
||||
#define BROTLI_64_BITS 0
|
||||
#elif defined(BROTLI_TARGET_X64) || defined(BROTLI_TARGET_ARMV8) || \
|
||||
defined(BROTLI_TARGET_POWERPC64)
|
||||
#define BROTLI_64_BITS 1
|
||||
#else
|
||||
#define BROTLI_64_BITS 0
|
||||
#endif
|
||||
|
||||
#if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
|
||||
#if defined(BROTLI_BUILD_BIG_ENDIAN)
|
||||
#define BROTLI_LITTLE_ENDIAN 0
|
||||
#define BROTLI_BIG_ENDIAN 1
|
||||
#elif defined(BROTLI_BUILD_LITTLE_ENDIAN)
|
||||
#define BROTLI_LITTLE_ENDIAN 1
|
||||
#define BROTLI_BIG_ENDIAN 0
|
||||
#elif defined(BROTLI_BUILD_ENDIAN_NEUTRAL)
|
||||
#define BROTLI_LITTLE_ENDIAN 0
|
||||
#define BROTLI_BIG_ENDIAN 0
|
||||
#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||
#define BROTLI_LITTLE_ENDIAN 1
|
||||
#define BROTLI_BIG_ENDIAN 0
|
||||
#elif defined(_WIN32)
|
||||
/* Win32 can currently always be assumed to be little endian */
|
||||
#define BROTLI_LITTLE_ENDIAN 1
|
||||
#define BROTLI_BIG_ENDIAN 0
|
||||
#else
|
||||
#if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
|
||||
#define BROTLI_BIG_ENDIAN 1
|
||||
#else
|
||||
#define BROTLI_BIG_ENDIAN 0
|
||||
#endif
|
||||
#define BROTLI_LITTLE_ENDIAN 0
|
||||
#endif
|
||||
|
||||
#if (BROTLI_64_BITS && BROTLI_LITTLE_ENDIAN)
|
||||
#define BROTLI_64_BITS_LITTLE_ENDIAN 1
|
||||
#else
|
||||
#define BROTLI_64_BITS_LITTLE_ENDIAN 0
|
||||
#endif
|
||||
|
||||
#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) || \
|
||||
(defined(__llvm__) && __has_attribute(noinline))
|
||||
#define BROTLI_NOINLINE __attribute__ ((noinline))
|
||||
#if BROTLI_MODERN_COMPILER || __has_attribute(noinline)
|
||||
#define BROTLI_NOINLINE __attribute__((noinline))
|
||||
#else
|
||||
#define BROTLI_NOINLINE
|
||||
#endif
|
||||
|
||||
#if BROTLI_ASAN_BUILD && !defined(BROTLI_BUILD_PORTABLE)
|
||||
#define BROTLI_NO_ASAN __attribute__((no_sanitize("address"))) BROTLI_NOINLINE
|
||||
#else
|
||||
#define BROTLI_NO_ASAN
|
||||
#endif
|
||||
|
||||
#define BROTLI_REPEAT(N, X) { \
|
||||
if ((N & 1) != 0) {X;} \
|
||||
if ((N & 2) != 0) {X; X;} \
|
||||
#define BROTLI_REPEAT(N, X) { \
|
||||
if ((N & 1) != 0) {X;} \
|
||||
if ((N & 2) != 0) {X; X;} \
|
||||
if ((N & 4) != 0) {X; X; X; X;} \
|
||||
}
|
||||
|
||||
#if (__GNUC__ > 2) || defined(__llvm__)
|
||||
#if (defined(__ARM_ARCH) && (__ARM_ARCH >= 7))
|
||||
#if BROTLI_MODERN_COMPILER || defined(__llvm__)
|
||||
#if defined(BROTLI_TARGET_ARMV7)
|
||||
static BROTLI_INLINE unsigned BrotliRBit(unsigned input) {
|
||||
unsigned output;
|
||||
__asm__("rbit %0, %1\n" : "=r"(output) : "r"(input));
|
||||
@@ -161,4 +234,19 @@ static BROTLI_INLINE unsigned BrotliRBit(unsigned input) {
|
||||
#endif /* armv7 */
|
||||
#endif /* gcc || clang */
|
||||
|
||||
#if defined(BROTLI_TARGET_ARM)
|
||||
#define BROTLI_HAS_UBFX (!!1)
|
||||
#else
|
||||
#define BROTLI_HAS_UBFX (!!0)
|
||||
#endif
|
||||
|
||||
#define BROTLI_ALLOC(S, L) S->alloc_func(S->memory_manager_opaque, L)
|
||||
|
||||
#define BROTLI_FREE(S, X) { \
|
||||
S->free_func(S->memory_manager_opaque, X); \
|
||||
X = NULL; \
|
||||
}
|
||||
|
||||
#define BROTLI_UNUSED(X) (void)(X)
|
||||
|
||||
#endif /* BROTLI_DEC_PORT_H_ */
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Lookup tables to map prefix codes to value ranges. This is used during
|
||||
@@ -20,11 +11,13 @@
|
||||
#ifndef BROTLI_DEC_PREFIX_H_
|
||||
#define BROTLI_DEC_PREFIX_H_
|
||||
|
||||
#include "./types.h"
|
||||
|
||||
/* Represents the range of values belonging to a prefix code: */
|
||||
/* [offset, offset + 2^nbits) */
|
||||
struct PrefixCodeRange {
|
||||
int16_t offset;
|
||||
int8_t nbits;
|
||||
uint16_t offset;
|
||||
uint8_t nbits;
|
||||
};
|
||||
|
||||
static const struct PrefixCodeRange kBlockLengthPrefixCode[] = {
|
||||
|
||||
+85
-59
@@ -1,29 +1,51 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "./huffman.h"
|
||||
#include "./state.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h> /* free, malloc */
|
||||
|
||||
#include "./huffman.h"
|
||||
#include "./types.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Declared in decode.h */
|
||||
int BrotliStateIsStreamStart(const BrotliState* s);
|
||||
int BrotliStateIsStreamEnd(const BrotliState* s);
|
||||
|
||||
static void* DefaultAllocFunc(void* opaque, size_t size) {
|
||||
BROTLI_UNUSED(opaque);
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static void DefaultFreeFunc(void* opaque, void* address) {
|
||||
BROTLI_UNUSED(opaque);
|
||||
free(address);
|
||||
}
|
||||
|
||||
void BrotliStateInit(BrotliState* s) {
|
||||
BrotliStateInitWithCustomAllocators(s, 0, 0, 0);
|
||||
}
|
||||
|
||||
void BrotliStateInitWithCustomAllocators(BrotliState* s,
|
||||
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
|
||||
if (!alloc_func) {
|
||||
s->alloc_func = DefaultAllocFunc;
|
||||
s->free_func = DefaultFreeFunc;
|
||||
s->memory_manager_opaque = 0;
|
||||
} else {
|
||||
s->alloc_func = alloc_func;
|
||||
s->free_func = free_func;
|
||||
s->memory_manager_opaque = opaque;
|
||||
}
|
||||
|
||||
BrotliInitBitReader(&s->br);
|
||||
s->state = BROTLI_STATE_UNINITED;
|
||||
s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE;
|
||||
s->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
|
||||
@@ -31,6 +53,13 @@ void BrotliStateInit(BrotliState* s) {
|
||||
s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE;
|
||||
s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
|
||||
s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_NONE;
|
||||
s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE;
|
||||
|
||||
s->buffer_length = 0;
|
||||
s->loop_counter = 0;
|
||||
s->pos = 0;
|
||||
s->rb_roundtrips = 0;
|
||||
s->partial_pos_out = 0;
|
||||
|
||||
s->block_type_trees = NULL;
|
||||
s->block_len_trees = NULL;
|
||||
@@ -42,6 +71,8 @@ void BrotliStateInit(BrotliState* s) {
|
||||
s->context_map_slice = NULL;
|
||||
s->dist_context_map_slice = NULL;
|
||||
|
||||
s->sub_loop_counter = 0;
|
||||
|
||||
s->literal_hgroup.codes = NULL;
|
||||
s->literal_hgroup.htrees = NULL;
|
||||
s->insert_copy_hgroup.codes = NULL;
|
||||
@@ -49,7 +80,6 @@ void BrotliStateInit(BrotliState* s) {
|
||||
s->distance_hgroup.codes = NULL;
|
||||
s->distance_hgroup.htrees = NULL;
|
||||
|
||||
|
||||
s->custom_dict = NULL;
|
||||
s->custom_dict_size = 0;
|
||||
|
||||
@@ -72,9 +102,9 @@ void BrotliStateInit(BrotliState* s) {
|
||||
|
||||
void BrotliStateMetablockBegin(BrotliState* s) {
|
||||
s->meta_block_remaining_len = 0;
|
||||
s->block_length[0] = 1 << 28;
|
||||
s->block_length[1] = 1 << 28;
|
||||
s->block_length[2] = 1 << 28;
|
||||
s->block_length[0] = 1U << 28;
|
||||
s->block_length[1] = 1U << 28;
|
||||
s->block_length[2] = 1U << 28;
|
||||
s->num_block_types[0] = 1;
|
||||
s->num_block_types[1] = 1;
|
||||
s->num_block_types[2] = 1;
|
||||
@@ -88,7 +118,6 @@ void BrotliStateMetablockBegin(BrotliState* s) {
|
||||
s->context_modes = NULL;
|
||||
s->dist_context_map = NULL;
|
||||
s->context_map_slice = NULL;
|
||||
s->literal_htree_index = 0;
|
||||
s->literal_htree = NULL;
|
||||
s->dist_context_map_slice = NULL;
|
||||
s->dist_htree_index = 0;
|
||||
@@ -103,52 +132,49 @@ void BrotliStateMetablockBegin(BrotliState* s) {
|
||||
}
|
||||
|
||||
void BrotliStateCleanupAfterMetablock(BrotliState* s) {
|
||||
if (s->context_modes != 0) {
|
||||
free(s->context_modes);
|
||||
s->context_modes = NULL;
|
||||
}
|
||||
if (s->context_map != 0) {
|
||||
free(s->context_map);
|
||||
s->context_map = NULL;
|
||||
}
|
||||
if (s->dist_context_map != 0) {
|
||||
free(s->dist_context_map);
|
||||
s->dist_context_map = NULL;
|
||||
}
|
||||
BROTLI_FREE(s, s->context_modes);
|
||||
BROTLI_FREE(s, s->context_map);
|
||||
BROTLI_FREE(s, s->dist_context_map);
|
||||
|
||||
BrotliHuffmanTreeGroupRelease(&s->literal_hgroup);
|
||||
BrotliHuffmanTreeGroupRelease(&s->insert_copy_hgroup);
|
||||
BrotliHuffmanTreeGroupRelease(&s->distance_hgroup);
|
||||
s->literal_hgroup.codes = NULL;
|
||||
s->literal_hgroup.htrees = NULL;
|
||||
s->insert_copy_hgroup.codes = NULL;
|
||||
s->insert_copy_hgroup.htrees = NULL;
|
||||
s->distance_hgroup.codes = NULL;
|
||||
s->distance_hgroup.htrees = NULL;
|
||||
BrotliHuffmanTreeGroupRelease(s, &s->literal_hgroup);
|
||||
BrotliHuffmanTreeGroupRelease(s, &s->insert_copy_hgroup);
|
||||
BrotliHuffmanTreeGroupRelease(s, &s->distance_hgroup);
|
||||
}
|
||||
|
||||
void BrotliStateCleanup(BrotliState* s) {
|
||||
if (s->context_modes != 0) {
|
||||
free(s->context_modes);
|
||||
}
|
||||
if (s->context_map != 0) {
|
||||
free(s->context_map);
|
||||
}
|
||||
if (s->dist_context_map != 0) {
|
||||
free(s->dist_context_map);
|
||||
}
|
||||
BrotliHuffmanTreeGroupRelease(&s->literal_hgroup);
|
||||
BrotliHuffmanTreeGroupRelease(&s->insert_copy_hgroup);
|
||||
BrotliHuffmanTreeGroupRelease(&s->distance_hgroup);
|
||||
BrotliStateCleanupAfterMetablock(s);
|
||||
|
||||
if (s->ringbuffer != 0) {
|
||||
free(s->ringbuffer);
|
||||
}
|
||||
if (s->block_type_trees != 0) {
|
||||
free(s->block_type_trees);
|
||||
}
|
||||
BROTLI_FREE(s, s->ringbuffer);
|
||||
BROTLI_FREE(s, s->block_type_trees);
|
||||
}
|
||||
|
||||
int BrotliStateIsStreamStart(const BrotliState* s) {
|
||||
return (s->state == BROTLI_STATE_UNINITED &&
|
||||
BrotliGetAvailableBits(&s->br) == 0);
|
||||
}
|
||||
|
||||
int BrotliStateIsStreamEnd(const BrotliState* s) {
|
||||
return s->state == BROTLI_STATE_DONE;
|
||||
}
|
||||
|
||||
void BrotliHuffmanTreeGroupInit(BrotliState* s, HuffmanTreeGroup* group,
|
||||
uint32_t alphabet_size, uint32_t ntrees) {
|
||||
/* Pack two allocations into one */
|
||||
const size_t max_table_size = kMaxHuffmanTableSize[(alphabet_size + 31) >> 5];
|
||||
const size_t code_size = sizeof(HuffmanCode) * ntrees * max_table_size;
|
||||
const size_t htree_size = sizeof(HuffmanCode*) * ntrees;
|
||||
char* p = (char*)BROTLI_ALLOC(s, code_size + htree_size);
|
||||
group->alphabet_size = (uint16_t)alphabet_size;
|
||||
group->num_htrees = (uint16_t)ntrees;
|
||||
group->codes = (HuffmanCode*)p;
|
||||
group->htrees = (HuffmanCode**)(p + code_size);
|
||||
}
|
||||
|
||||
void BrotliHuffmanTreeGroupRelease(BrotliState* s, HuffmanTreeGroup* group) {
|
||||
BROTLI_FREE(s, group->codes);
|
||||
group->htrees = NULL;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
+73
-46
@@ -1,16 +1,7 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Brotli state for partial streaming decoding. */
|
||||
@@ -18,11 +9,10 @@
|
||||
#ifndef BROTLI_DEC_STATE_H_
|
||||
#define BROTLI_DEC_STATE_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include "./bit_reader.h"
|
||||
#include "./huffman.h"
|
||||
#include "./streams.h"
|
||||
#include "./types.h"
|
||||
#include "./port.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -30,19 +20,20 @@ extern "C" {
|
||||
|
||||
typedef enum {
|
||||
BROTLI_STATE_UNINITED,
|
||||
BROTLI_STATE_BITREADER_WARMUP,
|
||||
BROTLI_STATE_METABLOCK_BEGIN,
|
||||
BROTLI_STATE_METABLOCK_HEADER,
|
||||
BROTLI_STATE_METABLOCK_HEADER_2,
|
||||
BROTLI_STATE_CONTEXT_MODES,
|
||||
BROTLI_STATE_COMMAND_BEGIN,
|
||||
BROTLI_STATE_COMMAND_INNER,
|
||||
BROTLI_STATE_COMMAND_POST_DECODE_LITERALS,
|
||||
BROTLI_STATE_COMMAND_POST_WRAP_COPY,
|
||||
BROTLI_STATE_UNCOMPRESSED,
|
||||
BROTLI_STATE_METADATA,
|
||||
BROTLI_STATE_COMMAND_INNER_WRITE,
|
||||
BROTLI_STATE_METABLOCK_DONE,
|
||||
BROTLI_STATE_COMMAND_POST_WRITE_1,
|
||||
BROTLI_STATE_COMMAND_POST_WRITE_2,
|
||||
BROTLI_STATE_COMMAND_POST_WRAP_COPY,
|
||||
BROTLI_STATE_HUFFMAN_CODE_0,
|
||||
BROTLI_STATE_HUFFMAN_CODE_1,
|
||||
BROTLI_STATE_HUFFMAN_CODE_2,
|
||||
@@ -66,8 +57,6 @@ typedef enum {
|
||||
|
||||
typedef enum {
|
||||
BROTLI_STATE_UNCOMPRESSED_NONE,
|
||||
BROTLI_STATE_UNCOMPRESSED_SHORT,
|
||||
BROTLI_STATE_UNCOMPRESSED_COPY,
|
||||
BROTLI_STATE_UNCOMPRESSED_WRITE
|
||||
} BrotliRunningUncompressedState;
|
||||
|
||||
@@ -80,11 +69,16 @@ typedef enum {
|
||||
BROTLI_STATE_CONTEXT_MAP_NONE,
|
||||
BROTLI_STATE_CONTEXT_MAP_READ_PREFIX,
|
||||
BROTLI_STATE_CONTEXT_MAP_HUFFMAN,
|
||||
BROTLI_STATE_CONTEXT_MAP_DECODE
|
||||
BROTLI_STATE_CONTEXT_MAP_DECODE,
|
||||
BROTLI_STATE_CONTEXT_MAP_TRANSFORM
|
||||
} BrotliRunningContextMapState;
|
||||
|
||||
typedef enum {
|
||||
BROTLI_STATE_HUFFMAN_NONE,
|
||||
BROTLI_STATE_HUFFMAN_SIMPLE_SIZE,
|
||||
BROTLI_STATE_HUFFMAN_SIMPLE_READ,
|
||||
BROTLI_STATE_HUFFMAN_SIMPLE_BUILD,
|
||||
BROTLI_STATE_HUFFMAN_COMPLEX,
|
||||
BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS
|
||||
} BrotliRunningHuffmanState;
|
||||
|
||||
@@ -94,11 +88,30 @@ typedef enum {
|
||||
BROTLI_STATE_DECODE_UINT8_LONG
|
||||
} BrotliRunningDecodeUint8State;
|
||||
|
||||
typedef struct {
|
||||
typedef enum {
|
||||
BROTLI_STATE_READ_BLOCK_LENGTH_NONE,
|
||||
BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX
|
||||
} BrotliRunningReadBlockLengthState;
|
||||
|
||||
struct BrotliStateStruct {
|
||||
BrotliRunningState state;
|
||||
|
||||
/* This counter is reused for several disjoint loops. */
|
||||
BrotliBitReader br;
|
||||
int loop_counter;
|
||||
|
||||
BrotliBitReader br;
|
||||
|
||||
brotli_alloc_func alloc_func;
|
||||
brotli_free_func free_func;
|
||||
void* memory_manager_opaque;
|
||||
|
||||
/* Temporary storage for remaining input. */
|
||||
union {
|
||||
uint64_t u64;
|
||||
uint8_t u8[8];
|
||||
} buffer;
|
||||
uint32_t buffer_length;
|
||||
|
||||
int pos;
|
||||
int max_backward_distance;
|
||||
int max_backward_distance_minus_custom_dict_size;
|
||||
@@ -107,6 +120,8 @@ typedef struct {
|
||||
int ringbuffer_mask;
|
||||
int dist_rb_idx;
|
||||
int dist_rb[4];
|
||||
int error_code;
|
||||
uint32_t sub_loop_counter;
|
||||
uint8_t* ringbuffer;
|
||||
uint8_t* ringbuffer_end;
|
||||
HuffmanCode* htree_command;
|
||||
@@ -127,27 +142,26 @@ typedef struct {
|
||||
int trivial_literal_context;
|
||||
int distance_context;
|
||||
int meta_block_remaining_len;
|
||||
int block_length[3];
|
||||
int num_block_types[3];
|
||||
int block_type_rb[6];
|
||||
int distance_postfix_bits;
|
||||
int num_direct_distance_codes;
|
||||
uint32_t block_length_index;
|
||||
uint32_t block_length[3];
|
||||
uint32_t num_block_types[3];
|
||||
uint32_t block_type_rb[6];
|
||||
uint32_t distance_postfix_bits;
|
||||
uint32_t num_direct_distance_codes;
|
||||
int distance_postfix_mask;
|
||||
int num_dist_htrees;
|
||||
uint32_t num_dist_htrees;
|
||||
uint8_t* dist_context_map;
|
||||
HuffmanCode *literal_htree;
|
||||
uint8_t literal_htree_index;
|
||||
HuffmanCode* literal_htree;
|
||||
uint8_t dist_htree_index;
|
||||
uint8_t repeat_code_len;
|
||||
uint8_t prev_code_len;
|
||||
|
||||
uint32_t repeat_code_len;
|
||||
uint32_t prev_code_len;
|
||||
|
||||
int copy_length;
|
||||
int distance_code;
|
||||
|
||||
/* For partial write operations */
|
||||
int to_write;
|
||||
int partially_written;
|
||||
size_t rb_roundtrips; /* How many times we went around the ringbuffer */
|
||||
size_t partial_pos_out; /* How much output to the user in total (<= rb) */
|
||||
|
||||
/* For ReadHuffmanCode */
|
||||
uint32_t symbol;
|
||||
@@ -159,7 +173,7 @@ typedef struct {
|
||||
uint16_t* symbol_lists;
|
||||
/* Storage from symbol_lists. */
|
||||
uint16_t symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1 +
|
||||
BROTLI_HUFFMAN_MAX_CODE_LENGTHS_SIZE];
|
||||
BROTLI_HUFFMAN_MAX_CODE_LENGTHS_SIZE];
|
||||
/* Tails of symbol chains. */
|
||||
int next_symbol[32];
|
||||
uint8_t code_length_code_lengths[18];
|
||||
@@ -171,13 +185,14 @@ typedef struct {
|
||||
HuffmanCode* next;
|
||||
|
||||
/* For DecodeContextMap */
|
||||
int context_index;
|
||||
int max_run_length_prefix;
|
||||
HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_TABLE_SIZE];
|
||||
uint32_t context_index;
|
||||
uint32_t max_run_length_prefix;
|
||||
uint32_t code;
|
||||
HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_SIZE_272];
|
||||
|
||||
/* For InverseMoveToFrontTransform */
|
||||
int mtf_upper_bound;
|
||||
uint8_t mtf[256];
|
||||
uint32_t mtf_upper_bound;
|
||||
uint8_t mtf[256 + 4];
|
||||
|
||||
/* For custom dictionaries */
|
||||
const uint8_t* custom_dict;
|
||||
@@ -191,6 +206,7 @@ typedef struct {
|
||||
BrotliRunningUncompressedState substate_uncompressed;
|
||||
BrotliRunningHuffmanState substate_huffman;
|
||||
BrotliRunningDecodeUint8State substate_decode_uint8;
|
||||
BrotliRunningReadBlockLengthState substate_read_block_length;
|
||||
|
||||
uint8_t is_last_metablock;
|
||||
uint8_t is_uncompressed;
|
||||
@@ -198,18 +214,29 @@ typedef struct {
|
||||
uint8_t size_nibbles;
|
||||
uint32_t window_bits;
|
||||
|
||||
int num_literal_htrees;
|
||||
uint32_t num_literal_htrees;
|
||||
uint8_t* context_map;
|
||||
uint8_t* context_modes;
|
||||
} BrotliState;
|
||||
|
||||
void BrotliStateInit(BrotliState* s);
|
||||
void BrotliStateCleanup(BrotliState* s);
|
||||
void BrotliStateMetablockBegin(BrotliState* s);
|
||||
void BrotliStateCleanupAfterMetablock(BrotliState* s);
|
||||
uint32_t trivial_literal_contexts[8]; /* 256 bits */
|
||||
};
|
||||
|
||||
typedef struct BrotliStateStruct BrotliStateInternal;
|
||||
#define BrotliState BrotliStateInternal
|
||||
|
||||
BROTLI_INTERNAL void BrotliStateInit(BrotliState* s);
|
||||
BROTLI_INTERNAL void BrotliStateInitWithCustomAllocators(BrotliState* s,
|
||||
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque);
|
||||
BROTLI_INTERNAL void BrotliStateCleanup(BrotliState* s);
|
||||
BROTLI_INTERNAL void BrotliStateMetablockBegin(BrotliState* s);
|
||||
BROTLI_INTERNAL void BrotliStateCleanupAfterMetablock(BrotliState* s);
|
||||
BROTLI_INTERNAL void BrotliHuffmanTreeGroupInit(BrotliState* s,
|
||||
HuffmanTreeGroup* group, uint32_t alphabet_size, uint32_t ntrees);
|
||||
BROTLI_INTERNAL void BrotliHuffmanTreeGroupRelease(BrotliState* s,
|
||||
HuffmanTreeGroup* group);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* BROTLI_DEC_STATE_H_ */
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Transformations on dictionary words. */
|
||||
@@ -18,8 +9,6 @@
|
||||
#ifndef BROTLI_DEC_TRANSFORM_H_
|
||||
#define BROTLI_DEC_TRANSFORM_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "./port.h"
|
||||
#include "./types.h"
|
||||
|
||||
@@ -28,27 +17,27 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
enum WordTransformType {
|
||||
kIdentity = 0,
|
||||
kOmitLast1 = 1,
|
||||
kOmitLast2 = 2,
|
||||
kOmitLast3 = 3,
|
||||
kOmitLast4 = 4,
|
||||
kOmitLast5 = 5,
|
||||
kOmitLast6 = 6,
|
||||
kOmitLast7 = 7,
|
||||
kOmitLast8 = 8,
|
||||
kOmitLast9 = 9,
|
||||
kIdentity = 0,
|
||||
kOmitLast1 = 1,
|
||||
kOmitLast2 = 2,
|
||||
kOmitLast3 = 3,
|
||||
kOmitLast4 = 4,
|
||||
kOmitLast5 = 5,
|
||||
kOmitLast6 = 6,
|
||||
kOmitLast7 = 7,
|
||||
kOmitLast8 = 8,
|
||||
kOmitLast9 = 9,
|
||||
kUppercaseFirst = 10,
|
||||
kUppercaseAll = 11,
|
||||
kOmitFirst1 = 12,
|
||||
kOmitFirst2 = 13,
|
||||
kOmitFirst3 = 14,
|
||||
kOmitFirst4 = 15,
|
||||
kOmitFirst5 = 16,
|
||||
kOmitFirst6 = 17,
|
||||
kOmitFirst7 = 18,
|
||||
kOmitFirst8 = 19,
|
||||
kOmitFirst9 = 20
|
||||
kUppercaseAll = 11,
|
||||
kOmitFirst1 = 12,
|
||||
kOmitFirst2 = 13,
|
||||
kOmitFirst3 = 14,
|
||||
kOmitFirst4 = 15,
|
||||
kOmitFirst5 = 16,
|
||||
kOmitFirst6 = 17,
|
||||
kOmitFirst7 = 18,
|
||||
kOmitFirst8 = 19,
|
||||
kOmitFirst9 = 20
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -77,15 +66,15 @@ enum {
|
||||
kPFix_SP = 1,
|
||||
kPFix_COMMASP = 3,
|
||||
kPFix_SPofSPtheSP = 6,
|
||||
kPFix_SPtheSP = 9,
|
||||
kPFix_SPtheSP = 9,
|
||||
kPFix_eSP = 12,
|
||||
kPFix_SPofSP = 15,
|
||||
kPFix_SPofSP = 15,
|
||||
kPFix_sSP = 20,
|
||||
kPFix_DOT = 23,
|
||||
kPFix_SPandSP = 25,
|
||||
kPFix_SPinSP = 31,
|
||||
kPFix_DQUOT = 36,
|
||||
kPFix_SPtoSP = 38,
|
||||
kPFix_SPtoSP = 38,
|
||||
kPFix_DQUOTGT = 43,
|
||||
kPFix_NEWLINE = 46,
|
||||
kPFix_DOTSP = 48,
|
||||
@@ -95,20 +84,20 @@ enum {
|
||||
kPFix_SPthatSP = 63,
|
||||
kPFix_SQUOT = 70,
|
||||
kPFix_SPwithSP = 72,
|
||||
kPFix_SPfromSP = 79,
|
||||
kPFix_SPbySP = 86,
|
||||
kPFix_SPfromSP = 79,
|
||||
kPFix_SPbySP = 86,
|
||||
kPFix_OPEN = 91,
|
||||
kPFix_DOTSPTheSP = 93,
|
||||
kPFix_SPonSP = 100,
|
||||
kPFix_SPasSP = 105,
|
||||
kPFix_SPisSP = 110,
|
||||
kPFix_SPonSP = 100,
|
||||
kPFix_SPasSP = 105,
|
||||
kPFix_SPisSP = 110,
|
||||
kPFix_ingSP = 115,
|
||||
kPFix_NEWLINETAB = 120,
|
||||
kPFix_COLON = 123,
|
||||
kPFix_edSP = 125,
|
||||
kPFix_EQDQUOT = 129,
|
||||
kPFix_SPatSP = 132,
|
||||
kPFix_lySP = 137,
|
||||
kPFix_lySP = 137,
|
||||
kPFix_COMMA = 141,
|
||||
kPFix_EQSQUOT = 143,
|
||||
kPFix_DOTcomSLASH = 146,
|
||||
@@ -125,7 +114,6 @@ enum {
|
||||
kPFix_ousSP = 203
|
||||
};
|
||||
|
||||
|
||||
static const Transform kTransforms[] = {
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_EMPTY },
|
||||
{ kPFix_EMPTY, kIdentity, kPFix_SP },
|
||||
@@ -252,7 +240,7 @@ static const Transform kTransforms[] = {
|
||||
|
||||
static const int kNumTransforms = sizeof(kTransforms) / sizeof(kTransforms[0]);
|
||||
|
||||
static int ToUpperCase(uint8_t *p) {
|
||||
static int ToUpperCase(uint8_t* p) {
|
||||
if (p[0] < 0xc0) {
|
||||
if (p[0] >= 'a' && p[0] <= 'z') {
|
||||
p[0] ^= 32;
|
||||
@@ -278,22 +266,19 @@ static BROTLI_NOINLINE int TransformDictionaryWord(
|
||||
}
|
||||
{
|
||||
const int t = kTransforms[transform].transform;
|
||||
int skip = t < kOmitFirst1 ? 0 : t - (kOmitFirst1 - 1);
|
||||
int i = 0;
|
||||
uint8_t* uppercase;
|
||||
if (skip > len) {
|
||||
skip = len;
|
||||
}
|
||||
word += skip;
|
||||
len -= skip;
|
||||
if (t <= kOmitLast9) {
|
||||
int skip = t - (kOmitFirst1 - 1);
|
||||
if (skip > 0) {
|
||||
word += skip;
|
||||
len -= skip;
|
||||
} else if (t <= kOmitLast9) {
|
||||
len -= t;
|
||||
}
|
||||
while (i < len) { dst[idx++] = word[i++]; }
|
||||
uppercase = &dst[idx - len];
|
||||
if (t == kUppercaseFirst) {
|
||||
ToUpperCase(uppercase);
|
||||
ToUpperCase(&dst[idx - len]);
|
||||
} else if (t == kUppercaseAll) {
|
||||
uint8_t* uppercase = &dst[idx - len];
|
||||
while (len > 0) {
|
||||
int step = ToUpperCase(uppercase);
|
||||
uppercase += step;
|
||||
@@ -309,7 +294,7 @@ static BROTLI_NOINLINE int TransformDictionaryWord(
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* BROTLI_DEC_TRANSFORM_H_ */
|
||||
|
||||
+21
-19
@@ -1,16 +1,7 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Common types */
|
||||
@@ -21,16 +12,27 @@
|
||||
#include <stddef.h> /* for size_t */
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1600)
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long long int uint64_t;
|
||||
typedef long long int int64_t;
|
||||
typedef __int8 int8_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef __int16 int16_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef __int32 int32_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
typedef __int64 int64_t;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif /* defined(_MSC_VER) && (_MSC_VER < 1600) */
|
||||
|
||||
/* Allocating function pointer. Function MUST return 0 in the case of failure.
|
||||
Otherwise it MUST return a valid pointer to a memory region of at least
|
||||
size length. Neither items nor size are allowed to be 0.
|
||||
opaque argument is a pointer provided by client and could be used to bind
|
||||
function to specific object (memory pool). */
|
||||
typedef void* (*brotli_alloc_func)(void* opaque, size_t size);
|
||||
|
||||
/* Deallocating function pointer. Function SHOULD be no-op in the case the
|
||||
address is 0. */
|
||||
typedef void (*brotli_free_func)(void* opaque, void* address);
|
||||
|
||||
#endif /* BROTLI_DEC_TYPES_H_ */
|
||||
|
||||
+19
-23
@@ -358,8 +358,8 @@ pref("media.gstreamer.enable-blacklist", true);
|
||||
#ifdef MOZ_WIDGET_UIKIT
|
||||
pref("media.mp3.enabled", true);
|
||||
#endif
|
||||
pref("media.apple.mp3.enabled", true);
|
||||
pref("media.apple.mp4.enabled", true);
|
||||
pref("media.apple.mp3.enabled", false);
|
||||
pref("media.apple.mp4.enabled", false);
|
||||
#endif
|
||||
#ifdef MOZ_WEBRTC
|
||||
pref("media.navigator.enabled", true);
|
||||
@@ -398,7 +398,7 @@ pref("media.peerconnection.video.max_bitrate", 1000);
|
||||
#else
|
||||
pref("media.navigator.video.default_width",0); // adaptive default
|
||||
pref("media.navigator.video.default_height",0); // adaptive default
|
||||
pref("media.peerconnection.enabled", true);
|
||||
pref("media.peerconnection.enabled", false);
|
||||
pref("media.peerconnection.video.enabled", true);
|
||||
pref("media.navigator.video.max_fs", 12288); // Enough for 2048x1536
|
||||
pref("media.navigator.video.max_fr", 60);
|
||||
@@ -493,16 +493,11 @@ pref("media.webvtt.regions.enabled", false);
|
||||
pref("media.track.enabled", false);
|
||||
|
||||
// Whether to enable MediaSource support.
|
||||
pref("media.mediasource.enabled", true);
|
||||
|
||||
pref("media.mediasource.mp4.enabled", true);
|
||||
|
||||
#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID)
|
||||
// MediaSource is pretty much hosed on PowerPC OS X, so ... no.
|
||||
pref("media.mediasource.enabled", false);
|
||||
pref("media.mediasource.mp4.enabled", false);
|
||||
pref("media.mediasource.webm.enabled", false);
|
||||
#else
|
||||
pref("media.mediasource.webm.enabled", true);
|
||||
#endif
|
||||
pref("media.mediasource.webm.audio.enabled", true);
|
||||
pref("media.mediasource.webm.audio.enabled", false);
|
||||
|
||||
// Enable new MediaFormatReader architecture for plain webm.
|
||||
pref("media.format-reader.webm", true);
|
||||
@@ -644,10 +639,10 @@ pref("gfx.perf-warnings.enabled", false);
|
||||
|
||||
// 0 = Off, 1 = Full, 2 = Tagged Images Only.
|
||||
// See eCMSMode in gfx/thebes/gfxPlatform.h
|
||||
pref("gfx.color_management.mode", 2);
|
||||
pref("gfx.color_management.mode", 1);
|
||||
pref("gfx.color_management.display_profile", "");
|
||||
pref("gfx.color_management.rendering_intent", 0);
|
||||
pref("gfx.color_management.enablev4", false);
|
||||
pref("gfx.color_management.enablev4", true);
|
||||
|
||||
pref("gfx.downloadable_fonts.enabled", true);
|
||||
pref("gfx.downloadable_fonts.fallback_delay", 3000);
|
||||
@@ -708,10 +703,10 @@ pref("gfx.canvas.azure.backends", "direct2d1.1,direct2d,skia,cairo");
|
||||
pref("gfx.content.azure.backends", "direct2d1.1,direct2d,cairo");
|
||||
#else
|
||||
#ifdef XP_MACOSX
|
||||
// TenFourFox is CoreGraphics, all the CoreTime, CoreBeyotches.
|
||||
pref("gfx.content.azure.backends", "cg");
|
||||
pref("gfx.canvas.azure.backends", "skia");
|
||||
// Accelerated cg canvas where available (10.7+)
|
||||
pref("gfx.canvas.azure.accelerated", true);
|
||||
pref("gfx.canvas.azure.backends", "cg");
|
||||
pref("gfx.canvas.azure.accelerated", false);
|
||||
#else
|
||||
pref("gfx.canvas.azure.backends", "cairo");
|
||||
pref("gfx.content.azure.backends", "cairo");
|
||||
@@ -1139,7 +1134,7 @@ pref("javascript.options.strict.debug", false);
|
||||
#endif
|
||||
pref("javascript.options.baselinejit", true);
|
||||
pref("javascript.options.ion", true);
|
||||
pref("javascript.options.asmjs", true);
|
||||
pref("javascript.options.asmjs", false);
|
||||
pref("javascript.options.native_regexp", true);
|
||||
pref("javascript.options.parallel_parsing", true);
|
||||
#if !defined(RELEASE_BUILD) && !defined(ANDROID) && !defined(MOZ_B2G) && !defined(XP_IOS)
|
||||
@@ -1162,7 +1157,7 @@ pref("javascript.options.mem.high_water_mark", 128);
|
||||
pref("javascript.options.mem.max", -1);
|
||||
pref("javascript.options.mem.gc_per_compartment", true);
|
||||
pref("javascript.options.mem.gc_incremental", true);
|
||||
pref("javascript.options.mem.gc_incremental_slice_ms", 10);
|
||||
pref("javascript.options.mem.gc_incremental_slice_ms", 100); // issue 253
|
||||
pref("javascript.options.mem.gc_compacting", true);
|
||||
pref("javascript.options.mem.log", false);
|
||||
pref("javascript.options.mem.notify", false);
|
||||
@@ -2516,9 +2511,9 @@ pref("editor.resizing.preserve_ratio", true);
|
||||
pref("editor.positioning.offset", 0);
|
||||
|
||||
pref("dom.use_watchdog", true);
|
||||
pref("dom.max_chrome_script_run_time", 20);
|
||||
pref("dom.max_child_script_run_time", 10);
|
||||
pref("dom.max_script_run_time", 10);
|
||||
pref("dom.max_chrome_script_run_time", 40); // TenFourFox issue 227
|
||||
pref("dom.max_child_script_run_time", 40);
|
||||
pref("dom.max_script_run_time", 40);
|
||||
|
||||
// If true, ArchiveReader will be enabled
|
||||
pref("dom.archivereader.enabled", false);
|
||||
@@ -4166,7 +4161,8 @@ pref("image.mem.discardable", true);
|
||||
pref("image.mem.allow_locking_in_content_processes", true);
|
||||
|
||||
// Chunk size for calls to the image decoders
|
||||
pref("image.mem.decode_bytes_at_a_time", 16384);
|
||||
// Increased for issue 112 (even the larger amount in Fx19 is not enough)
|
||||
pref("image.mem.decode_bytes_at_a_time", 200000);
|
||||
|
||||
// Minimum timeout for expiring unused images from the surface cache, in
|
||||
// milliseconds. This controls how long we store cached temporary surfaces.
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "nsIForcePendingChannel.h"
|
||||
#include "nsIRequest.h"
|
||||
|
||||
// brotli headers
|
||||
#include "state.h"
|
||||
@@ -134,7 +136,6 @@ nsHTTPCompressConv::OnStopRequest(nsIRequest* request, nsISupports *aContext,
|
||||
LOG(("nsHttpCompresssConv %p onstop partial gzip\n", this));
|
||||
}
|
||||
if (NS_SUCCEEDED(status) && mMode == HTTP_COMPRESS_BROTLI) {
|
||||
uint32_t waste;
|
||||
nsCOMPtr<nsIForcePendingChannel> fpChannel = do_QueryInterface(request);
|
||||
bool isPending = false;
|
||||
if (request) {
|
||||
@@ -143,7 +144,9 @@ nsHTTPCompressConv::OnStopRequest(nsIRequest* request, nsISupports *aContext,
|
||||
if (fpChannel && !isPending) {
|
||||
fpChannel->ForcePending(true);
|
||||
}
|
||||
status = BrotliHandler(nullptr, this, nullptr, 0, 0, &waste);
|
||||
if (mBrotli && (mBrotli->mTotalOut == 0) && !BrotliStateIsStreamEnd(&mBrotli->mState)) {
|
||||
status = NS_ERROR_INVALID_CONTENT_ENCODING;
|
||||
}
|
||||
LOG(("nsHttpCompresssConv %p onstop brotlihandler rv %x\n", this, status));
|
||||
if (fpChannel && !isPending) {
|
||||
fpChannel->ForcePending(false);
|
||||
@@ -158,12 +161,12 @@ NS_METHOD
|
||||
nsHTTPCompressConv::BrotliHandler(nsIInputStream *stream, void *closure, const char *dataIn,
|
||||
uint32_t, uint32_t aAvail, uint32_t *countRead)
|
||||
{
|
||||
MOZ_ASSERT(stream);
|
||||
nsHTTPCompressConv *self = static_cast<nsHTTPCompressConv *>(closure);
|
||||
*countRead = 0;
|
||||
|
||||
const uint32_t kOutSize = 128 * 1024; // just a chunk size, we call in a loop
|
||||
unsigned char outBuffer[kOutSize];
|
||||
unsigned char *outPtr;
|
||||
const size_t kOutSize = 128 * 1024; // just a chunk size, we call in a loop
|
||||
uint8_t *outPtr;
|
||||
size_t outSize;
|
||||
size_t avail = aAvail;
|
||||
BrotliResult res;
|
||||
@@ -173,15 +176,20 @@ nsHTTPCompressConv::BrotliHandler(nsIInputStream *stream, void *closure, const c
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
auto outBuffer = MakeUniqueFallible<uint8_t[]>(kOutSize);
|
||||
if (outBuffer == nullptr) {
|
||||
self->mBrotli->mStatus = NS_ERROR_OUT_OF_MEMORY;
|
||||
return self->mBrotli->mStatus;
|
||||
}
|
||||
|
||||
do {
|
||||
outSize = kOutSize;
|
||||
outPtr = outBuffer;
|
||||
outPtr = outBuffer.get();
|
||||
|
||||
// brotli api is documented in brotli/dec/decode.h
|
||||
LOG(("nsHttpCompresssConv %p brotlihandler decompress %d finish %d\n",
|
||||
self, avail, !stream));
|
||||
res = ::BrotliDecompressBufferStreaming(
|
||||
&avail, reinterpret_cast<const unsigned char **>(&dataIn), stream ? 0 : 1,
|
||||
// brotli api is documented in brotli/dec/decode.h and brotli/dec/decode.c
|
||||
LOG(("nsHttpCompresssConv %p brotlihandler decompress %d\n", self, avail));
|
||||
res = ::BrotliDecompressStream(
|
||||
&avail, reinterpret_cast<const unsigned char **>(&dataIn),
|
||||
&outSize, &outPtr, &self->mBrotli->mTotalOut, &self->mBrotli->mState);
|
||||
outSize = kOutSize - outSize;
|
||||
LOG(("nsHttpCompresssConv %p brotlihandler decompress rv=%x out=%d\n",
|
||||
@@ -193,18 +201,21 @@ nsHTTPCompressConv::BrotliHandler(nsIInputStream *stream, void *closure, const c
|
||||
return self->mBrotli->mStatus;
|
||||
}
|
||||
|
||||
// in 'the current implementation' brotli consumes all input on success
|
||||
MOZ_ASSERT(!avail);
|
||||
if (avail) {
|
||||
LOG(("nsHttpCompressConv %p did not consume all input", self));
|
||||
self->mBrotli->mStatus = NS_ERROR_UNEXPECTED;
|
||||
return self->mBrotli->mStatus;
|
||||
// in 'the current implementation' brotli must consume everything before
|
||||
// asking for more input
|
||||
if (res == BROTLI_RESULT_NEEDS_MORE_INPUT) {
|
||||
MOZ_ASSERT(!avail);
|
||||
if (avail) {
|
||||
LOG(("nsHttpCompressConv %p did not consume all input", self));
|
||||
self->mBrotli->mStatus = NS_ERROR_UNEXPECTED;
|
||||
return self->mBrotli->mStatus;
|
||||
}
|
||||
}
|
||||
if (outSize > 0) {
|
||||
nsresult rv = self->do_OnDataAvailable(self->mBrotli->mRequest,
|
||||
self->mBrotli->mContext,
|
||||
self->mBrotli->mSourceOffset,
|
||||
reinterpret_cast<const char *>(outBuffer),
|
||||
reinterpret_cast<const char *>(outBuffer.get()),
|
||||
outSize);
|
||||
LOG(("nsHttpCompressConv %p BrotliHandler ODA rv=%x", self, rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
@@ -261,7 +272,7 @@ nsHTTPCompressConv::OnDataAvailable(nsIRequest* request,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// FALLTHROUGH
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
case HTTP_COMPRESS_DEFLATE:
|
||||
|
||||
@@ -569,7 +580,7 @@ nsHTTPCompressConv::check_header(nsIInputStream *iStr, uint32_t streamLen, nsres
|
||||
case GZIP_EXTRA1:
|
||||
iStr->Read(&c, 1, &unused);
|
||||
streamLen--;
|
||||
mLen = ((uInt) c & 0377) << 8;
|
||||
mLen |= ((uInt) c & 0377) << 8;
|
||||
mSkipCount = 0;
|
||||
hMode = GZIP_EXTRA2;
|
||||
break;
|
||||
|
||||
@@ -117,7 +117,6 @@ def main():
|
||||
parser.add_argument("-v", "--verbose", action="store_const",
|
||||
dest="loglevel", const=logging.DEBUG,
|
||||
default=logging.INFO)
|
||||
parser.add_argument("--product", help="Override product name from application.ini")
|
||||
args = parser.parse_args()
|
||||
logging.basicConfig(format="%(asctime)s - %(levelname)s - %(message)s",
|
||||
level=args.loglevel)
|
||||
@@ -158,9 +157,8 @@ def main():
|
||||
partial_info[0]["previousBuildNumber"] = e["previousBuildNumber"]
|
||||
submitter = ReleaseSubmitterV4(api_root=args.api_root, auth=auth,
|
||||
dummy=args.dummy)
|
||||
productName = args.product or e["appName"]
|
||||
retry(lambda: submitter.run(
|
||||
platform=e["platform"], productName=productName,
|
||||
platform=e["platform"], productName=e["appName"],
|
||||
version=e["toVersion"],
|
||||
build_number=e["toBuildNumber"],
|
||||
appVersion=e["version"], extVersion=e["version"],
|
||||
@@ -194,10 +192,9 @@ def main():
|
||||
partial_info[0]["from_buildid"] = e["from_buildid"]
|
||||
submitter = NightlySubmitterV4(api_root=args.api_root, auth=auth,
|
||||
dummy=args.dummy)
|
||||
productName = args.product or e["appName"]
|
||||
retry(lambda: submitter.run(
|
||||
platform=e["platform"], buildID=e["to_buildid"],
|
||||
productName=productName, branch=e["branch"],
|
||||
productName=e["appName"], branch=e["branch"],
|
||||
appVersion=e["version"], locale=e["locale"],
|
||||
hashFunction='sha512', extVersion=e["version"],
|
||||
partialInfo=partial_info, completeInfo=complete_info),
|
||||
|
||||
@@ -58,7 +58,7 @@ RootCABinNumber(const SECItem* cert)
|
||||
("pkpinTelem: First bytes %02hx %02hx %02hx %02hx\n",
|
||||
digest.get().data[0], digest.get().data[1], digest.get().data[2], digest.get().data[3]));
|
||||
|
||||
if (mozilla::BinarySearchIf(ROOT_TABLE, 0, ArrayLength(ROOT_TABLE),
|
||||
if (mozilla::BinarySearchIf(ROOT_TABLE, 0, mozilla::ArrayLength(ROOT_TABLE),
|
||||
BinaryHashSearchArrayComparator(
|
||||
reinterpret_cast<const uint8_t*>(digest.get().data), digest.get().len),
|
||||
&idx)) {
|
||||
|
||||
@@ -18,9 +18,10 @@ pref("datareporting.healthreport.nextDataSubmissionTime", "0");
|
||||
pref("datareporting.healthreport.pendingDeleteRemoteData", false);
|
||||
|
||||
// Health Report is enabled by default on all channels.
|
||||
pref("datareporting.healthreport.uploadEnabled", true);
|
||||
// But we're TenFourFox. So f'all that, we've gotta get on with these.
|
||||
pref("datareporting.healthreport.uploadEnabled", false);
|
||||
|
||||
pref("datareporting.healthreport.service.enabled", true);
|
||||
pref("datareporting.healthreport.service.enabled", false);
|
||||
pref("datareporting.healthreport.service.loadDelayMsec", 10000);
|
||||
pref("datareporting.healthreport.service.loadDelayFirstRunMsec", 60000);
|
||||
|
||||
|
||||
@@ -1686,6 +1686,7 @@ function pad(aS, aN, aC)
|
||||
// implemented in terminals, and this code sticks to that subset to maximize
|
||||
// the chance that copying and pasting about:memory output to a terminal will
|
||||
// work correctly.
|
||||
/*
|
||||
const kHorizontal = "\u2500",
|
||||
kVertical = "\u2502",
|
||||
kUpAndRight = "\u2514",
|
||||
@@ -1695,6 +1696,17 @@ const kHorizontal = "\u2500",
|
||||
kVertical_Space_Space = "\u2502 ";
|
||||
|
||||
const kNoKidsSep = " \u2500\u2500 ",
|
||||
*/
|
||||
// It doesn't. 10.4Fx issue 121.
|
||||
const kHorizontal = "-",
|
||||
kVertical = "|",
|
||||
kUpAndRight = "+",
|
||||
kUpAndRight_Right_Right = "+--",
|
||||
kVerticalAndRight = "+",
|
||||
kVerticalAndRight_Right_Right = "+--",
|
||||
kVertical_Space_Space = "| ";
|
||||
|
||||
const kNoKidsSep = " -- ",
|
||||
kHideKidsSep = " ++ ",
|
||||
kShowKidsSep = " -- ";
|
||||
|
||||
|
||||
@@ -799,7 +799,11 @@ nsAutoCompleteController::OnUpdateSearchResult(nsIAutoCompleteSearch *aSearch, n
|
||||
NS_IMETHODIMP
|
||||
nsAutoCompleteController::OnSearchResult(nsIAutoCompleteSearch *aSearch, nsIAutoCompleteResult* aResult)
|
||||
{
|
||||
/* BADFIX??? */
|
||||
/*
|
||||
MOZ_ASSERT(mSearchesOngoing > 0 && mSearches.Contains(aSearch));
|
||||
*/
|
||||
MOZ_ASSERT(mSearches.Contains(aSearch));
|
||||
|
||||
// If this is the first search result we are processing
|
||||
// we should clear out the previously cached results.
|
||||
@@ -813,6 +817,7 @@ nsAutoCompleteController::OnSearchResult(nsIAutoCompleteSearch *aSearch, nsIAuto
|
||||
aResult->GetSearchResult(&result);
|
||||
}
|
||||
|
||||
if (mSearchesOngoing) // BADFIX???
|
||||
// If our results are incremental, the search is still ongoing.
|
||||
if (result != nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING &&
|
||||
result != nsIAutoCompleteResult::RESULT_NOMATCH_ONGOING) {
|
||||
|
||||
@@ -806,6 +806,24 @@ nsPlacesAutoComplete.prototype = {
|
||||
if (aSearchOngoing) {
|
||||
resultCode += "_ONGOING";
|
||||
}
|
||||
|
||||
/* 10.4Fx issue 21. This makes me absolutely nauseous just writing this
|
||||
because this is about the most naked, improper wallpaper job I've ever
|
||||
written. But it works. In short, NEVER return RESULT_NOMATCH -- if we
|
||||
are about to do that, forge a single stub match to make a blank box and
|
||||
_SUCCESS, and this solves the problem. I am going to take a shower and
|
||||
try to scrub the disgust from my heaving, vomiting body. */
|
||||
|
||||
if (resultCode == "RESULT_NOMATCH") { // well, shoot. let's fudge.
|
||||
this._result.appendMatch(
|
||||
"", // blank URL
|
||||
"", // blank title
|
||||
"", // no favicon
|
||||
"favicon" // but use a favicon style -- thus a blank drop-down
|
||||
);
|
||||
resultCode = "RESULT_SUCCESS";
|
||||
} // end issue
|
||||
|
||||
result.setSearchResult(Ci.nsIAutoCompleteResult[resultCode]);
|
||||
this._listener.onSearchResult(this, result);
|
||||
if (this._telemetryStartTime) {
|
||||
|
||||
@@ -653,7 +653,7 @@ var Impl = {
|
||||
* @return {Boolean} True if Telemetry is allowed to record at least base (FHR) data,
|
||||
* false otherwise.
|
||||
*/
|
||||
enableTelemetryRecording: function enableTelemetryRecording() {
|
||||
enableTelemetryRecording: function enableTelemetryRecording() { return false;
|
||||
// The thumbnail service also runs in a content process, even with e10s off.
|
||||
// We need to check if e10s is on so we don't submit child payloads for it.
|
||||
// We still need xpcshell child tests to work, so we skip this if test mode is enabled.
|
||||
|
||||
@@ -336,7 +336,7 @@ var TelemetryReportingPolicyImpl = {
|
||||
*
|
||||
* @return {Boolean} True if we are allowed to upload data, false otherwise.
|
||||
*/
|
||||
canUpload: function() {
|
||||
canUpload: function() { return false;
|
||||
// If data submission is disabled, there's no point in showing the infobar. Just
|
||||
// forbid to upload.
|
||||
if (!this.dataSubmissionEnabled) {
|
||||
|
||||
@@ -1030,7 +1030,7 @@ var TelemetrySendImpl = {
|
||||
* @param {Object} [ping=null] A ping to be checked.
|
||||
* @return {Boolean} True if pings can be send to the servers, false otherwise.
|
||||
*/
|
||||
sendingEnabled: function(ping = null) {
|
||||
sendingEnabled: function(ping = null) { return false;
|
||||
// We only send pings from official builds, but allow overriding this for tests.
|
||||
if (!Telemetry.isOfficialTelemetry && !this._testMode) {
|
||||
return false;
|
||||
|
||||
@@ -302,7 +302,7 @@ var TelemetryScheduler = {
|
||||
this._lastDailyPingTime = now.getTime();
|
||||
this._lastSessionCheckpointTime = now.getTime();
|
||||
this._rescheduleTimeout();
|
||||
idleService.addIdleObserver(this, IDLE_TIMEOUT_SECONDS);
|
||||
//idleService.addIdleObserver(this, IDLE_TIMEOUT_SECONDS);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,7 +35,7 @@ this.TelemetryStopwatch = {
|
||||
* timer already exists, it can't be started again, and the existing
|
||||
* one will be cleared in order to avoid measurements errors.
|
||||
*/
|
||||
start: function(aHistogram, aObj) {
|
||||
start: function(aHistogram, aObj) { return;
|
||||
if (!validTypes(aHistogram, aObj))
|
||||
return false;
|
||||
|
||||
@@ -74,7 +74,7 @@ this.TelemetryStopwatch = {
|
||||
*
|
||||
* @return true if the timer exist and it was cleared, false otherwise.
|
||||
*/
|
||||
cancel: function ts_cancel(aHistogram, aObj) {
|
||||
cancel: function ts_cancel(aHistogram, aObj) { return;
|
||||
if (!validTypes(aHistogram, aObj))
|
||||
return false;
|
||||
|
||||
@@ -103,7 +103,7 @@ this.TelemetryStopwatch = {
|
||||
*
|
||||
* @return time in milliseconds or -1 if the stopwatch was not found.
|
||||
*/
|
||||
timeElapsed: function(aHistogram, aObj) {
|
||||
timeElapsed: function(aHistogram, aObj) { return 0;
|
||||
if (!validTypes(aHistogram, aObj))
|
||||
return -1;
|
||||
let timers = aObj
|
||||
@@ -132,7 +132,7 @@ this.TelemetryStopwatch = {
|
||||
* @return true if the timer was succesfully stopped and the data was
|
||||
* added to the histogram, false otherwise.
|
||||
*/
|
||||
finish: function(aHistogram, aObj) {
|
||||
finish: function(aHistogram, aObj) { return true;
|
||||
if (!validTypes(aHistogram, aObj))
|
||||
return false;
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ this.UITelemetry = {
|
||||
_measurements: [],
|
||||
|
||||
// Lazily decide whether telemetry is enabled.
|
||||
get enabled() {
|
||||
get enabled() { return false;
|
||||
if (this._enabled !== undefined) {
|
||||
return this._enabled;
|
||||
}
|
||||
@@ -45,7 +45,7 @@ this.UITelemetry = {
|
||||
return this._enabled;
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
observe: function(aSubject, aTopic, aData) { return;
|
||||
if (aTopic == "profile-before-change") {
|
||||
Services.obs.removeObserver(this, "profile-before-change");
|
||||
Services.prefs.removeObserver(PREF_ENABLED, this);
|
||||
|
||||
@@ -265,6 +265,20 @@ nsNativeTheme::GetIndeterminate(nsIFrame* aFrame)
|
||||
return false;
|
||||
}
|
||||
|
||||
// backout bug 672050
|
||||
bool
|
||||
nsNativeTheme::IsLastTab(nsIFrame* aFrame)
|
||||
{
|
||||
if (!aFrame)
|
||||
return false;
|
||||
|
||||
while ((aFrame = aFrame->GetNextSibling())) {
|
||||
if (aFrame->GetRect().width > 0 && aFrame->GetContent()->NodeInfo()->NameAtom() == nsGkAtoms::tab)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nsNativeTheme::IsWidgetStyled(nsPresContext* aPresContext, nsIFrame* aFrame,
|
||||
uint8_t aWidgetType)
|
||||
|
||||
@@ -134,6 +134,7 @@ class nsNativeTheme : public nsITimerCallback
|
||||
// tab:
|
||||
bool IsBottomTab(nsIFrame* aFrame);
|
||||
bool IsFirstTab(nsIFrame* aFrame);
|
||||
bool IsLastTab(nsIFrame* aFrame);
|
||||
|
||||
bool IsHorizontal(nsIFrame* aFrame);
|
||||
|
||||
|
||||
@@ -1306,6 +1306,7 @@ CycleCollectedJSRuntime::OnGC(JSGCStatus aStatus)
|
||||
switch (aStatus) {
|
||||
case JSGC_BEGIN:
|
||||
nsCycleCollector_prepareForGarbageCollection();
|
||||
mZonesWaitingForGC.Clear();
|
||||
break;
|
||||
case JSGC_END: {
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
@@ -1345,3 +1346,16 @@ CycleCollectedJSRuntime::OnLargeAllocationFailure()
|
||||
AnnotateAndSetOutOfMemory(&mLargeAllocationFailureState, OOMState::Reported);
|
||||
}
|
||||
|
||||
void
|
||||
CycleCollectedJSRuntime::PrepareWaitingZonesForGC()
|
||||
{
|
||||
if (mZonesWaitingForGC.Count() == 0) {
|
||||
JS::PrepareForFullGC(Runtime());
|
||||
} else {
|
||||
for (auto iter = mZonesWaitingForGC.Iter(); !iter.Done(); iter.Next()) {
|
||||
JS::PrepareZoneForGC(iter.Get()->GetKey());
|
||||
}
|
||||
mZonesWaitingForGC.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsTHashtable.h"
|
||||
|
||||
class nsCycleCollectionNoteRootCallback;
|
||||
class nsIException;
|
||||
@@ -317,6 +318,18 @@ public:
|
||||
// isn't one.
|
||||
static CycleCollectedJSRuntime* Get();
|
||||
|
||||
// Add aZone to the set of zones waiting for a GC.
|
||||
void AddZoneWaitingForGC(JS::Zone* aZone)
|
||||
{
|
||||
mZonesWaitingForGC.PutEntry(aZone);
|
||||
}
|
||||
|
||||
// Prepare any zones for GC that have been passed to AddZoneWaitingForGC()
|
||||
// since the last GC or since the last call to PrepareWaitingZonesForGC(),
|
||||
// whichever was most recent. If there were no such zones, prepare for a
|
||||
// full GC.
|
||||
void PrepareWaitingZonesForGC();
|
||||
|
||||
// Storage for watching rejected promises waiting for some client to
|
||||
// consume their rejection.
|
||||
// We store values as `nsISupports` to avoid adding compile-time dependencies
|
||||
@@ -361,6 +374,8 @@ private:
|
||||
|
||||
OOMState mOutOfMemoryState;
|
||||
OOMState mLargeAllocationFailureState;
|
||||
|
||||
nsTHashtable<nsPtrHashKey<JS::Zone>> mZonesWaitingForGC;
|
||||
};
|
||||
|
||||
void TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user