Compare commits
69
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dabdec3b3a | ||
|
|
cd17592001 | ||
|
|
62d550e22d | ||
|
|
2f60cae35e | ||
|
|
65bbd1acb6 | ||
|
|
3edea8e9e0 | ||
|
|
fc539ba189 | ||
|
|
68299c8613 | ||
|
|
d0b7069d1c | ||
|
|
55dbbe4d16 | ||
|
|
a52529970f | ||
|
|
bcb46bf65e | ||
|
|
176f4fe206 | ||
|
|
aed41dc542 | ||
|
|
a7a521e378 | ||
|
|
e9b56e301c | ||
|
|
57debb342a | ||
|
|
78219cdbf1 | ||
|
|
c68e97f01c | ||
|
|
5165ed0228 | ||
|
|
ca9abcdf17 | ||
|
|
459c36b9df | ||
|
|
c9508464d5 | ||
|
|
2219a336dd | ||
|
|
a6763e7451 | ||
|
|
727f4372a9 | ||
|
|
556a15567d | ||
|
|
95d93b55c9 | ||
|
|
693dc6a5fc | ||
|
|
08cc9cd558 | ||
|
|
4f0f4aa879 | ||
|
|
53ca366d2b | ||
|
|
14f7bec523 | ||
|
|
976ccaa922 | ||
|
|
8b3375e2c2 | ||
|
|
8fefeee3c3 | ||
|
|
b645d59b1e | ||
|
|
71e0814af2 | ||
|
|
5744d59188 | ||
|
|
45a976a5f1 | ||
|
|
06f9b815ce | ||
|
|
0032e8313d | ||
|
|
d7df9b336a | ||
|
|
6c1b1bd18f | ||
|
|
770cb9a4b9 | ||
|
|
90309c01a8 | ||
|
|
4de0e9c68d | ||
|
|
4dae04e594 | ||
|
|
b9c41e2624 | ||
|
|
e1db27e199 | ||
|
|
a5203631d8 | ||
|
|
e2fe23c90b | ||
|
|
fcc0241430 | ||
|
|
24657db629 | ||
|
|
4939447eb7 | ||
|
|
f07d60c09f | ||
|
|
d7a05ea9e5 | ||
|
|
10bf4a6d5b | ||
|
|
c3778db14d | ||
|
|
abcee4f85c | ||
|
|
67a7e4eabd | ||
|
|
c1ef954679 | ||
|
|
eac19e3356 | ||
|
|
a98d06380f | ||
|
|
1e8d07cac2 | ||
|
|
e7a0013f81 | ||
|
|
17b4d049f4 | ||
|
|
abf1d5a099 | ||
|
|
b7dac18c0e |
No files matched your search
@@ -22,4 +22,4 @@
|
||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Clobber for CSS flow-root implementation
|
||||
Clobber for NSS update
|
||||
@@ -36,4 +36,4 @@ improvement patches upstream to its origin to mutually improve the platform and
|
||||
a future for XUL.
|
||||
|
||||
## Looking for Pale Moon and Basilisk?
|
||||
As of [`Issue #969`](https://github.com/MoonchildProductions/UXP/issues/969), release versions `28.9.0` and `2020.03.04` respectively, they have been split off into their own dedicated repositories located at [`MoonchildProductions/Pale-Moon`](https://github.com/MoonchildProductions/Pale-Moon) and [`MoonchildProductions/Basilisk`](https://github.com/MoonchildProductions/Basilisk).
|
||||
As of [`Issue #969`](https://repo.palemoon.org/MoonchildProductions/UXP/issues/969), release versions `28.9.0` and `2020.03.04` respectively, they have been split off into their own dedicated repositories located at [`MoonchildProductions/Pale-Moon`](https://repo.palemoon.org/MoonchildProductions/Pale-Moon) and [`MoonchildProductions/Basilisk`](https://repo.palemoon.org/MoonchildProductions/Basilisk).
|
||||
+1
-1
@@ -23,7 +23,7 @@ Generally not security vulnerabilities:
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you find an issue in UXP or the applications it builds on that could impact the security or safety of users please **do not**
|
||||
make an issue on GitHub about it. GitHub does not support restricted viewability for security sensitive bugs.
|
||||
make an issue on Gitea about it. Gitea does not support restricted viewability for security sensitive bugs.
|
||||
|
||||
If you want to report a security-sensitive issue then please go to the [forum](https://forum.palemoon.org) and report the issue
|
||||
via a **private message** to **Moonchild** (the founder and prime responsible for security issues).
|
||||
|
||||
@@ -162,6 +162,8 @@ def old_configure_options(*options):
|
||||
'--enable-b2g-camera',
|
||||
'--enable-b2g-ril',
|
||||
'--enable-bundled-fonts',
|
||||
'--enable-chrome-compression',
|
||||
'--enable-chrome-format',
|
||||
'--enable-clang-plugin',
|
||||
'--enable-content-sandbox',
|
||||
'--enable-cookies',
|
||||
@@ -263,6 +265,7 @@ def old_configure_options(*options):
|
||||
'--with-app-name',
|
||||
'--with-arch',
|
||||
'--with-branding',
|
||||
'--with-chrome-name',
|
||||
'--with-crashreporter-enable-percent',
|
||||
'--with-cross-lib',
|
||||
'--with-debug-label',
|
||||
|
||||
+1
-1
@@ -216,7 +216,7 @@ endif # NO_PROFILE_GUIDED_OPTIMIZE
|
||||
|
||||
MAKE_JARS_FLAGS = \
|
||||
-t $(topsrcdir) \
|
||||
-f $(MOZ_JAR_MAKER_FILE_FORMAT) \
|
||||
-f $(MOZ_CHROME_FILE_FORMAT) \
|
||||
$(NULL)
|
||||
|
||||
ifdef USE_EXTENSION_MANIFEST
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
# hardcoded milestones in the tree from these two files.
|
||||
#--------------------------------------------------------
|
||||
|
||||
4.6.0
|
||||
4.7.0
|
||||
@@ -526,7 +526,6 @@ hardware/lights.h
|
||||
hardware/power.h
|
||||
hardware_legacy/power.h
|
||||
hardware_legacy/uevent.h
|
||||
hardware_legacy/vibrator.h
|
||||
#endif
|
||||
HIToolbox/HIToolbox.h
|
||||
hlink.h
|
||||
|
||||
@@ -22,7 +22,7 @@ REF_MANIFEST = $(if $(USE_EXTENSION_MANIFEST),chrome.manifest,test.manifest)
|
||||
|
||||
check-%::
|
||||
if test -d $(FINAL_TARGET); then rm -rf $(FINAL_TARGET); fi;
|
||||
$(MAKE) realchrome MOZ_JAR_MAKER_FILE_FORMAT=$*
|
||||
$(MAKE) realchrome MOZ_CHROME_FILE_FORMAT=$*
|
||||
@echo 'Comparing manifests...'
|
||||
@if ! sort $(MY_MANIFEST) | diff --text -U 0 $(srcdir)/../$(REF_MANIFEST).$* - ; then \
|
||||
echo 'TEST-UNEXPECTED-FAIL | config/tests/$(REF_MANIFEST).$* | differing content in manifest!' ; \
|
||||
|
||||
@@ -30,7 +30,7 @@ function* testTopLeft(inspector, view) {
|
||||
elementRulesNb: 4,
|
||||
firstLineRulesNb: 2,
|
||||
firstLetterRulesNb: 1,
|
||||
selectionRulesNb: 0,
|
||||
selectionRulesNb: 1,
|
||||
afterRulesNb: 1,
|
||||
beforeRulesNb: 2
|
||||
}
|
||||
@@ -167,7 +167,7 @@ function* testParagraph(inspector, view) {
|
||||
elementRulesNb: 3,
|
||||
firstLineRulesNb: 1,
|
||||
firstLetterRulesNb: 1,
|
||||
selectionRulesNb: 1,
|
||||
selectionRulesNb: 2,
|
||||
beforeRulesNb: 0,
|
||||
afterRulesNb: 0
|
||||
});
|
||||
@@ -217,7 +217,7 @@ function* assertPseudoElementRulesNumbers(selector, inspector, view, ruleNbs) {
|
||||
firstLetterRules: elementStyle.rules.filter(rule =>
|
||||
rule.pseudoElement === ":first-letter"),
|
||||
selectionRules: elementStyle.rules.filter(rule =>
|
||||
rule.pseudoElement === ":-moz-selection"),
|
||||
rule.pseudoElement === ":selection"),
|
||||
beforeRules: elementStyle.rules.filter(rule =>
|
||||
rule.pseudoElement === ":before"),
|
||||
afterRules: elementStyle.rules.filter(rule =>
|
||||
|
||||
@@ -94,7 +94,7 @@ exports.menuitems = [
|
||||
},
|
||||
key: {
|
||||
id: "browserToolbox",
|
||||
modifiers: "accel,alt,shift",
|
||||
modifiers: isMac ? "accel,alt" : "accel,shift",
|
||||
keytext: true
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1233,7 +1233,7 @@ exports.CSS_PROPERTIES = {
|
||||
"-moz-tab-size": {
|
||||
"isInherited": true,
|
||||
"subproperties": [
|
||||
"-moz-tab-size"
|
||||
"tab-size"
|
||||
],
|
||||
"supports": [
|
||||
7
|
||||
@@ -2872,6 +2872,7 @@ exports.CSS_PROPERTIES = {
|
||||
"box-shadow",
|
||||
"box-sizing",
|
||||
"caption-side",
|
||||
"caret-color",
|
||||
"clear",
|
||||
"clip",
|
||||
"clip-path",
|
||||
@@ -3051,7 +3052,7 @@ exports.CSS_PROPERTIES = {
|
||||
"stroke-opacity",
|
||||
"stroke-width",
|
||||
"-x-system-font",
|
||||
"-moz-tab-size",
|
||||
"tab-size",
|
||||
"table-layout",
|
||||
"text-align",
|
||||
"text-align-last",
|
||||
@@ -5277,6 +5278,28 @@ exports.CSS_PROPERTIES = {
|
||||
"unset"
|
||||
]
|
||||
},
|
||||
"caret-color": {
|
||||
"isInherited": true,
|
||||
"subproperties": [
|
||||
"caret-color"
|
||||
],
|
||||
"supports": [
|
||||
2
|
||||
],
|
||||
"values": [
|
||||
"COLOR",
|
||||
"auto",
|
||||
"currentColor",
|
||||
"hsl",
|
||||
"hsla",
|
||||
"inherit",
|
||||
"initial",
|
||||
"rgb",
|
||||
"rgba",
|
||||
"transparent",
|
||||
"unset"
|
||||
]
|
||||
},
|
||||
"clear": {
|
||||
"isInherited": false,
|
||||
"subproperties": [
|
||||
@@ -7857,6 +7880,7 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"supports": [],
|
||||
"values": [
|
||||
"anywhere",
|
||||
"break-word",
|
||||
"inherit",
|
||||
"initial",
|
||||
@@ -8626,6 +8650,23 @@ exports.CSS_PROPERTIES = {
|
||||
"unset"
|
||||
]
|
||||
},
|
||||
"tab-size": {
|
||||
"isInherited": true,
|
||||
"subproperties": [
|
||||
"tab-size"
|
||||
],
|
||||
"supports": [
|
||||
6,
|
||||
7
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
"unset"
|
||||
]
|
||||
},
|
||||
"table-layout": {
|
||||
"isInherited": false,
|
||||
"subproperties": [
|
||||
@@ -9317,6 +9358,7 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"supports": [],
|
||||
"values": [
|
||||
"anywhere",
|
||||
"break-word",
|
||||
"inherit",
|
||||
"initial",
|
||||
@@ -9373,6 +9415,7 @@ exports.PSEUDO_ELEMENTS = [
|
||||
":backdrop",
|
||||
":first-letter",
|
||||
":first-line",
|
||||
":selection",
|
||||
":-moz-selection",
|
||||
":-moz-focus-inner",
|
||||
":-moz-focus-outer",
|
||||
|
||||
@@ -93,15 +93,20 @@ With rare exception, it is advisable to use the following style for commit messa
|
||||
|
||||
This would directly apply to anyone making a pull request.
|
||||
|
||||
Single commits are where issues can be reasonably resolved in a single commit.
|
||||
- Single Commit: `Issue #xxx - Cited issue title or appropriate direct description of changes`
|
||||
- *`Issue #1083 - Deprecate FUEL extension helper javascript library`*
|
||||
- Multi-Part Commits: `Issue #xxx - Part Number: Appropriate direct description of changes`
|
||||
|
||||
Multi-part commits would be used for complex issues. However, an exception exists for multi-part commits where the issue is anticipated or ends up being long term such as "Stop using unified compilation of sources". In these instances the multi-part form is not required.
|
||||
- Multi-Part Form: `Issue #xxx - Part Number: Appropriate direct description of changes`
|
||||
- *`Issue #492 - Part 1: Remove files`*
|
||||
- *`Issue #492 - Part 2: Build system, Installer/Packaging`*
|
||||
- *`Issue #492 - Part 3: nsUpdateService.js, updater.cpp, nsUpdateDriver.cpp`*
|
||||
- *`Issue #492 - Part 4: Remove superfluous brackets in nsUpdateService.js and updater.cpp`*
|
||||
|
||||
An exception exists for multi-part commits where the issue is anticipated or ends up being long term such as "Stop using unified compilation of sources". In these instances the multi-part form is not required.
|
||||
Occasionally a resolved (and shipped) issue requires further changes to fix bugs. However, If follow-ups are complex enough to be multi-part it should be considered a new issue.
|
||||
- Follow-up Form: *`Issue #xxx - Follow-up: Appropriate direct description of changes`*
|
||||
- *`Issue #1643 - Follow-up: Make sure things aren't changed while iterating.`*
|
||||
|
||||
### Commits with no issue
|
||||
|
||||
|
||||
@@ -75,11 +75,6 @@ const gMozillaSpecificProperties = {
|
||||
from: "ignore",
|
||||
to: "stretch-to-fit"
|
||||
},
|
||||
"-moz-tab-size": {
|
||||
// https://drafts.csswg.org/css-text-3/#propdef-tab-size
|
||||
from: "1",
|
||||
to: "5"
|
||||
},
|
||||
"-moz-text-size-adjust": {
|
||||
// https://drafts.csswg.org/css-size-adjust/#propdef-text-size-adjust
|
||||
from: "none",
|
||||
|
||||
+1
-192
@@ -98,11 +98,6 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
static bool sVibratorEnabled = false;
|
||||
static uint32_t sMaxVibrateMS = 0;
|
||||
static uint32_t sMaxVibrateListLen = 0;
|
||||
static const char* kVibrationPermissionType = "vibration";
|
||||
|
||||
static void
|
||||
AddPermission(nsIPrincipal* aPrincipal, const char* aType, uint32_t aPermission,
|
||||
uint32_t aExpireType, int64_t aExpireTime)
|
||||
@@ -153,12 +148,7 @@ GetPermission(nsIPrincipal* aPrincipal, const char* aType)
|
||||
void
|
||||
Navigator::Init()
|
||||
{
|
||||
Preferences::AddBoolVarCache(&sVibratorEnabled,
|
||||
"dom.vibrator.enabled", true);
|
||||
Preferences::AddUintVarCache(&sMaxVibrateMS,
|
||||
"dom.vibrator.max_vibrate_ms", 10000);
|
||||
Preferences::AddUintVarCache(&sMaxVibrateListLen,
|
||||
"dom.vibrator.max_vibrate_list_len", 128);
|
||||
// Add any Preferences::Add*VarCache(&sPref, "pref", default) here if needed.
|
||||
}
|
||||
|
||||
Navigator::Navigator(nsPIDOMWindowInner* aWindow)
|
||||
@@ -706,82 +696,6 @@ Navigator::RefreshMIMEArray()
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class VibrateWindowListener : public nsIDOMEventListener
|
||||
{
|
||||
public:
|
||||
VibrateWindowListener(nsPIDOMWindowInner* aWindow, nsIDocument* aDocument)
|
||||
{
|
||||
mWindow = do_GetWeakReference(aWindow);
|
||||
mDocument = do_GetWeakReference(aDocument);
|
||||
|
||||
NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange");
|
||||
aDocument->AddSystemEventListener(visibilitychange,
|
||||
this, /* listener */
|
||||
true, /* use capture */
|
||||
false /* wants untrusted */);
|
||||
}
|
||||
|
||||
void RemoveListener();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
|
||||
private:
|
||||
virtual ~VibrateWindowListener()
|
||||
{
|
||||
}
|
||||
|
||||
nsWeakPtr mWindow;
|
||||
nsWeakPtr mDocument;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(VibrateWindowListener, nsIDOMEventListener)
|
||||
|
||||
StaticRefPtr<VibrateWindowListener> gVibrateWindowListener;
|
||||
|
||||
static bool
|
||||
MayVibrate(nsIDocument* doc) {
|
||||
// Hidden documents cannot start or stop a vibration.
|
||||
return (doc && !doc->Hidden());
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
VibrateWindowListener::HandleEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> doc =
|
||||
do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget());
|
||||
|
||||
if (!MayVibrate(doc)) {
|
||||
// It's important that we call CancelVibrate(), not Vibrate() with an
|
||||
// empty list, because Vibrate() will fail if we're no longer focused, but
|
||||
// CancelVibrate() will succeed, so long as nobody else has started a new
|
||||
// vibration pattern.
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mWindow);
|
||||
hal::CancelVibrate(window);
|
||||
RemoveListener();
|
||||
gVibrateWindowListener = nullptr;
|
||||
// Careful: The line above might have deleted |this|!
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
VibrateWindowListener::RemoveListener()
|
||||
{
|
||||
nsCOMPtr<EventTarget> target = do_QueryReferent(mDocument);
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange");
|
||||
target->RemoveSystemEventListener(visibilitychange, this,
|
||||
true /* use capture */);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void
|
||||
Navigator::AddIdleObserver(MozIdleObserver& aIdleObserver, ErrorResult& aRv)
|
||||
{
|
||||
@@ -810,111 +724,6 @@ Navigator::RemoveIdleObserver(MozIdleObserver& aIdleObserver, ErrorResult& aRv)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Navigator::SetVibrationPermission(bool aPermitted, bool aPersistent)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsTArray<uint32_t> pattern;
|
||||
pattern.SwapElements(mRequestedVibrationPattern);
|
||||
|
||||
if (!mWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
|
||||
|
||||
if (!MayVibrate(doc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aPermitted) {
|
||||
// Add a listener to cancel the vibration if the document becomes hidden,
|
||||
// and remove the old visibility listener, if there was one.
|
||||
if (!gVibrateWindowListener) {
|
||||
// If gVibrateWindowListener is null, this is the first time we've vibrated,
|
||||
// and we need to register a listener to clear gVibrateWindowListener on
|
||||
// shutdown.
|
||||
ClearOnShutdown(&gVibrateWindowListener);
|
||||
} else {
|
||||
gVibrateWindowListener->RemoveListener();
|
||||
}
|
||||
gVibrateWindowListener = new VibrateWindowListener(mWindow, doc);
|
||||
hal::Vibrate(pattern, mWindow);
|
||||
}
|
||||
|
||||
if (aPersistent) {
|
||||
AddPermission(doc->NodePrincipal(), kVibrationPermissionType,
|
||||
aPermitted ? nsIPermissionManager::ALLOW_ACTION :
|
||||
nsIPermissionManager::DENY_ACTION,
|
||||
nsIPermissionManager::EXPIRE_SESSION, 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Navigator::Vibrate(uint32_t aDuration)
|
||||
{
|
||||
AutoTArray<uint32_t, 1> pattern;
|
||||
pattern.AppendElement(aDuration);
|
||||
return Vibrate(pattern);
|
||||
}
|
||||
|
||||
bool
|
||||
Navigator::Vibrate(const nsTArray<uint32_t>& aPattern)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mWindow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
|
||||
|
||||
if (!MayVibrate(doc)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsTArray<uint32_t> pattern(aPattern);
|
||||
|
||||
if (pattern.Length() > sMaxVibrateListLen) {
|
||||
pattern.SetLength(sMaxVibrateListLen);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < pattern.Length(); ++i) {
|
||||
pattern[i] = std::min(sMaxVibrateMS, pattern[i]);
|
||||
}
|
||||
|
||||
// The spec says we check sVibratorEnabled after we've done the sanity
|
||||
// checking on the pattern.
|
||||
if (!sVibratorEnabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
mRequestedVibrationPattern.SwapElements(pattern);
|
||||
uint32_t permission = GetPermission(mWindow, kVibrationPermissionType);
|
||||
|
||||
if (permission == nsIPermissionManager::ALLOW_ACTION ||
|
||||
mRequestedVibrationPattern.IsEmpty() ||
|
||||
(mRequestedVibrationPattern.Length() == 1 &&
|
||||
mRequestedVibrationPattern[0] == 0)) {
|
||||
// Always allow cancelling vibration and respect session permissions.
|
||||
SetVibrationPermission(true /* permitted */, false /* persistent */);
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (!obs || permission == nsIPermissionManager::DENY_ACTION) {
|
||||
// Abort without observer service or on denied session permission.
|
||||
SetVibrationPermission(false /* permitted */, false /* persistent */);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Request user permission.
|
||||
obs->NotifyObservers(ToSupports(this), "Vibration:Request", nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// Pointer Events interface
|
||||
//*****************************************************************************
|
||||
|
||||
@@ -150,9 +150,6 @@ public:
|
||||
// NavigatorBinding::ClearCachedUserAgentValue(this);
|
||||
void ClearUserAgentCache();
|
||||
|
||||
bool Vibrate(uint32_t aDuration);
|
||||
bool Vibrate(const nsTArray<uint32_t>& aDuration);
|
||||
void SetVibrationPermission(bool aPermitted, bool aPersistent);
|
||||
uint32_t MaxTouchPoints();
|
||||
void GetAppCodeName(nsString& aAppCodeName, ErrorResult& aRv)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace dom {
|
||||
void
|
||||
ResizeObserverNotificationHelper::WillRefresh(TimeStamp aTime)
|
||||
{
|
||||
MOZ_ASSERT(mOwner, "Why is mOwner already dead when this RefreshObserver is still registered?");
|
||||
MOZ_DIAGNOSTIC_ASSERT(mOwner, "RefreshObserver should have been de-registered on time, but isn't.");
|
||||
if (mOwner) {
|
||||
mOwner->Notify();
|
||||
}
|
||||
@@ -70,10 +70,8 @@ ResizeObserverNotificationHelper::Unregister()
|
||||
}
|
||||
|
||||
nsRefreshDriver* refreshDriver = GetRefreshDriver();
|
||||
if (!refreshDriver) {
|
||||
// We can't access RefreshDriver now. Just abort the Unregister().
|
||||
return;
|
||||
}
|
||||
MOZ_RELEASE_ASSERT(refreshDriver,
|
||||
"We should not leave a dangling reference to the observer around");
|
||||
|
||||
refreshDriver->RemoveRefreshObserver(this, Flush_Display);
|
||||
mRegistered = false;
|
||||
@@ -82,9 +80,8 @@ ResizeObserverNotificationHelper::Unregister()
|
||||
void
|
||||
ResizeObserverNotificationHelper::Disconnect()
|
||||
{
|
||||
Unregister();
|
||||
// Our owner is dying. Clear our pointer to it, in case we outlive it.
|
||||
mOwner = nullptr;
|
||||
MOZ_RELEASE_ASSERT(!mRegistered, "How can we die when registered?");
|
||||
MOZ_RELEASE_ASSERT(!mOwner, "Forgot to clear weak pointer?");
|
||||
}
|
||||
|
||||
ResizeObserverNotificationHelper::~ResizeObserverNotificationHelper()
|
||||
@@ -112,6 +109,10 @@ ResizeObserverController::AddResizeObserver(ResizeObserver* aObserver)
|
||||
mResizeObservers.AppendElement(aObserver);
|
||||
}
|
||||
|
||||
void ResizeObserverController::DetachFromDocument() {
|
||||
mResizeObserverNotificationHelper->Unregister();
|
||||
}
|
||||
|
||||
void
|
||||
ResizeObserverController::Notify()
|
||||
{
|
||||
@@ -241,7 +242,10 @@ ResizeObserverController::GetShell() const
|
||||
|
||||
ResizeObserverController::~ResizeObserverController()
|
||||
{
|
||||
mResizeObserverNotificationHelper->Disconnect();
|
||||
MOZ_RELEASE_ASSERT(
|
||||
!mResizeObserverNotificationHelper->IsRegistered(),
|
||||
"Nothing else should keep a reference to our notification helper when we go away");
|
||||
mResizeObserverNotificationHelper->DetachFromOwner();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -42,6 +42,10 @@ public:
|
||||
|
||||
void Disconnect();
|
||||
|
||||
bool IsRegistered() const { return mRegistered; }
|
||||
|
||||
void DetachFromOwner() { mOwner = nullptr; }
|
||||
|
||||
protected:
|
||||
virtual ~ResizeObserverNotificationHelper();
|
||||
|
||||
@@ -69,6 +73,7 @@ public:
|
||||
void Traverse(nsCycleCollectionTraversalCallback& aCb);
|
||||
void Unlink();
|
||||
|
||||
void DetachFromDocument();
|
||||
void AddResizeObserver(ResizeObserver* aObserver);
|
||||
|
||||
/*
|
||||
|
||||
@@ -3689,6 +3689,12 @@ nsDocument::DeleteShell()
|
||||
// objects for @font-face rules that came from the style set.
|
||||
RebuildUserFontSet();
|
||||
|
||||
if (mResizeObserverController) {
|
||||
// If the shell is going away, we need to remove any links to this document
|
||||
// from the observer.
|
||||
mResizeObserverController->DetachFromDocument();
|
||||
}
|
||||
|
||||
nsIPresShell* oldShell = mPresShell;
|
||||
mPresShell = nullptr;
|
||||
UpdateFrameRequestCallbackSchedulingState(oldShell);
|
||||
|
||||
@@ -933,8 +933,12 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
|
||||
MOZ_ASSERT(!req, "Shouldn't have non-null request here");
|
||||
// If we don't have a current URI, we might as well store this URI so people
|
||||
// know what we tried (and failed) to load.
|
||||
if (!mCurrentRequest)
|
||||
if (!mCurrentRequest) {
|
||||
mCurrentURI = aNewURI;
|
||||
if (mImageBlockingStatus == nsIContentPolicy::ACCEPT) {
|
||||
mImageBlockingStatus = nsIContentPolicy::REJECT_REQUEST;
|
||||
}
|
||||
}
|
||||
|
||||
FireEvent(NS_LITERAL_STRING("error"));
|
||||
FireEvent(NS_LITERAL_STRING("loadend"));
|
||||
|
||||
@@ -298,10 +298,11 @@ nsJSUtils::CompileModule(JSContext* aCx,
|
||||
|
||||
NS_ENSURE_TRUE(xpc::Scriptability::Get(aEvaluationGlobal).Allowed(), NS_OK);
|
||||
|
||||
if (!JS::CompileModule(aCx, aCompileOptions, aSrcBuf, aModule)) {
|
||||
bool compileResult = JS::CompileModule(aCx, aCompileOptions, aSrcBuf, aModule);
|
||||
|
||||
if (!compileResult) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -1385,6 +1385,8 @@ nsTreeSanitizer::SanitizeChildren(nsINode* aRoot)
|
||||
nsAutoString styleText;
|
||||
nsContentUtils::GetNodeTextContent(node, false, styleText);
|
||||
|
||||
RemoveAllAttributesFromDescendants(elt);
|
||||
|
||||
nsAutoString sanitizedStyle;
|
||||
nsCOMPtr<nsIURI> baseURI = node->GetBaseURI();
|
||||
if (SanitizeStyleSheet(styleText,
|
||||
@@ -1480,6 +1482,17 @@ nsTreeSanitizer::RemoveAllAttributes(nsIContent* aElement)
|
||||
}
|
||||
}
|
||||
|
||||
void nsTreeSanitizer::RemoveAllAttributesFromDescendants(mozilla::dom::Element* aElement) {
|
||||
nsIContent* node = aElement->GetFirstChild();
|
||||
while (node) {
|
||||
if (node->IsElement()) {
|
||||
mozilla::dom::Element* elt = node->AsElement();
|
||||
RemoveAllAttributes(elt);
|
||||
}
|
||||
node = node->GetNextNode(aElement);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsTreeSanitizer::InitializeStatics()
|
||||
{
|
||||
|
||||
@@ -183,6 +183,12 @@ class MOZ_STACK_CLASS nsTreeSanitizer {
|
||||
*/
|
||||
void RemoveAllAttributes(nsIContent* aElement);
|
||||
|
||||
/**
|
||||
* Removes all attributes from the descendants of an element but not from
|
||||
* the element itself.
|
||||
*/
|
||||
void RemoveAllAttributesFromDescendants(mozilla::dom::Element* aElement);
|
||||
|
||||
/**
|
||||
* The whitelist of HTML elements.
|
||||
*/
|
||||
|
||||
@@ -709,10 +709,12 @@ FetchDriver::OnDataAvailable(nsIRequest* aRequest,
|
||||
// about races.
|
||||
|
||||
if (mObserver) {
|
||||
// Need to keep mObserver alive.
|
||||
RefPtr<FetchDriverObserver> observer = mObserver;
|
||||
if (NS_IsMainThread()) {
|
||||
mObserver->OnDataAvailable();
|
||||
observer->OnDataAvailable();
|
||||
} else {
|
||||
RefPtr<Runnable> runnable = new DataAvailableRunnable(mObserver);
|
||||
RefPtr<Runnable> runnable = new DataAvailableRunnable(observer);
|
||||
nsresult rv = NS_DispatchToMainThread(runnable);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
@@ -720,12 +722,15 @@ FetchDriver::OnDataAvailable(nsIRequest* aRequest,
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t aRead;
|
||||
// Explicitly initialized to 0 because in some cases nsStringInputStream may
|
||||
// not write to aRead.
|
||||
uint32_t aRead = 0;
|
||||
MOZ_ASSERT(mResponse);
|
||||
MOZ_ASSERT(mPipeOutputStream);
|
||||
|
||||
// From "Main Fetch" step 17: SRI-part2.
|
||||
if (mResponse->Type() != ResponseType::Error &&
|
||||
if (mResponse &&
|
||||
mResponse->Type() != ResponseType::Error &&
|
||||
!mRequest->GetIntegrity().IsEmpty()) {
|
||||
MOZ_ASSERT(mSRIDataVerifier);
|
||||
|
||||
@@ -767,6 +772,17 @@ FetchDriver::OnDataAvailable(nsIRequest* aRequest,
|
||||
nsresult rv = aInputStream->ReadSegments(NS_CopySegmentToStream,
|
||||
mPipeOutputStream,
|
||||
aCount, &aRead);
|
||||
|
||||
// If no data was read, it's possible the output stream is closed but the
|
||||
// ReadSegments call followed its contract of returning NS_OK despite write
|
||||
// errors. Unfortunately, nsIOutputStream has an ill-conceived contract when
|
||||
// taken together with ReadSegments' contract, because the pipe will just
|
||||
// NS_OK if we try and invoke its Write* functions ourselves with a 0 count.
|
||||
// So we must just assume the pipe is broken.
|
||||
if (aRead == 0 && aCount != 0) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
@@ -195,6 +195,7 @@ nsSMILCSSProperty::IsPropertyAnimatable(nsCSSPropertyID aPropID)
|
||||
// writing-mode
|
||||
|
||||
switch (aPropID) {
|
||||
case eCSSProperty_caret_color:
|
||||
case eCSSProperty_clip:
|
||||
case eCSSProperty_clip_rule:
|
||||
case eCSSProperty_clip_path:
|
||||
|
||||
@@ -122,7 +122,6 @@ run-if = e10s
|
||||
[test_storagePermissionsReject.html]
|
||||
[test_storagePermissionsRejectForeign.html]
|
||||
[test_stylesheetPI.html]
|
||||
[test_vibrator.html]
|
||||
[test_WebKitCSSMatrix.html]
|
||||
[test_windowedhistoryframes.html]
|
||||
[test_windowProperties.html]
|
||||
@@ -1,93 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Vibrator</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Although we can't test that the vibrator works properly, we can test that
|
||||
navigator.vibrate throws an exception where appropriate. -->
|
||||
|
||||
<script class="testbody" type="text/javascript;version=1.7">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var result;
|
||||
function expectFailure(param) {
|
||||
result = navigator.vibrate(param);
|
||||
is(result, false, 'vibrate(' + param + ') should have failed.');
|
||||
}
|
||||
|
||||
function expectSuccess(param) {
|
||||
result = navigator.vibrate(param);
|
||||
is(result, true, 'vibrate(' + param + ') must succeed.');
|
||||
}
|
||||
|
||||
function tests(aEnabled) {
|
||||
// Some edge cases that the bindings should handle for us.
|
||||
expectSuccess(null);
|
||||
expectSuccess(undefined);
|
||||
// -1 will be converted to the highest unsigned long then clamped.
|
||||
expectSuccess(-1);
|
||||
expectSuccess('a');
|
||||
// -1 will be converted to the highest unsigned long then clamped.
|
||||
expectSuccess([100, -1]);
|
||||
expectSuccess([100, 'a']);
|
||||
|
||||
var maxVibrateMs = SpecialPowers.getIntPref('dom.vibrator.max_vibrate_ms');
|
||||
var maxVibrateListLen = SpecialPowers.getIntPref('dom.vibrator.max_vibrate_list_len');
|
||||
|
||||
// If we pass a vibration pattern with a value higher than max_vibrate_ms or a
|
||||
// pattern longer than max_vibrate_list_len, the call should succeed but the
|
||||
// pattern should be modified to match the restrictions.
|
||||
|
||||
// Values will be clamped to dom.vibrator.max_vibrate_ms.
|
||||
expectSuccess(maxVibrateMs + 1);
|
||||
expectSuccess([maxVibrateMs + 1]);
|
||||
|
||||
var arr = [];
|
||||
for (var i = 0; i < maxVibrateListLen + 1; i++) {
|
||||
arr[i] = 0;
|
||||
}
|
||||
// The array will be truncated to have a length equal to dom.vibrator.max_vibrate_list_len.
|
||||
expectSuccess(arr);
|
||||
|
||||
|
||||
expectSuccess(0);
|
||||
expectSuccess([]);
|
||||
expectSuccess('1000');
|
||||
expectSuccess(1000);
|
||||
expectSuccess(1000.1);
|
||||
expectSuccess([0, 0, 0]);
|
||||
expectSuccess(['1000', 1000]);
|
||||
expectSuccess([1000, 1000]);
|
||||
expectSuccess([1000, 1000.1]);
|
||||
|
||||
// The following loop shouldn't cause us to crash. See bug 701716.
|
||||
for (var i = 0; i < 10000; i++) {
|
||||
navigator.vibrate([100, 100]);
|
||||
}
|
||||
ok(true, "Didn't crash after issuing a lot of vibrate() calls.");
|
||||
if(!aEnabled)
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SpecialPowers.pushPermissions([
|
||||
{type: 'vibration', allow: true, context: document}
|
||||
], function() {
|
||||
// Test with the vibrator pref enabled.
|
||||
SpecialPowers.pushPrefEnv({"set": [['dom.vibrator.enabled', true]]}, function() {
|
||||
tests(true);
|
||||
SpecialPowers.pushPrefEnv({"set": [['dom.vibrator.enabled', false]]}, tests(false));
|
||||
});
|
||||
// Everything should be the same when the vibrator is disabled -- in
|
||||
// particular, a disabled vibrator shouldn't eat failures we'd otherwise
|
||||
// observe.
|
||||
}
|
||||
);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -13,9 +13,9 @@
|
||||
* http://www.w3.org/TR/beacon/#sec-beacon-method
|
||||
* https://html.spec.whatwg.org/#navigatorconcurrenthardware
|
||||
*
|
||||
* © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
|
||||
* Opera Software ASA. You are granted a license to use, reproduce
|
||||
* and create derivative works of this document.
|
||||
* © Copyright 2004-2020 Apple Computer, Inc., Mozilla Foundation,
|
||||
* Opera Software ASA and Moonchild Productions. You are granted a license to use,
|
||||
* reproduce and create derivative works of this document.
|
||||
*/
|
||||
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#the-navigator-object
|
||||
@@ -124,14 +124,6 @@ interface NavigatorGeolocation {
|
||||
};
|
||||
Navigator implements NavigatorGeolocation;
|
||||
|
||||
// http://www.w3.org/TR/vibration/#vibration-interface
|
||||
partial interface Navigator {
|
||||
// We don't support sequences in unions yet
|
||||
//boolean vibrate ((unsigned long or sequence<unsigned long>) pattern);
|
||||
boolean vibrate(unsigned long duration);
|
||||
boolean vibrate(sequence<unsigned long> pattern);
|
||||
};
|
||||
|
||||
// http://www.w3.org/TR/pointerevents/#extensions-to-the-navigator-interface
|
||||
partial interface Navigator {
|
||||
[Pref="dom.w3c_pointer_events.enabled"]
|
||||
@@ -140,17 +132,6 @@ partial interface Navigator {
|
||||
|
||||
// Mozilla-specific extensions
|
||||
|
||||
// Chrome-only interface for Vibration API permission handling.
|
||||
partial interface Navigator {
|
||||
/* Set permission state to device vibration.
|
||||
* @param permitted permission state (true for allowing vibration)
|
||||
* @param persistent make the permission session-persistent
|
||||
*/
|
||||
[ChromeOnly]
|
||||
void setVibrationPermission(boolean permitted,
|
||||
optional boolean persistent = true);
|
||||
};
|
||||
|
||||
callback interface MozIdleObserver {
|
||||
// Time is in seconds and is read only when idle observers are added
|
||||
// and removed.
|
||||
|
||||
+30
-16
@@ -212,7 +212,7 @@ VerifyRGBXCorners(uint8_t* aData, const IntSize &aSize, const int32_t aStride, S
|
||||
#endif
|
||||
|
||||
static sk_sp<SkImage>
|
||||
GetSkImageForSurface(SourceSurface* aSurface)
|
||||
GetSkImageForSurface(SourceSurface* aSurface, Maybe<MutexAutoLock>* aLock)
|
||||
{
|
||||
if (!aSurface) {
|
||||
gfxDebug() << "Creating null Skia image from null SourceSurface";
|
||||
@@ -220,7 +220,7 @@ GetSkImageForSurface(SourceSurface* aSurface)
|
||||
}
|
||||
|
||||
if (aSurface->GetType() == SurfaceType::SKIA) {
|
||||
return static_cast<SourceSurfaceSkia*>(aSurface)->GetImage();
|
||||
return static_cast<SourceSurfaceSkia*>(aSurface)->GetImage(aLock);
|
||||
}
|
||||
|
||||
DataSourceSurface* surf = aSurface->GetDataSurface().take();
|
||||
@@ -390,9 +390,9 @@ ExtractAlphaBitmap(sk_sp<SkImage> aImage, SkBitmap* aResultBitmap)
|
||||
}
|
||||
|
||||
static sk_sp<SkImage>
|
||||
ExtractAlphaForSurface(SourceSurface* aSurface)
|
||||
ExtractAlphaForSurface(SourceSurface* aSurface, Maybe<MutexAutoLock>& aLock)
|
||||
{
|
||||
sk_sp<SkImage> image = GetSkImageForSurface(aSurface);
|
||||
sk_sp<SkImage> image = GetSkImageForSurface(aSurface, &aLock);
|
||||
if (!image) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -411,7 +411,11 @@ ExtractAlphaForSurface(SourceSurface* aSurface)
|
||||
}
|
||||
|
||||
static void
|
||||
SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0, Point aOffset = Point(0, 0))
|
||||
SetPaintPattern(SkPaint& aPaint,
|
||||
const Pattern& aPattern,
|
||||
Maybe<MutexAutoLock>& aLock,
|
||||
Float aAlpha = 1.0,
|
||||
Point aOffset = Point(0, 0))
|
||||
{
|
||||
switch (aPattern.GetType()) {
|
||||
case PatternType::COLOR: {
|
||||
@@ -473,7 +477,7 @@ SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0, Po
|
||||
}
|
||||
case PatternType::SURFACE: {
|
||||
const SurfacePattern& pat = static_cast<const SurfacePattern&>(aPattern);
|
||||
sk_sp<SkImage> image = GetSkImageForSurface(pat.mSurface);
|
||||
sk_sp<SkImage> image = GetSkImageForSurface(pat.mSurface, &aLock);
|
||||
if (!image) {
|
||||
aPaint.setColor(SK_ColorTRANSPARENT);
|
||||
break;
|
||||
@@ -525,7 +529,7 @@ struct AutoPaintSetup {
|
||||
: mNeedsRestore(false), mAlpha(1.0)
|
||||
{
|
||||
Init(aCanvas, aOptions, aMaskBounds, false);
|
||||
SetPaintPattern(mPaint, aPattern, mAlpha, aOffset);
|
||||
SetPaintPattern(mPaint, aPattern, mLock, mAlpha, aOffset);
|
||||
}
|
||||
|
||||
AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions, const Rect* aMaskBounds = nullptr, bool aForceGroup = false)
|
||||
@@ -579,6 +583,7 @@ struct AutoPaintSetup {
|
||||
SkPaint mPaint;
|
||||
bool mNeedsRestore;
|
||||
SkCanvas* mCanvas;
|
||||
Maybe<MutexAutoLock> mLock;
|
||||
Float mAlpha;
|
||||
};
|
||||
|
||||
@@ -601,7 +606,8 @@ DrawTargetSkia::DrawSurface(SourceSurface *aSurface,
|
||||
|
||||
MarkChanged();
|
||||
|
||||
sk_sp<SkImage> image = GetSkImageForSurface(aSurface);
|
||||
Maybe<MutexAutoLock> lock;
|
||||
sk_sp<SkImage> image = GetSkImageForSurface(aSurface, &lock);
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
@@ -654,7 +660,8 @@ DrawTargetSkia::DrawSurfaceWithShadow(SourceSurface *aSurface,
|
||||
|
||||
MarkChanged();
|
||||
|
||||
sk_sp<SkImage> image = GetSkImageForSurface(aSurface);
|
||||
Maybe<MutexAutoLock> lock;
|
||||
sk_sp<SkImage> image = GetSkImageForSurface(aSurface, &lock);
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
@@ -1407,8 +1414,9 @@ DrawTargetSkia::Mask(const Pattern &aSource,
|
||||
MarkChanged();
|
||||
AutoPaintSetup paint(mCanvas.get(), aOptions, aSource);
|
||||
|
||||
Maybe<MutexAutoLock> lock;
|
||||
SkPaint maskPaint;
|
||||
SetPaintPattern(maskPaint, aMask);
|
||||
SetPaintPattern(maskPaint, aMask, lock);
|
||||
|
||||
SkLayerRasterizer::Builder builder;
|
||||
builder.addLayer(maskPaint);
|
||||
@@ -1427,7 +1435,8 @@ DrawTargetSkia::MaskSurface(const Pattern &aSource,
|
||||
MarkChanged();
|
||||
AutoPaintSetup paint(mCanvas.get(), aOptions, aSource, nullptr, -aOffset);
|
||||
|
||||
sk_sp<SkImage> alphaMask = ExtractAlphaForSurface(aMask);
|
||||
Maybe<MutexAutoLock> lock;
|
||||
sk_sp<SkImage> alphaMask = ExtractAlphaForSurface(aMask, lock);
|
||||
if (!alphaMask) {
|
||||
gfxDebug() << *this << ": MaskSurface() failed to extract alpha for mask";
|
||||
return;
|
||||
@@ -1456,7 +1465,8 @@ DrawTarget::Draw3DTransformedSurface(SourceSurface* aSurface, const Matrix4x4& a
|
||||
fullMat.PostTranslate(-xformBounds.x, -xformBounds.y, 0);
|
||||
|
||||
// Read in the source data.
|
||||
sk_sp<SkImage> srcImage = GetSkImageForSurface(aSurface);
|
||||
Maybe<MutexAutoLock> lock;
|
||||
sk_sp<SkImage> srcImage = GetSkImageForSurface(aSurface, &lock);
|
||||
if (!srcImage) {
|
||||
return true;
|
||||
}
|
||||
@@ -1515,7 +1525,8 @@ DrawTargetSkia::Draw3DTransformedSurface(SourceSurface* aSurface, const Matrix4x
|
||||
|
||||
MarkChanged();
|
||||
|
||||
sk_sp<SkImage> image = GetSkImageForSurface(aSurface);
|
||||
Maybe<MutexAutoLock> lock;
|
||||
sk_sp<SkImage> image = GetSkImageForSurface(aSurface, &lock);
|
||||
if (!image) {
|
||||
return true;
|
||||
}
|
||||
@@ -1599,7 +1610,8 @@ already_AddRefed<SourceSurface>
|
||||
DrawTargetSkia::OptimizeGPUSourceSurface(SourceSurface *aSurface) const
|
||||
{
|
||||
// Check if the underlying SkImage already has an associated GrTexture.
|
||||
sk_sp<SkImage> image = GetSkImageForSurface(aSurface);
|
||||
Maybe<MutexAutoLock> lock;
|
||||
sk_sp<SkImage> image = GetSkImageForSurface(aSurface, &lock);
|
||||
if (!image || image->isTextureBacked()) {
|
||||
RefPtr<SourceSurface> surface(aSurface);
|
||||
return surface.forget();
|
||||
@@ -1716,7 +1728,8 @@ DrawTargetSkia::CopySurface(SourceSurface *aSurface,
|
||||
{
|
||||
MarkChanged();
|
||||
|
||||
sk_sp<SkImage> image = GetSkImageForSurface(aSurface);
|
||||
Maybe<MutexAutoLock> lock;
|
||||
sk_sp<SkImage> image = GetSkImageForSurface(aSurface, &lock);
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
@@ -2061,7 +2074,8 @@ DrawTargetSkia::PopLayer()
|
||||
paint.setColor(SK_ColorTRANSPARENT);
|
||||
}
|
||||
|
||||
sk_sp<SkImage> alphaMask = ExtractAlphaForSurface(layer.mMask);
|
||||
Maybe<MutexAutoLock> lock;
|
||||
sk_sp<SkImage> alphaMask = ExtractAlphaForSurface(layer.mMask, lock);
|
||||
if (!alphaMask) {
|
||||
gfxDebug() << *this << ": PopLayer() failed to extract alpha for mask";
|
||||
} else {
|
||||
|
||||
@@ -40,6 +40,25 @@ SourceSurfaceSkia::GetFormat() const
|
||||
return mFormat;
|
||||
}
|
||||
|
||||
sk_sp<SkImage>
|
||||
SourceSurfaceSkia::GetImage(Maybe<MutexAutoLock>* aLock) {
|
||||
// If we were provided a lock object, we can let the caller access
|
||||
// a shared SkImage and we know it won't go away while the lock is held.
|
||||
if (aLock) {
|
||||
// We are locked, so now we can check mDrawTarget.
|
||||
// If it's null, then we're not shared and we can unlock eagerly.
|
||||
if (!mDrawTarget) {
|
||||
aLock->reset();
|
||||
}
|
||||
} else {
|
||||
// Otherwise we need to call DrawTargetWillChange to ensure we have our
|
||||
// own copy of the SkImage.
|
||||
DrawTargetWillChange();
|
||||
}
|
||||
sk_sp<SkImage> image = mImage;
|
||||
return image;
|
||||
}
|
||||
|
||||
static sk_sp<SkData>
|
||||
MakeSkData(unsigned char* aData, const IntSize& aSize, int32_t aStride)
|
||||
{
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
#include <vector>
|
||||
#include "skia/include/core/SkCanvas.h"
|
||||
#include "skia/include/core/SkImage.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
typedef mozilla::MutexAutoLock MutexAutoLock;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@@ -28,7 +32,7 @@ public:
|
||||
virtual IntSize GetSize() const;
|
||||
virtual SurfaceFormat GetFormat() const;
|
||||
|
||||
sk_sp<SkImage>& GetImage() { return mImage; }
|
||||
sk_sp<SkImage> GetImage(Maybe<MutexAutoLock>* aLock);
|
||||
|
||||
bool InitFromData(unsigned char* aData,
|
||||
const IntSize &aSize,
|
||||
|
||||
@@ -1858,8 +1858,8 @@ GLContext::InitExtensions()
|
||||
// textures with glCompressedTexSubImage2D. Works on Intel HD 4000
|
||||
// and Intel HD 5000/Iris that I tested.
|
||||
// Bug 1124996: Appears to be the same on OSX Yosemite (10.10)
|
||||
if (nsCocoaFeatures::OSXVersionMajor() == 10 &&
|
||||
nsCocoaFeatures::OSXVersionMinor() >= 9 &&
|
||||
if (nsCocoaFeatures::macOSVersionMajor() == 10 &&
|
||||
nsCocoaFeatures::macOSVersionMinor() >= 9 &&
|
||||
Renderer() == GLRenderer::IntelHD3000)
|
||||
{
|
||||
MarkExtensionUnsupported(EXT_texture_compression_s3tc);
|
||||
|
||||
@@ -1072,6 +1072,34 @@ gfxTextRun::GetAdvanceWidth(Range aRange, PropertyProvider *aProvider,
|
||||
return result + GetAdvanceForGlyphs(ligatureRange);
|
||||
}
|
||||
|
||||
gfxFloat
|
||||
gfxTextRun::GetMinAdvanceWidth(Range aRange)
|
||||
{
|
||||
MOZ_ASSERT(aRange.end <= GetLength(), "Substring out of range");
|
||||
|
||||
Range ligatureRange = aRange;
|
||||
ShrinkToLigatureBoundaries(&ligatureRange);
|
||||
|
||||
gfxFloat result = std::max(
|
||||
ComputePartialLigatureWidth(Range(aRange.start, ligatureRange.start),
|
||||
nullptr),
|
||||
ComputePartialLigatureWidth(Range(ligatureRange.end, aRange.end),
|
||||
nullptr));
|
||||
|
||||
// XXX Do we need to take spacing into account? When each grapheme cluster
|
||||
// takes its own line, we shouldn't be adding spacings around them.
|
||||
gfxFloat clusterAdvance = 0;
|
||||
for (uint32_t i = ligatureRange.start; i < ligatureRange.end; ++i) {
|
||||
clusterAdvance += GetAdvanceForGlyph(i);
|
||||
if (i + 1 == ligatureRange.end || IsClusterStart(i + 1)) {
|
||||
result = std::max(result, clusterAdvance);
|
||||
clusterAdvance = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxTextRun::SetLineBreaks(Range aRange,
|
||||
bool aLineBreakBefore, bool aLineBreakAfter,
|
||||
|
||||
@@ -298,6 +298,12 @@ public:
|
||||
return GetAdvanceWidth(Range(this), nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the minimum advance width for a substring assuming line
|
||||
* breaking is allowed everywhere.
|
||||
*/
|
||||
gfxFloat GetMinAdvanceWidth(Range aRange);
|
||||
|
||||
/**
|
||||
* Clear all stored line breaks for the given range (both before and after),
|
||||
* and then set the line-break state before aRange.start to aBreakBefore and
|
||||
|
||||
-79
@@ -95,87 +95,8 @@ WindowIsActive(nsPIDOMWindowInner* aWindow)
|
||||
return !document->Hidden();
|
||||
}
|
||||
|
||||
StaticAutoPtr<WindowIdentifier::IDArrayType> gLastIDToVibrate;
|
||||
|
||||
void InitLastIDToVibrate()
|
||||
{
|
||||
gLastIDToVibrate = new WindowIdentifier::IDArrayType();
|
||||
ClearOnShutdown(&gLastIDToVibrate);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void
|
||||
Vibrate(const nsTArray<uint32_t>& pattern, nsPIDOMWindowInner* window)
|
||||
{
|
||||
Vibrate(pattern, WindowIdentifier(window));
|
||||
}
|
||||
|
||||
void
|
||||
Vibrate(const nsTArray<uint32_t>& pattern, const WindowIdentifier &id)
|
||||
{
|
||||
AssertMainThread();
|
||||
|
||||
// Only active windows may start vibrations. If |id| hasn't gone
|
||||
// through the IPC layer -- that is, if our caller is the outside
|
||||
// world, not hal_proxy -- check whether the window is active. If
|
||||
// |id| has gone through IPC, don't check the window's visibility;
|
||||
// only the window corresponding to the bottommost process has its
|
||||
// visibility state set correctly.
|
||||
if (!id.HasTraveledThroughIPC() && !WindowIsActive(id.GetWindow())) {
|
||||
HAL_LOG("Vibrate: Window is inactive, dropping vibrate.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!InSandbox()) {
|
||||
if (!gLastIDToVibrate) {
|
||||
InitLastIDToVibrate();
|
||||
}
|
||||
*gLastIDToVibrate = id.AsArray();
|
||||
}
|
||||
|
||||
// Don't forward our ID if we are not in the sandbox, because hal_impl
|
||||
// doesn't need it, and we don't want it to be tempted to read it. The
|
||||
// empty identifier will assert if it's used.
|
||||
PROXY_IF_SANDBOXED(Vibrate(pattern, InSandbox() ? id : WindowIdentifier()));
|
||||
}
|
||||
|
||||
void
|
||||
CancelVibrate(nsPIDOMWindowInner* window)
|
||||
{
|
||||
CancelVibrate(WindowIdentifier(window));
|
||||
}
|
||||
|
||||
void
|
||||
CancelVibrate(const WindowIdentifier &id)
|
||||
{
|
||||
AssertMainThread();
|
||||
|
||||
// Although only active windows may start vibrations, a window may
|
||||
// cancel its own vibration even if it's no longer active.
|
||||
//
|
||||
// After a window is marked as inactive, it sends a CancelVibrate
|
||||
// request. We want this request to cancel a playing vibration
|
||||
// started by that window, so we certainly don't want to reject the
|
||||
// cancellation request because the window is now inactive.
|
||||
//
|
||||
// But it could be the case that, after this window became inactive,
|
||||
// some other window came along and started a vibration. We don't
|
||||
// want this window's cancellation request to cancel that window's
|
||||
// actively-playing vibration!
|
||||
//
|
||||
// To solve this problem, we keep track of the id of the last window
|
||||
// to start a vibration, and only accepts cancellation requests from
|
||||
// the same window. All other cancellation requests are ignored.
|
||||
|
||||
if (InSandbox() || (gLastIDToVibrate && *gLastIDToVibrate == id.AsArray())) {
|
||||
// Don't forward our ID if we are not in the sandbox, because hal_impl
|
||||
// doesn't need it, and we don't want it to be tempted to read it. The
|
||||
// empty identifier will assert if it's used.
|
||||
PROXY_IF_SANDBOXED(CancelVibrate(InSandbox() ? id : WindowIdentifier()));
|
||||
}
|
||||
}
|
||||
|
||||
template <class InfoType>
|
||||
class ObserversManager
|
||||
{
|
||||
|
||||
@@ -51,41 +51,6 @@ typedef Observer<SystemTimezoneChangeInformation> SystemTimezoneChangeObserver;
|
||||
|
||||
namespace MOZ_HAL_NAMESPACE {
|
||||
|
||||
/**
|
||||
* Turn the default vibrator device on/off per the pattern specified
|
||||
* by |pattern|. Each element in the pattern is the number of
|
||||
* milliseconds to turn the vibrator on or off. The first element in
|
||||
* |pattern| is an "on" element, the next is "off", and so on.
|
||||
*
|
||||
* If |pattern| is empty, any in-progress vibration is canceled.
|
||||
*
|
||||
* Only an active window within an active tab may call Vibrate; calls
|
||||
* from inactive windows and windows on inactive tabs do nothing.
|
||||
*
|
||||
* If you're calling hal::Vibrate from the outside world, pass an
|
||||
* nsIDOMWindow* in place of the WindowIdentifier parameter.
|
||||
* The method with WindowIdentifier will be called automatically.
|
||||
*/
|
||||
void Vibrate(const nsTArray<uint32_t>& pattern,
|
||||
nsPIDOMWindowInner* aWindow);
|
||||
void Vibrate(const nsTArray<uint32_t>& pattern,
|
||||
const hal::WindowIdentifier &id);
|
||||
|
||||
/**
|
||||
* Cancel a vibration started by the content window identified by
|
||||
* WindowIdentifier.
|
||||
*
|
||||
* If the window was the last window to start a vibration, the
|
||||
* cancellation request will go through even if the window is not
|
||||
* active.
|
||||
*
|
||||
* As with hal::Vibrate(), if you're calling hal::CancelVibrate from the outside
|
||||
* world, pass an nsIDOMWindow*. The method with WindowIdentifier will be called
|
||||
* automatically.
|
||||
*/
|
||||
void CancelVibrate(nsPIDOMWindowInner* aWindow);
|
||||
void CancelVibrate(const hal::WindowIdentifier &id);
|
||||
|
||||
/**
|
||||
* Determine whether the device's screen is currently enabled.
|
||||
*/
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "Hal.h"
|
||||
|
||||
using mozilla::hal::WindowIdentifier;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
void
|
||||
Vibrate(const nsTArray<uint32_t>& pattern, const hal::WindowIdentifier &)
|
||||
{}
|
||||
|
||||
void
|
||||
CancelVibrate(const hal::WindowIdentifier &)
|
||||
{}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
@@ -30,7 +30,6 @@ if CONFIG['OS_TARGET'] == 'Linux':
|
||||
'fallback/FallbackAlarm.cpp',
|
||||
'fallback/FallbackScreenConfiguration.cpp',
|
||||
'fallback/FallbackSensor.cpp',
|
||||
'fallback/FallbackVibration.cpp',
|
||||
'linux/LinuxMemory.cpp',
|
||||
'linux/LinuxPower.cpp',
|
||||
]
|
||||
@@ -40,7 +39,6 @@ elif CONFIG['OS_TARGET'] == 'WINNT':
|
||||
'fallback/FallbackMemory.cpp',
|
||||
'fallback/FallbackPower.cpp',
|
||||
'fallback/FallbackScreenConfiguration.cpp',
|
||||
'fallback/FallbackVibration.cpp',
|
||||
'windows/WindowsSensor.cpp',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
@@ -49,7 +47,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
'fallback/FallbackMemory.cpp',
|
||||
'fallback/FallbackPower.cpp',
|
||||
'fallback/FallbackScreenConfiguration.cpp',
|
||||
'fallback/FallbackVibration.cpp',
|
||||
]
|
||||
elif CONFIG['OS_TARGET'] in ('OpenBSD', 'NetBSD', 'FreeBSD', 'DragonFly'):
|
||||
UNIFIED_SOURCES += [
|
||||
@@ -58,7 +55,6 @@ elif CONFIG['OS_TARGET'] in ('OpenBSD', 'NetBSD', 'FreeBSD', 'DragonFly'):
|
||||
'fallback/FallbackPower.cpp',
|
||||
'fallback/FallbackScreenConfiguration.cpp',
|
||||
'fallback/FallbackSensor.cpp',
|
||||
'fallback/FallbackVibration.cpp',
|
||||
]
|
||||
else:
|
||||
UNIFIED_SOURCES += [
|
||||
@@ -67,7 +63,6 @@ else:
|
||||
'fallback/FallbackPower.cpp',
|
||||
'fallback/FallbackScreenConfiguration.cpp',
|
||||
'fallback/FallbackSensor.cpp',
|
||||
'fallback/FallbackVibration.cpp',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
|
||||
@@ -70,9 +70,6 @@ child:
|
||||
async NotifySystemTimezoneChange(SystemTimezoneChangeInformation aSystemTimezoneChangeInfo);
|
||||
|
||||
parent:
|
||||
async Vibrate(uint32_t[] pattern, uint64_t[] id, PBrowser browser);
|
||||
async CancelVibrate(uint64_t[] id, PBrowser browser);
|
||||
|
||||
async EnableNetworkNotifications();
|
||||
async DisableNetworkNotifications();
|
||||
sync GetCurrentNetworkInformation()
|
||||
|
||||
@@ -46,28 +46,6 @@ Hal()
|
||||
return sHal;
|
||||
}
|
||||
|
||||
void
|
||||
Vibrate(const nsTArray<uint32_t>& pattern, const WindowIdentifier &id)
|
||||
{
|
||||
HAL_LOG("Vibrate: Sending to parent process.");
|
||||
|
||||
AutoTArray<uint32_t, 8> p(pattern);
|
||||
|
||||
WindowIdentifier newID(id);
|
||||
newID.AppendProcessID();
|
||||
Hal()->SendVibrate(p, newID.AsArray(), TabChild::GetFrom(newID.GetWindow()));
|
||||
}
|
||||
|
||||
void
|
||||
CancelVibrate(const WindowIdentifier &id)
|
||||
{
|
||||
HAL_LOG("CancelVibrate: Sending to parent process.");
|
||||
|
||||
WindowIdentifier newID(id);
|
||||
newID.AppendProcessID();
|
||||
Hal()->SendCancelVibrate(newID.AsArray(), TabChild::GetFrom(newID.GetWindow()));
|
||||
}
|
||||
|
||||
void
|
||||
EnableNetworkNotifications()
|
||||
{
|
||||
@@ -380,36 +358,6 @@ public:
|
||||
hal::UnregisterSystemTimezoneChangeObserver(this);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvVibrate(InfallibleTArray<unsigned int>&& pattern,
|
||||
InfallibleTArray<uint64_t>&& id,
|
||||
PBrowserParent *browserParent) override
|
||||
{
|
||||
// We give all content vibration permission.
|
||||
// TabParent *tabParent = TabParent::GetFrom(browserParent);
|
||||
/* xxxkhuey wtf
|
||||
nsCOMPtr<nsIDOMWindow> window =
|
||||
do_QueryInterface(tabParent->GetBrowserDOMWindow());
|
||||
*/
|
||||
WindowIdentifier newID(id, nullptr);
|
||||
hal::Vibrate(pattern, newID);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvCancelVibrate(InfallibleTArray<uint64_t> &&id,
|
||||
PBrowserParent *browserParent) override
|
||||
{
|
||||
//TabParent *tabParent = TabParent::GetFrom(browserParent);
|
||||
/* XXXkhuey wtf
|
||||
nsCOMPtr<nsIDOMWindow> window =
|
||||
tabParent->GetBrowserDOMWindow();
|
||||
*/
|
||||
WindowIdentifier newID(id, nullptr);
|
||||
hal::CancelVibrate(newID);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvEnableNetworkNotifications() override {
|
||||
// We give all content access to this network-status information.
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
<ms_asmv3:application xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||
<ms_asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
|
||||
<dpiAware>True/PM</dpiAware>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2,PerMonitor</dpiAwareness>
|
||||
</ms_asmv3:windowsSettings>
|
||||
</ms_asmv3:application>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "js/HeapAPI.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/TracingAPI.h"
|
||||
#include "js/TraceKind.h"
|
||||
|
||||
struct JSRuntime;
|
||||
|
||||
@@ -273,6 +274,23 @@ struct Cell
|
||||
|
||||
static MOZ_ALWAYS_INLINE bool needWriteBarrierPre(JS::Zone* zone);
|
||||
|
||||
template <class T>
|
||||
inline bool is() const {
|
||||
return getTraceKind() == JS::MapTypeToTraceKind<T>::kind;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline T* as() {
|
||||
MOZ_ASSERT(is<T>());
|
||||
return static_cast<T*>(this);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline const T* as() const {
|
||||
MOZ_ASSERT(is<T>());
|
||||
return static_cast<const T*>(this);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
inline bool isAligned() const;
|
||||
void dump(FILE* fp) const;
|
||||
|
||||
+6
-1
@@ -6608,6 +6608,9 @@ JS_SetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t v
|
||||
case JSJITCOMPILER_ION_INTERRUPT_WITHOUT_SIGNAL:
|
||||
jit::JitOptions.ionInterruptWithoutSignals = !!value;
|
||||
break;
|
||||
case JSJITCOMPILER_ION_INLINING:
|
||||
jit::JitOptions.disableInlining = !value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -7040,7 +7043,9 @@ JS::CaptureCurrentStack(JSContext* cx, JS::MutableHandleObject stackp,
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
MOZ_RELEASE_ASSERT(cx->compartment());
|
||||
if (!cx->compartment()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JSCompartment* compartment = cx->compartment();
|
||||
Rooted<SavedFrame*> frame(cx);
|
||||
|
||||
@@ -5906,6 +5906,7 @@ JS_SetOffthreadIonCompilationEnabled(JSContext* cx, bool enabled);
|
||||
Register(ION_GVN_ENABLE, "ion.gvn.enable") \
|
||||
Register(ION_FORCE_IC, "ion.forceinlineCaches") \
|
||||
Register(ION_ENABLE, "ion.enable") \
|
||||
Register(ION_INLINING, "ion.inlining") \
|
||||
Register(ION_INTERRUPT_WITHOUT_SIGNAL, "ion.interrupt-without-signals") \
|
||||
Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis") \
|
||||
Register(BASELINE_ENABLE, "baseline.enable") \
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=8 sts=4 et sw=4 tw=99: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
@@ -1429,6 +1428,8 @@ ReloadPrefsCallback(const char* pref, void* data)
|
||||
|
||||
bool unboxedObjects = Preferences::GetBool(JS_OPTIONS_DOT_STR "unboxed_objects");
|
||||
|
||||
bool inlining = Preferences::GetBool(JS_OPTIONS_DOT_STR "ion.inlining");
|
||||
|
||||
sSharedMemoryEnabled = Preferences::GetBool(JS_OPTIONS_DOT_STR "shared_memory");
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -1459,6 +1460,8 @@ ReloadPrefsCallback(const char* pref, void* data)
|
||||
useIonEager ? 0 : -1);
|
||||
JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_UNBOXED_OBJECTS,
|
||||
unboxedObjects);
|
||||
JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_ION_INLINING,
|
||||
inlining);
|
||||
}
|
||||
|
||||
XPCJSContext::~XPCJSContext()
|
||||
|
||||
@@ -1833,8 +1833,7 @@ nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder,
|
||||
nscolor
|
||||
nsIFrame::GetCaretColorAt(int32_t aOffset)
|
||||
{
|
||||
// Use text color.
|
||||
return StyleColor()->mColor;
|
||||
return nsLayoutUtils::GetColor(this, eCSSProperty_caret_color);
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -1718,6 +1718,16 @@ GetSpaceWidthAppUnits(const gfxTextRun* aTextRun)
|
||||
return spaceWidthAppUnits;
|
||||
}
|
||||
|
||||
static gfxFloat
|
||||
GetMinTabAdvanceAppUnits(const gfxTextRun* aTextRun)
|
||||
{
|
||||
gfxFloat chWidthAppUnits =
|
||||
NS_round(GetFirstFontMetrics(aTextRun->GetFontGroup(),
|
||||
aTextRun->IsVertical()).zeroOrAveCharWidth *
|
||||
aTextRun->GetAppUnitsPerDevUnit());
|
||||
return 0.5 * chWidthAppUnits;
|
||||
}
|
||||
|
||||
static nscoord
|
||||
LetterSpacing(nsIFrame* aFrame, const nsStyleText* aStyleText = nullptr)
|
||||
{
|
||||
@@ -3092,6 +3102,7 @@ public:
|
||||
mLength(aLength),
|
||||
mWordSpacing(WordSpacing(aFrame, mTextRun, aTextStyle)),
|
||||
mLetterSpacing(LetterSpacing(aFrame, aTextStyle)),
|
||||
mMinTabAdvance(-1.0),
|
||||
mHyphenWidth(-1),
|
||||
mOffsetFromBlockOriginForTabs(aOffsetFromBlockOriginForTabs),
|
||||
mReflowing(true),
|
||||
@@ -3116,6 +3127,7 @@ public:
|
||||
mLength(aFrame->GetContentLength()),
|
||||
mWordSpacing(WordSpacing(aFrame, mTextRun)),
|
||||
mLetterSpacing(LetterSpacing(aFrame)),
|
||||
mMinTabAdvance(-1.0),
|
||||
mHyphenWidth(-1),
|
||||
mOffsetFromBlockOriginForTabs(0),
|
||||
mReflowing(false),
|
||||
@@ -3178,7 +3190,14 @@ public:
|
||||
return mFontMetrics;
|
||||
}
|
||||
|
||||
void CalcTabWidths(Range aTransformedRange);
|
||||
void CalcTabWidths(Range aTransformedRange, gfxFloat aTabWidth);
|
||||
|
||||
gfxFloat MinTabAdvance() {
|
||||
if (mMinTabAdvance < 0.0) {
|
||||
mMinTabAdvance = GetMinTabAdvanceAppUnits(mTextRun);
|
||||
}
|
||||
return mMinTabAdvance;
|
||||
}
|
||||
|
||||
const gfxSkipCharsIterator& GetEndHint() { return mTempIterator; }
|
||||
|
||||
@@ -3212,6 +3231,7 @@ protected:
|
||||
int32_t mLength; // DOM string length, may be INT32_MAX
|
||||
gfxFloat mWordSpacing; // space for each whitespace char
|
||||
gfxFloat mLetterSpacing; // space for each letter
|
||||
gfxFloat mMinTabAdvance; // min advance for <tab> char
|
||||
gfxFloat mHyphenWidth;
|
||||
gfxFloat mOffsetFromBlockOriginForTabs;
|
||||
|
||||
@@ -3364,6 +3384,28 @@ CanAddSpacingAfter(const gfxTextRun* aTextRun, uint32_t aOffset)
|
||||
aTextRun->IsLigatureGroupStart(aOffset + 1);
|
||||
}
|
||||
|
||||
static gfxFloat
|
||||
ComputeTabWidthAppUnits(nsIFrame* aFrame, gfxTextRun* aTextRun)
|
||||
{
|
||||
const nsStyleText* textStyle = aFrame->StyleText();
|
||||
if (textStyle->mTabSize.GetUnit() != eStyleUnit_Factor) {
|
||||
nscoord w = textStyle->mTabSize.GetCoordValue();
|
||||
MOZ_ASSERT(w >= 0);
|
||||
return w;
|
||||
}
|
||||
|
||||
gfxFloat spaces = textStyle->mTabSize.GetFactorValue();
|
||||
MOZ_ASSERT(spaces >= 0);
|
||||
|
||||
// Round the space width when converting to appunits the same way
|
||||
// textruns do.
|
||||
gfxFloat spaceWidthAppUnits =
|
||||
NS_round(GetFirstFontMetrics(aTextRun->GetFontGroup(),
|
||||
aTextRun->IsVertical()).spaceWidth *
|
||||
aTextRun->GetAppUnitsPerDevUnit());
|
||||
return spaces * spaceWidthAppUnits;
|
||||
}
|
||||
|
||||
void
|
||||
PropertyProvider::GetSpacingInternal(Range aRange, Spacing* aSpacing,
|
||||
bool aIgnoreTabs)
|
||||
@@ -3411,17 +3453,16 @@ PropertyProvider::GetSpacingInternal(Range aRange, Spacing* aSpacing,
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore tab spacing rather than computing it, if the tab size is 0
|
||||
if (!aIgnoreTabs)
|
||||
aIgnoreTabs = mFrame->StyleText()->mTabSize == 0;
|
||||
|
||||
// Now add tab spacing, if there is any
|
||||
if (!aIgnoreTabs) {
|
||||
CalcTabWidths(aRange);
|
||||
if (mTabWidths) {
|
||||
mTabWidths->ApplySpacing(aSpacing,
|
||||
aRange.start - mStart.GetSkippedOffset(),
|
||||
aRange.Length());
|
||||
gfxFloat tabWidth = ComputeTabWidthAppUnits(mFrame, mTextRun);
|
||||
if (tabWidth > 0) {
|
||||
CalcTabWidths(aRange, tabWidth);
|
||||
if (mTabWidths) {
|
||||
mTabWidths->ApplySpacing(aSpacing,
|
||||
aRange.start - mStart.GetSkippedOffset(),
|
||||
aRange.Length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3444,33 +3485,22 @@ PropertyProvider::GetSpacingInternal(Range aRange, Spacing* aSpacing,
|
||||
}
|
||||
}
|
||||
|
||||
static gfxFloat
|
||||
ComputeTabWidthAppUnits(nsIFrame* aFrame, const gfxTextRun* aTextRun)
|
||||
{
|
||||
// Get the number of spaces from CSS -moz-tab-size
|
||||
const nsStyleText* textStyle = aFrame->StyleText();
|
||||
|
||||
return textStyle->mTabSize * GetSpaceWidthAppUnits(aTextRun);
|
||||
}
|
||||
|
||||
// aX and the result are in whole appunits.
|
||||
static gfxFloat
|
||||
AdvanceToNextTab(gfxFloat aX, nsIFrame* aFrame,
|
||||
const gfxTextRun* aTextRun, gfxFloat* aCachedTabWidth)
|
||||
AdvanceToNextTab(gfxFloat aX, nsIFrame* aFrame, gfxTextRun* aTextRun,
|
||||
gfxFloat aTabWidth, gfxFloat aMinAdvance)
|
||||
{
|
||||
if (*aCachedTabWidth < 0) {
|
||||
*aCachedTabWidth = ComputeTabWidthAppUnits(aFrame, aTextRun);
|
||||
}
|
||||
|
||||
// Advance aX to the next multiple of *aCachedTabWidth. We must advance
|
||||
// by at least 1 appunit.
|
||||
// XXX should we make this 1 CSS pixel?
|
||||
return ceil((aX + 1)/(*aCachedTabWidth))*(*aCachedTabWidth);
|
||||
// Advance aX to the next multiple of aTabWidth. We must advance
|
||||
// by at least aMinAdvance.
|
||||
return ceil((aX + aMinAdvance) / aTabWidth) * aTabWidth;
|
||||
}
|
||||
|
||||
void
|
||||
PropertyProvider::CalcTabWidths(Range aRange)
|
||||
PropertyProvider::CalcTabWidths(Range aRange, gfxFloat aTabWidth)
|
||||
{
|
||||
MOZ_ASSERT(aTabWidth > 0);
|
||||
|
||||
if (!mTabWidths) {
|
||||
if (mReflowing && !mLineContainer) {
|
||||
// Intrinsic width computation does its own tab processing. We
|
||||
@@ -3505,7 +3535,6 @@ PropertyProvider::CalcTabWidths(Range aRange)
|
||||
NS_ASSERTION(mReflowing,
|
||||
"We need precomputed tab widths, but don't have enough.");
|
||||
|
||||
gfxFloat tabWidth = -1;
|
||||
for (uint32_t i = tabsEnd; i < aRange.end; ++i) {
|
||||
Spacing spacing;
|
||||
GetSpacingInternal(Range(i, i + 1), &spacing, true);
|
||||
@@ -3527,7 +3556,7 @@ PropertyProvider::CalcTabWidths(Range aRange)
|
||||
mFrame->SetProperty(TabWidthProperty(), mTabWidths);
|
||||
}
|
||||
double nextTab = AdvanceToNextTab(mOffsetFromBlockOriginForTabs,
|
||||
mFrame, mTextRun, &tabWidth);
|
||||
mFrame, mTextRun, aTabWidth, MinTabAdvance());
|
||||
mTabWidths->mWidths.AppendElement(TabWidth(i - startOffset,
|
||||
NSToIntRound(nextTab - mOffsetFromBlockOriginForTabs)));
|
||||
mOffsetFromBlockOriginForTabs = nextTab;
|
||||
@@ -3949,11 +3978,18 @@ nsTextPaintStyle::InitSelectionColorsAndShadow()
|
||||
if (selectionElement &&
|
||||
selectionStatus == nsISelectionController::SELECTION_ON) {
|
||||
RefPtr<nsStyleContext> sc = nullptr;
|
||||
// Probe for both selection and -moz-selection
|
||||
sc = mPresContext->StyleSet()->
|
||||
ProbePseudoElementStyle(selectionElement,
|
||||
CSSPseudoElementType::mozSelection,
|
||||
CSSPseudoElementType::selection,
|
||||
mFrame->StyleContext());
|
||||
// Use -moz-selection pseudo class.
|
||||
if (!sc) {
|
||||
sc = mPresContext->StyleSet()->
|
||||
ProbePseudoElementStyle(selectionElement,
|
||||
CSSPseudoElementType::mozSelection,
|
||||
mFrame->StyleContext());
|
||||
}
|
||||
// Use selection pseudo class.
|
||||
if (sc) {
|
||||
mSelectionBGColor =
|
||||
sc->GetVisitedDependentColor(eCSSProperty_background_color);
|
||||
@@ -8245,6 +8281,17 @@ nsTextFrame::AddInlineMinISizeForFlow(nsRenderingContext *aRenderingContext,
|
||||
return;
|
||||
}
|
||||
|
||||
// If overflow-wrap is 'anywhere', we can wrap everywhere.
|
||||
if (textStyle->mOverflowWrap == NS_STYLE_OVERFLOWWRAP_ANYWHERE &&
|
||||
textStyle->WordCanWrap(this)) {
|
||||
aData->OptionallyBreak();
|
||||
aData->mCurrentLine +=
|
||||
textRun->GetMinAdvanceWidth(Range(start, flowEndInTextRun));
|
||||
aData->mTrailingWhitespace = 0;
|
||||
aData->OptionallyBreak();
|
||||
return;
|
||||
}
|
||||
|
||||
AutoTArray<bool,BIG_TEXT_NODE_SIZE> hyphBuffer;
|
||||
bool *hyphBreakBefore = nullptr;
|
||||
if (hyphenating) {
|
||||
@@ -8303,9 +8350,12 @@ nsTextFrame::AddInlineMinISizeForFlow(nsRenderingContext *aRenderingContext,
|
||||
PropertyProvider::Spacing spacing;
|
||||
provider.GetSpacing(Range(i, i + 1), &spacing);
|
||||
aData->mCurrentLine += nscoord(spacing.mBefore);
|
||||
if (tabWidth < 0) {
|
||||
tabWidth = ComputeTabWidthAppUnits(this, textRun);
|
||||
}
|
||||
gfxFloat afterTab =
|
||||
AdvanceToNextTab(aData->mCurrentLine, this,
|
||||
textRun, &tabWidth);
|
||||
AdvanceToNextTab(aData->mCurrentLine, this, textRun, tabWidth,
|
||||
provider.MinTabAdvance());
|
||||
aData->mCurrentLine = nscoord(afterTab + spacing.mAfter);
|
||||
wordStart = i + 1;
|
||||
} else if (i < flowEndInTextRun ||
|
||||
@@ -8462,9 +8512,12 @@ nsTextFrame::AddInlinePrefISizeForFlow(nsRenderingContext *aRenderingContext,
|
||||
PropertyProvider::Spacing spacing;
|
||||
provider.GetSpacing(Range(i, i + 1), &spacing);
|
||||
aData->mCurrentLine += nscoord(spacing.mBefore);
|
||||
if (tabWidth < 0) {
|
||||
tabWidth = ComputeTabWidthAppUnits(this, textRun);
|
||||
}
|
||||
gfxFloat afterTab =
|
||||
AdvanceToNextTab(aData->mCurrentLine, this,
|
||||
textRun, &tabWidth);
|
||||
AdvanceToNextTab(aData->mCurrentLine, this, textRun, tabWidth,
|
||||
provider.MinTabAdvance());
|
||||
aData->mCurrentLine = nscoord(afterTab + spacing.mAfter);
|
||||
lineStart = i + 1;
|
||||
} else if (preformattedNewline) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
":first-letter",
|
||||
":first-line",
|
||||
":placeholder",
|
||||
":selection",
|
||||
":-moz-color-swatch",
|
||||
":-moz-focus-inner",
|
||||
":-moz-focus-outer",
|
||||
|
||||
@@ -126,3 +126,5 @@ fuzzy(1,1) == image-orientation-background.html?90&flip image-orientation-r
|
||||
|
||||
== image-resize-percent-height.html image-resize-ref.html
|
||||
== image-resize-percent-width.html image-resize-ref.html
|
||||
|
||||
== unknown-protocol.html unknown-protocol-ref.html
|
||||
@@ -0,0 +1 @@
|
||||
<img src="mailto://foo">
|
||||
@@ -0,0 +1 @@
|
||||
<img src="foobar://baz">
|
||||
@@ -4469,8 +4469,12 @@ StyleAnimationValue::ExtractComputedValue(nsCSSPropertyID aProperty,
|
||||
StyleDataAtOffset<nscolor>(styleStruct, ssOffset));
|
||||
return true;
|
||||
case eStyleAnimType_ComplexColor: {
|
||||
aComputedValue.SetComplexColorValue(
|
||||
StyleDataAtOffset<StyleComplexColor>(styleStruct, ssOffset));
|
||||
auto& color = StyleDataAtOffset<StyleComplexColor>(styleStruct, ssOffset);
|
||||
if (color.mIsAuto) {
|
||||
aComputedValue.SetAutoValue();
|
||||
} else {
|
||||
aComputedValue.SetComplexColorValue(color);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case eStyleAnimType_PaintServer: {
|
||||
@@ -4783,7 +4787,9 @@ StyleAnimationValue::SetCurrentColorValue()
|
||||
void
|
||||
StyleAnimationValue::SetComplexColorValue(const StyleComplexColor& aColor)
|
||||
{
|
||||
if (aColor.IsCurrentColor()) {
|
||||
if (aColor.mIsAuto) {
|
||||
SetAutoValue();
|
||||
} else if (aColor.IsCurrentColor()) {
|
||||
SetCurrentColorValue();
|
||||
} else if (aColor.IsNumericColor()) {
|
||||
SetColorValue(aColor.mColor);
|
||||
|
||||
@@ -24,16 +24,29 @@ struct StyleComplexColor
|
||||
{
|
||||
nscolor mColor;
|
||||
uint8_t mForegroundRatio;
|
||||
// Whether the complex color represents a computed-value time auto
|
||||
// value. This is only a flag indicating that this value should not
|
||||
// be interpolatable with other colors, while other fields still
|
||||
// represents the actual used color of this value.
|
||||
bool mIsAuto;
|
||||
|
||||
static StyleComplexColor FromColor(nscolor aColor) { return {aColor, 0}; }
|
||||
static StyleComplexColor CurrentColor() { return {NS_RGBA(0, 0, 0, 0), 255}; }
|
||||
static StyleComplexColor FromColor(nscolor aColor) {
|
||||
return {aColor, 0, false};
|
||||
}
|
||||
static StyleComplexColor CurrentColor() {
|
||||
return {NS_RGBA(0, 0, 0, 0), 255, false};
|
||||
}
|
||||
static StyleComplexColor Auto() {
|
||||
return {NS_RGBA(0, 0, 0, 0), 255, true};
|
||||
}
|
||||
|
||||
bool IsNumericColor() const { return mForegroundRatio == 0; }
|
||||
bool IsCurrentColor() const { return mForegroundRatio == 255; }
|
||||
|
||||
bool operator==(const StyleComplexColor& aOther) const {
|
||||
return mForegroundRatio == aOther.mForegroundRatio &&
|
||||
(IsCurrentColor() || mColor == aOther.mColor);
|
||||
(IsCurrentColor() || mColor == aOther.mColor) &&
|
||||
mIsAuto == aOther.mIsAuto;
|
||||
}
|
||||
bool operator!=(const StyleComplexColor& aOther) const {
|
||||
return !(*this == aOther);
|
||||
|
||||
@@ -144,6 +144,7 @@ CSS_KEY(alternate, alternate)
|
||||
CSS_KEY(alternate-reverse, alternate_reverse)
|
||||
CSS_KEY(always, always)
|
||||
CSS_KEY(annotation, annotation)
|
||||
CSS_KEY(anywhere, anywhere)
|
||||
CSS_KEY(appworkspace, appworkspace)
|
||||
CSS_KEY(auto, auto)
|
||||
CSS_KEY(auto-fill, auto_fill)
|
||||
|
||||
@@ -223,6 +223,10 @@ CSS_PROP_ALIAS(-moz-columns,
|
||||
columns,
|
||||
MozColumns,
|
||||
"")
|
||||
CSS_PROP_ALIAS(-moz-tab-size,
|
||||
tab_size,
|
||||
MozTabSize,
|
||||
"")
|
||||
|
||||
#define WEBKIT_PREFIX_PREF "layout.css.prefixes.webkit"
|
||||
|
||||
|
||||
@@ -1394,6 +1394,17 @@ CSS_PROP_TABLEBORDER(
|
||||
kCaptionSideKTable,
|
||||
CSS_PROP_NO_OFFSET,
|
||||
eStyleAnimType_Discrete)
|
||||
CSS_PROP_USERINTERFACE(
|
||||
caret-color,
|
||||
caret_color,
|
||||
CaretColor,
|
||||
CSS_PROPERTY_PARSE_VALUE |
|
||||
CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
|
||||
"",
|
||||
VARIANT_AUTO | VARIANT_HC,
|
||||
nullptr,
|
||||
offsetof(nsStyleUserInterface, mCaretColor),
|
||||
eStyleAnimType_ComplexColor)
|
||||
CSS_PROP_DISPLAY(
|
||||
clear,
|
||||
clear,
|
||||
@@ -3868,16 +3879,16 @@ CSS_PROP_FONT(
|
||||
eStyleAnimType_None)
|
||||
#endif // CSS_PROP_LIST_EXCLUDE_INTERNAL
|
||||
CSS_PROP_TEXT(
|
||||
-moz-tab-size,
|
||||
_moz_tab_size,
|
||||
CSS_PROP_DOMPROP_PREFIXED(TabSize),
|
||||
tab-size,
|
||||
tab_size,
|
||||
TabSize,
|
||||
CSS_PROPERTY_PARSE_VALUE |
|
||||
CSS_PROPERTY_VALUE_NONNEGATIVE,
|
||||
"",
|
||||
VARIANT_HI,
|
||||
VARIANT_INHERIT | VARIANT_LNCALC,
|
||||
nullptr,
|
||||
offsetof(nsStyleText, mTabSize),
|
||||
eStyleAnimType_Discrete)
|
||||
eStyleAnimType_Coord)
|
||||
CSS_PROP_TABLE(
|
||||
table-layout,
|
||||
table_layout,
|
||||
|
||||
@@ -2284,6 +2284,7 @@ const KTableEntry nsCSSProps::kWordBreakKTable[] = {
|
||||
const KTableEntry nsCSSProps::kOverflowWrapKTable[] = {
|
||||
{ eCSSKeyword_normal, NS_STYLE_OVERFLOWWRAP_NORMAL },
|
||||
{ eCSSKeyword_break_word, NS_STYLE_OVERFLOWWRAP_BREAK_WORD },
|
||||
{ eCSSKeyword_anywhere, NS_STYLE_OVERFLOWWRAP_ANYWHERE },
|
||||
{ eCSSKeyword_UNKNOWN, -1 }
|
||||
};
|
||||
|
||||
|
||||
@@ -37,6 +37,9 @@ CSS_PSEUDO_ELEMENT(firstLine, ":first-line",
|
||||
CSS_PSEUDO_ELEMENT_IS_CSS2 |
|
||||
CSS_PSEUDO_ELEMENT_CONTAINS_ELEMENTS)
|
||||
|
||||
CSS_PSEUDO_ELEMENT(selection, ":selection",
|
||||
CSS_PSEUDO_ELEMENT_CONTAINS_ELEMENTS)
|
||||
// Keep the prefixed version for now.
|
||||
CSS_PSEUDO_ELEMENT(mozSelection, ":-moz-selection",
|
||||
CSS_PSEUDO_ELEMENT_CONTAINS_ELEMENTS)
|
||||
|
||||
|
||||
@@ -3972,7 +3972,7 @@ already_AddRefed<CSSValue>
|
||||
nsComputedDOMStyle::DoGetTabSize()
|
||||
{
|
||||
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
|
||||
val->SetNumber(StyleText()->mTabSize);
|
||||
SetValueToCoord(val, StyleText()->mTabSize, true);
|
||||
return val.forget();
|
||||
}
|
||||
|
||||
@@ -4146,6 +4146,14 @@ nsComputedDOMStyle::DoGetUnicodeBidi()
|
||||
return val.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<CSSValue>
|
||||
nsComputedDOMStyle::DoGetCaretColor()
|
||||
{
|
||||
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
|
||||
SetValueFromComplexColor(val, StyleUserInterface()->mCaretColor);
|
||||
return val.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<CSSValue>
|
||||
nsComputedDOMStyle::DoGetCursor()
|
||||
{
|
||||
|
||||
@@ -482,6 +482,7 @@ private:
|
||||
already_AddRefed<CSSValue> DoGetShapeOutside();
|
||||
|
||||
/* User interface properties */
|
||||
already_AddRefed<CSSValue> DoGetCaretColor();
|
||||
already_AddRefed<CSSValue> DoGetCursor();
|
||||
already_AddRefed<CSSValue> DoGetForceBrokenImageIcon();
|
||||
already_AddRefed<CSSValue> DoGetIMEMode();
|
||||
|
||||
@@ -101,6 +101,7 @@ COMPUTED_STYLE_PROP(box_decoration_break, BoxDecorationBreak)
|
||||
COMPUTED_STYLE_PROP(box_shadow, BoxShadow)
|
||||
COMPUTED_STYLE_PROP(box_sizing, BoxSizing)
|
||||
COMPUTED_STYLE_PROP(caption_side, CaptionSide)
|
||||
COMPUTED_STYLE_PROP(caret_color, CaretColor)
|
||||
COMPUTED_STYLE_PROP(clear, Clear)
|
||||
COMPUTED_STYLE_PROP(clip, Clip)
|
||||
COMPUTED_STYLE_PROP(color, Color)
|
||||
@@ -227,6 +228,7 @@ COMPUTED_STYLE_PROP(scroll_snap_type_x, ScrollSnapTypeX)
|
||||
COMPUTED_STYLE_PROP(scroll_snap_type_y, ScrollSnapTypeY)
|
||||
COMPUTED_STYLE_PROP(shape_outside, ShapeOutside)
|
||||
//// COMPUTED_STYLE_PROP(size, Size)
|
||||
COMPUTED_STYLE_PROP(tab_size, TabSize)
|
||||
COMPUTED_STYLE_PROP(table_layout, TableLayout)
|
||||
COMPUTED_STYLE_PROP(text_align, TextAlign)
|
||||
COMPUTED_STYLE_PROP(text_align_last, TextAlignLast)
|
||||
@@ -294,7 +296,6 @@ COMPUTED_STYLE_PROP(_moz_outline_radius_bottomRight,OutlineRadiusBottomRight)
|
||||
COMPUTED_STYLE_PROP(_moz_outline_radius_topLeft, OutlineRadiusTopLeft)
|
||||
COMPUTED_STYLE_PROP(_moz_outline_radius_topRight, OutlineRadiusTopRight)
|
||||
COMPUTED_STYLE_PROP(stack_sizing, StackSizing)
|
||||
COMPUTED_STYLE_PROP(_moz_tab_size, TabSize)
|
||||
COMPUTED_STYLE_PROP(text_size_adjust, TextSizeAdjust)
|
||||
COMPUTED_STYLE_PROP(user_focus, UserFocus)
|
||||
COMPUTED_STYLE_PROP(user_input, UserInput)
|
||||
|
||||
+298
-283
File diff suppressed because it is too large.
Load diff
@@ -997,6 +997,7 @@ enum class StyleDisplay : uint8_t {
|
||||
// See nsStyleText
|
||||
#define NS_STYLE_OVERFLOWWRAP_NORMAL 0
|
||||
#define NS_STYLE_OVERFLOWWRAP_BREAK_WORD 1
|
||||
#define NS_STYLE_OVERFLOWWRAP_ANYWHERE 2
|
||||
|
||||
// See nsStyleText
|
||||
#define NS_STYLE_HYPHENS_NONE 0
|
||||
|
||||
@@ -1255,6 +1255,17 @@ nsStyleContext::CalcStyleDifferenceInternal(StyleContextLike* aNewContext,
|
||||
}
|
||||
}
|
||||
|
||||
// NB: Calling Peek on |this|, not |thisVis| (see above).
|
||||
if (!change && PeekStyleUserInterface()) {
|
||||
const nsStyleUserInterface *thisVisUserInterface = thisVis->StyleUserInterface();
|
||||
const nsStyleUserInterface *otherVisUserInterface = otherVis->StyleUserInterface();
|
||||
if (thisVisUserInterface->mCaretColor !=
|
||||
otherVisUserInterface->mCaretColor) {
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (change) {
|
||||
hint |= nsChangeHint_RepaintFrame;
|
||||
}
|
||||
@@ -1487,6 +1498,9 @@ ExtractColor(nsCSSPropertyID aProperty,
|
||||
case StyleAnimationValue::eUnit_ComplexColor:
|
||||
return Some(aStyleContext->StyleColor()->
|
||||
CalcComplexColor(val.GetStyleComplexColorValue()));
|
||||
case StyleAnimationValue::eUnit_Auto:
|
||||
return Some(aStyleContext->StyleColor()->
|
||||
CalcComplexColor(StyleComplexColor::Auto()));
|
||||
default:
|
||||
return Nothing();
|
||||
}
|
||||
@@ -1508,7 +1522,8 @@ static const ColorIndexSet gVisitedIndices[2] = { { 0, 0 }, { 1, 0 } };
|
||||
nscolor
|
||||
nsStyleContext::GetVisitedDependentColor(nsCSSPropertyID aProperty)
|
||||
{
|
||||
NS_ASSERTION(aProperty == eCSSProperty_color ||
|
||||
NS_ASSERTION(aProperty == eCSSProperty_caret_color ||
|
||||
aProperty == eCSSProperty_color ||
|
||||
aProperty == eCSSProperty_background_color ||
|
||||
aProperty == eCSSProperty_border_top_color ||
|
||||
aProperty == eCSSProperty_border_right_color ||
|
||||
|
||||
@@ -3807,10 +3807,10 @@ nsStyleText::nsStyleText(StyleStructContext aContext)
|
||||
, mControlCharacterVisibility(nsCSSParser::ControlCharVisibilityDefault())
|
||||
, mTextEmphasisStyle(NS_STYLE_TEXT_EMPHASIS_STYLE_NONE)
|
||||
, mTextRendering(NS_STYLE_TEXT_RENDERING_AUTO)
|
||||
, mTabSize(NS_STYLE_TABSIZE_INITIAL)
|
||||
, mTextEmphasisColor(StyleComplexColor::CurrentColor())
|
||||
, mWebkitTextFillColor(StyleComplexColor::CurrentColor())
|
||||
, mWebkitTextStrokeColor(StyleComplexColor::CurrentColor())
|
||||
, mTabSize(float(NS_STYLE_TABSIZE_INITIAL), eStyleUnit_Factor)
|
||||
, mWordSpacing(0, nsStyleCoord::CoordConstructor)
|
||||
, mLetterSpacing(eStyleUnit_Normal)
|
||||
, mLineHeight(eStyleUnit_Normal)
|
||||
@@ -3845,10 +3845,10 @@ nsStyleText::nsStyleText(const nsStyleText& aSource)
|
||||
, mTextEmphasisPosition(aSource.mTextEmphasisPosition)
|
||||
, mTextEmphasisStyle(aSource.mTextEmphasisStyle)
|
||||
, mTextRendering(aSource.mTextRendering)
|
||||
, mTabSize(aSource.mTabSize)
|
||||
, mTextEmphasisColor(aSource.mTextEmphasisColor)
|
||||
, mWebkitTextFillColor(aSource.mWebkitTextFillColor)
|
||||
, mWebkitTextStrokeColor(aSource.mWebkitTextStrokeColor)
|
||||
, mTabSize(aSource.mTabSize)
|
||||
, mWordSpacing(aSource.mWordSpacing)
|
||||
, mLetterSpacing(aSource.mLetterSpacing)
|
||||
, mLineHeight(aSource.mLineHeight)
|
||||
@@ -4024,6 +4024,7 @@ nsStyleUserInterface::nsStyleUserInterface(StyleStructContext aContext)
|
||||
, mUserFocus(StyleUserFocus::None)
|
||||
, mPointerEvents(NS_STYLE_POINTER_EVENTS_AUTO)
|
||||
, mCursor(NS_STYLE_CURSOR_AUTO)
|
||||
, mCaretColor(StyleComplexColor::Auto())
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsStyleUserInterface);
|
||||
}
|
||||
@@ -4035,6 +4036,7 @@ nsStyleUserInterface::nsStyleUserInterface(const nsStyleUserInterface& aSource)
|
||||
, mPointerEvents(aSource.mPointerEvents)
|
||||
, mCursor(aSource.mCursor)
|
||||
, mCursorImages(aSource.mCursorImages)
|
||||
, mCaretColor(aSource.mCaretColor)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsStyleUserInterface);
|
||||
}
|
||||
@@ -4083,6 +4085,10 @@ nsStyleUserInterface::CalcDifference(const nsStyleUserInterface& aNewData) const
|
||||
hint |= nsChangeHint_NeutralChange;
|
||||
}
|
||||
|
||||
if (mCaretColor != aNewData.mCaretColor) {
|
||||
hint |= nsChangeHint_RepaintFrame;
|
||||
}
|
||||
|
||||
return hint;
|
||||
}
|
||||
|
||||
|
||||
@@ -2088,11 +2088,11 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText
|
||||
uint8_t mTextEmphasisPosition; // [inherited] see nsStyleConsts.h
|
||||
uint8_t mTextEmphasisStyle; // [inherited] see nsStyleConsts.h
|
||||
uint8_t mTextRendering; // [inherited] see nsStyleConsts.h
|
||||
int32_t mTabSize; // [inherited] see nsStyleConsts.h
|
||||
mozilla::StyleComplexColor mTextEmphasisColor; // [inherited]
|
||||
mozilla::StyleComplexColor mWebkitTextFillColor; // [inherited]
|
||||
mozilla::StyleComplexColor mWebkitTextStrokeColor; // [inherited]
|
||||
|
||||
nsStyleCoord mTabSize; // [inherited] coord, factor, calc
|
||||
nsStyleCoord mWordSpacing; // [inherited] coord, percent, calc
|
||||
nsStyleCoord mLetterSpacing; // [inherited] coord, normal
|
||||
nsStyleCoord mLineHeight; // [inherited] coord, factor, normal
|
||||
@@ -2134,8 +2134,11 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText
|
||||
}
|
||||
|
||||
bool WordCanWrapStyle() const {
|
||||
return WhiteSpaceCanWrapStyle() &&
|
||||
mOverflowWrap == NS_STYLE_OVERFLOWWRAP_BREAK_WORD;
|
||||
if (!WhiteSpaceCanWrapStyle()) {
|
||||
return false;
|
||||
}
|
||||
return (mOverflowWrap == NS_STYLE_OVERFLOWWRAP_BREAK_WORD ||
|
||||
mOverflowWrap == NS_STYLE_OVERFLOWWRAP_ANYWHERE);
|
||||
}
|
||||
|
||||
bool HasTextEmphasis() const {
|
||||
@@ -3414,6 +3417,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUserInterface
|
||||
|
||||
uint8_t mCursor; // [inherited] See nsStyleConsts.h
|
||||
nsTArray<nsCursorImage> mCursorImages; // [inherited] images and coords
|
||||
mozilla::StyleComplexColor mCaretColor; // [inherited]
|
||||
|
||||
inline uint8_t GetEffectivePointerEvents(nsIFrame* aFrame) const;
|
||||
};
|
||||
|
||||
@@ -46,6 +46,9 @@
|
||||
backface-visibility: inherit;
|
||||
clip: inherit;
|
||||
/* When the table wrapper is a Flex/Grid item we need these: */
|
||||
flex-grow: inherit;
|
||||
flex-shrink: inherit;
|
||||
flex-basis: inherit;
|
||||
align-self: inherit;
|
||||
justify-self: inherit;
|
||||
grid-column-start: inherit;
|
||||
|
||||
@@ -2028,13 +2028,22 @@ var gCSSProperties = {
|
||||
other_values: [ "ignore" ],
|
||||
invalid_values: []
|
||||
},
|
||||
"-moz-tab-size": {
|
||||
domProp: "MozTabSize",
|
||||
"tab-size": {
|
||||
domProp: "TabSize",
|
||||
inherited: true,
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
initial_values: [ "8" ],
|
||||
other_values: [ "0", "3", "99", "12000" ],
|
||||
invalid_values: [ "-1", "-808", "3.0", "17.5" ]
|
||||
other_values: [ "0", "2.5", "3", "99", "12000", "0px", "1em",
|
||||
"calc(1px + 1em)", "calc(1px - 2px)", "calc(1 + 1)", "calc(-2.5)" ],
|
||||
invalid_values: [ "9%", "calc(9% + 1px)", "calc(1 + 1em)", "-1", "-808",
|
||||
"auto" ]
|
||||
},
|
||||
"-moz-tab-size": {
|
||||
domProp: "MozTabSize",
|
||||
inherited: true,
|
||||
type: CSS_TYPE_SHORTHAND_AND_LONGHAND
|
||||
alias_for: "tab-size",
|
||||
subproperties: [ "tab-size" ]
|
||||
},
|
||||
"-moz-text-size-adjust": {
|
||||
domProp: "MozTextSizeAdjust",
|
||||
@@ -2837,6 +2846,18 @@ var gCSSProperties = {
|
||||
other_values: [ "bottom", "left", "right", "top-outside", "bottom-outside" ],
|
||||
invalid_values: []
|
||||
},
|
||||
"caret-color": {
|
||||
domProp: "caretColor",
|
||||
inherited: true,
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
prerequisites: { "color": "black" },
|
||||
// Though "auto" is an independent computed-value time keyword value,
|
||||
// it is not distinguishable from currentcolor because getComputedStyle
|
||||
// always returns used value for <color>.
|
||||
initial_values: [ "auto", "currentcolor", "black", "rgb(0,0,0)" ],
|
||||
other_values: [ "green", "transparent", "rgba(128,128,128,.5)", "#123" ],
|
||||
invalid_values: [ "#0", "#00", "#00000", "cc00ff" ]
|
||||
},
|
||||
"clear": {
|
||||
domProp: "clear",
|
||||
inherited: false,
|
||||
|
||||
@@ -248,6 +248,8 @@ var supported_properties = {
|
||||
// test_length_percent_calc_transition.
|
||||
"stroke-width": [ test_length_transition_svg, test_percent_transition,
|
||||
test_length_clamped_svg, test_percent_clamped ],
|
||||
"tab-size": [ test_float_zeroToOne_transition,
|
||||
test_float_aboveOne_transition, test_length_clamped ],
|
||||
"text-decoration": [ test_color_shorthand_transition,
|
||||
test_true_currentcolor_shorthand_transition ],
|
||||
"text-decoration-color": [ test_color_transition,
|
||||
@@ -1373,6 +1375,21 @@ function test_true_currentcolor_transition(prop, get_color=(x => x), is_shorthan
|
||||
div.style.removeProperty("color");
|
||||
}
|
||||
|
||||
function test_auto_color_transition(prop, get_color=(x => x), is_shorthand=false) {
|
||||
const msg_prefix = `color-valued property ${prop}: `;
|
||||
const test_color = "rgb(51, 102, 153)";
|
||||
div.style.setProperty("transition-property", "none", "");
|
||||
div.style.setProperty(prop, "auto", "");
|
||||
let used_value_of_auto = get_color(cs.getPropertyValue(prop));
|
||||
isnot(used_value_of_auto, test_color,
|
||||
msg_prefix + "ensure used auto value is different than our test color");
|
||||
|
||||
div.style.setProperty("transition-property", prop, "");
|
||||
div.style.setProperty(prop, test_color, "");
|
||||
is(get_color(cs.getPropertyValue(prop)), test_color,
|
||||
msg_prefix + "not interpolatable between auto and rgb color");
|
||||
}
|
||||
|
||||
function get_color_from_shorthand_value(value) {
|
||||
var m = value.match(/rgba?\([^, ]*, [^, ]*, [^, ]*(?:, [^, ]*)?\)/);
|
||||
isnot(m, null, "shorthand property value should contain color");
|
||||
|
||||
@@ -104,6 +104,14 @@ struct TableReflowInput {
|
||||
availSize.BSize(wm) = std::max(0, availSize.BSize(wm));
|
||||
}
|
||||
}
|
||||
|
||||
void ReduceAvailableBSizeBy(WritingMode aWM, nscoord aAmount) {
|
||||
if (availSize.BSize(aWM) == NS_UNCONSTRAINEDSIZE) {
|
||||
return;
|
||||
}
|
||||
availSize.BSize(aWM) -= aAmount;
|
||||
availSize.BSize(aWM) = std::max(0, availSize.BSize(aWM));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -2682,9 +2690,7 @@ nsTableFrame::PlaceChild(TableReflowInput& aReflowInput,
|
||||
aReflowInput.bCoord += aKidDesiredSize.BSize(wm);
|
||||
|
||||
// If our bsize is constrained, then update the available bsize
|
||||
if (NS_UNCONSTRAINEDSIZE != aReflowInput.availSize.BSize(wm)) {
|
||||
aReflowInput.availSize.BSize(wm) -= aKidDesiredSize.BSize(wm);
|
||||
}
|
||||
aReflowInput.ReduceAvailableBSizeBy(wm, aKidDesiredSize.BSize(wm));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2928,17 +2934,28 @@ nsTableFrame::ReflowChildren(TableReflowInput& aReflowInput,
|
||||
// using the footer's prev-in-flow's height instead of reflowing it again,
|
||||
// but there's no real need.
|
||||
if (isPaginated) {
|
||||
bool reorder = false;
|
||||
if (thead && !GetPrevInFlow()) {
|
||||
if (thead->GetNextInFlow()) {
|
||||
reorder = true;
|
||||
}
|
||||
nscoord desiredHeight;
|
||||
nsresult rv = SetupHeaderFooterChild(aReflowInput, thead, &desiredHeight);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
}
|
||||
if (tfoot) {
|
||||
if (tfoot->GetNextInFlow()) {
|
||||
reorder = true;
|
||||
}
|
||||
nsresult rv = SetupHeaderFooterChild(aReflowInput, tfoot, &footerHeight);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
}
|
||||
if (reorder) {
|
||||
// Reorder row groups, because the reflow may have changed what's next-in-flow.
|
||||
OrderRowGroups(rowGroups, &thead, &tfoot);
|
||||
}
|
||||
}
|
||||
// if the child is a tbody in paginated mode reduce the height by a repeated footer
|
||||
bool allowRepeatedFooter = false;
|
||||
@@ -3004,14 +3021,13 @@ nsTableFrame::ReflowChildren(TableReflowInput& aReflowInput,
|
||||
kidReflowInput.mFlags.mIsTopOfPage = false;
|
||||
}
|
||||
aReflowInput.bCoord += cellSpacingB;
|
||||
if (NS_UNCONSTRAINEDSIZE != aReflowInput.availSize.BSize(wm)) {
|
||||
aReflowInput.availSize.BSize(wm) -= cellSpacingB;
|
||||
}
|
||||
aReflowInput.ReduceAvailableBSizeBy(wm, cellSpacingB);
|
||||
// record the presence of a next in flow, it might get destroyed so we
|
||||
// need to reorder the row group array
|
||||
bool reorder = false;
|
||||
if (kidFrame->GetNextInFlow())
|
||||
if (kidFrame->GetNextInFlow()) {
|
||||
reorder = true;
|
||||
}
|
||||
|
||||
LogicalPoint kidPosition(wm, aReflowInput.iCoord, aReflowInput.bCoord);
|
||||
ReflowChild(kidFrame, presContext, desiredSize, kidReflowInput,
|
||||
@@ -3019,7 +3035,7 @@ nsTableFrame::ReflowChildren(TableReflowInput& aReflowInput,
|
||||
kidReflowInput.ApplyRelativePositioning(&kidPosition, containerSize);
|
||||
|
||||
if (reorder) {
|
||||
// reorder row groups the reflow may have changed the nextinflows
|
||||
// Reorder row groups, because the reflow may have changed what's next-in-flow.
|
||||
OrderRowGroups(rowGroups, &thead, &tfoot);
|
||||
childX = rowGroups.IndexOf(kidFrame);
|
||||
if (childX == RowGroupArray::NoIndex) {
|
||||
@@ -3171,9 +3187,7 @@ nsTableFrame::ReflowChildren(TableReflowInput& aReflowInput,
|
||||
aReflowInput.bCoord += kidRect.BSize(wm);
|
||||
|
||||
// If our bsize is constrained then update the available bsize.
|
||||
if (NS_UNCONSTRAINEDSIZE != aReflowInput.availSize.BSize(wm)) {
|
||||
aReflowInput.availSize.BSize(wm) -= cellSpacingB + kidRect.BSize(wm);
|
||||
}
|
||||
aReflowInput.ReduceAvailableBSizeBy(wm, cellSpacingB + kidRect.BSize(wm));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <stddef.h> // size_t
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "webrtc/common_audio/ring_buffer.h"
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
@@ -1573,33 +1574,36 @@ AecCore* WebRtcAec_CreateAec() {
|
||||
#endif
|
||||
aec->extended_filter_enabled = 0;
|
||||
|
||||
// Assembly optimization
|
||||
WebRtcAec_FilterFar = FilterFar;
|
||||
WebRtcAec_ScaleErrorSignal = ScaleErrorSignal;
|
||||
WebRtcAec_FilterAdaptation = FilterAdaptation;
|
||||
WebRtcAec_OverdriveAndSuppress = OverdriveAndSuppress;
|
||||
WebRtcAec_ComfortNoise = ComfortNoise;
|
||||
WebRtcAec_SubbandCoherence = SubbandCoherence;
|
||||
static bool initted = false;
|
||||
if (!initted) {
|
||||
initted = true;
|
||||
// Assembly optimization
|
||||
WebRtcAec_FilterFar = FilterFar;
|
||||
WebRtcAec_ScaleErrorSignal = ScaleErrorSignal;
|
||||
WebRtcAec_FilterAdaptation = FilterAdaptation;
|
||||
WebRtcAec_OverdriveAndSuppress = OverdriveAndSuppress;
|
||||
WebRtcAec_ComfortNoise = ComfortNoise;
|
||||
WebRtcAec_SubbandCoherence = SubbandCoherence;
|
||||
|
||||
#if defined(WEBRTC_ARCH_X86_FAMILY)
|
||||
if (WebRtc_GetCPUInfo(kSSE2)) {
|
||||
WebRtcAec_InitAec_SSE2();
|
||||
}
|
||||
if (WebRtc_GetCPUInfo(kSSE2)) {
|
||||
WebRtcAec_InitAec_SSE2();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MIPS_FPU_LE)
|
||||
WebRtcAec_InitAec_mips();
|
||||
WebRtcAec_InitAec_mips();
|
||||
#endif
|
||||
|
||||
#if defined(WEBRTC_ARCH_ARM_NEON)
|
||||
WebRtcAec_InitAec_neon();
|
||||
#elif defined(WEBRTC_DETECT_ARM_NEON)
|
||||
if ((WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) != 0) {
|
||||
WebRtcAec_InitAec_neon();
|
||||
}
|
||||
#elif defined(WEBRTC_DETECT_ARM_NEON)
|
||||
if ((WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) != 0) {
|
||||
WebRtcAec_InitAec_neon();
|
||||
}
|
||||
#endif
|
||||
|
||||
aec_rdft_init();
|
||||
aec_rdft_init();
|
||||
}
|
||||
|
||||
return aec;
|
||||
}
|
||||
|
||||
@@ -302,6 +302,9 @@ typedef long ssize_t;
|
||||
#include <mach/mach_init.h>
|
||||
#include <mach/vm_map.h>
|
||||
#include <malloc/malloc.h>
|
||||
#ifndef _pthread_self
|
||||
#define _pthread_self() pthread_self()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -314,7 +314,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
T& operator*() const { return *get(); }
|
||||
typename AddLvalueReference<T>::Type operator*() const { return *get(); }
|
||||
Pointer operator->() const
|
||||
{
|
||||
MOZ_ASSERT(get(), "dereferencing a UniquePtr containing nullptr");
|
||||
|
||||
@@ -11,4 +11,4 @@ The in-tree copy is updated by running
|
||||
sh update.sh
|
||||
from within the modules/brotli directory.
|
||||
|
||||
Current version: [commit d6d98957ca8ccb1ef45922e978bb10efca0ea541].
|
||||
Current version: 1.0.9 Re-release [commit e61745a6b7add50d380cfd7d3883dd6c62fc2c71].
|
||||
@@ -0,0 +1,15 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "./constants.h"
|
||||
|
||||
const BrotliPrefixCodeRange
|
||||
_kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
|
||||
{1, 2}, {5, 2}, {9, 2}, {13, 2}, {17, 3}, {25, 3},
|
||||
{33, 3}, {41, 3}, {49, 4}, {65, 4}, {81, 4}, {97, 4},
|
||||
{113, 5}, {145, 5}, {177, 5}, {209, 5}, {241, 6}, {305, 6},
|
||||
{369, 7}, {497, 8}, {753, 9}, {1265, 10}, {2289, 11}, {4337, 12},
|
||||
{8433, 13}, {16625, 24}};
|
||||
@@ -4,9 +4,18 @@
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Common constants used in decoder and encoder API.
|
||||
*/
|
||||
|
||||
#ifndef BROTLI_COMMON_CONSTANTS_H_
|
||||
#define BROTLI_COMMON_CONSTANTS_H_
|
||||
|
||||
#include "./platform.h"
|
||||
#include <brotli/port.h>
|
||||
#include <brotli/types.h>
|
||||
|
||||
/* Specification: 7.3. Encoding of the context map */
|
||||
#define BROTLI_CONTEXT_MAP_MAX_RLE 16
|
||||
|
||||
@@ -29,12 +38,31 @@
|
||||
#define BROTLI_INITIAL_REPEATED_CODE_LENGTH 8
|
||||
|
||||
/* "Large Window Brotli" */
|
||||
|
||||
/**
|
||||
* The theoretical maximum number of distance bits specified for large window
|
||||
* brotli, for 64-bit encoders and decoders. Even when in practice 32-bit
|
||||
* encoders and decoders only support up to 30 max distance bits, the value is
|
||||
* set to 62 because it affects the large window brotli file format.
|
||||
* Specifically, it affects the encoding of simple huffman tree for distances,
|
||||
* see Specification RFC 7932 chapter 3.4.
|
||||
*/
|
||||
#define BROTLI_LARGE_MAX_DISTANCE_BITS 62U
|
||||
#define BROTLI_LARGE_MIN_WBITS 10
|
||||
/**
|
||||
* The maximum supported large brotli window bits by the encoder and decoder.
|
||||
* Large window brotli allows up to 62 bits, however the current encoder and
|
||||
* decoder, designed for 32-bit integers, only support up to 30 bits maximum.
|
||||
*/
|
||||
#define BROTLI_LARGE_MAX_WBITS 30
|
||||
|
||||
/* Specification: 4. Encoding of distances */
|
||||
#define BROTLI_NUM_DISTANCE_SHORT_CODES 16
|
||||
/**
|
||||
* Maximal number of "postfix" bits.
|
||||
*
|
||||
* Number of "postfix" bits is stored as 2 bits in meta-block header.
|
||||
*/
|
||||
#define BROTLI_MAX_NPOSTFIX 3
|
||||
#define BROTLI_MAX_NDIRECT 120
|
||||
#define BROTLI_MAX_DISTANCE_BITS 24U
|
||||
@@ -45,9 +73,22 @@
|
||||
#define BROTLI_NUM_DISTANCE_SYMBOLS \
|
||||
BROTLI_DISTANCE_ALPHABET_SIZE( \
|
||||
BROTLI_MAX_NDIRECT, BROTLI_MAX_NPOSTFIX, BROTLI_LARGE_MAX_DISTANCE_BITS)
|
||||
|
||||
/* ((1 << 26) - 4) is the maximal distance that can be expressed in RFC 7932
|
||||
brotli stream using NPOSTFIX = 0 and NDIRECT = 0. With other NPOSTFIX and
|
||||
NDIRECT values distances up to ((1 << 29) + 88) could be expressed. */
|
||||
#define BROTLI_MAX_DISTANCE 0x3FFFFFC
|
||||
|
||||
/* ((1 << 31) - 4) is the safe distance limit. Using this number as a limit
|
||||
allows safe distance calculation without overflows, given the distance
|
||||
alphabet size is limited to corresponding size
|
||||
(see kLargeWindowDistanceCodeLimits). */
|
||||
#define BROTLI_MAX_ALLOWED_DISTANCE 0x7FFFFFFC
|
||||
|
||||
|
||||
/* Specification: 4. Encoding of Literal Insertion Lengths and Copy Lengths */
|
||||
#define BROTLI_NUM_INS_COPY_CODES 24
|
||||
|
||||
/* 7.1. Context modes and context ID lookup for literals */
|
||||
/* "context IDs for literals are in the range of 0..63" */
|
||||
#define BROTLI_LITERAL_CONTEXT_BITS 6
|
||||
@@ -61,4 +102,99 @@
|
||||
#define BROTLI_WINDOW_GAP 16
|
||||
#define BROTLI_MAX_BACKWARD_LIMIT(W) (((size_t)1 << (W)) - BROTLI_WINDOW_GAP)
|
||||
|
||||
typedef struct BrotliDistanceCodeLimit {
|
||||
uint32_t max_alphabet_size;
|
||||
uint32_t max_distance;
|
||||
} BrotliDistanceCodeLimit;
|
||||
|
||||
/* This function calculates maximal size of distance alphabet, such that the
|
||||
distances greater than the given values can not be represented.
|
||||
|
||||
This limits are designed to support fast and safe 32-bit decoders.
|
||||
"32-bit" means that signed integer values up to ((1 << 31) - 1) could be
|
||||
safely expressed.
|
||||
|
||||
Brotli distance alphabet symbols do not represent consecutive distance
|
||||
ranges. Each distance alphabet symbol (excluding direct distances and short
|
||||
codes), represent interleaved (for NPOSTFIX > 0) range of distances.
|
||||
A "group" of consecutive (1 << NPOSTFIX) symbols represent non-interleaved
|
||||
range. Two consecutive groups require the same amount of "extra bits".
|
||||
|
||||
It is important that distance alphabet represents complete "groups".
|
||||
To avoid complex logic on encoder side about interleaved ranges
|
||||
it was decided to restrict both sides to complete distance code "groups".
|
||||
*/
|
||||
BROTLI_UNUSED_FUNCTION BrotliDistanceCodeLimit BrotliCalculateDistanceCodeLimit(
|
||||
uint32_t max_distance, uint32_t npostfix, uint32_t ndirect) {
|
||||
BrotliDistanceCodeLimit result;
|
||||
/* Marking this function as unused, because not all files
|
||||
including "constants.h" use it -> compiler warns about that. */
|
||||
BROTLI_UNUSED(&BrotliCalculateDistanceCodeLimit);
|
||||
if (max_distance <= ndirect) {
|
||||
/* This case never happens / exists only for the sake of completeness. */
|
||||
result.max_alphabet_size = max_distance + BROTLI_NUM_DISTANCE_SHORT_CODES;
|
||||
result.max_distance = max_distance;
|
||||
return result;
|
||||
} else {
|
||||
/* The first prohibited value. */
|
||||
uint32_t forbidden_distance = max_distance + 1;
|
||||
/* Subtract "directly" encoded region. */
|
||||
uint32_t offset = forbidden_distance - ndirect - 1;
|
||||
uint32_t ndistbits = 0;
|
||||
uint32_t tmp;
|
||||
uint32_t half;
|
||||
uint32_t group;
|
||||
/* Postfix for the last dcode in the group. */
|
||||
uint32_t postfix = (1u << npostfix) - 1;
|
||||
uint32_t extra;
|
||||
uint32_t start;
|
||||
/* Remove postfix and "head-start". */
|
||||
offset = (offset >> npostfix) + 4;
|
||||
/* Calculate the number of distance bits. */
|
||||
tmp = offset / 2;
|
||||
/* Poor-man's log2floor, to avoid extra dependencies. */
|
||||
while (tmp != 0) {ndistbits++; tmp = tmp >> 1;}
|
||||
/* One bit is covered with subrange addressing ("half"). */
|
||||
ndistbits--;
|
||||
/* Find subrange. */
|
||||
half = (offset >> ndistbits) & 1;
|
||||
/* Calculate the "group" part of dcode. */
|
||||
group = ((ndistbits - 1) << 1) | half;
|
||||
/* Calculated "group" covers the prohibited distance value. */
|
||||
if (group == 0) {
|
||||
/* This case is added for correctness; does not occur for limit > 128. */
|
||||
result.max_alphabet_size = ndirect + BROTLI_NUM_DISTANCE_SHORT_CODES;
|
||||
result.max_distance = ndirect;
|
||||
return result;
|
||||
}
|
||||
/* Decrement "group", so it is the last permitted "group". */
|
||||
group--;
|
||||
/* After group was decremented, ndistbits and half must be recalculated. */
|
||||
ndistbits = (group >> 1) + 1;
|
||||
/* The last available distance in the subrange has all extra bits set. */
|
||||
extra = (1u << ndistbits) - 1;
|
||||
/* Calculate region start. NB: ndistbits >= 1. */
|
||||
start = (1u << (ndistbits + 1)) - 4;
|
||||
/* Move to subregion. */
|
||||
start += (group & 1) << ndistbits;
|
||||
/* Calculate the alphabet size. */
|
||||
result.max_alphabet_size = ((group << npostfix) | postfix) + ndirect +
|
||||
BROTLI_NUM_DISTANCE_SHORT_CODES + 1;
|
||||
/* Calculate the maximal distance representable by alphabet. */
|
||||
result.max_distance = ((start + extra) << npostfix) + postfix + ndirect + 1;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/* Represents the range of values belonging to a prefix code:
|
||||
[offset, offset + 2^nbits) */
|
||||
typedef struct {
|
||||
uint16_t offset;
|
||||
uint8_t nbits;
|
||||
} BrotliPrefixCodeRange;
|
||||
|
||||
/* "Soft-private", it is exported, but not "advertised" as API. */
|
||||
BROTLI_COMMON_API extern const BrotliPrefixCodeRange
|
||||
_kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS];
|
||||
|
||||
#endif /* BROTLI_COMMON_CONSTANTS_H_ */
|
||||
@@ -0,0 +1,156 @@
|
||||
#include "./context.h"
|
||||
|
||||
#include <brotli/types.h>
|
||||
|
||||
/* Common context lookup table for all context modes. */
|
||||
const uint8_t _kBrotliContextLookupTable[2048] = {
|
||||
/* CONTEXT_LSB6, last byte. */
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
|
||||
/* CONTEXT_LSB6, second last byte, */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
/* CONTEXT_MSB6, last byte. */
|
||||
0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
|
||||
8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
|
||||
12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
|
||||
16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
|
||||
20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
|
||||
24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
|
||||
28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
|
||||
32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,
|
||||
36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
|
||||
40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
|
||||
44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,
|
||||
48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,
|
||||
52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,
|
||||
56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,
|
||||
60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63,
|
||||
|
||||
/* CONTEXT_MSB6, second last byte, */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
/* CONTEXT_UTF8, last byte. */
|
||||
/* ASCII range. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12,
|
||||
44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12,
|
||||
12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48,
|
||||
52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12,
|
||||
12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56,
|
||||
60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0,
|
||||
/* UTF8 continuation byte range. */
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
/* UTF8 lead byte range. */
|
||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
||||
|
||||
/* CONTEXT_UTF8 second last byte. */
|
||||
/* ASCII range. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
|
||||
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
|
||||
1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0,
|
||||
/* UTF8 continuation byte range. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* UTF8 lead byte range. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
|
||||
/* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */
|
||||
0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
||||
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
||||
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
||||
48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56,
|
||||
|
||||
/* CONTEXT_SIGNED, second last byte. */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
|
||||
};
|
||||
@@ -88,6 +88,7 @@
|
||||
#ifndef BROTLI_COMMON_CONTEXT_H_
|
||||
#define BROTLI_COMMON_CONTEXT_H_
|
||||
|
||||
#include <brotli/port.h>
|
||||
#include <brotli/types.h>
|
||||
|
||||
typedef enum ContextType {
|
||||
@@ -97,163 +98,14 @@ typedef enum ContextType {
|
||||
CONTEXT_SIGNED = 3
|
||||
} ContextType;
|
||||
|
||||
/* "Soft-private", it is exported, but not "advertised" as API. */
|
||||
/* Common context lookup table for all context modes. */
|
||||
static const uint8_t kContextLookup[2048] = {
|
||||
/* CONTEXT_LSB6, last byte. */
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
|
||||
/* CONTEXT_LSB6, second last byte, */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
/* CONTEXT_MSB6, last byte. */
|
||||
0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
|
||||
8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
|
||||
12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
|
||||
16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
|
||||
20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
|
||||
24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
|
||||
28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
|
||||
32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,
|
||||
36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
|
||||
40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
|
||||
44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,
|
||||
48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,
|
||||
52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,
|
||||
56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,
|
||||
60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63,
|
||||
|
||||
/* CONTEXT_MSB6, second last byte, */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
/* CONTEXT_UTF8, last byte. */
|
||||
/* ASCII range. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12,
|
||||
44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12,
|
||||
12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48,
|
||||
52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12,
|
||||
12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56,
|
||||
60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0,
|
||||
/* UTF8 continuation byte range. */
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
/* UTF8 lead byte range. */
|
||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
||||
|
||||
/* CONTEXT_UTF8 second last byte. */
|
||||
/* ASCII range. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
|
||||
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
|
||||
1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0,
|
||||
/* UTF8 continuation byte range. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* UTF8 lead byte range. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
|
||||
/* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */
|
||||
0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
||||
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
||||
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
||||
48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56,
|
||||
|
||||
/* CONTEXT_SIGNED, second last byte. */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
|
||||
};
|
||||
BROTLI_COMMON_API extern const uint8_t _kBrotliContextLookupTable[2048];
|
||||
|
||||
typedef const uint8_t* ContextLut;
|
||||
|
||||
/* typeof(MODE) == ContextType; returns ContextLut */
|
||||
#define BROTLI_CONTEXT_LUT(MODE) (&kContextLookup[(MODE) << 9])
|
||||
#define BROTLI_CONTEXT_LUT(MODE) (&_kBrotliContextLookupTable[(MODE) << 9])
|
||||
|
||||
/* typeof(LUT) == ContextLut */
|
||||
#define BROTLI_CONTEXT(P1, P2, LUT) ((LUT)[P1] | ((LUT) + 256)[P2])
|
||||
|
||||
@@ -5,12 +5,13 @@
|
||||
*/
|
||||
|
||||
#include "./dictionary.h"
|
||||
#include "./platform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef BROTLI_EXTERNAL_DICTIONARY_DATA
|
||||
#if !defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
|
||||
static const uint8_t kBrotliDictionaryData[] =
|
||||
{
|
||||
116,105,109,101,100,111,119,110,108,105,102,101,108,101,102,116,98,97,99,107,99,
|
||||
@@ -5862,7 +5863,11 @@ static const uint8_t kBrotliDictionaryData[] =
|
||||
;
|
||||
#endif /* !BROTLI_EXTERNAL_DICTIONARY_DATA */
|
||||
|
||||
#if !defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
|
||||
static const BrotliDictionary kBrotliDictionary = {
|
||||
#else
|
||||
static BrotliDictionary kBrotliDictionary = {
|
||||
#endif
|
||||
/* size_bits_by_length */
|
||||
{
|
||||
0, 0, 0, 0, 10, 10, 11, 11,
|
||||
@@ -5895,9 +5900,13 @@ const BrotliDictionary* BrotliGetDictionary() {
|
||||
}
|
||||
|
||||
void BrotliSetDictionaryData(const uint8_t* data) {
|
||||
#if defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
|
||||
if (!!data && !kBrotliDictionary.data) {
|
||||
kBrotliDictionary.data = data;
|
||||
}
|
||||
#else
|
||||
BROTLI_UNUSED(data); // Appease -Werror=unused-parameter
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/* Copyright 2016 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "./platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
/* Default brotli_alloc_func */
|
||||
void* BrotliDefaultAllocFunc(void* opaque, size_t size) {
|
||||
BROTLI_UNUSED(opaque);
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
/* Default brotli_free_func */
|
||||
void BrotliDefaultFreeFunc(void* opaque, void* address) {
|
||||
BROTLI_UNUSED(opaque);
|
||||
free(address);
|
||||
}
|
||||
@@ -24,12 +24,11 @@
|
||||
#define BROTLI_COMMON_PLATFORM_H_
|
||||
|
||||
#include <string.h> /* memcpy */
|
||||
#include <stdlib.h> /* malloc, free */
|
||||
|
||||
#include <brotli/port.h>
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(OS_LINUX) || defined(OS_CYGWIN)
|
||||
#if defined(OS_LINUX) || defined(OS_CYGWIN) || defined(__EMSCRIPTEN__)
|
||||
#include <endian.h>
|
||||
#elif defined(OS_FREEBSD)
|
||||
#include <machine/endian.h>
|
||||
@@ -41,6 +40,10 @@
|
||||
#define BROTLI_X_BIG_ENDIAN BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
#if BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_ENABLE_LOG) || defined(BROTLI_DEBUG)
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
@@ -308,8 +311,7 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
||||
}
|
||||
#else /* BROTLI_ALIGNED_READ */
|
||||
/* Unaligned memory access is allowed: just cast pointer to requested type. */
|
||||
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
|
||||
defined(MEMORY_SANITIZER)
|
||||
#if BROTLI_SANITIZED
|
||||
/* Consider we have an unaligned load/store of 4 bytes from address 0x...05.
|
||||
AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
|
||||
will miss a bug if 08 is the first unaddressable byte.
|
||||
@@ -334,7 +336,7 @@ extern "C" {
|
||||
#define BrotliUnalignedRead32 __sanitizer_unaligned_load32
|
||||
#define BrotliUnalignedRead64 __sanitizer_unaligned_load64
|
||||
#define BrotliUnalignedWrite64 __sanitizer_unaligned_store64
|
||||
#else
|
||||
#else /* BROTLI_SANITIZED */
|
||||
static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) {
|
||||
return *(const uint16_t*)p;
|
||||
}
|
||||
@@ -356,7 +358,7 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
||||
typedef BROTLI_ALIGNED(1) uint64_t brotli_unaligned_uint64_t;
|
||||
|
||||
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
|
||||
return (uint64_t) ((brotli_unaligned_uint64_t*) p)[0];
|
||||
return (uint64_t) ((const brotli_unaligned_uint64_t*) p)[0];
|
||||
}
|
||||
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
||||
brotli_unaligned_uint64_t* dwords = (brotli_unaligned_uint64_t*) p;
|
||||
@@ -374,7 +376,7 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
||||
}
|
||||
#endif /* BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) */
|
||||
#endif /* BROTLI_64_BITS */
|
||||
#endif /* ASAN / TSAN / MSAN */
|
||||
#endif /* BROTLI_SANITIZED */
|
||||
#endif /* BROTLI_ALIGNED_READ */
|
||||
|
||||
#if BROTLI_LITTLE_ENDIAN
|
||||
@@ -466,20 +468,20 @@ static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void* p, uint64_t v) {
|
||||
#endif
|
||||
|
||||
#if defined(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(BROTLI_DEBUG) || defined(BROTLI_ENABLE_LOG)
|
||||
#define BROTLI_DCHECK(x) assert(x)
|
||||
static BROTLI_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_DCHECK(x)
|
||||
#define BROTLI_DUMP() (void)(0)
|
||||
#endif
|
||||
|
||||
@@ -523,17 +525,41 @@ BROTLI_MIN_MAX(size_t) BROTLI_MIN_MAX(uint32_t) BROTLI_MIN_MAX(uint8_t)
|
||||
(A)[(J)] = __brotli_swap_tmp; \
|
||||
}
|
||||
|
||||
/* Default brotli_alloc_func */
|
||||
static void* BrotliDefaultAllocFunc(void* opaque, size_t size) {
|
||||
BROTLI_UNUSED(opaque);
|
||||
return malloc(size);
|
||||
#if BROTLI_64_BITS
|
||||
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_ctzll, 3, 4, 0) || \
|
||||
BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
|
||||
#define BROTLI_TZCNT64 __builtin_ctzll
|
||||
#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
|
||||
#if defined(BROTLI_TARGET_X64)
|
||||
#define BROTLI_TZCNT64 _tzcnt_u64
|
||||
#else /* BROTLI_TARGET_X64 */
|
||||
static BROTLI_INLINE uint32_t BrotliBsf64Msvc(uint64_t x) {
|
||||
uint32_t lsb;
|
||||
_BitScanForward64(&lsb, x);
|
||||
return lsb;
|
||||
}
|
||||
#define BROTLI_TZCNT64 BrotliBsf64Msvc
|
||||
#endif /* BROTLI_TARGET_X64 */
|
||||
#endif /* __builtin_ctzll */
|
||||
#endif /* BROTLI_64_BITS */
|
||||
|
||||
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_clz, 3, 4, 0) || \
|
||||
BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
|
||||
#define BROTLI_BSR32(x) (31u ^ (uint32_t)__builtin_clz(x))
|
||||
#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
|
||||
static BROTLI_INLINE uint32_t BrotliBsr32Msvc(uint32_t x) {
|
||||
unsigned long msb;
|
||||
_BitScanReverse(&msb, x);
|
||||
return (uint32_t)msb;
|
||||
}
|
||||
#define BROTLI_BSR32 BrotliBsr32Msvc
|
||||
#endif /* __builtin_clz */
|
||||
|
||||
/* Default brotli_alloc_func */
|
||||
BROTLI_COMMON_API void* BrotliDefaultAllocFunc(void* opaque, size_t size);
|
||||
|
||||
/* Default brotli_free_func */
|
||||
static void BrotliDefaultFreeFunc(void* opaque, void* address) {
|
||||
BROTLI_UNUSED(opaque);
|
||||
free(address);
|
||||
}
|
||||
BROTLI_COMMON_API void BrotliDefaultFreeFunc(void* opaque, void* address);
|
||||
|
||||
BROTLI_UNUSED_FUNCTION void BrotliSuppressUnusedFunctions(void) {
|
||||
BROTLI_UNUSED(&BrotliSuppressUnusedFunctions);
|
||||
|
||||
@@ -24,8 +24,8 @@ static const char kPrefixSuffix[217] =
|
||||
/* 8x _0 _ _3 _8 _C _E _ _1 _7 _F */
|
||||
" not \3er \3al \4ful \4ive \5less \4es"
|
||||
/* Ax _5 _9 _D _2 _7 _D */
|
||||
"t \4ize \2\xc2\xa0\4ous \5 the \2e \0";
|
||||
/* Cx _2 _7___ ___ _A _F _5 _8 */
|
||||
"t \4ize \2\xc2\xa0\4ous \5 the \2e "; /* \0 - implicit trailing zero. */
|
||||
/* Cx _2 _7___ ___ _A _F _5 _8 */
|
||||
|
||||
static const uint16_t kPrefixSuffixMap[50] = {
|
||||
0x00, 0x02, 0x05, 0x0E, 0x13, 0x16, 0x18, 0x1E, 0x23, 0x25,
|
||||
@@ -160,12 +160,13 @@ static const uint8_t kTransformsData[] = {
|
||||
0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 34,
|
||||
};
|
||||
|
||||
static BrotliTransforms kBrotliTransforms = {
|
||||
static const BrotliTransforms kBrotliTransforms = {
|
||||
sizeof(kPrefixSuffix),
|
||||
(const uint8_t*)kPrefixSuffix,
|
||||
kPrefixSuffixMap,
|
||||
sizeof(kTransformsData) / (3 * sizeof(kTransformsData[0])),
|
||||
kTransformsData,
|
||||
NULL, /* no extra parameters */
|
||||
{0, 12, 27, 23, 42, 63, 56, 48, 59, 64}
|
||||
};
|
||||
|
||||
@@ -190,6 +191,48 @@ static int ToUpperCase(uint8_t* p) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int Shift(uint8_t* word, int word_len, uint16_t parameter) {
|
||||
/* Limited sign extension: scalar < (1 << 24). */
|
||||
uint32_t scalar =
|
||||
(parameter & 0x7FFFu) + (0x1000000u - (parameter & 0x8000u));
|
||||
if (word[0] < 0x80) {
|
||||
/* 1-byte rune / 0sssssss / 7 bit scalar (ASCII). */
|
||||
scalar += (uint32_t)word[0];
|
||||
word[0] = (uint8_t)(scalar & 0x7Fu);
|
||||
return 1;
|
||||
} else if (word[0] < 0xC0) {
|
||||
/* Continuation / 10AAAAAA. */
|
||||
return 1;
|
||||
} else if (word[0] < 0xE0) {
|
||||
/* 2-byte rune / 110sssss AAssssss / 11 bit scalar. */
|
||||
if (word_len < 2) return 1;
|
||||
scalar += (uint32_t)((word[1] & 0x3Fu) | ((word[0] & 0x1Fu) << 6u));
|
||||
word[0] = (uint8_t)(0xC0 | ((scalar >> 6u) & 0x1F));
|
||||
word[1] = (uint8_t)((word[1] & 0xC0) | (scalar & 0x3F));
|
||||
return 2;
|
||||
} else if (word[0] < 0xF0) {
|
||||
/* 3-byte rune / 1110ssss AAssssss BBssssss / 16 bit scalar. */
|
||||
if (word_len < 3) return word_len;
|
||||
scalar += (uint32_t)((word[2] & 0x3Fu) | ((word[1] & 0x3Fu) << 6u) |
|
||||
((word[0] & 0x0Fu) << 12u));
|
||||
word[0] = (uint8_t)(0xE0 | ((scalar >> 12u) & 0x0F));
|
||||
word[1] = (uint8_t)((word[1] & 0xC0) | ((scalar >> 6u) & 0x3F));
|
||||
word[2] = (uint8_t)((word[2] & 0xC0) | (scalar & 0x3F));
|
||||
return 3;
|
||||
} else if (word[0] < 0xF8) {
|
||||
/* 4-byte rune / 11110sss AAssssss BBssssss CCssssss / 21 bit scalar. */
|
||||
if (word_len < 4) return word_len;
|
||||
scalar += (uint32_t)((word[3] & 0x3Fu) | ((word[2] & 0x3Fu) << 6u) |
|
||||
((word[1] & 0x3Fu) << 12u) | ((word[0] & 0x07u) << 18u));
|
||||
word[0] = (uint8_t)(0xF0 | ((scalar >> 18u) & 0x07));
|
||||
word[1] = (uint8_t)((word[1] & 0xC0) | ((scalar >> 12u) & 0x3F));
|
||||
word[2] = (uint8_t)((word[2] & 0xC0) | ((scalar >> 6u) & 0x3F));
|
||||
word[3] = (uint8_t)((word[3] & 0xC0) | (scalar & 0x3F));
|
||||
return 4;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BrotliTransformDictionaryWord(uint8_t* dst, const uint8_t* word, int len,
|
||||
const BrotliTransforms* transforms, int transform_idx) {
|
||||
int idx = 0;
|
||||
@@ -221,6 +264,19 @@ int BrotliTransformDictionaryWord(uint8_t* dst, const uint8_t* word, int len,
|
||||
uppercase += step;
|
||||
len -= step;
|
||||
}
|
||||
} else if (t == BROTLI_TRANSFORM_SHIFT_FIRST) {
|
||||
uint16_t param = (uint16_t)(transforms->params[transform_idx * 2]
|
||||
+ (transforms->params[transform_idx * 2 + 1] << 8u));
|
||||
Shift(&dst[idx - len], len, param);
|
||||
} else if (t == BROTLI_TRANSFORM_SHIFT_ALL) {
|
||||
uint16_t param = (uint16_t)(transforms->params[transform_idx * 2]
|
||||
+ (transforms->params[transform_idx * 2 + 1] << 8u));
|
||||
uint8_t* shift = &dst[idx - len];
|
||||
while (len > 0) {
|
||||
int step = Shift(shift, len, param);
|
||||
shift += step;
|
||||
len -= step;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
|
||||
@@ -37,6 +37,8 @@ enum BrotliWordTransformType {
|
||||
BROTLI_TRANSFORM_OMIT_FIRST_7 = 18,
|
||||
BROTLI_TRANSFORM_OMIT_FIRST_8 = 19,
|
||||
BROTLI_TRANSFORM_OMIT_FIRST_9 = 20,
|
||||
BROTLI_TRANSFORM_SHIFT_FIRST = 21,
|
||||
BROTLI_TRANSFORM_SHIFT_ALL = 22,
|
||||
BROTLI_NUM_TRANSFORM_TYPES /* Counts transforms, not a transform itself. */
|
||||
};
|
||||
|
||||
@@ -50,6 +52,9 @@ typedef struct BrotliTransforms {
|
||||
uint32_t num_transforms;
|
||||
/* Each entry is a [prefix_id, transform, suffix_id] triplet. */
|
||||
const uint8_t* transforms;
|
||||
/* Shift for BROTLI_TRANSFORM_SHIFT_FIRST and BROTLI_TRANSFORM_SHIFT_ALL,
|
||||
must be NULL if and only if no such transforms are present. */
|
||||
const uint8_t* params;
|
||||
/* Indices of transforms like ["", BROTLI_TRANSFORM_OMIT_LAST_#, ""].
|
||||
0-th element corresponds to ["", BROTLI_TRANSFORM_IDENTITY, ""].
|
||||
-1, if cut-off transform does not exist. */
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
BrotliEncoderVersion methods. */
|
||||
|
||||
/* Semantic version, calculated as (MAJOR << 24) | (MINOR << 12) | PATCH */
|
||||
#define BROTLI_VERSION 0x1000007
|
||||
#define BROTLI_VERSION 0x1000009
|
||||
|
||||
/* This macro is used by build system to produce Libtool-friendly soname. See
|
||||
https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
|
||||
*/
|
||||
|
||||
/* ABI version, calculated as (CURRENT << 24) | (REVISION << 12) | AGE */
|
||||
#define BROTLI_ABI_VERSION 0x1007000
|
||||
#define BROTLI_ABI_VERSION 0x1009000
|
||||
|
||||
#endif /* BROTLI_COMMON_VERSION_H_ */
|
||||
@@ -15,6 +15,17 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const uint32_t kBrotliBitMask[33] = { 0x00000000,
|
||||
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
|
||||
};
|
||||
|
||||
void BrotliInitBitReader(BrotliBitReader* const br) {
|
||||
br->val_ = 0;
|
||||
br->bit_pos_ = sizeof(br->val_) << 3;
|
||||
@@ -43,6 +54,23 @@ BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br) {
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
BROTLI_BOOL BrotliSafeReadBits32Slow(BrotliBitReader* const br,
|
||||
uint32_t n_bits, uint32_t* val) {
|
||||
uint32_t low_val;
|
||||
uint32_t high_val;
|
||||
BrotliBitReaderState memento;
|
||||
BROTLI_DCHECK(n_bits <= 32);
|
||||
BROTLI_DCHECK(n_bits > 24);
|
||||
BrotliBitReaderSaveState(br, &memento);
|
||||
if (!BrotliSafeReadBits(br, 16, &low_val) ||
|
||||
!BrotliSafeReadBits(br, n_bits - 16, &high_val)) {
|
||||
BrotliBitReaderRestoreState(br, &memento);
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
*val = low_val | (high_val << 16);
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <string.h> /* memcpy */
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
@@ -20,16 +21,7 @@ extern "C" {
|
||||
|
||||
#define BROTLI_SHORT_FILL_BIT_WINDOW_READ (sizeof(brotli_reg_t) >> 1)
|
||||
|
||||
static const uint32_t kBitMask[33] = { 0x00000000,
|
||||
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
|
||||
};
|
||||
BROTLI_INTERNAL extern const uint32_t kBrotliBitMask[33];
|
||||
|
||||
static BROTLI_INLINE uint32_t BitMask(uint32_t n) {
|
||||
if (BROTLI_IS_CONSTANT(n) || BROTLI_HAS_UBFX) {
|
||||
@@ -37,7 +29,7 @@ static BROTLI_INLINE uint32_t BitMask(uint32_t n) {
|
||||
"Unsigned Bit Field Extract" UBFX instruction on ARM. */
|
||||
return ~((0xFFFFFFFFu) << n);
|
||||
} else {
|
||||
return kBitMask[n];
|
||||
return kBrotliBitMask[n];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +57,12 @@ BROTLI_INTERNAL void BrotliInitBitReader(BrotliBitReader* const br);
|
||||
reading. */
|
||||
BROTLI_INTERNAL BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br);
|
||||
|
||||
/* Fallback for BrotliSafeReadBits32. Extracted as noninlined method to unburden
|
||||
the main code-path. Never called for RFC brotli streams, required only for
|
||||
"large-window" mode and other extensions. */
|
||||
BROTLI_INTERNAL BROTLI_NOINLINE BROTLI_BOOL BrotliSafeReadBits32Slow(
|
||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val);
|
||||
|
||||
static BROTLI_INLINE void BrotliBitReaderSaveState(
|
||||
BrotliBitReader* const from, BrotliBitReaderState* to) {
|
||||
to->val_ = from->val_;
|
||||
@@ -87,8 +85,11 @@ static BROTLI_INLINE uint32_t BrotliGetAvailableBits(
|
||||
}
|
||||
|
||||
/* Returns amount of unread bytes the bit reader still has buffered from the
|
||||
BrotliInput, including whole bytes in br->val_. */
|
||||
BrotliInput, including whole bytes in br->val_. Result is capped with
|
||||
maximal ring-buffer size (larger number won't be utilized anyway). */
|
||||
static BROTLI_INLINE size_t BrotliGetRemainingBytes(BrotliBitReader* br) {
|
||||
static const size_t kCap = (size_t)1 << BROTLI_LARGE_MAX_WBITS;
|
||||
if (br->avail_in > kCap) return kCap;
|
||||
return br->avail_in + (BrotliGetAvailableBits(br) >> 3);
|
||||
}
|
||||
|
||||
@@ -237,15 +238,17 @@ static BROTLI_INLINE void BrotliBitReaderUnload(BrotliBitReader* br) {
|
||||
static BROTLI_INLINE void BrotliTakeBits(
|
||||
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",
|
||||
BROTLI_LOG(("[BrotliTakeBits] %d %d %d val: %6x\n",
|
||||
(int)br->avail_in, (int)br->bit_pos_, (int)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(
|
||||
Assumes that there is enough input to perform BrotliFillBitWindow.
|
||||
Up to 24 bits are allowed to be requested from this method. */
|
||||
static BROTLI_INLINE uint32_t BrotliReadBits24(
|
||||
BrotliBitReader* const br, uint32_t n_bits) {
|
||||
BROTLI_DCHECK(n_bits <= 24);
|
||||
if (BROTLI_64_BITS || (n_bits <= 16)) {
|
||||
uint32_t val;
|
||||
BrotliFillBitWindow(br, n_bits);
|
||||
@@ -262,10 +265,32 @@ static BROTLI_INLINE uint32_t BrotliReadBits(
|
||||
}
|
||||
}
|
||||
|
||||
/* Same as BrotliReadBits24, but allows reading up to 32 bits. */
|
||||
static BROTLI_INLINE uint32_t BrotliReadBits32(
|
||||
BrotliBitReader* const br, uint32_t n_bits) {
|
||||
BROTLI_DCHECK(n_bits <= 32);
|
||||
if (BROTLI_64_BITS || (n_bits <= 16)) {
|
||||
uint32_t val;
|
||||
BrotliFillBitWindow(br, n_bits);
|
||||
BrotliTakeBits(br, n_bits, &val);
|
||||
return val;
|
||||
} else {
|
||||
uint32_t low_val;
|
||||
uint32_t high_val;
|
||||
BrotliFillBitWindow(br, 16);
|
||||
BrotliTakeBits(br, 16, &low_val);
|
||||
BrotliFillBitWindow(br, 16);
|
||||
BrotliTakeBits(br, n_bits - 16, &high_val);
|
||||
return low_val | (high_val << 16);
|
||||
}
|
||||
}
|
||||
|
||||
/* Tries to read the specified amount of bits. Returns BROTLI_FALSE, if there
|
||||
is not enough input. |n_bits| MUST be positive. */
|
||||
is not enough input. |n_bits| MUST be positive.
|
||||
Up to 24 bits are allowed to be requested from this method. */
|
||||
static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits(
|
||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||
BROTLI_DCHECK(n_bits <= 24);
|
||||
while (BrotliGetAvailableBits(br) < n_bits) {
|
||||
if (!BrotliPullByte(br)) {
|
||||
return BROTLI_FALSE;
|
||||
@@ -275,6 +300,23 @@ static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits(
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
/* Same as BrotliSafeReadBits, but allows reading up to 32 bits. */
|
||||
static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits32(
|
||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||
BROTLI_DCHECK(n_bits <= 32);
|
||||
if (BROTLI_64_BITS || (n_bits <= 24)) {
|
||||
while (BrotliGetAvailableBits(br) < n_bits) {
|
||||
if (!BrotliPullByte(br)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
BrotliTakeBits(br, n_bits, val);
|
||||
return BROTLI_TRUE;
|
||||
} else {
|
||||
return BrotliSafeReadBits32Slow(br, n_bits, val);
|
||||
}
|
||||
}
|
||||
|
||||
/* Advances the bit reader position to the next byte boundary and verifies
|
||||
that any skipped bits are set to zero. */
|
||||
static BROTLI_INLINE BROTLI_BOOL BrotliJumpToByteBoundary(BrotliBitReader* br) {
|
||||
|
||||
+353
-251
@@ -41,7 +41,8 @@ extern "C" {
|
||||
|
||||
/* We need the slack region for the following reasons:
|
||||
- doing up to two 16-byte copies for fast backward copying
|
||||
- inserting transformed dictionary word (5 prefix + 24 base + 8 suffix) */
|
||||
- inserting transformed dictionary word:
|
||||
5 prefix + 24 base + 8 suffix */
|
||||
static const uint32_t kRingBufferWriteAheadSlack = 42;
|
||||
|
||||
static const uint8_t kCodeLengthCodeOrder[BROTLI_CODE_LENGTH_CODES] = {
|
||||
@@ -274,7 +275,8 @@ static BrotliDecoderErrorCode BROTLI_NOINLINE DecodeMetaBlockLength(
|
||||
s->loop_counter = i;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
if (i + 1 == s->size_nibbles && s->size_nibbles > 4 && bits == 0) {
|
||||
if (i + 1 == (int)s->size_nibbles && s->size_nibbles > 4 &&
|
||||
bits == 0) {
|
||||
return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE);
|
||||
}
|
||||
s->meta_block_remaining_len |= (int)(bits << (i * 4));
|
||||
@@ -323,7 +325,8 @@ static BrotliDecoderErrorCode BROTLI_NOINLINE DecodeMetaBlockLength(
|
||||
s->loop_counter = i;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
if (i + 1 == s->size_nibbles && s->size_nibbles > 1 && bits == 0) {
|
||||
if (i + 1 == (int)s->size_nibbles && s->size_nibbles > 1 &&
|
||||
bits == 0) {
|
||||
return BROTLI_FAILURE(
|
||||
BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE);
|
||||
}
|
||||
@@ -470,32 +473,34 @@ static BROTLI_INLINE uint32_t Log2Floor(uint32_t x) {
|
||||
Totally 1..4 symbols are read, 1..11 bits each.
|
||||
The list of symbols MUST NOT contain duplicates. */
|
||||
static BrotliDecoderErrorCode ReadSimpleHuffmanSymbols(
|
||||
uint32_t alphabet_size, uint32_t max_symbol, BrotliDecoderState* s) {
|
||||
uint32_t alphabet_size_max, uint32_t alphabet_size_limit,
|
||||
BrotliDecoderState* s) {
|
||||
/* max_bits == 1..11; symbol == 0..3; 1..44 bits will be read. */
|
||||
BrotliBitReader* br = &s->br;
|
||||
uint32_t max_bits = Log2Floor(alphabet_size - 1);
|
||||
uint32_t i = s->sub_loop_counter;
|
||||
uint32_t num_symbols = s->symbol;
|
||||
BrotliMetablockHeaderArena* h = &s->arena.header;
|
||||
uint32_t max_bits = Log2Floor(alphabet_size_max - 1);
|
||||
uint32_t i = h->sub_loop_counter;
|
||||
uint32_t num_symbols = h->symbol;
|
||||
while (i <= num_symbols) {
|
||||
uint32_t v;
|
||||
if (BROTLI_PREDICT_FALSE(!BrotliSafeReadBits(br, max_bits, &v))) {
|
||||
s->sub_loop_counter = i;
|
||||
s->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_READ;
|
||||
h->sub_loop_counter = i;
|
||||
h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_READ;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
if (v >= max_symbol) {
|
||||
if (v >= alphabet_size_limit) {
|
||||
return
|
||||
BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET);
|
||||
}
|
||||
s->symbols_lists_array[i] = (uint16_t)v;
|
||||
BROTLI_LOG_UINT(s->symbols_lists_array[i]);
|
||||
h->symbols_lists_array[i] = (uint16_t)v;
|
||||
BROTLI_LOG_UINT(h->symbols_lists_array[i]);
|
||||
++i;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_symbols; ++i) {
|
||||
uint32_t k = i + 1;
|
||||
for (; k <= num_symbols; ++k) {
|
||||
if (s->symbols_lists_array[i] == s->symbols_lists_array[k]) {
|
||||
if (h->symbols_lists_array[i] == h->symbols_lists_array[k]) {
|
||||
return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME);
|
||||
}
|
||||
}
|
||||
@@ -588,27 +593,28 @@ static BROTLI_INLINE void ProcessRepeatedCodeLength(uint32_t code_len,
|
||||
static BrotliDecoderErrorCode ReadSymbolCodeLengths(
|
||||
uint32_t alphabet_size, BrotliDecoderState* s) {
|
||||
BrotliBitReader* br = &s->br;
|
||||
uint32_t symbol = s->symbol;
|
||||
uint32_t repeat = s->repeat;
|
||||
uint32_t space = s->space;
|
||||
uint32_t prev_code_len = s->prev_code_len;
|
||||
uint32_t repeat_code_len = s->repeat_code_len;
|
||||
uint16_t* symbol_lists = s->symbol_lists;
|
||||
uint16_t* code_length_histo = s->code_length_histo;
|
||||
int* next_symbol = s->next_symbol;
|
||||
BrotliMetablockHeaderArena* h = &s->arena.header;
|
||||
uint32_t symbol = h->symbol;
|
||||
uint32_t repeat = h->repeat;
|
||||
uint32_t space = h->space;
|
||||
uint32_t prev_code_len = h->prev_code_len;
|
||||
uint32_t repeat_code_len = h->repeat_code_len;
|
||||
uint16_t* symbol_lists = h->symbol_lists;
|
||||
uint16_t* code_length_histo = h->code_length_histo;
|
||||
int* next_symbol = h->next_symbol;
|
||||
if (!BrotliWarmupBitReader(br)) {
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
while (symbol < alphabet_size && space > 0) {
|
||||
const HuffmanCode* p = s->table;
|
||||
const HuffmanCode* p = h->table;
|
||||
uint32_t code_len;
|
||||
BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(p);
|
||||
if (!BrotliCheckInputAmount(br, BROTLI_SHORT_FILL_BIT_WINDOW_READ)) {
|
||||
s->symbol = symbol;
|
||||
s->repeat = repeat;
|
||||
s->prev_code_len = prev_code_len;
|
||||
s->repeat_code_len = repeat_code_len;
|
||||
s->space = space;
|
||||
h->symbol = symbol;
|
||||
h->repeat = repeat;
|
||||
h->prev_code_len = prev_code_len;
|
||||
h->repeat_code_len = repeat_code_len;
|
||||
h->space = space;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
BrotliFillBitWindow16(br);
|
||||
@@ -630,16 +636,17 @@ static BrotliDecoderErrorCode ReadSymbolCodeLengths(
|
||||
symbol_lists, code_length_histo, next_symbol);
|
||||
}
|
||||
}
|
||||
s->space = space;
|
||||
h->space = space;
|
||||
return BROTLI_DECODER_SUCCESS;
|
||||
}
|
||||
|
||||
static BrotliDecoderErrorCode SafeReadSymbolCodeLengths(
|
||||
uint32_t alphabet_size, BrotliDecoderState* s) {
|
||||
BrotliBitReader* br = &s->br;
|
||||
BrotliMetablockHeaderArena* h = &s->arena.header;
|
||||
BROTLI_BOOL get_byte = BROTLI_FALSE;
|
||||
while (s->symbol < alphabet_size && s->space > 0) {
|
||||
const HuffmanCode* p = s->table;
|
||||
while (h->symbol < alphabet_size && h->space > 0) {
|
||||
const HuffmanCode* p = h->table;
|
||||
uint32_t code_len;
|
||||
uint32_t available_bits;
|
||||
uint32_t bits = 0;
|
||||
@@ -659,9 +666,9 @@ static BrotliDecoderErrorCode SafeReadSymbolCodeLengths(
|
||||
code_len = BROTLI_HC_FAST_LOAD_VALUE(p); /* code_len == 0..17 */
|
||||
if (code_len < BROTLI_REPEAT_PREVIOUS_CODE_LENGTH) {
|
||||
BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p));
|
||||
ProcessSingleCodeLength(code_len, &s->symbol, &s->repeat, &s->space,
|
||||
&s->prev_code_len, s->symbol_lists, s->code_length_histo,
|
||||
s->next_symbol);
|
||||
ProcessSingleCodeLength(code_len, &h->symbol, &h->repeat, &h->space,
|
||||
&h->prev_code_len, h->symbol_lists, h->code_length_histo,
|
||||
h->next_symbol);
|
||||
} else { /* code_len == 16..17, extra_bits == 2..3 */
|
||||
uint32_t extra_bits = code_len - 14U;
|
||||
uint32_t repeat_delta = (bits >> BROTLI_HC_FAST_LOAD_BITS(p)) &
|
||||
@@ -672,9 +679,9 @@ static BrotliDecoderErrorCode SafeReadSymbolCodeLengths(
|
||||
}
|
||||
BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p) + extra_bits);
|
||||
ProcessRepeatedCodeLength(code_len, repeat_delta, alphabet_size,
|
||||
&s->symbol, &s->repeat, &s->space, &s->prev_code_len,
|
||||
&s->repeat_code_len, s->symbol_lists, s->code_length_histo,
|
||||
s->next_symbol);
|
||||
&h->symbol, &h->repeat, &h->space, &h->prev_code_len,
|
||||
&h->repeat_code_len, h->symbol_lists, h->code_length_histo,
|
||||
h->next_symbol);
|
||||
}
|
||||
}
|
||||
return BROTLI_DECODER_SUCCESS;
|
||||
@@ -684,9 +691,10 @@ static BrotliDecoderErrorCode SafeReadSymbolCodeLengths(
|
||||
Each code is 2..4 bits long. In total 30..72 bits are used. */
|
||||
static BrotliDecoderErrorCode ReadCodeLengthCodeLengths(BrotliDecoderState* s) {
|
||||
BrotliBitReader* br = &s->br;
|
||||
uint32_t num_codes = s->repeat;
|
||||
unsigned space = s->space;
|
||||
uint32_t i = s->sub_loop_counter;
|
||||
BrotliMetablockHeaderArena* h = &s->arena.header;
|
||||
uint32_t num_codes = h->repeat;
|
||||
unsigned space = h->space;
|
||||
uint32_t i = h->sub_loop_counter;
|
||||
for (; i < BROTLI_CODE_LENGTH_CODES; ++i) {
|
||||
const uint8_t code_len_idx = kCodeLengthCodeOrder[i];
|
||||
uint32_t ix;
|
||||
@@ -699,21 +707,21 @@ static BrotliDecoderErrorCode ReadCodeLengthCodeLengths(BrotliDecoderState* s) {
|
||||
ix = 0;
|
||||
}
|
||||
if (kCodeLengthPrefixLength[ix] > available_bits) {
|
||||
s->sub_loop_counter = i;
|
||||
s->repeat = num_codes;
|
||||
s->space = space;
|
||||
s->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
|
||||
h->sub_loop_counter = i;
|
||||
h->repeat = num_codes;
|
||||
h->space = space;
|
||||
h->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
}
|
||||
v = kCodeLengthPrefixValue[ix];
|
||||
BrotliDropBits(br, kCodeLengthPrefixLength[ix]);
|
||||
s->code_length_code_lengths[code_len_idx] = (uint8_t)v;
|
||||
BROTLI_LOG_ARRAY_INDEX(s->code_length_code_lengths, code_len_idx);
|
||||
h->code_length_code_lengths[code_len_idx] = (uint8_t)v;
|
||||
BROTLI_LOG_ARRAY_INDEX(h->code_length_code_lengths, code_len_idx);
|
||||
if (v != 0) {
|
||||
space = space - (32U >> v);
|
||||
++num_codes;
|
||||
++s->code_length_histo[v];
|
||||
++h->code_length_histo[v];
|
||||
if (space - 1U >= 32U) {
|
||||
/* space is 0 or wrapped around. */
|
||||
break;
|
||||
@@ -737,49 +745,48 @@ static BrotliDecoderErrorCode ReadCodeLengthCodeLengths(BrotliDecoderState* s) {
|
||||
encoded with predefined entropy code. 32 - 74 bits are used.
|
||||
B.2) Decoded table is used to decode code lengths of symbols in resulting
|
||||
Huffman table. In worst case 3520 bits are read. */
|
||||
static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size,
|
||||
uint32_t max_symbol,
|
||||
static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size_max,
|
||||
uint32_t alphabet_size_limit,
|
||||
HuffmanCode* table,
|
||||
uint32_t* opt_table_size,
|
||||
BrotliDecoderState* s) {
|
||||
BrotliBitReader* br = &s->br;
|
||||
/* Unnecessary masking, but might be good for safety. */
|
||||
alphabet_size &= 0x7FF;
|
||||
BrotliMetablockHeaderArena* h = &s->arena.header;
|
||||
/* State machine. */
|
||||
for (;;) {
|
||||
switch (s->substate_huffman) {
|
||||
switch (h->substate_huffman) {
|
||||
case BROTLI_STATE_HUFFMAN_NONE:
|
||||
if (!BrotliSafeReadBits(br, 2, &s->sub_loop_counter)) {
|
||||
if (!BrotliSafeReadBits(br, 2, &h->sub_loop_counter)) {
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
BROTLI_LOG_UINT(s->sub_loop_counter);
|
||||
BROTLI_LOG_UINT(h->sub_loop_counter);
|
||||
/* The value is used as follows:
|
||||
1 for simple code;
|
||||
0 for no skipping, 2 skips 2 code lengths, 3 skips 3 code lengths */
|
||||
if (s->sub_loop_counter != 1) {
|
||||
s->space = 32;
|
||||
s->repeat = 0; /* num_codes */
|
||||
memset(&s->code_length_histo[0], 0, sizeof(s->code_length_histo[0]) *
|
||||
if (h->sub_loop_counter != 1) {
|
||||
h->space = 32;
|
||||
h->repeat = 0; /* num_codes */
|
||||
memset(&h->code_length_histo[0], 0, sizeof(h->code_length_histo[0]) *
|
||||
(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH + 1));
|
||||
memset(&s->code_length_code_lengths[0], 0,
|
||||
sizeof(s->code_length_code_lengths));
|
||||
s->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
|
||||
memset(&h->code_length_code_lengths[0], 0,
|
||||
sizeof(h->code_length_code_lengths));
|
||||
h->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
|
||||
continue;
|
||||
}
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_HUFFMAN_SIMPLE_SIZE:
|
||||
/* Read symbols, codes & code lengths directly. */
|
||||
if (!BrotliSafeReadBits(br, 2, &s->symbol)) { /* num_symbols */
|
||||
s->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_SIZE;
|
||||
if (!BrotliSafeReadBits(br, 2, &h->symbol)) { /* num_symbols */
|
||||
h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_SIZE;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
s->sub_loop_counter = 0;
|
||||
h->sub_loop_counter = 0;
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_HUFFMAN_SIMPLE_READ: {
|
||||
BrotliDecoderErrorCode result =
|
||||
ReadSimpleHuffmanSymbols(alphabet_size, max_symbol, s);
|
||||
ReadSimpleHuffmanSymbols(alphabet_size_max, alphabet_size_limit, s);
|
||||
if (result != BROTLI_DECODER_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
@@ -788,21 +795,21 @@ static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size,
|
||||
|
||||
case BROTLI_STATE_HUFFMAN_SIMPLE_BUILD: {
|
||||
uint32_t table_size;
|
||||
if (s->symbol == 3) {
|
||||
if (h->symbol == 3) {
|
||||
uint32_t bits;
|
||||
if (!BrotliSafeReadBits(br, 1, &bits)) {
|
||||
s->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_BUILD;
|
||||
h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_BUILD;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
s->symbol += bits;
|
||||
h->symbol += bits;
|
||||
}
|
||||
BROTLI_LOG_UINT(s->symbol);
|
||||
BROTLI_LOG_UINT(h->symbol);
|
||||
table_size = BrotliBuildSimpleHuffmanTable(
|
||||
table, HUFFMAN_TABLE_BITS, s->symbols_lists_array, s->symbol);
|
||||
table, HUFFMAN_TABLE_BITS, h->symbols_lists_array, h->symbol);
|
||||
if (opt_table_size) {
|
||||
*opt_table_size = table_size;
|
||||
}
|
||||
s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
|
||||
h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
|
||||
return BROTLI_DECODER_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -813,44 +820,45 @@ static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size,
|
||||
if (result != BROTLI_DECODER_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
BrotliBuildCodeLengthsHuffmanTable(s->table,
|
||||
s->code_length_code_lengths,
|
||||
s->code_length_histo);
|
||||
memset(&s->code_length_histo[0], 0, sizeof(s->code_length_histo));
|
||||
BrotliBuildCodeLengthsHuffmanTable(h->table,
|
||||
h->code_length_code_lengths,
|
||||
h->code_length_histo);
|
||||
memset(&h->code_length_histo[0], 0, sizeof(h->code_length_histo));
|
||||
for (i = 0; i <= BROTLI_HUFFMAN_MAX_CODE_LENGTH; ++i) {
|
||||
s->next_symbol[i] = (int)i - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
|
||||
s->symbol_lists[s->next_symbol[i]] = 0xFFFF;
|
||||
h->next_symbol[i] = (int)i - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
|
||||
h->symbol_lists[h->next_symbol[i]] = 0xFFFF;
|
||||
}
|
||||
|
||||
s->symbol = 0;
|
||||
s->prev_code_len = BROTLI_INITIAL_REPEATED_CODE_LENGTH;
|
||||
s->repeat = 0;
|
||||
s->repeat_code_len = 0;
|
||||
s->space = 32768;
|
||||
s->substate_huffman = BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS;
|
||||
h->symbol = 0;
|
||||
h->prev_code_len = BROTLI_INITIAL_REPEATED_CODE_LENGTH;
|
||||
h->repeat = 0;
|
||||
h->repeat_code_len = 0;
|
||||
h->space = 32768;
|
||||
h->substate_huffman = BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS;
|
||||
}
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS: {
|
||||
uint32_t table_size;
|
||||
BrotliDecoderErrorCode result = ReadSymbolCodeLengths(max_symbol, s);
|
||||
BrotliDecoderErrorCode result = ReadSymbolCodeLengths(
|
||||
alphabet_size_limit, s);
|
||||
if (result == BROTLI_DECODER_NEEDS_MORE_INPUT) {
|
||||
result = SafeReadSymbolCodeLengths(max_symbol, s);
|
||||
result = SafeReadSymbolCodeLengths(alphabet_size_limit, s);
|
||||
}
|
||||
if (result != BROTLI_DECODER_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (s->space != 0) {
|
||||
BROTLI_LOG(("[ReadHuffmanCode] space = %d\n", (int)s->space));
|
||||
if (h->space != 0) {
|
||||
BROTLI_LOG(("[ReadHuffmanCode] space = %d\n", (int)h->space));
|
||||
return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE);
|
||||
}
|
||||
table_size = BrotliBuildHuffmanTable(
|
||||
table, HUFFMAN_TABLE_BITS, s->symbol_lists, s->code_length_histo);
|
||||
table, HUFFMAN_TABLE_BITS, h->symbol_lists, h->code_length_histo);
|
||||
if (opt_table_size) {
|
||||
*opt_table_size = table_size;
|
||||
}
|
||||
s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
|
||||
h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
|
||||
return BROTLI_DECODER_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -867,8 +875,8 @@ static BROTLI_INLINE uint32_t ReadBlockLength(const HuffmanCode* table,
|
||||
uint32_t code;
|
||||
uint32_t nbits;
|
||||
code = ReadSymbol(table, br);
|
||||
nbits = kBlockLengthPrefixCode[code].nbits; /* nbits == 2..24 */
|
||||
return kBlockLengthPrefixCode[code].offset + BrotliReadBits(br, nbits);
|
||||
nbits = _kBrotliPrefixCodeRanges[code].nbits; /* nbits == 2..24 */
|
||||
return _kBrotliPrefixCodeRanges[code].offset + BrotliReadBits24(br, nbits);
|
||||
}
|
||||
|
||||
/* WARNING: if state is not BROTLI_STATE_READ_BLOCK_LENGTH_NONE, then
|
||||
@@ -886,13 +894,14 @@ static BROTLI_INLINE BROTLI_BOOL SafeReadBlockLength(
|
||||
}
|
||||
{
|
||||
uint32_t bits;
|
||||
uint32_t nbits = kBlockLengthPrefixCode[index].nbits; /* nbits == 2..24 */
|
||||
uint32_t nbits = _kBrotliPrefixCodeRanges[index].nbits;
|
||||
uint32_t offset = _kBrotliPrefixCodeRanges[index].offset;
|
||||
if (!BrotliSafeReadBits(br, nbits, &bits)) {
|
||||
s->block_length_index = index;
|
||||
s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX;
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
*result = kBlockLengthPrefixCode[index].offset + bits;
|
||||
*result = offset + bits;
|
||||
s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
@@ -952,22 +961,22 @@ static BROTLI_NOINLINE void InverseMoveToFrontTransform(
|
||||
/* Decodes a series of Huffman table using ReadHuffmanCode function. */
|
||||
static BrotliDecoderErrorCode HuffmanTreeGroupDecode(
|
||||
HuffmanTreeGroup* group, BrotliDecoderState* s) {
|
||||
if (s->substate_tree_group != BROTLI_STATE_TREE_GROUP_LOOP) {
|
||||
s->next = group->codes;
|
||||
s->htree_index = 0;
|
||||
s->substate_tree_group = BROTLI_STATE_TREE_GROUP_LOOP;
|
||||
BrotliMetablockHeaderArena* h = &s->arena.header;
|
||||
if (h->substate_tree_group != BROTLI_STATE_TREE_GROUP_LOOP) {
|
||||
h->next = group->codes;
|
||||
h->htree_index = 0;
|
||||
h->substate_tree_group = BROTLI_STATE_TREE_GROUP_LOOP;
|
||||
}
|
||||
while (s->htree_index < group->num_htrees) {
|
||||
while (h->htree_index < group->num_htrees) {
|
||||
uint32_t table_size;
|
||||
BrotliDecoderErrorCode result =
|
||||
ReadHuffmanCode(group->alphabet_size, group->max_symbol,
|
||||
s->next, &table_size, s);
|
||||
BrotliDecoderErrorCode result = ReadHuffmanCode(group->alphabet_size_max,
|
||||
group->alphabet_size_limit, h->next, &table_size, s);
|
||||
if (result != BROTLI_DECODER_SUCCESS) return result;
|
||||
group->htrees[s->htree_index] = s->next;
|
||||
s->next += table_size;
|
||||
++s->htree_index;
|
||||
group->htrees[h->htree_index] = h->next;
|
||||
h->next += table_size;
|
||||
++h->htree_index;
|
||||
}
|
||||
s->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
|
||||
h->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
|
||||
return BROTLI_DECODER_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -985,15 +994,16 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size,
|
||||
BrotliDecoderState* s) {
|
||||
BrotliBitReader* br = &s->br;
|
||||
BrotliDecoderErrorCode result = BROTLI_DECODER_SUCCESS;
|
||||
BrotliMetablockHeaderArena* h = &s->arena.header;
|
||||
|
||||
switch ((int)s->substate_context_map) {
|
||||
switch ((int)h->substate_context_map) {
|
||||
case BROTLI_STATE_CONTEXT_MAP_NONE:
|
||||
result = DecodeVarLenUint8(s, br, num_htrees);
|
||||
if (result != BROTLI_DECODER_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
(*num_htrees)++;
|
||||
s->context_index = 0;
|
||||
h->context_index = 0;
|
||||
BROTLI_LOG_UINT(context_map_size);
|
||||
BROTLI_LOG_UINT(*num_htrees);
|
||||
*context_map_arg =
|
||||
@@ -1005,7 +1015,7 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size,
|
||||
memset(*context_map_arg, 0, (size_t)context_map_size);
|
||||
return BROTLI_DECODER_SUCCESS;
|
||||
}
|
||||
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_READ_PREFIX;
|
||||
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_READ_PREFIX;
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_CONTEXT_MAP_READ_PREFIX: {
|
||||
@@ -1016,38 +1026,38 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size,
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
if ((bits & 1) != 0) { /* Use RLE for zeros. */
|
||||
s->max_run_length_prefix = (bits >> 1) + 1;
|
||||
h->max_run_length_prefix = (bits >> 1) + 1;
|
||||
BrotliDropBits(br, 5);
|
||||
} else {
|
||||
s->max_run_length_prefix = 0;
|
||||
h->max_run_length_prefix = 0;
|
||||
BrotliDropBits(br, 1);
|
||||
}
|
||||
BROTLI_LOG_UINT(s->max_run_length_prefix);
|
||||
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_HUFFMAN;
|
||||
BROTLI_LOG_UINT(h->max_run_length_prefix);
|
||||
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_HUFFMAN;
|
||||
}
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_CONTEXT_MAP_HUFFMAN: {
|
||||
uint32_t alphabet_size = *num_htrees + s->max_run_length_prefix;
|
||||
uint32_t alphabet_size = *num_htrees + h->max_run_length_prefix;
|
||||
result = ReadHuffmanCode(alphabet_size, alphabet_size,
|
||||
s->context_map_table, NULL, s);
|
||||
h->context_map_table, NULL, s);
|
||||
if (result != BROTLI_DECODER_SUCCESS) return result;
|
||||
s->code = 0xFFFF;
|
||||
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_DECODE;
|
||||
h->code = 0xFFFF;
|
||||
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_DECODE;
|
||||
}
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_CONTEXT_MAP_DECODE: {
|
||||
uint32_t context_index = s->context_index;
|
||||
uint32_t max_run_length_prefix = s->max_run_length_prefix;
|
||||
uint32_t context_index = h->context_index;
|
||||
uint32_t max_run_length_prefix = h->max_run_length_prefix;
|
||||
uint8_t* context_map = *context_map_arg;
|
||||
uint32_t code = s->code;
|
||||
uint32_t code = h->code;
|
||||
BROTLI_BOOL skip_preamble = (code != 0xFFFF);
|
||||
while (context_index < context_map_size || skip_preamble) {
|
||||
if (!skip_preamble) {
|
||||
if (!SafeReadSymbol(s->context_map_table, br, &code)) {
|
||||
s->code = 0xFFFF;
|
||||
s->context_index = context_index;
|
||||
if (!SafeReadSymbol(h->context_map_table, br, &code)) {
|
||||
h->code = 0xFFFF;
|
||||
h->context_index = context_index;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
BROTLI_LOG_UINT(code);
|
||||
@@ -1068,8 +1078,8 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size,
|
||||
{
|
||||
uint32_t reps;
|
||||
if (!BrotliSafeReadBits(br, code, &reps)) {
|
||||
s->code = code;
|
||||
s->context_index = context_index;
|
||||
h->code = code;
|
||||
h->context_index = context_index;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
reps += 1U << code;
|
||||
@@ -1089,13 +1099,13 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size,
|
||||
case BROTLI_STATE_CONTEXT_MAP_TRANSFORM: {
|
||||
uint32_t bits;
|
||||
if (!BrotliSafeReadBits(br, 1, &bits)) {
|
||||
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_TRANSFORM;
|
||||
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_TRANSFORM;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
if (bits != 0) {
|
||||
InverseMoveToFrontTransform(*context_map_arg, context_map_size, s);
|
||||
}
|
||||
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
|
||||
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
|
||||
return BROTLI_DECODER_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1457,32 +1467,28 @@ static BrotliDecoderErrorCode ReadContextModes(BrotliDecoderState* s) {
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void TakeDistanceFromRingBuffer(BrotliDecoderState* s) {
|
||||
if (s->distance_code == 0) {
|
||||
--s->dist_rb_idx;
|
||||
s->distance_code = s->dist_rb[s->dist_rb_idx & 3];
|
||||
int offset = s->distance_code - 3;
|
||||
if (s->distance_code <= 3) {
|
||||
/* Compensate double distance-ring-buffer roll for dictionary items. */
|
||||
s->distance_context = 1;
|
||||
s->distance_context = 1 >> s->distance_code;
|
||||
s->distance_code = s->dist_rb[(s->dist_rb_idx - offset) & 3];
|
||||
s->dist_rb_idx -= s->distance_context;
|
||||
} else {
|
||||
int distance_code = s->distance_code << 1;
|
||||
/* kDistanceShortCodeIndexOffset has 2-bit values from LSB:
|
||||
3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 */
|
||||
const uint32_t kDistanceShortCodeIndexOffset = 0xAAAFFF1B;
|
||||
/* kDistanceShortCodeValueOffset has 2-bit values from LSB:
|
||||
-0, 0,-0, 0,-1, 1,-2, 2,-3, 3,-1, 1,-2, 2,-3, 3 */
|
||||
const uint32_t kDistanceShortCodeValueOffset = 0xFA5FA500;
|
||||
int v = (s->dist_rb_idx +
|
||||
(int)(kDistanceShortCodeIndexOffset >> distance_code)) & 0x3;
|
||||
s->distance_code = s->dist_rb[v];
|
||||
v = (int)(kDistanceShortCodeValueOffset >> distance_code) & 0x3;
|
||||
if ((distance_code & 0x3) != 0) {
|
||||
s->distance_code += v;
|
||||
int index_delta = 3;
|
||||
int delta;
|
||||
int base = s->distance_code - 10;
|
||||
if (s->distance_code < 10) {
|
||||
base = s->distance_code - 4;
|
||||
} else {
|
||||
s->distance_code -= v;
|
||||
if (s->distance_code <= 0) {
|
||||
/* A huge distance will cause a BROTLI_FAILURE() soon.
|
||||
This is a little faster than failing here. */
|
||||
s->distance_code = 0x7FFFFFFF;
|
||||
}
|
||||
index_delta = 2;
|
||||
}
|
||||
/* Unpack one of six 4-bit values. */
|
||||
delta = ((0x605142 >> (4 * base)) & 0xF) - 3;
|
||||
s->distance_code = s->dist_rb[(s->dist_rb_idx + index_delta) & 0x3] + delta;
|
||||
if (s->distance_code <= 0) {
|
||||
/* A huge distance will cause a BROTLI_FAILURE() soon.
|
||||
This is a little faster than failing here. */
|
||||
s->distance_code = 0x7FFFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1497,62 +1503,153 @@ static BROTLI_INLINE BROTLI_BOOL SafeReadBits(
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE BROTLI_BOOL SafeReadBits32(
|
||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||
if (n_bits != 0) {
|
||||
return BrotliSafeReadBits32(br, n_bits, val);
|
||||
} else {
|
||||
*val = 0;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
RFC 7932 Section 4 with "..." shortenings and "[]" emendations.
|
||||
|
||||
Each distance ... is represented with a pair <distance code, extra bits>...
|
||||
The distance code is encoded using a prefix code... The number of extra bits
|
||||
can be 0..24... Two additional parameters: NPOSTFIX (0..3), and ...
|
||||
NDIRECT (0..120) ... are encoded in the meta-block header...
|
||||
|
||||
The first 16 distance symbols ... reference past distances... ring buffer ...
|
||||
Next NDIRECT distance symbols ... represent distances from 1 to NDIRECT...
|
||||
[For] distance symbols 16 + NDIRECT and greater ... the number of extra bits
|
||||
... is given by the following formula:
|
||||
|
||||
[ xcode = dcode - NDIRECT - 16 ]
|
||||
ndistbits = 1 + [ xcode ] >> (NPOSTFIX + 1)
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
/*
|
||||
RFC 7932 Section 9.2 with "..." shortenings and "[]" emendations.
|
||||
|
||||
... to get the actual value of the parameter NDIRECT, left-shift this
|
||||
four-bit number by NPOSTFIX bits ...
|
||||
*/
|
||||
|
||||
/* Remaining formulas from RFC 7932 Section 4 could be rewritten as following:
|
||||
|
||||
alphabet_size = 16 + NDIRECT + (max_distbits << (NPOSTFIX + 1))
|
||||
|
||||
half = ((xcode >> NPOSTFIX) & 1) << ndistbits
|
||||
postfix = xcode & ((1 << NPOSTFIX) - 1)
|
||||
range_start = 2 * (1 << ndistbits - 1 - 1)
|
||||
|
||||
distance = (range_start + half + extra) << NPOSTFIX + postfix + NDIRECT + 1
|
||||
|
||||
NB: ndistbits >= 1 -> range_start >= 0
|
||||
NB: range_start has factor 2, as the range is covered by 2 "halves"
|
||||
NB: extra -1 offset in range_start formula covers the absence of
|
||||
ndistbits = 0 case
|
||||
NB: when NPOSTFIX = 0, NDIRECT is not greater than 15
|
||||
|
||||
In other words, xcode has the following binary structure - XXXHPPP:
|
||||
- XXX represent the number of extra distance bits
|
||||
- H selects upper / lower range of distances
|
||||
- PPP represent "postfix"
|
||||
|
||||
"Regular" distance encoding has NPOSTFIX = 0; omitting the postfix part
|
||||
simplifies distance calculation.
|
||||
|
||||
Using NPOSTFIX > 0 allows cheaper encoding of regular structures, e.g. where
|
||||
most of distances have the same reminder of division by 2/4/8. For example,
|
||||
the table of int32_t values that come from different sources; if it is likely
|
||||
that 3 highest bytes of values from the same source are the same, then
|
||||
copy distance often looks like 4x + y.
|
||||
|
||||
Distance calculation could be rewritten to:
|
||||
|
||||
ndistbits = NDISTBITS(NDIRECT, NPOSTFIX)[dcode]
|
||||
distance = OFFSET(NDIRECT, NPOSTFIX)[dcode] + extra << NPOSTFIX
|
||||
|
||||
NDISTBITS and OFFSET could be pre-calculated, as NDIRECT and NPOSTFIX could
|
||||
change only once per meta-block.
|
||||
*/
|
||||
|
||||
/* Calculates distance lookup table.
|
||||
NB: it is possible to have all 64 tables precalculated. */
|
||||
static void CalculateDistanceLut(BrotliDecoderState* s) {
|
||||
BrotliMetablockBodyArena* b = &s->arena.body;
|
||||
uint32_t npostfix = s->distance_postfix_bits;
|
||||
uint32_t ndirect = s->num_direct_distance_codes;
|
||||
uint32_t alphabet_size_limit = s->distance_hgroup.alphabet_size_limit;
|
||||
uint32_t postfix = 1u << npostfix;
|
||||
uint32_t j;
|
||||
uint32_t bits = 1;
|
||||
uint32_t half = 0;
|
||||
|
||||
/* Skip short codes. */
|
||||
uint32_t i = BROTLI_NUM_DISTANCE_SHORT_CODES;
|
||||
|
||||
/* Fill direct codes. */
|
||||
for (j = 0; j < ndirect; ++j) {
|
||||
b->dist_extra_bits[i] = 0;
|
||||
b->dist_offset[i] = j + 1;
|
||||
++i;
|
||||
}
|
||||
|
||||
/* Fill regular distance codes. */
|
||||
while (i < alphabet_size_limit) {
|
||||
uint32_t base = ndirect + ((((2 + half) << bits) - 4) << npostfix) + 1;
|
||||
/* Always fill the complete group. */
|
||||
for (j = 0; j < postfix; ++j) {
|
||||
b->dist_extra_bits[i] = (uint8_t)bits;
|
||||
b->dist_offset[i] = base + j;
|
||||
++i;
|
||||
}
|
||||
bits = bits + half;
|
||||
half = half ^ 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Precondition: s->distance_code < 0. */
|
||||
static BROTLI_INLINE BROTLI_BOOL ReadDistanceInternal(
|
||||
int safe, BrotliDecoderState* s, BrotliBitReader* br) {
|
||||
int distval;
|
||||
BrotliMetablockBodyArena* b = &s->arena.body;
|
||||
uint32_t code;
|
||||
uint32_t bits;
|
||||
BrotliBitReaderState memento;
|
||||
HuffmanCode* distance_tree = s->distance_hgroup.htrees[s->dist_htree_index];
|
||||
if (!safe) {
|
||||
s->distance_code = (int)ReadSymbol(distance_tree, br);
|
||||
code = ReadSymbol(distance_tree, br);
|
||||
} else {
|
||||
uint32_t code;
|
||||
BrotliBitReaderSaveState(br, &memento);
|
||||
if (!SafeReadSymbol(distance_tree, br, &code)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
s->distance_code = (int)code;
|
||||
}
|
||||
--s->block_length[2];
|
||||
/* Convert the distance code to the actual distance by possibly
|
||||
looking up past distances from the s->ringbuffer. */
|
||||
looking up past distances from the s->dist_rb. */
|
||||
s->distance_context = 0;
|
||||
if ((s->distance_code & ~0xF) == 0) {
|
||||
if ((code & ~0xFu) == 0) {
|
||||
s->distance_code = (int)code;
|
||||
TakeDistanceFromRingBuffer(s);
|
||||
--s->block_length[2];
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
distval = s->distance_code - (int)s->num_direct_distance_codes;
|
||||
if (distval >= 0) {
|
||||
uint32_t nbits;
|
||||
int postfix;
|
||||
int offset;
|
||||
if (!safe && (s->distance_postfix_bits == 0)) {
|
||||
nbits = ((uint32_t)distval >> 1) + 1;
|
||||
offset = ((2 + (distval & 1)) << nbits) - 4;
|
||||
s->distance_code = (int)s->num_direct_distance_codes + offset +
|
||||
(int)BrotliReadBits(br, nbits);
|
||||
} else {
|
||||
/* This branch also works well when s->distance_postfix_bits == 0. */
|
||||
uint32_t bits;
|
||||
postfix = distval & s->distance_postfix_mask;
|
||||
distval >>= s->distance_postfix_bits;
|
||||
nbits = ((uint32_t)distval >> 1) + 1;
|
||||
if (safe) {
|
||||
if (!SafeReadBits(br, nbits, &bits)) {
|
||||
s->distance_code = -1; /* Restore precondition. */
|
||||
BrotliBitReaderRestoreState(br, &memento);
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
} else {
|
||||
bits = BrotliReadBits(br, nbits);
|
||||
}
|
||||
offset = ((2 + (distval & 1)) << nbits) - 4;
|
||||
s->distance_code = (int)s->num_direct_distance_codes +
|
||||
((offset + (int)bits) << s->distance_postfix_bits) + postfix;
|
||||
if (!safe) {
|
||||
bits = BrotliReadBits32(br, b->dist_extra_bits[code]);
|
||||
} else {
|
||||
if (!SafeReadBits32(br, b->dist_extra_bits[code], &bits)) {
|
||||
++s->block_length[2];
|
||||
BrotliBitReaderRestoreState(br, &memento);
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
s->distance_code = s->distance_code - BROTLI_NUM_DISTANCE_SHORT_CODES + 1;
|
||||
--s->block_length[2];
|
||||
s->distance_code =
|
||||
(int)(b->dist_offset[code] + (bits << s->distance_postfix_bits));
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
@@ -1588,9 +1685,9 @@ static BROTLI_INLINE BROTLI_BOOL ReadCommandInternal(
|
||||
*insert_length = v.insert_len_offset;
|
||||
if (!safe) {
|
||||
if (BROTLI_PREDICT_FALSE(v.insert_len_extra_bits != 0)) {
|
||||
insert_len_extra = BrotliReadBits(br, v.insert_len_extra_bits);
|
||||
insert_len_extra = BrotliReadBits24(br, v.insert_len_extra_bits);
|
||||
}
|
||||
copy_length = BrotliReadBits(br, v.copy_len_extra_bits);
|
||||
copy_length = BrotliReadBits24(br, v.copy_len_extra_bits);
|
||||
} else {
|
||||
if (!SafeReadBits(br, v.insert_len_extra_bits, &insert_len_extra) ||
|
||||
!SafeReadBits(br, v.copy_len_extra_bits, ©_length)) {
|
||||
@@ -1935,21 +2032,6 @@ static BROTLI_NOINLINE BrotliDecoderErrorCode SafeProcessCommands(
|
||||
return ProcessCommandsInternal(1, s);
|
||||
}
|
||||
|
||||
/* Returns the maximum number of distance symbols which can only represent
|
||||
distances not exceeding BROTLI_MAX_ALLOWED_DISTANCE. */
|
||||
static uint32_t BrotliMaxDistanceSymbol(uint32_t ndirect, uint32_t npostfix) {
|
||||
static const uint32_t bound[BROTLI_MAX_NPOSTFIX + 1] = {0, 4, 12, 28};
|
||||
static const uint32_t diff[BROTLI_MAX_NPOSTFIX + 1] = {73, 126, 228, 424};
|
||||
uint32_t postfix = 1U << npostfix;
|
||||
if (ndirect < bound[npostfix]) {
|
||||
return ndirect + diff[npostfix] + postfix;
|
||||
} else if (ndirect > bound[npostfix] + postfix) {
|
||||
return ndirect + diff[npostfix];
|
||||
} else {
|
||||
return bound[npostfix] + diff[npostfix] + postfix;
|
||||
}
|
||||
}
|
||||
|
||||
BrotliDecoderResult BrotliDecoderDecompress(
|
||||
size_t encoded_size, const uint8_t* encoded_buffer, size_t* decoded_size,
|
||||
uint8_t* decoded_buffer) {
|
||||
@@ -2167,33 +2249,23 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
|
||||
s->state = BROTLI_STATE_UNCOMPRESSED;
|
||||
break;
|
||||
}
|
||||
s->state = BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER;
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER: {
|
||||
BrotliMetablockHeaderArena* h = &s->arena.header;
|
||||
s->loop_counter = 0;
|
||||
/* Initialize compressed metablock header arena. */
|
||||
h->sub_loop_counter = 0;
|
||||
/* Make small negative indexes addressable. */
|
||||
h->symbol_lists =
|
||||
&h->symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1];
|
||||
h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
|
||||
h->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
|
||||
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
|
||||
s->state = BROTLI_STATE_HUFFMAN_CODE_0;
|
||||
break;
|
||||
|
||||
case BROTLI_STATE_UNCOMPRESSED: {
|
||||
result = CopyUncompressedBlockToOutput(
|
||||
available_out, next_out, total_out, s);
|
||||
if (result != BROTLI_DECODER_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
s->state = BROTLI_STATE_METABLOCK_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
case BROTLI_STATE_METADATA:
|
||||
for (; s->meta_block_remaining_len > 0; --s->meta_block_remaining_len) {
|
||||
uint32_t bits;
|
||||
/* Read one byte and ignore it. */
|
||||
if (!BrotliSafeReadBits(br, 8, &bits)) {
|
||||
result = BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result == BROTLI_DECODER_SUCCESS) {
|
||||
s->state = BROTLI_STATE_METABLOCK_DONE;
|
||||
}
|
||||
break;
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_HUFFMAN_CODE_0:
|
||||
if (s->loop_counter >= 3) {
|
||||
@@ -2247,6 +2319,30 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
|
||||
break;
|
||||
}
|
||||
|
||||
case BROTLI_STATE_UNCOMPRESSED: {
|
||||
result = CopyUncompressedBlockToOutput(
|
||||
available_out, next_out, total_out, s);
|
||||
if (result != BROTLI_DECODER_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
s->state = BROTLI_STATE_METABLOCK_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
case BROTLI_STATE_METADATA:
|
||||
for (; s->meta_block_remaining_len > 0; --s->meta_block_remaining_len) {
|
||||
uint32_t bits;
|
||||
/* Read one byte and ignore it. */
|
||||
if (!BrotliSafeReadBits(br, 8, &bits)) {
|
||||
result = BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result == BROTLI_DECODER_SUCCESS) {
|
||||
s->state = BROTLI_STATE_METABLOCK_DONE;
|
||||
}
|
||||
break;
|
||||
|
||||
case BROTLI_STATE_METABLOCK_HEADER_2: {
|
||||
uint32_t bits;
|
||||
if (!BrotliSafeReadBits(br, 6, &bits)) {
|
||||
@@ -2255,11 +2351,9 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
|
||||
}
|
||||
s->distance_postfix_bits = bits & BitMask(2);
|
||||
bits >>= 2;
|
||||
s->num_direct_distance_codes = BROTLI_NUM_DISTANCE_SHORT_CODES +
|
||||
(bits << s->distance_postfix_bits);
|
||||
s->num_direct_distance_codes = bits << s->distance_postfix_bits;
|
||||
BROTLI_LOG_UINT(s->num_direct_distance_codes);
|
||||
BROTLI_LOG_UINT(s->distance_postfix_bits);
|
||||
s->distance_postfix_mask = (int)BitMask(s->distance_postfix_bits);
|
||||
s->context_modes =
|
||||
(uint8_t*)BROTLI_DECODER_ALLOC(s, (size_t)s->num_block_types[0]);
|
||||
if (s->context_modes == 0) {
|
||||
@@ -2291,17 +2385,19 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_CONTEXT_MAP_2: {
|
||||
uint32_t num_direct_codes =
|
||||
s->num_direct_distance_codes - BROTLI_NUM_DISTANCE_SHORT_CODES;
|
||||
uint32_t num_distance_codes = BROTLI_DISTANCE_ALPHABET_SIZE(
|
||||
s->distance_postfix_bits, num_direct_codes,
|
||||
(s->large_window ? BROTLI_LARGE_MAX_DISTANCE_BITS :
|
||||
BROTLI_MAX_DISTANCE_BITS));
|
||||
uint32_t max_distance_symbol = (s->large_window ?
|
||||
BrotliMaxDistanceSymbol(
|
||||
num_direct_codes, s->distance_postfix_bits) :
|
||||
num_distance_codes);
|
||||
uint32_t npostfix = s->distance_postfix_bits;
|
||||
uint32_t ndirect = s->num_direct_distance_codes;
|
||||
uint32_t distance_alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
|
||||
npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS);
|
||||
uint32_t distance_alphabet_size_limit = distance_alphabet_size_max;
|
||||
BROTLI_BOOL allocation_success = BROTLI_TRUE;
|
||||
if (s->large_window) {
|
||||
BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit(
|
||||
BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect);
|
||||
distance_alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
|
||||
npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS);
|
||||
distance_alphabet_size_limit = limit.max_alphabet_size;
|
||||
}
|
||||
result = DecodeContextMap(
|
||||
s->num_block_types[2] << BROTLI_DISTANCE_CONTEXT_BITS,
|
||||
&s->num_dist_htrees, &s->dist_context_map, s);
|
||||
@@ -2315,8 +2411,8 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
|
||||
s, &s->insert_copy_hgroup, BROTLI_NUM_COMMAND_SYMBOLS,
|
||||
BROTLI_NUM_COMMAND_SYMBOLS, s->num_block_types[1]);
|
||||
allocation_success &= BrotliDecoderHuffmanTreeGroupInit(
|
||||
s, &s->distance_hgroup, num_distance_codes,
|
||||
max_distance_symbol, s->num_dist_htrees);
|
||||
s, &s->distance_hgroup, distance_alphabet_size_max,
|
||||
distance_alphabet_size_limit, s->num_dist_htrees);
|
||||
if (!allocation_success) {
|
||||
return SaveErrorCode(s,
|
||||
BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS));
|
||||
@@ -2338,18 +2434,24 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
|
||||
result = HuffmanTreeGroupDecode(hgroup, s);
|
||||
if (result != BROTLI_DECODER_SUCCESS) break;
|
||||
s->loop_counter++;
|
||||
if (s->loop_counter >= 3) {
|
||||
PrepareLiteralDecoding(s);
|
||||
s->dist_context_map_slice = s->dist_context_map;
|
||||
s->htree_command = s->insert_copy_hgroup.htrees[0];
|
||||
if (!BrotliEnsureRingBuffer(s)) {
|
||||
result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2);
|
||||
break;
|
||||
}
|
||||
s->state = BROTLI_STATE_COMMAND_BEGIN;
|
||||
if (s->loop_counter < 3) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
s->state = BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY;
|
||||
}
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY:
|
||||
PrepareLiteralDecoding(s);
|
||||
s->dist_context_map_slice = s->dist_context_map;
|
||||
s->htree_command = s->insert_copy_hgroup.htrees[0];
|
||||
if (!BrotliEnsureRingBuffer(s)) {
|
||||
result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2);
|
||||
break;
|
||||
}
|
||||
CalculateDistanceLut(s);
|
||||
s->state = BROTLI_STATE_COMMAND_BEGIN;
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_COMMAND_BEGIN:
|
||||
/* Fall through. */
|
||||
|
||||
@@ -18,12 +18,6 @@ extern "C" {
|
||||
|
||||
#define BROTLI_HUFFMAN_MAX_CODE_LENGTH 15
|
||||
|
||||
/* 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, 1112, 1144, 1176, 1208, 1240, 1272,
|
||||
1304, 1336, 1368, 1400, 1432, 1464, 1496, 1528};
|
||||
/* BROTLI_NUM_BLOCK_LEN_SYMBOLS == 26 */
|
||||
#define BROTLI_HUFFMAN_MAX_SIZE_26 396
|
||||
/* BROTLI_MAX_BLOCK_TYPE_SYMBOLS == 258 */
|
||||
@@ -82,7 +76,7 @@ typedef BROTLI_ALIGNED(4) uint32_t HuffmanCode;
|
||||
|
||||
static BROTLI_INLINE HuffmanCode ConstructHuffmanCode(const uint8_t bits,
|
||||
const uint16_t value) {
|
||||
return ((value & 0xFFFF) << 16) | (bits & 0xFF);
|
||||
return (HuffmanCode) ((value & 0xFFFF) << 16) | (bits & 0xFF);
|
||||
}
|
||||
|
||||
#define BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(H) uint32_t __fastload_##H = (*H)
|
||||
@@ -100,7 +94,7 @@ BROTLI_INTERNAL void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* root_table,
|
||||
/* Builds Huffman lookup table assuming code lengths are in symbol order.
|
||||
Returns size of resulting table. */
|
||||
BROTLI_INTERNAL uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||
int root_bits, const uint16_t* const symbol_lists, uint16_t* count_arg);
|
||||
int root_bits, const uint16_t* const symbol_lists, uint16_t* count);
|
||||
|
||||
/* Builds a simple Huffman table. The |num_symbols| parameter is to be
|
||||
interpreted as follows: 0 means 1 symbol, 1 means 2 symbols,
|
||||
@@ -110,13 +104,13 @@ 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. */
|
||||
/* max_symbol is needed due to simple codes since log2(alphabet_size) could be
|
||||
greater than log2(max_symbol). */
|
||||
/* alphabet_size_limit is needed due to simple codes, since
|
||||
log2(alphabet_size_max) could be greater than log2(alphabet_size_limit). */
|
||||
typedef struct {
|
||||
HuffmanCode** htrees;
|
||||
HuffmanCode* codes;
|
||||
uint16_t alphabet_size;
|
||||
uint16_t max_symbol;
|
||||
uint16_t alphabet_size_max;
|
||||
uint16_t alphabet_size_limit;
|
||||
uint16_t num_htrees;
|
||||
} HuffmanTreeGroup;
|
||||
|
||||
|
||||
@@ -13,24 +13,6 @@
|
||||
#include "../common/constants.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
/* Represents the range of values belonging to a prefix code:
|
||||
[offset, offset + 2^nbits) */
|
||||
struct PrefixCodeRange {
|
||||
uint16_t offset;
|
||||
uint8_t nbits;
|
||||
};
|
||||
|
||||
static const struct PrefixCodeRange
|
||||
kBlockLengthPrefixCode[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
|
||||
{ 1, 2}, { 5, 2}, { 9, 2}, { 13, 2},
|
||||
{ 17, 3}, { 25, 3}, { 33, 3}, { 41, 3},
|
||||
{ 49, 4}, { 65, 4}, { 81, 4}, { 97, 4},
|
||||
{ 113, 5}, { 145, 5}, { 177, 5}, { 209, 5},
|
||||
{ 241, 6}, { 305, 6}, { 369, 7}, { 497, 8},
|
||||
{ 753, 9}, { 1265, 10}, {2289, 11}, {4337, 12},
|
||||
{8433, 13}, {16625, 24}
|
||||
};
|
||||
|
||||
typedef struct CmdLutElement {
|
||||
uint8_t insert_len_extra_bits;
|
||||
uint8_t copy_len_extra_bits;
|
||||
|
||||
@@ -33,10 +33,7 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
|
||||
s->state = BROTLI_STATE_UNINITED;
|
||||
s->large_window = 0;
|
||||
s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE;
|
||||
s->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
|
||||
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
|
||||
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;
|
||||
|
||||
@@ -59,8 +56,6 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* 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;
|
||||
@@ -84,9 +79,6 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
|
||||
s->block_type_trees = NULL;
|
||||
s->block_len_trees = NULL;
|
||||
|
||||
/* Make small negative indexes addressable. */
|
||||
s->symbol_lists = &s->symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1];
|
||||
|
||||
s->mtf_upper_bound = 63;
|
||||
|
||||
s->dictionary = BrotliGetDictionary();
|
||||
@@ -142,17 +134,20 @@ void BrotliDecoderStateCleanup(BrotliDecoderState* s) {
|
||||
}
|
||||
|
||||
BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(BrotliDecoderState* s,
|
||||
HuffmanTreeGroup* group, uint32_t alphabet_size, uint32_t max_symbol,
|
||||
uint32_t ntrees) {
|
||||
/* Pack two allocations into one */
|
||||
const size_t max_table_size = kMaxHuffmanTableSize[(alphabet_size + 31) >> 5];
|
||||
HuffmanTreeGroup* group, uint32_t alphabet_size_max,
|
||||
uint32_t alphabet_size_limit, uint32_t ntrees) {
|
||||
/* 376 = 256 (1-st level table) + 4 + 7 + 15 + 31 + 63 (2-nd level mix-tables)
|
||||
This number is discovered "unlimited" "enough" calculator; it is actually
|
||||
a wee bigger than required in several cases (especially for alphabets with
|
||||
less than 16 symbols). */
|
||||
const size_t max_table_size = alphabet_size_limit + 376;
|
||||
const size_t code_size = sizeof(HuffmanCode) * ntrees * max_table_size;
|
||||
const size_t htree_size = sizeof(HuffmanCode*) * ntrees;
|
||||
/* Pointer alignment is, hopefully, wider than sizeof(HuffmanCode). */
|
||||
HuffmanCode** p = (HuffmanCode**)BROTLI_DECODER_ALLOC(s,
|
||||
code_size + htree_size);
|
||||
group->alphabet_size = (uint16_t)alphabet_size;
|
||||
group->max_symbol = (uint16_t)max_symbol;
|
||||
group->alphabet_size_max = (uint16_t)alphabet_size_max;
|
||||
group->alphabet_size_limit = (uint16_t)alphabet_size_limit;
|
||||
group->num_htrees = (uint16_t)ntrees;
|
||||
group->htrees = p;
|
||||
group->codes = (HuffmanCode*)(&p[ntrees]);
|
||||
|
||||
+144
-37
@@ -21,6 +21,95 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Graphviz diagram that describes state transitions:
|
||||
|
||||
digraph States {
|
||||
graph [compound=true]
|
||||
concentrate=true
|
||||
node [shape="box"]
|
||||
|
||||
UNINITED -> {LARGE_WINDOW_BITS -> INITIALIZE}
|
||||
subgraph cluster_metablock_workflow {
|
||||
style="rounded"
|
||||
label=< <B>METABLOCK CYCLE</B> >
|
||||
METABLOCK_BEGIN -> METABLOCK_HEADER
|
||||
METABLOCK_HEADER:sw -> METADATA
|
||||
METABLOCK_HEADER:s -> UNCOMPRESSED
|
||||
METABLOCK_HEADER:se -> METABLOCK_DONE:ne
|
||||
METADATA:s -> METABLOCK_DONE:w
|
||||
UNCOMPRESSED:s -> METABLOCK_DONE:n
|
||||
METABLOCK_DONE:e -> METABLOCK_BEGIN:e [constraint="false"]
|
||||
}
|
||||
INITIALIZE -> METABLOCK_BEGIN
|
||||
METABLOCK_DONE -> DONE
|
||||
|
||||
subgraph cluster_compressed_metablock {
|
||||
style="rounded"
|
||||
label=< <B>COMPRESSED METABLOCK</B> >
|
||||
|
||||
subgraph cluster_command {
|
||||
style="rounded"
|
||||
label=< <B>HOT LOOP</B> >
|
||||
|
||||
_METABLOCK_DONE_PORT_ [shape=point style=invis]
|
||||
|
||||
{
|
||||
// Set different shape for nodes returning from "compressed metablock".
|
||||
node [shape=invhouse]; CMD_INNER CMD_POST_DECODE_LITERALS;
|
||||
CMD_POST_WRAP_COPY; CMD_INNER_WRITE; CMD_POST_WRITE_1;
|
||||
}
|
||||
|
||||
CMD_BEGIN -> CMD_INNER -> CMD_POST_DECODE_LITERALS -> CMD_POST_WRAP_COPY
|
||||
|
||||
// IO ("write") nodes are not in the hot loop!
|
||||
CMD_INNER_WRITE [style=dashed]
|
||||
CMD_INNER -> CMD_INNER_WRITE
|
||||
CMD_POST_WRITE_1 [style=dashed]
|
||||
CMD_POST_DECODE_LITERALS -> CMD_POST_WRITE_1
|
||||
CMD_POST_WRITE_2 [style=dashed]
|
||||
CMD_POST_WRAP_COPY -> CMD_POST_WRITE_2
|
||||
|
||||
CMD_POST_WRITE_1 -> CMD_BEGIN:s [constraint="false"]
|
||||
CMD_INNER_WRITE -> {CMD_INNER CMD_POST_DECODE_LITERALS}
|
||||
[constraint="false"]
|
||||
CMD_BEGIN:ne -> CMD_POST_DECODE_LITERALS [constraint="false"]
|
||||
CMD_POST_WRAP_COPY -> CMD_BEGIN [constraint="false"]
|
||||
CMD_POST_DECODE_LITERALS -> CMD_BEGIN:ne [constraint="false"]
|
||||
CMD_POST_WRITE_2 -> CMD_POST_WRAP_COPY [constraint="false"]
|
||||
{rank=same; CMD_BEGIN; CMD_INNER; CMD_POST_DECODE_LITERALS;
|
||||
CMD_POST_WRAP_COPY}
|
||||
{rank=same; CMD_INNER_WRITE; CMD_POST_WRITE_1; CMD_POST_WRITE_2}
|
||||
|
||||
{CMD_INNER CMD_POST_DECODE_LITERALS CMD_POST_WRAP_COPY} ->
|
||||
_METABLOCK_DONE_PORT_ [style=invis]
|
||||
{CMD_INNER_WRITE CMD_POST_WRITE_1} -> _METABLOCK_DONE_PORT_
|
||||
[constraint="false" style=invis]
|
||||
}
|
||||
|
||||
BEFORE_COMPRESSED_METABLOCK_HEADER:s -> HUFFMAN_CODE_0:n
|
||||
HUFFMAN_CODE_0 -> HUFFMAN_CODE_1 -> HUFFMAN_CODE_2 -> HUFFMAN_CODE_3
|
||||
HUFFMAN_CODE_0 -> METABLOCK_HEADER_2 -> CONTEXT_MODES -> CONTEXT_MAP_1
|
||||
CONTEXT_MAP_1 -> CONTEXT_MAP_2 -> TREE_GROUP
|
||||
TREE_GROUP -> BEFORE_COMPRESSED_METABLOCK_BODY:e
|
||||
BEFORE_COMPRESSED_METABLOCK_BODY:s -> CMD_BEGIN:n
|
||||
|
||||
HUFFMAN_CODE_3:e -> HUFFMAN_CODE_0:ne [constraint="false"]
|
||||
{rank=same; HUFFMAN_CODE_0; HUFFMAN_CODE_1; HUFFMAN_CODE_2; HUFFMAN_CODE_3}
|
||||
{rank=same; METABLOCK_HEADER_2; CONTEXT_MODES; CONTEXT_MAP_1; CONTEXT_MAP_2;
|
||||
TREE_GROUP}
|
||||
}
|
||||
METABLOCK_HEADER:e -> BEFORE_COMPRESSED_METABLOCK_HEADER:n
|
||||
|
||||
_METABLOCK_DONE_PORT_ -> METABLOCK_DONE:se
|
||||
[constraint="false" ltail=cluster_command]
|
||||
|
||||
UNINITED [shape=Mdiamond];
|
||||
DONE [shape=Msquare];
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
BROTLI_STATE_UNINITED,
|
||||
BROTLI_STATE_LARGE_WINDOW_BITS,
|
||||
@@ -39,6 +128,7 @@ typedef enum {
|
||||
BROTLI_STATE_METABLOCK_DONE,
|
||||
BROTLI_STATE_COMMAND_POST_WRITE_1,
|
||||
BROTLI_STATE_COMMAND_POST_WRITE_2,
|
||||
BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER,
|
||||
BROTLI_STATE_HUFFMAN_CODE_0,
|
||||
BROTLI_STATE_HUFFMAN_CODE_1,
|
||||
BROTLI_STATE_HUFFMAN_CODE_2,
|
||||
@@ -46,6 +136,7 @@ typedef enum {
|
||||
BROTLI_STATE_CONTEXT_MAP_1,
|
||||
BROTLI_STATE_CONTEXT_MAP_2,
|
||||
BROTLI_STATE_TREE_GROUP,
|
||||
BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY,
|
||||
BROTLI_STATE_DONE
|
||||
} BrotliRunningState;
|
||||
|
||||
@@ -98,6 +189,50 @@ typedef enum {
|
||||
BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX
|
||||
} BrotliRunningReadBlockLengthState;
|
||||
|
||||
typedef struct BrotliMetablockHeaderArena {
|
||||
BrotliRunningTreeGroupState substate_tree_group;
|
||||
BrotliRunningContextMapState substate_context_map;
|
||||
BrotliRunningHuffmanState substate_huffman;
|
||||
|
||||
uint32_t sub_loop_counter;
|
||||
|
||||
uint32_t repeat_code_len;
|
||||
uint32_t prev_code_len;
|
||||
|
||||
/* For ReadHuffmanCode. */
|
||||
uint32_t symbol;
|
||||
uint32_t repeat;
|
||||
uint32_t space;
|
||||
|
||||
/* Huffman table for "histograms". */
|
||||
HuffmanCode table[32];
|
||||
/* List of heads of symbol chains. */
|
||||
uint16_t* symbol_lists;
|
||||
/* Storage from symbol_lists. */
|
||||
uint16_t symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1 +
|
||||
BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
/* Tails of symbol chains. */
|
||||
int next_symbol[32];
|
||||
uint8_t code_length_code_lengths[BROTLI_CODE_LENGTH_CODES];
|
||||
/* Population counts for the code lengths. */
|
||||
uint16_t code_length_histo[16];
|
||||
|
||||
/* For HuffmanTreeGroupDecode. */
|
||||
int htree_index;
|
||||
HuffmanCode* next;
|
||||
|
||||
/* For DecodeContextMap. */
|
||||
uint32_t context_index;
|
||||
uint32_t max_run_length_prefix;
|
||||
uint32_t code;
|
||||
HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_SIZE_272];
|
||||
} BrotliMetablockHeaderArena;
|
||||
|
||||
typedef struct BrotliMetablockBodyArena {
|
||||
uint8_t dist_extra_bits[544];
|
||||
uint32_t dist_offset[544];
|
||||
} BrotliMetablockBodyArena;
|
||||
|
||||
struct BrotliDecoderStateStruct {
|
||||
BrotliRunningState state;
|
||||
|
||||
@@ -110,7 +245,8 @@ struct BrotliDecoderStateStruct {
|
||||
brotli_free_func free_func;
|
||||
void* memory_manager_opaque;
|
||||
|
||||
/* Temporary storage for remaining input. */
|
||||
/* Temporary storage for remaining input. Brotli stream format is designed in
|
||||
a way, that 64 bits are enough to make progress in decoding. */
|
||||
union {
|
||||
uint64_t u64;
|
||||
uint8_t u8[8];
|
||||
@@ -125,7 +261,6 @@ struct BrotliDecoderStateStruct {
|
||||
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;
|
||||
@@ -153,13 +288,10 @@ struct BrotliDecoderStateStruct {
|
||||
uint32_t block_type_rb[6];
|
||||
uint32_t distance_postfix_bits;
|
||||
uint32_t num_direct_distance_codes;
|
||||
int distance_postfix_mask;
|
||||
uint32_t num_dist_htrees;
|
||||
uint8_t* dist_context_map;
|
||||
HuffmanCode* literal_htree;
|
||||
uint8_t dist_htree_index;
|
||||
uint32_t repeat_code_len;
|
||||
uint32_t prev_code_len;
|
||||
|
||||
int copy_length;
|
||||
int distance_code;
|
||||
@@ -168,33 +300,6 @@ struct BrotliDecoderStateStruct {
|
||||
size_t rb_roundtrips; /* how many times we went around the ring-buffer */
|
||||
size_t partial_pos_out; /* how much output to the user in total */
|
||||
|
||||
/* For ReadHuffmanCode. */
|
||||
uint32_t symbol;
|
||||
uint32_t repeat;
|
||||
uint32_t space;
|
||||
|
||||
HuffmanCode table[32];
|
||||
/* List of heads of symbol chains. */
|
||||
uint16_t* symbol_lists;
|
||||
/* Storage from symbol_lists. */
|
||||
uint16_t symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1 +
|
||||
BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
/* Tails of symbol chains. */
|
||||
int next_symbol[32];
|
||||
uint8_t code_length_code_lengths[BROTLI_CODE_LENGTH_CODES];
|
||||
/* Population counts for the code lengths. */
|
||||
uint16_t code_length_histo[16];
|
||||
|
||||
/* For HuffmanTreeGroupDecode. */
|
||||
int htree_index;
|
||||
HuffmanCode* next;
|
||||
|
||||
/* For DecodeContextMap. */
|
||||
uint32_t context_index;
|
||||
uint32_t max_run_length_prefix;
|
||||
uint32_t code;
|
||||
HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_SIZE_272];
|
||||
|
||||
/* For InverseMoveToFrontTransform. */
|
||||
uint32_t mtf_upper_bound;
|
||||
uint32_t mtf[64 + 1];
|
||||
@@ -203,10 +308,7 @@ struct BrotliDecoderStateStruct {
|
||||
|
||||
/* States inside function calls. */
|
||||
BrotliRunningMetablockHeaderState substate_metablock_header;
|
||||
BrotliRunningTreeGroupState substate_tree_group;
|
||||
BrotliRunningContextMapState substate_context_map;
|
||||
BrotliRunningUncompressedState substate_uncompressed;
|
||||
BrotliRunningHuffmanState substate_huffman;
|
||||
BrotliRunningDecodeUint8State substate_decode_uint8;
|
||||
BrotliRunningReadBlockLengthState substate_read_block_length;
|
||||
|
||||
@@ -229,6 +331,11 @@ struct BrotliDecoderStateStruct {
|
||||
const BrotliTransforms* transforms;
|
||||
|
||||
uint32_t trivial_literal_contexts[8]; /* 256 bits */
|
||||
|
||||
union {
|
||||
BrotliMetablockHeaderArena header;
|
||||
BrotliMetablockBodyArena body;
|
||||
} arena;
|
||||
};
|
||||
|
||||
typedef struct BrotliDecoderStateStruct BrotliDecoderStateInternal;
|
||||
@@ -241,8 +348,8 @@ BROTLI_INTERNAL void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s);
|
||||
BROTLI_INTERNAL void BrotliDecoderStateCleanupAfterMetablock(
|
||||
BrotliDecoderState* s);
|
||||
BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(
|
||||
BrotliDecoderState* s, HuffmanTreeGroup* group, uint32_t alphabet_size,
|
||||
uint32_t max_symbol, uint32_t ntrees);
|
||||
BrotliDecoderState* s, HuffmanTreeGroup* group, uint32_t alphabet_size_max,
|
||||
uint32_t alphabet_size_limit, uint32_t ntrees);
|
||||
|
||||
#define BROTLI_DECODER_ALLOC(S, L) S->alloc_func(S->memory_manager_opaque, L)
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "./backward_references.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
@@ -119,17 +120,17 @@ static BROTLI_INLINE size_t ComputeDistanceCode(size_t distance,
|
||||
#undef CAT
|
||||
#undef EXPAND_CAT
|
||||
|
||||
void BrotliCreateBackwardReferences(
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask, const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
void BrotliCreateBackwardReferences(size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals) {
|
||||
switch (params->hasher.type) {
|
||||
#define CASE_(N) \
|
||||
case N: \
|
||||
CreateBackwardReferencesNH ## N( \
|
||||
num_bytes, position, ringbuffer, \
|
||||
ringbuffer_mask, params, hasher, dist_cache, \
|
||||
CreateBackwardReferencesNH ## N(num_bytes, \
|
||||
position, ringbuffer, ringbuffer_mask, \
|
||||
literal_context_lut, params, hasher, dist_cache, \
|
||||
last_insert_len, commands, num_commands, num_literals); \
|
||||
return;
|
||||
FOR_GENERIC_HASHERS(CASE_)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#define BROTLI_ENC_BACKWARD_REFERENCES_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
@@ -25,10 +26,10 @@ extern "C" {
|
||||
initially the total amount of commands output by previous
|
||||
CreateBackwardReferences calls, and must be incremented by the amount written
|
||||
by this call. */
|
||||
BROTLI_INTERNAL void BrotliCreateBackwardReferences(
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask, const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
BROTLI_INTERNAL void BrotliCreateBackwardReferences(size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <string.h> /* memcpy, memset */
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./command.h"
|
||||
@@ -26,6 +27,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* BrotliCalculateDistanceCodeLimit(BROTLI_MAX_ALLOWED_DISTANCE, 3, 120). */
|
||||
#define BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE 544
|
||||
|
||||
static const float kInfinity = 1.7e38f; /* ~= 2 ^ 127 */
|
||||
@@ -86,14 +88,10 @@ typedef struct ZopfliCostModel {
|
||||
static void InitZopfliCostModel(
|
||||
MemoryManager* m, ZopfliCostModel* self, const BrotliDistanceParams* dist,
|
||||
size_t num_bytes) {
|
||||
uint32_t distance_histogram_size = dist->alphabet_size;
|
||||
if (distance_histogram_size > BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE) {
|
||||
distance_histogram_size = BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE;
|
||||
}
|
||||
self->num_bytes_ = num_bytes;
|
||||
self->literal_costs_ = BROTLI_ALLOC(m, float, num_bytes + 2);
|
||||
self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size);
|
||||
self->distance_histogram_size = distance_histogram_size;
|
||||
self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size_limit);
|
||||
self->distance_histogram_size = dist->alphabet_size_limit;
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
}
|
||||
|
||||
@@ -408,9 +406,12 @@ static size_t UpdateNodes(
|
||||
const int* starting_dist_cache, const size_t num_matches,
|
||||
const BackwardMatch* matches, const ZopfliCostModel* model,
|
||||
StartPosQueue* queue, ZopfliNode* nodes) {
|
||||
const size_t stream_offset = params->stream_offset;
|
||||
const size_t cur_ix = block_start + pos;
|
||||
const size_t cur_ix_masked = cur_ix & ringbuffer_mask;
|
||||
const size_t max_distance = BROTLI_MIN(size_t, cur_ix, max_backward_limit);
|
||||
const size_t dictionary_start = BROTLI_MIN(size_t,
|
||||
cur_ix + stream_offset, max_backward_limit);
|
||||
const size_t max_len = num_bytes - pos;
|
||||
const size_t max_zopfli_len = MaxZopfliLen(params);
|
||||
const size_t max_iters = MaxZopfliCandidates(params);
|
||||
@@ -419,8 +420,8 @@ static size_t UpdateNodes(
|
||||
size_t k;
|
||||
size_t gap = 0;
|
||||
|
||||
EvaluateNode(block_start, pos, max_backward_limit, gap, starting_dist_cache,
|
||||
model, queue, nodes);
|
||||
EvaluateNode(block_start + stream_offset, pos, max_backward_limit, gap,
|
||||
starting_dist_cache, model, queue, nodes);
|
||||
|
||||
{
|
||||
const PosData* posdata = StartPosQueueAt(queue, 0);
|
||||
@@ -453,7 +454,7 @@ static size_t UpdateNodes(
|
||||
if (cur_ix_masked + best_len > ringbuffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (BROTLI_PREDICT_FALSE(backward > max_distance + gap)) {
|
||||
if (BROTLI_PREDICT_FALSE(backward > dictionary_start + gap)) {
|
||||
/* Word dictionary -> ignore. */
|
||||
continue;
|
||||
}
|
||||
@@ -472,6 +473,8 @@ static size_t UpdateNodes(
|
||||
&ringbuffer[cur_ix_masked],
|
||||
max_len);
|
||||
} else {
|
||||
/* "Gray" area. It is addressable by decoder, but this encoder
|
||||
instance does not have that data -> should not touch it. */
|
||||
continue;
|
||||
}
|
||||
{
|
||||
@@ -506,7 +509,7 @@ static size_t UpdateNodes(
|
||||
BackwardMatch match = matches[j];
|
||||
size_t dist = match.distance;
|
||||
BROTLI_BOOL is_dictionary_match =
|
||||
TO_BROTLI_BOOL(dist > max_distance + gap);
|
||||
TO_BROTLI_BOOL(dist > dictionary_start + gap);
|
||||
/* We already tried all possible last distance matches, so we can use
|
||||
normal distance code here. */
|
||||
size_t dist_code = dist + BROTLI_NUM_DISTANCE_SHORT_CODES - 1;
|
||||
@@ -569,6 +572,7 @@ void BrotliZopfliCreateCommands(const size_t num_bytes,
|
||||
const size_t block_start, const ZopfliNode* nodes, int* dist_cache,
|
||||
size_t* last_insert_len, const BrotliEncoderParams* params,
|
||||
Command* commands, size_t* num_literals) {
|
||||
const size_t stream_offset = params->stream_offset;
|
||||
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
||||
size_t pos = 0;
|
||||
uint32_t offset = nodes[0].u.next;
|
||||
@@ -587,9 +591,10 @@ void BrotliZopfliCreateCommands(const size_t num_bytes,
|
||||
{
|
||||
size_t distance = ZopfliNodeCopyDistance(next);
|
||||
size_t len_code = ZopfliNodeLengthCode(next);
|
||||
size_t max_distance =
|
||||
BROTLI_MIN(size_t, block_start + pos, max_backward_limit);
|
||||
BROTLI_BOOL is_dictionary = TO_BROTLI_BOOL(distance > max_distance + gap);
|
||||
size_t dictionary_start = BROTLI_MIN(size_t,
|
||||
block_start + pos + stream_offset, max_backward_limit);
|
||||
BROTLI_BOOL is_dictionary =
|
||||
TO_BROTLI_BOOL(distance > dictionary_start + gap);
|
||||
size_t dist_code = ZopfliNodeDistanceCode(next);
|
||||
InitCommand(&commands[i], ¶ms->dist, insert_length,
|
||||
copy_length, (int)len_code - (int)copy_length, dist_code);
|
||||
@@ -613,6 +618,7 @@ static size_t ZopfliIterate(size_t num_bytes, size_t position,
|
||||
const BrotliEncoderParams* params, const size_t gap, const int* dist_cache,
|
||||
const ZopfliCostModel* model, const uint32_t* num_matches,
|
||||
const BackwardMatch* matches, ZopfliNode* nodes) {
|
||||
const size_t stream_offset = params->stream_offset;
|
||||
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
||||
const size_t max_zopfli_len = MaxZopfliLen(params);
|
||||
StartPosQueue queue;
|
||||
@@ -637,7 +643,7 @@ static size_t ZopfliIterate(size_t num_bytes, size_t position,
|
||||
while (skip) {
|
||||
i++;
|
||||
if (i + 3 >= num_bytes) break;
|
||||
EvaluateNode(position, i, max_backward_limit, gap,
|
||||
EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
|
||||
dist_cache, model, &queue, nodes);
|
||||
cur_match_pos += num_matches[i];
|
||||
skip--;
|
||||
@@ -650,8 +656,9 @@ static size_t ZopfliIterate(size_t num_bytes, size_t position,
|
||||
/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
|
||||
size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
const BrotliEncoderParams* params,
|
||||
const int* dist_cache, HasherHandle hasher, ZopfliNode* nodes) {
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
const int* dist_cache, Hasher* hasher, ZopfliNode* nodes) {
|
||||
const size_t stream_offset = params->stream_offset;
|
||||
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
||||
const size_t max_zopfli_len = MaxZopfliLen(params);
|
||||
ZopfliCostModel model;
|
||||
@@ -662,6 +669,7 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
||||
size_t i;
|
||||
size_t gap = 0;
|
||||
size_t lz_matches_offset = 0;
|
||||
BROTLI_UNUSED(literal_context_lut);
|
||||
nodes[0].length = 0;
|
||||
nodes[0].u.cost = 0;
|
||||
InitZopfliCostModel(m, &model, ¶ms->dist, num_bytes);
|
||||
@@ -672,12 +680,14 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
||||
for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; i++) {
|
||||
const size_t pos = position + i;
|
||||
const size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
|
||||
const size_t dictionary_start = BROTLI_MIN(size_t,
|
||||
pos + stream_offset, max_backward_limit);
|
||||
size_t skip;
|
||||
size_t num_matches;
|
||||
num_matches = FindAllMatchesH10(hasher,
|
||||
num_matches = FindAllMatchesH10(&hasher->privat._H10,
|
||||
¶ms->dictionary,
|
||||
ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance,
|
||||
gap, params, &matches[lz_matches_offset]);
|
||||
dictionary_start + gap, params, &matches[lz_matches_offset]);
|
||||
if (num_matches > 0 &&
|
||||
BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) {
|
||||
matches[0] = matches[num_matches - 1];
|
||||
@@ -692,13 +702,14 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
||||
}
|
||||
if (skip > 1) {
|
||||
/* Add the tail of the copy to the hasher. */
|
||||
StoreRangeH10(hasher, ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
|
||||
StoreRangeH10(&hasher->privat._H10,
|
||||
ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
|
||||
size_t, pos + skip, store_end));
|
||||
skip--;
|
||||
while (skip) {
|
||||
i++;
|
||||
if (i + HashTypeLengthH10() - 1 >= num_bytes) break;
|
||||
EvaluateNode(position, i, max_backward_limit, gap,
|
||||
EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
|
||||
dist_cache, &model, &queue, nodes);
|
||||
skip--;
|
||||
}
|
||||
@@ -710,15 +721,14 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
||||
|
||||
void BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals) {
|
||||
ZopfliNode* nodes;
|
||||
nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
|
||||
BrotliInitZopfliNodes(nodes, num_bytes + 1);
|
||||
*num_commands += BrotliZopfliComputeShortestPath(m, num_bytes,
|
||||
position, ringbuffer, ringbuffer_mask, params,
|
||||
position, ringbuffer, ringbuffer_mask, literal_context_lut, params,
|
||||
dist_cache, hasher, nodes);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
|
||||
@@ -728,9 +738,10 @@ void BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
||||
|
||||
void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals) {
|
||||
const size_t stream_offset = params->stream_offset;
|
||||
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
||||
uint32_t* num_matches = BROTLI_ALLOC(m, uint32_t, num_bytes);
|
||||
size_t matches_size = 4 * num_bytes;
|
||||
@@ -747,10 +758,16 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
||||
BackwardMatch* matches = BROTLI_ALLOC(m, BackwardMatch, matches_size);
|
||||
size_t gap = 0;
|
||||
size_t shadow_matches = 0;
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BROTLI_UNUSED(literal_context_lut);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(num_matches) ||
|
||||
BROTLI_IS_NULL(matches)) {
|
||||
return;
|
||||
}
|
||||
for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; ++i) {
|
||||
const size_t pos = position + i;
|
||||
size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
|
||||
size_t dictionary_start = BROTLI_MIN(size_t,
|
||||
pos + stream_offset, max_backward_limit);
|
||||
size_t max_length = num_bytes - i;
|
||||
size_t num_found_matches;
|
||||
size_t cur_match_end;
|
||||
@@ -759,10 +776,10 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
||||
BROTLI_ENSURE_CAPACITY(m, BackwardMatch, matches, matches_size,
|
||||
cur_match_pos + MAX_NUM_MATCHES_H10 + shadow_matches);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
num_found_matches = FindAllMatchesH10(hasher,
|
||||
num_found_matches = FindAllMatchesH10(&hasher->privat._H10,
|
||||
¶ms->dictionary,
|
||||
ringbuffer, ringbuffer_mask, pos, max_length,
|
||||
max_distance, gap, params,
|
||||
max_distance, dictionary_start + gap, params,
|
||||
&matches[cur_match_pos + shadow_matches]);
|
||||
cur_match_end = cur_match_pos + num_found_matches;
|
||||
for (j = cur_match_pos; j + 1 < cur_match_end; ++j) {
|
||||
@@ -777,7 +794,8 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
||||
matches[cur_match_pos++] = matches[cur_match_end - 1];
|
||||
num_matches[i] = 1;
|
||||
/* Add the tail of the copy to the hasher. */
|
||||
StoreRangeH10(hasher, ringbuffer, ringbuffer_mask, pos + 1,
|
||||
StoreRangeH10(&hasher->privat._H10,
|
||||
ringbuffer, ringbuffer_mask, pos + 1,
|
||||
BROTLI_MIN(size_t, pos + match_len, store_end));
|
||||
memset(&num_matches[i + 1], 0, skip * sizeof(num_matches[0]));
|
||||
i += skip;
|
||||
@@ -791,7 +809,7 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
||||
memcpy(orig_dist_cache, dist_cache, 4 * sizeof(dist_cache[0]));
|
||||
orig_num_commands = *num_commands;
|
||||
nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
|
||||
InitZopfliCostModel(m, &model, ¶ms->dist, num_bytes);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
for (i = 0; i < 2; i++) {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#define BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
@@ -23,15 +24,17 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
BROTLI_INTERNAL void BrotliCreateZopfliBackwardReferences(MemoryManager* m,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask, const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals);
|
||||
|
||||
BROTLI_INTERNAL void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask, const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals);
|
||||
|
||||
typedef struct ZopfliNode {
|
||||
@@ -77,8 +80,8 @@ BROTLI_INTERNAL void BrotliInitZopfliNodes(ZopfliNode* array, size_t length);
|
||||
BROTLI_INTERNAL size_t BrotliZopfliComputeShortestPath(
|
||||
MemoryManager* m, size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
const BrotliEncoderParams* params,
|
||||
const int* dist_cache, HasherHandle hasher, ZopfliNode* nodes);
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
const int* dist_cache, Hasher* hasher, ZopfliNode* nodes);
|
||||
|
||||
BROTLI_INTERNAL void BrotliZopfliCreateCommands(
|
||||
const size_t num_bytes, const size_t block_start, const ZopfliNode* nodes,
|
||||
|
||||
@@ -10,11 +10,13 @@
|
||||
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||
size_t num_bytes, size_t position,
|
||||
const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals) {
|
||||
HASHER()* privat = &hasher->privat.FN(_);
|
||||
/* Set maximum distance, see section 9.1. of the spec. */
|
||||
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
||||
const size_t position_offset = params->stream_offset;
|
||||
|
||||
const Command* const orig_commands = commands;
|
||||
size_t insert_length = *last_insert_len;
|
||||
@@ -31,19 +33,23 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||
/* Minimum score to accept a backward reference. */
|
||||
const score_t kMinScore = BROTLI_SCORE_BASE + 100;
|
||||
|
||||
FN(PrepareDistanceCache)(hasher, dist_cache);
|
||||
BROTLI_UNUSED(literal_context_lut);
|
||||
|
||||
FN(PrepareDistanceCache)(privat, dist_cache);
|
||||
|
||||
while (position + FN(HashTypeLength)() < pos_end) {
|
||||
size_t max_length = pos_end - position;
|
||||
size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
|
||||
size_t dictionary_start = BROTLI_MIN(size_t,
|
||||
position + position_offset, max_backward_limit);
|
||||
HasherSearchResult sr;
|
||||
sr.len = 0;
|
||||
sr.len_code_delta = 0;
|
||||
sr.distance = 0;
|
||||
sr.score = kMinScore;
|
||||
FN(FindLongestMatch)(hasher, ¶ms->dictionary,
|
||||
FN(FindLongestMatch)(privat, ¶ms->dictionary,
|
||||
ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
|
||||
max_distance, gap, params->dist.max_distance, &sr);
|
||||
max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
|
||||
if (sr.score > kMinScore) {
|
||||
/* Found a match. Let's look for something even better ahead. */
|
||||
int delayed_backward_references_in_row = 0;
|
||||
@@ -57,10 +63,13 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||
sr2.distance = 0;
|
||||
sr2.score = kMinScore;
|
||||
max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
|
||||
FN(FindLongestMatch)(hasher,
|
||||
dictionary_start = BROTLI_MIN(size_t,
|
||||
position + 1 + position_offset, max_backward_limit);
|
||||
FN(FindLongestMatch)(privat,
|
||||
¶ms->dictionary,
|
||||
ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
|
||||
max_distance, gap, params->dist.max_distance, &sr2);
|
||||
max_distance, dictionary_start + gap, params->dist.max_distance,
|
||||
&sr2);
|
||||
if (sr2.score >= sr.score + cost_diff_lazy) {
|
||||
/* Ok, let's just write one byte for now and start a match from the
|
||||
next byte. */
|
||||
@@ -76,18 +85,19 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||
}
|
||||
apply_random_heuristics =
|
||||
position + 2 * sr.len + random_heuristics_window_size;
|
||||
max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
|
||||
dictionary_start = BROTLI_MIN(size_t,
|
||||
position + position_offset, max_backward_limit);
|
||||
{
|
||||
/* The first 16 codes are special short-codes,
|
||||
and the minimum offset is 1. */
|
||||
size_t distance_code = ComputeDistanceCode(
|
||||
sr.distance, max_distance + gap, dist_cache);
|
||||
if ((sr.distance <= (max_distance + gap)) && distance_code > 0) {
|
||||
sr.distance, dictionary_start + gap, dist_cache);
|
||||
if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
|
||||
dist_cache[3] = dist_cache[2];
|
||||
dist_cache[2] = dist_cache[1];
|
||||
dist_cache[1] = dist_cache[0];
|
||||
dist_cache[0] = (int)sr.distance;
|
||||
FN(PrepareDistanceCache)(hasher, dist_cache);
|
||||
FN(PrepareDistanceCache)(privat, dist_cache);
|
||||
}
|
||||
InitCommand(commands++, ¶ms->dist, insert_length,
|
||||
sr.len, sr.len_code_delta, distance_code);
|
||||
@@ -105,7 +115,7 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||
range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
|
||||
range_start, position + sr.len - (sr.distance << 2)));
|
||||
}
|
||||
FN(StoreRange)(hasher, ringbuffer, ringbuffer_mask, range_start,
|
||||
FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
|
||||
range_end);
|
||||
}
|
||||
position += sr.len;
|
||||
@@ -131,7 +141,7 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||
size_t pos_jump =
|
||||
BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
|
||||
for (; position < pos_jump; position += 4) {
|
||||
FN(Store)(hasher, ringbuffer, ringbuffer_mask, position);
|
||||
FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
|
||||
insert_length += 4;
|
||||
}
|
||||
} else {
|
||||
@@ -140,7 +150,7 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||
size_t pos_jump =
|
||||
BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
|
||||
for (; position < pos_jump; position += 2) {
|
||||
FN(Store)(hasher, ringbuffer, ringbuffer_mask, position);
|
||||
FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
|
||||
insert_length += 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ void BrotliSplitBlock(MemoryManager* m,
|
||||
{
|
||||
size_t literals_count = CountLiterals(cmds, num_commands);
|
||||
uint8_t* literals = BROTLI_ALLOC(m, uint8_t, literals_count);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literals)) return;
|
||||
/* Create a continuous array of literals. */
|
||||
CopyLiteralsToByteArray(cmds, num_commands, data, pos, mask, literals);
|
||||
/* Create the block split on the array of literals.
|
||||
@@ -150,7 +150,7 @@ void BrotliSplitBlock(MemoryManager* m,
|
||||
/* Compute prefix codes for commands. */
|
||||
uint16_t* insert_and_copy_codes = BROTLI_ALLOC(m, uint16_t, num_commands);
|
||||
size_t i;
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(insert_and_copy_codes)) return;
|
||||
for (i = 0; i < num_commands; ++i) {
|
||||
insert_and_copy_codes[i] = cmds[i].cmd_prefix_;
|
||||
}
|
||||
@@ -170,7 +170,7 @@ void BrotliSplitBlock(MemoryManager* m,
|
||||
uint16_t* distance_prefixes = BROTLI_ALLOC(m, uint16_t, num_commands);
|
||||
size_t j = 0;
|
||||
size_t i;
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(distance_prefixes)) return;
|
||||
for (i = 0; i < num_commands; ++i) {
|
||||
const Command* cmd = &cmds[i];
|
||||
if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
|
||||
|
||||
@@ -219,7 +219,12 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
uint32_t symbols[HISTOGRAMS_PER_BATCH] = { 0 };
|
||||
uint32_t remap[HISTOGRAMS_PER_BATCH] = { 0 };
|
||||
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histogram_symbols) ||
|
||||
BROTLI_IS_NULL(block_lengths) || BROTLI_IS_NULL(all_histograms) ||
|
||||
BROTLI_IS_NULL(cluster_size) || BROTLI_IS_NULL(histograms) ||
|
||||
BROTLI_IS_NULL(pairs)) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(block_lengths, 0, num_blocks * sizeof(uint32_t));
|
||||
|
||||
@@ -278,11 +283,11 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
if (pairs_capacity < max_num_pairs + 1) {
|
||||
BROTLI_FREE(m, pairs);
|
||||
pairs = BROTLI_ALLOC(m, HistogramPair, max_num_pairs + 1);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(pairs)) return;
|
||||
}
|
||||
|
||||
clusters = BROTLI_ALLOC(m, uint32_t, num_clusters);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(clusters)) return;
|
||||
for (i = 0; i < num_clusters; ++i) {
|
||||
clusters[i] = (uint32_t)i;
|
||||
}
|
||||
@@ -294,7 +299,7 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
BROTLI_FREE(m, cluster_size);
|
||||
|
||||
new_index = BROTLI_ALLOC(m, uint32_t, num_clusters);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return;
|
||||
for (i = 0; i < num_clusters; ++i) new_index[i] = kInvalidIndex;
|
||||
pos = 0;
|
||||
{
|
||||
@@ -386,7 +391,7 @@ static void FN(SplitByteVector)(MemoryManager* m,
|
||||
return;
|
||||
}
|
||||
histograms = BROTLI_ALLOC(m, HistogramType, num_histograms);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histograms)) return;
|
||||
/* Find good entropy codes. */
|
||||
FN(InitialEntropyCodes)(data, length,
|
||||
sampling_stride_length,
|
||||
@@ -405,7 +410,11 @@ static void FN(SplitByteVector)(MemoryManager* m,
|
||||
uint16_t* new_id = BROTLI_ALLOC(m, uint16_t, num_histograms);
|
||||
const size_t iters = params->quality < HQ_ZOPFLIFICATION_QUALITY ? 3 : 10;
|
||||
size_t i;
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(block_ids) ||
|
||||
BROTLI_IS_NULL(insert_cost) || BROTLI_IS_NULL(cost) ||
|
||||
BROTLI_IS_NULL(switch_signal) || BROTLI_IS_NULL(new_id)) {
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < iters; ++i) {
|
||||
num_blocks = FN(FindBlocks)(data, length,
|
||||
block_switch_cost,
|
||||
|
||||
@@ -34,33 +34,18 @@ extern "C" {
|
||||
BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_LARGE_MAX_DISTANCE_BITS)
|
||||
/* MAX_SIMPLE_DISTANCE_ALPHABET_SIZE == 140 */
|
||||
|
||||
/* Represents the range of values belonging to a prefix code:
|
||||
[offset, offset + 2^nbits) */
|
||||
typedef struct PrefixCodeRange {
|
||||
uint32_t offset;
|
||||
uint32_t nbits;
|
||||
} PrefixCodeRange;
|
||||
|
||||
static const PrefixCodeRange
|
||||
kBlockLengthPrefixCode[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
|
||||
{ 1, 2}, { 5, 2}, { 9, 2}, {13, 2}, {17, 3}, { 25, 3}, { 33, 3},
|
||||
{41, 3}, {49, 4}, {65, 4}, {81, 4}, {97, 4}, {113, 5}, {145, 5},
|
||||
{177, 5}, { 209, 5}, { 241, 6}, { 305, 6}, { 369, 7}, { 497, 8},
|
||||
{753, 9}, {1265, 10}, {2289, 11}, {4337, 12}, {8433, 13}, {16625, 24}
|
||||
};
|
||||
|
||||
static BROTLI_INLINE uint32_t BlockLengthPrefixCode(uint32_t len) {
|
||||
uint32_t code = (len >= 177) ? (len >= 753 ? 20 : 14) : (len >= 41 ? 7 : 0);
|
||||
while (code < (BROTLI_NUM_BLOCK_LEN_SYMBOLS - 1) &&
|
||||
len >= kBlockLengthPrefixCode[code + 1].offset) ++code;
|
||||
len >= _kBrotliPrefixCodeRanges[code + 1].offset) ++code;
|
||||
return code;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void GetBlockLengthPrefixCode(uint32_t len, size_t* code,
|
||||
uint32_t* n_extra, uint32_t* extra) {
|
||||
*code = BlockLengthPrefixCode(len);
|
||||
*n_extra = kBlockLengthPrefixCode[*code].nbits;
|
||||
*extra = len - kBlockLengthPrefixCode[*code].offset;
|
||||
*n_extra = _kBrotliPrefixCodeRanges[*code].nbits;
|
||||
*extra = len - _kBrotliPrefixCodeRanges[*code].offset;
|
||||
}
|
||||
|
||||
typedef struct BlockTypeCodeCalculator {
|
||||
@@ -450,7 +435,7 @@ void BrotliBuildAndStoreHuffmanTreeFast(MemoryManager* m,
|
||||
const size_t max_tree_size = 2 * length + 1;
|
||||
HuffmanTree* tree = BROTLI_ALLOC(m, HuffmanTree, max_tree_size);
|
||||
uint32_t count_limit;
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return;
|
||||
for (count_limit = 1; ; count_limit *= 2) {
|
||||
HuffmanTree* node = tree;
|
||||
size_t l;
|
||||
@@ -714,7 +699,7 @@ static void EncodeContextMap(MemoryManager* m,
|
||||
}
|
||||
|
||||
rle_symbols = BROTLI_ALLOC(m, uint32_t, context_map_size);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(rle_symbols)) return;
|
||||
MoveToFrontTransform(context_map, context_map_size, rle_symbols);
|
||||
RunLengthCodeZeros(context_map_size, rle_symbols,
|
||||
&num_rle_symbols, &max_run_length_prefix);
|
||||
@@ -956,23 +941,21 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||
|
||||
size_t pos = start_pos;
|
||||
size_t i;
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size;
|
||||
uint32_t num_effective_distance_symbols = num_distance_symbols;
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size_max;
|
||||
uint32_t num_effective_distance_symbols = params->dist.alphabet_size_limit;
|
||||
HuffmanTree* tree;
|
||||
ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
|
||||
BlockEncoder literal_enc;
|
||||
BlockEncoder command_enc;
|
||||
BlockEncoder distance_enc;
|
||||
const BrotliDistanceParams* dist = ¶ms->dist;
|
||||
if (params->large_window &&
|
||||
num_effective_distance_symbols > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS) {
|
||||
num_effective_distance_symbols = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS;
|
||||
}
|
||||
BROTLI_DCHECK(
|
||||
num_effective_distance_symbols <= BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS);
|
||||
|
||||
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
|
||||
|
||||
tree = BROTLI_ALLOC(m, HuffmanTree, MAX_HUFFMAN_TREE_SIZE);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return;
|
||||
InitBlockEncoder(&literal_enc, BROTLI_NUM_LITERAL_SYMBOLS,
|
||||
mb->literal_split.num_types, mb->literal_split.types,
|
||||
mb->literal_split.lengths, mb->literal_split.num_blocks);
|
||||
@@ -1163,7 +1146,7 @@ void BrotliStoreMetaBlockTrivial(MemoryManager* m,
|
||||
uint8_t dist_depth[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||
uint16_t dist_bits[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||
HuffmanTree* tree;
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size;
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size_max;
|
||||
|
||||
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
|
||||
|
||||
@@ -1177,7 +1160,7 @@ void BrotliStoreMetaBlockTrivial(MemoryManager* m,
|
||||
BrotliWriteBits(13, 0, storage_ix, storage);
|
||||
|
||||
tree = BROTLI_ALLOC(m, HuffmanTree, MAX_HUFFMAN_TREE_SIZE);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return;
|
||||
BuildAndStoreHuffmanTree(lit_histo.data_, BROTLI_NUM_LITERAL_SYMBOLS,
|
||||
BROTLI_NUM_LITERAL_SYMBOLS, tree,
|
||||
lit_depth, lit_bits,
|
||||
@@ -1206,7 +1189,7 @@ void BrotliStoreMetaBlockFast(MemoryManager* m,
|
||||
BROTLI_BOOL is_last, const BrotliEncoderParams* params,
|
||||
const Command* commands, size_t n_commands,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size;
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size_max;
|
||||
uint32_t distance_alphabet_bits =
|
||||
Log2FloorNonZero(num_distance_symbols - 1) + 1;
|
||||
|
||||
|
||||
@@ -215,7 +215,7 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m,
|
||||
uint32_t next_index;
|
||||
HistogramType* tmp;
|
||||
size_t i;
|
||||
if (BROTLI_IS_OOM(m)) return 0;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return 0;
|
||||
for (i = 0; i < length; ++i) {
|
||||
new_index[i] = kInvalidIndex;
|
||||
}
|
||||
@@ -229,7 +229,7 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m,
|
||||
/* TODO: by using idea of "cycle-sort" we can avoid allocation of
|
||||
tmp and reduce the number of copying by the factor of 2. */
|
||||
tmp = BROTLI_ALLOC(m, HistogramType, next_index);
|
||||
if (BROTLI_IS_OOM(m)) return 0;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp)) return 0;
|
||||
next_index = 0;
|
||||
for (i = 0; i < length; ++i) {
|
||||
if (new_index[symbols[i]] == next_index) {
|
||||
@@ -259,7 +259,10 @@ BROTLI_INTERNAL void FN(BrotliClusterHistograms)(
|
||||
HistogramPair* pairs = BROTLI_ALLOC(m, HistogramPair, pairs_capacity + 1);
|
||||
size_t i;
|
||||
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(cluster_size) ||
|
||||
BROTLI_IS_NULL(clusters) || BROTLI_IS_NULL(pairs)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < in_size; ++i) {
|
||||
cluster_size[i] = 1;
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "./command.h"
|
||||
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const uint32_t kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26,
|
||||
34, 50, 66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594};
|
||||
const uint32_t kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES] = {
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 12, 14, 24};
|
||||
const uint32_t kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES] = {
|
||||
2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 18,
|
||||
22, 30, 38, 54, 70, 102, 134, 198, 326, 582, 1094, 2118};
|
||||
const uint32_t kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 24};
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
Loaded 100 of 214 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user