This commit is contained in:
2018-05-29 20:37:36 +08:00
parent 8d10bb7abd
commit 3d7d3ae7fe
101 changed files with 3524 additions and 2008 deletions
+12 -14
View File
@@ -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");
+39 -3
View File
@@ -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);
+8 -4
View File
@@ -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)
+1 -1
View File
@@ -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",
+23 -7
View File
@@ -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
}
},
+2
View File
@@ -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:
+8 -8
View 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;
}
+19 -1
View File
@@ -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;
+2 -2
View File
@@ -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);
+8 -7
View File
@@ -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);
}
};
+19
View File
@@ -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) {
+3 -3
View File
@@ -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 {
+4
View File
@@ -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,
+72 -17
View File
@@ -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;
+1 -6
View File
@@ -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;
+47 -1
View File
@@ -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();
+21 -6
View File
@@ -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
+6 -3
View File
@@ -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);
+5
View File
@@ -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);
}
}
+22
View File
@@ -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
}
+2 -1
View File
@@ -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
+1 -1
View File
@@ -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);
+7
View File
@@ -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
{
+1
View File
@@ -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;
}
+23
View File
@@ -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(&region.mImpl, &n);
boxes = pixman_region32_rectangles(&region.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,
+4
View File
@@ -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 =
+59 -10
View File
@@ -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();
}
}
+3
View File
@@ -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;
+1 -1
View File
@@ -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);
+7 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+1 -1
View File
@@ -71,7 +71,7 @@ private:
};
inline XPCShellEnvironment*
Environment(Handle<JSObject*> global)
Environment(JS::Handle<JSObject*> global)
{
AutoSafeJSContext cx;
JSAutoCompartment ac(cx, global);
+1
View File
@@ -144,6 +144,7 @@ namespace JS {
\
_(ICNameStub_ReadSlot) \
_(ICNameStub_CallGetter) \
_(ICNameStub_TypeOfNoProperty) \
\
_(CantInlineGeneric) \
_(CantInlineNoTarget) \
+5
View File
@@ -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.
+14
View File
@@ -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
+5 -1
View File
@@ -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();
+11
View File
@@ -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
+3
View File
@@ -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;
}
+60 -1
View File
@@ -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;
}
}
+3
View File
@@ -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);
+1 -1
View File
@@ -46,7 +46,7 @@ OptimizationInfo::initNormalOptimizationInfo()
inliningMaxCallerBytecodeLength_ = 1500;
maxInlineDepth_ = 3;
scalarReplacement_ = true;
smallFunctionMaxInlineDepth_ = 10;
smallFunctionMaxInlineDepth_ = 13;
compilerWarmUpThreshold_ = CompilerWarmupThreshold;
inliningWarmUpThresholdFactor_ = 0.125;
inliningRecompileThresholdFactor_ = 4;
+2
View File
@@ -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"))
+2 -1
View File
@@ -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,
+14
View File
@@ -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;
}
+27
View File
@@ -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 {
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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();
}
+16
View File
@@ -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
View File
@@ -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>());
+1 -1
View File
@@ -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);
+5
View File
@@ -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.
+7 -7
View File
@@ -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);
+29 -6
View File
@@ -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
+71 -2
View File
@@ -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;
}
+1
View File
@@ -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(),
+2 -2
View File
@@ -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,
+24
View File
@@ -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());
+31 -6
View File
@@ -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);
+16 -1
View File
@@ -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;
+12
View File
@@ -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
+7 -3
View File
@@ -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();
+18
View File
@@ -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
View File
@@ -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: \
+2 -1
View File
@@ -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 {
+1 -1
View File
@@ -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)
+15 -25
View File
@@ -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
View File
@@ -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_ */
+6 -15
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+112 -111
View File
@@ -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" */
+10 -11
View File
@@ -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
+10 -20
View File
@@ -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
View File
@@ -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
+22 -35
View File
@@ -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
View File
@@ -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_ */
+6 -13
View File
@@ -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
View File
@@ -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
View File
@@ -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_ */
+40 -55
View File
@@ -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
View File
@@ -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
View File
@@ -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)) {
+3 -2
View File
@@ -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;
+2 -2
View File
@@ -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);
+14
View File
@@ -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)
+1
View File
@@ -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);
+14
View File
@@ -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();
}
}
+15
View File
@@ -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