mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-27 19:07:31 +09:00
Compare commits
No commits in common. "85f7844b5ad03643f768b4932d24429c853d73dc" and "91b45c0d14ce0a6a1771249fc0bc906a3e9bc98e" have entirely different histories.
85f7844b5a
...
91b45c0d14
18 changed files with 31 additions and 1727 deletions
|
|
@ -65,9 +65,9 @@ pref("@GUAO_PREF@.mewe.com", "Mozilla/5.0 (%OS_SLICE% rv:102.0) Gecko/20100101 F
|
||||||
|
|
||||||
// UA-sniffing domains that are "app/vendor-specific" and do not like Dactyloidae
|
// UA-sniffing domains that are "app/vendor-specific" and do not like Dactyloidae
|
||||||
pref("@GUAO_PREF@.web.whatsapp.com","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36");
|
pref("@GUAO_PREF@.web.whatsapp.com","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36");
|
||||||
pref("@GUAO_PREF@.youtube.com","Mozilla/5.0 (%OS_SLICE%; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0");
|
pref("@GUAO_PREF@.youtube.com","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36");
|
||||||
pref("@GUAO_PREF@.studio.youtube.com","Mozilla/5.0 (%OS_SLICE%; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0");
|
pref("@GUAO_PREF@.studio.youtube.com","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36");
|
||||||
pref("@GUAO_PREF@.gaming.youtube.com","Mozilla/5.0 (%OS_SLICE%; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0");
|
pref("@GUAO_PREF@.gaming.youtube.com","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36");
|
||||||
|
|
||||||
// The following domains do not like the Goanna slice
|
// The following domains do not like the Goanna slice
|
||||||
pref("@GUAO_PREF@.bab.la","Mozilla/5.0 (%OS_SLICE% rv:@GK_VERSION@) @GK_SLICE@ @FX_SLICE@");
|
pref("@GUAO_PREF@.bab.la","Mozilla/5.0 (%OS_SLICE% rv:@GK_VERSION@) @GK_SLICE@ @FX_SLICE@");
|
||||||
|
|
|
||||||
|
|
@ -952,38 +952,12 @@ using namespace std;
|
||||||
void
|
void
|
||||||
imgCacheQueue::Remove(imgCacheEntry* entry)
|
imgCacheQueue::Remove(imgCacheEntry* entry)
|
||||||
{
|
{
|
||||||
uint64_t index = mQueue.IndexOf(entry);
|
queueContainer::iterator it = find(mQueue.begin(), mQueue.end(), entry);
|
||||||
if (index == queueContainer::NoIndex) {
|
if (it != mQueue.end()) {
|
||||||
return;
|
mSize -= (*it)->GetDataSize();
|
||||||
|
mQueue.erase(it);
|
||||||
|
MarkDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
mSize -= mQueue[index]->GetDataSize();
|
|
||||||
|
|
||||||
// If the queue is clean and this is the first entry,
|
|
||||||
// then we can efficiently remove the entry without
|
|
||||||
// dirtying the sort order.
|
|
||||||
if (!IsDirty() && index == 0) {
|
|
||||||
std::pop_heap(mQueue.begin(), mQueue.end(),
|
|
||||||
imgLoader::CompareCacheEntries);
|
|
||||||
mQueue.RemoveElementAt(mQueue.Length() - 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove from the middle of the list. This potentially
|
|
||||||
// breaks the binary heap sort order.
|
|
||||||
mQueue.RemoveElementAt(index);
|
|
||||||
|
|
||||||
// If we only have one entry or the queue is empty, though,
|
|
||||||
// then the sort order is still effectively good.
|
|
||||||
// Simply refresh the list to clear the dirty flag.
|
|
||||||
if (mQueue.Length() <= 1) {
|
|
||||||
Refresh();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise we must mark the queue dirty and potentially
|
|
||||||
// trigger an expensive sort later.
|
|
||||||
MarkDirty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -992,26 +966,23 @@ imgCacheQueue::Push(imgCacheEntry* entry)
|
||||||
mSize += entry->GetDataSize();
|
mSize += entry->GetDataSize();
|
||||||
|
|
||||||
RefPtr<imgCacheEntry> refptr(entry);
|
RefPtr<imgCacheEntry> refptr(entry);
|
||||||
mQueue.AppendElement(Move(refptr));
|
mQueue.push_back(refptr);
|
||||||
// If we're not dirty already, then we can efficiently add this to the binary heap immediately.
|
MarkDirty();
|
||||||
if (!IsDirty()) {
|
|
||||||
std::push_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<imgCacheEntry>
|
already_AddRefed<imgCacheEntry>
|
||||||
imgCacheQueue::Pop()
|
imgCacheQueue::Pop()
|
||||||
{
|
{
|
||||||
if (mQueue.IsEmpty()) {
|
if (mQueue.empty()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (IsDirty()) {
|
if (IsDirty()) {
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RefPtr<imgCacheEntry> entry = mQueue[0];
|
||||||
std::pop_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries);
|
std::pop_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries);
|
||||||
RefPtr<imgCacheEntry> entry = Move(mQueue.LastElement());
|
mQueue.pop_back();
|
||||||
mQueue.RemoveElementAt(mQueue.Length() - 1);
|
|
||||||
|
|
||||||
mSize -= entry->GetDataSize();
|
mSize -= entry->GetDataSize();
|
||||||
return entry.forget();
|
return entry.forget();
|
||||||
|
|
@ -1020,7 +991,6 @@ imgCacheQueue::Pop()
|
||||||
void
|
void
|
||||||
imgCacheQueue::Refresh()
|
imgCacheQueue::Refresh()
|
||||||
{
|
{
|
||||||
// Re-heap the list. This is an O(3 * n) operation and best avoided if possible.
|
|
||||||
std::make_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries);
|
std::make_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries);
|
||||||
mDirty = false;
|
mDirty = false;
|
||||||
}
|
}
|
||||||
|
|
@ -1040,13 +1010,7 @@ imgCacheQueue::IsDirty()
|
||||||
uint32_t
|
uint32_t
|
||||||
imgCacheQueue::GetNumElements() const
|
imgCacheQueue::GetNumElements() const
|
||||||
{
|
{
|
||||||
return mQueue.Length();
|
return mQueue.size();
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
imgCacheQueue::Contains(imgCacheEntry* aEntry) const
|
|
||||||
{
|
|
||||||
return mQueue.Contains(aEntry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
imgCacheQueue::iterator
|
imgCacheQueue::iterator
|
||||||
|
|
@ -1638,11 +1602,7 @@ void
|
||||||
imgLoader::CacheEntriesChanged(bool aForChrome, int32_t aSizeDiff /* = 0 */)
|
imgLoader::CacheEntriesChanged(bool aForChrome, int32_t aSizeDiff /* = 0 */)
|
||||||
{
|
{
|
||||||
imgCacheQueue& queue = GetCacheQueue(aForChrome);
|
imgCacheQueue& queue = GetCacheQueue(aForChrome);
|
||||||
// We only need to dirty the queue if there is any sorting taking place.
|
queue.MarkDirty();
|
||||||
// Empty or single-entry lists can't become dirty.
|
|
||||||
if (queue.GetNumElements() > 1) {
|
|
||||||
queue.MarkDirty();
|
|
||||||
}
|
|
||||||
queue.UpdateSize(aSizeDiff);
|
queue.UpdateSize(aSizeDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1671,9 +1631,7 @@ imgLoader::CheckCacheLimits(imgCacheTable& cache, imgCacheQueue& queue)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry) {
|
if (entry) {
|
||||||
// We just popped this entry from the queue, so pass AlreadyRemoved
|
RemoveFromCache(entry);
|
||||||
// to avoid searching the queue again in RemoveFromCache.
|
|
||||||
RemoveFromCache(entry, QueueState::AlreadyRemoved);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1972,7 +1930,7 @@ imgLoader::RemoveFromCache(const ImageCacheKey& aKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
imgLoader::RemoveFromCache(imgCacheEntry* entry, QueueState aQueueState)
|
imgLoader::RemoveFromCache(imgCacheEntry* entry)
|
||||||
{
|
{
|
||||||
LOG_STATIC_FUNC(gImgLog, "imgLoader::RemoveFromCache entry");
|
LOG_STATIC_FUNC(gImgLog, "imgLoader::RemoveFromCache entry");
|
||||||
|
|
||||||
|
|
@ -1988,24 +1946,13 @@ imgLoader::RemoveFromCache(imgCacheEntry* entry, QueueState aQueueState)
|
||||||
|
|
||||||
cache.Remove(key);
|
cache.Remove(key);
|
||||||
|
|
||||||
if (queue.IsDirty()) {
|
|
||||||
queue.Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry->HasNoProxies()) {
|
if (entry->HasNoProxies()) {
|
||||||
LOG_STATIC_FUNC(gImgLog,
|
LOG_STATIC_FUNC(gImgLog,
|
||||||
"imgLoader::RemoveFromCache removing from tracker");
|
"imgLoader::RemoveFromCache removing from tracker");
|
||||||
if (mCacheTracker) {
|
if (mCacheTracker) {
|
||||||
mCacheTracker->RemoveObject(entry);
|
mCacheTracker->RemoveObject(entry);
|
||||||
}
|
}
|
||||||
// Only search the queue to remove the entry if its possible it might
|
queue.Remove(entry);
|
||||||
// be in the queue. If we know its not in the queue this would be
|
|
||||||
// wasted work.
|
|
||||||
MOZ_ASSERT_IF(aQueueState == QueueState::AlreadyRemoved,
|
|
||||||
!queue.Contains(entry));
|
|
||||||
if (aQueueState == QueueState::MaybeExists) {
|
|
||||||
queue.Remove(entry);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->SetEvicted(true);
|
entry->SetEvicted(true);
|
||||||
|
|
@ -2050,13 +1997,13 @@ imgLoader::EvictEntries(imgCacheQueue& aQueueToClear)
|
||||||
// We have to make a temporary, since RemoveFromCache removes the element
|
// We have to make a temporary, since RemoveFromCache removes the element
|
||||||
// from the queue, invalidating iterators.
|
// from the queue, invalidating iterators.
|
||||||
nsTArray<RefPtr<imgCacheEntry> > entries(aQueueToClear.GetNumElements());
|
nsTArray<RefPtr<imgCacheEntry> > entries(aQueueToClear.GetNumElements());
|
||||||
for (auto i = aQueueToClear.begin(); i != aQueueToClear.end(); ++i) {
|
for (imgCacheQueue::const_iterator i = aQueueToClear.begin();
|
||||||
|
i != aQueueToClear.end(); ++i) {
|
||||||
entries.AppendElement(*i);
|
entries.AppendElement(*i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate in reverse order to minimize array copying.
|
for (uint32_t i = 0; i < entries.Length(); ++i) {
|
||||||
for (auto& entry : entries) {
|
if (!RemoveFromCache(entries[i])) {
|
||||||
if (!RemoveFromCache(entry)) {
|
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -178,8 +178,7 @@ public:
|
||||||
uint32_t GetSize() const;
|
uint32_t GetSize() const;
|
||||||
void UpdateSize(int32_t diff);
|
void UpdateSize(int32_t diff);
|
||||||
uint32_t GetNumElements() const;
|
uint32_t GetNumElements() const;
|
||||||
bool Contains(imgCacheEntry* aEntry) const;
|
typedef std::vector<RefPtr<imgCacheEntry> > queueContainer;
|
||||||
typedef nsTArray<RefPtr<imgCacheEntry> > queueContainer;
|
|
||||||
typedef queueContainer::iterator iterator;
|
typedef queueContainer::iterator iterator;
|
||||||
typedef queueContainer::const_iterator const_iterator;
|
typedef queueContainer::const_iterator const_iterator;
|
||||||
|
|
||||||
|
|
@ -317,16 +316,7 @@ public:
|
||||||
nsresult InitCache();
|
nsresult InitCache();
|
||||||
|
|
||||||
bool RemoveFromCache(const ImageCacheKey& aKey);
|
bool RemoveFromCache(const ImageCacheKey& aKey);
|
||||||
|
bool RemoveFromCache(imgCacheEntry* entry);
|
||||||
// Enumeration describing if a given entry is in the cache queue or not.
|
|
||||||
// There are some cases we know the entry is definitely not in the queue.
|
|
||||||
enum class QueueState {
|
|
||||||
MaybeExists,
|
|
||||||
AlreadyRemoved
|
|
||||||
};
|
|
||||||
|
|
||||||
bool RemoveFromCache(imgCacheEntry* entry,
|
|
||||||
QueueState aQueueState = QueueState::MaybeExists);
|
|
||||||
|
|
||||||
bool PutIntoCache(const ImageCacheKey& aKey, imgCacheEntry* aEntry);
|
bool PutIntoCache(const ImageCacheKey& aKey, imgCacheEntry* aEntry);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -253,67 +253,6 @@ function ArraySort(comparefn) {
|
||||||
return MergeSort(O, len, comparefn);
|
return MergeSort(O, len, comparefn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ES2023 22.1.3.30 Array.prototype.toSorted ( comparefn )
|
|
||||||
function ArrayToSorted(comparefn) {
|
|
||||||
if (comparefn !== undefined) {
|
|
||||||
if (!IsCallable(comparefn)) {
|
|
||||||
ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, comparefn));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 1: Let O be ? ToObject(this). Let len be ? ToLength(O.length).
|
|
||||||
var O = ToObject(this);
|
|
||||||
var len = ToLength(O.length);
|
|
||||||
|
|
||||||
// Step 2: Snapshot values in ascending index order into a List.
|
|
||||||
var items = new List();
|
|
||||||
var itemsLen = len;
|
|
||||||
for (var k = 0; k < len; k++) {
|
|
||||||
items[k] = O[k];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 3: Create SortCompare per spec.
|
|
||||||
var wrappedCompareFn = comparefn;
|
|
||||||
var sortCompare;
|
|
||||||
if (wrappedCompareFn === undefined) {
|
|
||||||
sortCompare = function(x, y) {
|
|
||||||
if (x === undefined)
|
|
||||||
return y === undefined ? 0 : 1;
|
|
||||||
if (y === undefined)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
var xString = ToString(x);
|
|
||||||
var yString = ToString(y);
|
|
||||||
if (xString < yString)
|
|
||||||
return -1;
|
|
||||||
if (xString > yString)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
sortCompare = function(x, y) {
|
|
||||||
if (x === undefined)
|
|
||||||
return y === undefined ? 0 : 1;
|
|
||||||
if (y === undefined)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
var v = ToNumber(wrappedCompareFn(x, y));
|
|
||||||
return v !== v ? 0 : v;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 4: Sort the snapshot List using SortCompare.
|
|
||||||
if (itemsLen > 1)
|
|
||||||
MergeSort(items, itemsLen, sortCompare);
|
|
||||||
|
|
||||||
// Step 5: Create result array and write sorted values.
|
|
||||||
var A = ArraySpeciesCreate(O, len);
|
|
||||||
for (var j = 0; j < itemsLen; j++)
|
|
||||||
_DefineDataProperty(A, j, items[j]);
|
|
||||||
|
|
||||||
return A;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ES5 15.4.4.18. */
|
/* ES5 15.4.4.18. */
|
||||||
function ArrayForEach(callbackfn/*, thisArg*/) {
|
function ArrayForEach(callbackfn/*, thisArg*/) {
|
||||||
/* Step 1. */
|
/* Step 1. */
|
||||||
|
|
|
||||||
|
|
@ -3227,7 +3227,6 @@ static const JSFunctionSpec array_methods[] = {
|
||||||
/* ES2023 proposals */
|
/* ES2023 proposals */
|
||||||
JS_SELF_HOSTED_FN("findLast", "ArrayFindLast", 1,0),
|
JS_SELF_HOSTED_FN("findLast", "ArrayFindLast", 1,0),
|
||||||
JS_SELF_HOSTED_FN("findLastIndex", "ArrayFindLastIndex", 1,0),
|
JS_SELF_HOSTED_FN("findLastIndex", "ArrayFindLastIndex", 1,0),
|
||||||
JS_SELF_HOSTED_FN("toSorted", "ArrayToSorted", 1,0),
|
|
||||||
|
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
|
|
@ -3402,8 +3401,7 @@ array_proto_finish(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto)
|
||||||
!DefineProperty(cx, unscopables, cx->names().flatMap, value) ||
|
!DefineProperty(cx, unscopables, cx->names().flatMap, value) ||
|
||||||
!DefineProperty(cx, unscopables, cx->names().includes, value) ||
|
!DefineProperty(cx, unscopables, cx->names().includes, value) ||
|
||||||
!DefineProperty(cx, unscopables, cx->names().keys, value) ||
|
!DefineProperty(cx, unscopables, cx->names().keys, value) ||
|
||||||
!DefineProperty(cx, unscopables, cx->names().values, value) ||
|
!DefineProperty(cx, unscopables, cx->names().values, value))
|
||||||
!DefineProperty(cx, unscopables, cx->names().toSorted, value))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>Array.prototype.toSorted test</title>
|
|
||||||
<style>
|
|
||||||
body { font: 14px/1.4 sans-serif; padding: 16px; }
|
|
||||||
.pass { color: #0a0; }
|
|
||||||
.fail { color: #c00; }
|
|
||||||
pre { white-space: pre-wrap; }
|
|
||||||
</style>
|
|
||||||
<pre id="log"></pre>
|
|
||||||
<script>
|
|
||||||
(function() {
|
|
||||||
const log = document.getElementById("log");
|
|
||||||
function write(msg, cls) {
|
|
||||||
const line = document.createElement("div");
|
|
||||||
if (cls) line.className = cls;
|
|
||||||
line.textContent = msg;
|
|
||||||
log.appendChild(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.assertEq = function(actual, expected, msg) {
|
|
||||||
if (actual !== expected) {
|
|
||||||
throw new Error((msg ? msg + ": " : "") +
|
|
||||||
"expected " + expected + ", got " + actual);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.assertThrowsInstanceOf = function(fn, ctor, msg) {
|
|
||||||
let threw = false;
|
|
||||||
try {
|
|
||||||
fn();
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof ctor) {
|
|
||||||
threw = true;
|
|
||||||
} else {
|
|
||||||
throw new Error((msg ? msg + ": " : "") +
|
|
||||||
"threw " + e + ", expected " + ctor.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!threw) {
|
|
||||||
throw new Error((msg ? msg + ": " : "") + "did not throw");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.reportCompare = function() {};
|
|
||||||
|
|
||||||
let hadError = false;
|
|
||||||
window.addEventListener("error", function(e) {
|
|
||||||
hadError = true;
|
|
||||||
write("FAIL: " + e.message, "fail");
|
|
||||||
});
|
|
||||||
window.addEventListener("load", function() {
|
|
||||||
write("PASS: toSorted.js loaded", "pass");
|
|
||||||
if (!hadError)
|
|
||||||
write("PASS: all toSorted tests passed", "pass");
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
<script src="toSorted.js"></script>
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
/* Any copyright is dedicated to the Public Domain.
|
|
||||||
* http://creativecommons.org/licenses/publicdomain/ */
|
|
||||||
|
|
||||||
assertEq(typeof Array.prototype.toSorted, "function");
|
|
||||||
|
|
||||||
// Non-mutating behavior.
|
|
||||||
let original = [3, 1, 2];
|
|
||||||
let sorted = original.toSorted();
|
|
||||||
assertEq(original !== sorted, true);
|
|
||||||
assertEq(original.join(","), "3,1,2");
|
|
||||||
assertEq(sorted.join(","), "1,2,3");
|
|
||||||
|
|
||||||
// Compare function.
|
|
||||||
let nums = [10, 1, 5];
|
|
||||||
let desc = nums.toSorted((a, b) => b - a);
|
|
||||||
assertEq(desc.join(","), "10,5,1");
|
|
||||||
|
|
||||||
// Stable sort.
|
|
||||||
let stableInput = [
|
|
||||||
{v: 1, id: "a"},
|
|
||||||
{v: 1, id: "b"},
|
|
||||||
{v: 1, id: "c"}
|
|
||||||
];
|
|
||||||
let stableSorted = stableInput.toSorted((x, y) => x.v - y.v);
|
|
||||||
assertEq(stableSorted.map(o => o.id).join(""), "abc");
|
|
||||||
|
|
||||||
// Holes are treated as undefined (properties are created).
|
|
||||||
let sparse = [3, , 1];
|
|
||||||
let sparseSorted = sparse.toSorted();
|
|
||||||
assertEq(sparseSorted.length, 3);
|
|
||||||
assertEq(sparseSorted[0], 1);
|
|
||||||
assertEq(sparseSorted[1], 3);
|
|
||||||
assertEq(2 in sparseSorted, true);
|
|
||||||
assertEq(sparseSorted[2], undefined);
|
|
||||||
|
|
||||||
// Array-like input.
|
|
||||||
let arrayLike = {0: 2, 1: 1, length: 2};
|
|
||||||
let arrayLikeSorted = Array.prototype.toSorted.call(arrayLike);
|
|
||||||
assertEq(Array.isArray(arrayLikeSorted), true);
|
|
||||||
assertEq(arrayLikeSorted.join(","), "1,2");
|
|
||||||
|
|
||||||
// Getter access order (ascending indices).
|
|
||||||
let accessLog = [];
|
|
||||||
let getterArr = {
|
|
||||||
length: 3,
|
|
||||||
get 0() { accessLog.push(0); return 3; },
|
|
||||||
get 1() { accessLog.push(1); return 1; },
|
|
||||||
get 2() { accessLog.push(2); return 2; }
|
|
||||||
};
|
|
||||||
Array.prototype.toSorted.call(getterArr);
|
|
||||||
assertEq(accessLog.join(","), "0,1,2");
|
|
||||||
|
|
||||||
// Comparator errors propagate.
|
|
||||||
assertThrowsInstanceOf(() => [1, 2].toSorted(1), TypeError);
|
|
||||||
|
|
||||||
if (typeof reportCompare === "function")
|
|
||||||
reportCompare(0, 0);
|
|
||||||
|
|
@ -429,7 +429,6 @@
|
||||||
macro(toJSON, toJSON, "toJSON") \
|
macro(toJSON, toJSON, "toJSON") \
|
||||||
macro(toLocaleString, toLocaleString, "toLocaleString") \
|
macro(toLocaleString, toLocaleString, "toLocaleString") \
|
||||||
macro(toSource, toSource, "toSource") \
|
macro(toSource, toSource, "toSource") \
|
||||||
macro(toSorted, toSorted, "toSorted") \
|
|
||||||
macro(toString, toString, "toString") \
|
macro(toString, toString, "toString") \
|
||||||
macro(toUTCString, toUTCString, "toUTCString") \
|
macro(toUTCString, toUTCString, "toUTCString") \
|
||||||
macro(true, true_, "true") \
|
macro(true, true_, "true") \
|
||||||
|
|
|
||||||
|
|
@ -1,960 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* 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 "CSSNestingFlattener.h"
|
|
||||||
|
|
||||||
#include "mozilla/Assertions.h"
|
|
||||||
#include "nsString.h"
|
|
||||||
#include "nsTArray.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace css {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class CSSNestingFlattener final
|
|
||||||
{
|
|
||||||
using SelectorList = nsTArray<nsString>;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit CSSNestingFlattener(const nsAString& aInput)
|
|
||||||
: mInput(aInput)
|
|
||||||
, mPos(0)
|
|
||||||
, mSawNesting(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Flatten(nsAString& aOutput)
|
|
||||||
{
|
|
||||||
nsAutoString flattened;
|
|
||||||
if (!ProcessStylesheet(flattened, false)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SkipWhitespaceAndComments();
|
|
||||||
if (mPos != mInput.Length() || !mSawNesting) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
aOutput.Assign(flattened);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static bool
|
|
||||||
IsCSSWhitespace(char16_t aChar)
|
|
||||||
{
|
|
||||||
return aChar == ' ' || aChar == '\t' || aChar == '\r' ||
|
|
||||||
aChar == '\n' || aChar == '\f';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
AtEnd() const
|
|
||||||
{
|
|
||||||
return mPos >= mInput.Length();
|
|
||||||
}
|
|
||||||
|
|
||||||
char16_t
|
|
||||||
Peek() const
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(!AtEnd(), "cannot peek past end");
|
|
||||||
return mInput.CharAt(mPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
StartsWithComment() const
|
|
||||||
{
|
|
||||||
return mPos + 1 < mInput.Length() &&
|
|
||||||
mInput.CharAt(mPos) == '/' &&
|
|
||||||
mInput.CharAt(mPos + 1) == '*';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
SkipComment()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(StartsWithComment(), "expected comment");
|
|
||||||
|
|
||||||
mPos += 2;
|
|
||||||
while (mPos + 1 < mInput.Length()) {
|
|
||||||
if (mInput.CharAt(mPos) == '*' && mInput.CharAt(mPos + 1) == '/') {
|
|
||||||
mPos += 2;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
++mPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SkipWhitespaceAndComments()
|
|
||||||
{
|
|
||||||
while (!AtEnd()) {
|
|
||||||
if (IsCSSWhitespace(Peek())) {
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (StartsWithComment()) {
|
|
||||||
if (!SkipComment()) {
|
|
||||||
mPos = mInput.Length();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
SkipString(char16_t aQuote)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(!AtEnd() && Peek() == aQuote, "expected string start");
|
|
||||||
|
|
||||||
++mPos;
|
|
||||||
while (!AtEnd()) {
|
|
||||||
char16_t c = Peek();
|
|
||||||
++mPos;
|
|
||||||
if (c == aQuote) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (c == '\\' && !AtEnd()) {
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '\n' || c == '\r' || c == '\f') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
TrimWhitespace(nsAString& aText)
|
|
||||||
{
|
|
||||||
uint32_t start = 0;
|
|
||||||
uint32_t end = aText.Length();
|
|
||||||
|
|
||||||
while (start < end && IsCSSWhitespace(aText.CharAt(start))) {
|
|
||||||
++start;
|
|
||||||
}
|
|
||||||
while (end > start && IsCSSWhitespace(aText.CharAt(end - 1))) {
|
|
||||||
--end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start == 0 && end == aText.Length()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
aText.Assign(Substring(aText, start, end - start));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
SplitSelectorList(const nsAString& aSelectorText, SelectorList& aSelectors)
|
|
||||||
{
|
|
||||||
uint32_t itemStart = 0;
|
|
||||||
int32_t parenDepth = 0;
|
|
||||||
int32_t bracketDepth = 0;
|
|
||||||
bool inComment = false;
|
|
||||||
char16_t stringQuote = 0;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < aSelectorText.Length(); ++i) {
|
|
||||||
char16_t c = aSelectorText.CharAt(i);
|
|
||||||
|
|
||||||
if (inComment) {
|
|
||||||
if (c == '*' && i + 1 < aSelectorText.Length() &&
|
|
||||||
aSelectorText.CharAt(i + 1) == '/') {
|
|
||||||
inComment = false;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stringQuote) {
|
|
||||||
if (c == '\\') {
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == stringQuote) {
|
|
||||||
stringQuote = 0;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '/' && i + 1 < aSelectorText.Length() &&
|
|
||||||
aSelectorText.CharAt(i + 1) == '*') {
|
|
||||||
inComment = true;
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '"' || c == '\'') {
|
|
||||||
stringQuote = c;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '(') {
|
|
||||||
++parenDepth;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ')' && parenDepth > 0) {
|
|
||||||
--parenDepth;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '[') {
|
|
||||||
++bracketDepth;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ']' && bracketDepth > 0) {
|
|
||||||
--bracketDepth;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == ',' && parenDepth == 0 && bracketDepth == 0) {
|
|
||||||
nsAutoString selector;
|
|
||||||
selector.Assign(Substring(aSelectorText, itemStart, i - itemStart));
|
|
||||||
TrimWhitespace(selector);
|
|
||||||
if (!selector.IsEmpty()) {
|
|
||||||
aSelectors.AppendElement(selector);
|
|
||||||
}
|
|
||||||
itemStart = i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoString selector;
|
|
||||||
selector.Assign(Substring(aSelectorText, itemStart));
|
|
||||||
TrimWhitespace(selector);
|
|
||||||
if (!selector.IsEmpty()) {
|
|
||||||
aSelectors.AppendElement(selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
return !aSelectors.IsEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
SelectorHasAmpersand(const nsAString& aSelector) const
|
|
||||||
{
|
|
||||||
bool inComment = false;
|
|
||||||
char16_t stringQuote = 0;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < aSelector.Length(); ++i) {
|
|
||||||
char16_t c = aSelector.CharAt(i);
|
|
||||||
|
|
||||||
if (inComment) {
|
|
||||||
if (c == '*' && i + 1 < aSelector.Length() &&
|
|
||||||
aSelector.CharAt(i + 1) == '/') {
|
|
||||||
inComment = false;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stringQuote) {
|
|
||||||
if (c == '\\') {
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == stringQuote) {
|
|
||||||
stringQuote = 0;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '/' && i + 1 < aSelector.Length() &&
|
|
||||||
aSelector.CharAt(i + 1) == '*') {
|
|
||||||
inComment = true;
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '"' || c == '\'') {
|
|
||||||
stringQuote = c;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '&') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ReplaceAmpersands(const nsAString& aSelector,
|
|
||||||
const nsAString& aParent,
|
|
||||||
nsAString& aOutput) const
|
|
||||||
{
|
|
||||||
bool inComment = false;
|
|
||||||
char16_t stringQuote = 0;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < aSelector.Length(); ++i) {
|
|
||||||
char16_t c = aSelector.CharAt(i);
|
|
||||||
|
|
||||||
if (inComment) {
|
|
||||||
aOutput.Append(c);
|
|
||||||
if (c == '*' && i + 1 < aSelector.Length() &&
|
|
||||||
aSelector.CharAt(i + 1) == '/') {
|
|
||||||
aOutput.Append('/');
|
|
||||||
inComment = false;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stringQuote) {
|
|
||||||
aOutput.Append(c);
|
|
||||||
if (c == '\\' && i + 1 < aSelector.Length()) {
|
|
||||||
aOutput.Append(aSelector.CharAt(i + 1));
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == stringQuote) {
|
|
||||||
stringQuote = 0;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '/' && i + 1 < aSelector.Length() &&
|
|
||||||
aSelector.CharAt(i + 1) == '*') {
|
|
||||||
aOutput.AppendLiteral("/*");
|
|
||||||
inComment = true;
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '"' || c == '\'') {
|
|
||||||
aOutput.Append(c);
|
|
||||||
stringQuote = c;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '&') {
|
|
||||||
aOutput.Append(aParent);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
aOutput.Append(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ExpandNestedSelectors(const SelectorList& aParents,
|
|
||||||
const nsAString& aNestedSelectorText,
|
|
||||||
SelectorList& aSelectors)
|
|
||||||
{
|
|
||||||
SelectorList nestedSelectors;
|
|
||||||
if (!SplitSelectorList(aNestedSelectorText, nestedSelectors)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const nsString& nestedSelector : nestedSelectors) {
|
|
||||||
bool hasAmpersand = SelectorHasAmpersand(nestedSelector);
|
|
||||||
for (const nsString& parentSelector : aParents) {
|
|
||||||
nsAutoString combined;
|
|
||||||
if (hasAmpersand) {
|
|
||||||
ReplaceAmpersands(nestedSelector, parentSelector, combined);
|
|
||||||
} else {
|
|
||||||
combined.Assign(parentSelector);
|
|
||||||
if (!combined.IsEmpty()) {
|
|
||||||
combined.Append(' ');
|
|
||||||
}
|
|
||||||
combined.Append(nestedSelector);
|
|
||||||
}
|
|
||||||
TrimWhitespace(combined);
|
|
||||||
if (!combined.IsEmpty()) {
|
|
||||||
aSelectors.AppendElement(combined);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return !aSelectors.IsEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
AppendSelectors(const SelectorList& aSelectors, nsAString& aOutput)
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i < aSelectors.Length(); ++i) {
|
|
||||||
if (i) {
|
|
||||||
aOutput.AppendLiteral(", ");
|
|
||||||
}
|
|
||||||
aOutput.Append(aSelectors[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
StartsNestedSelector(char16_t aChar)
|
|
||||||
{
|
|
||||||
switch (aChar) {
|
|
||||||
case '.':
|
|
||||||
case '#':
|
|
||||||
case '[':
|
|
||||||
case ':':
|
|
||||||
case '&':
|
|
||||||
case '|':
|
|
||||||
case '>':
|
|
||||||
case '+':
|
|
||||||
case '~':
|
|
||||||
case '*':
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
StartsPotentialTypeSelector(char16_t aChar)
|
|
||||||
{
|
|
||||||
return (aChar >= 'a' && aChar <= 'z') ||
|
|
||||||
(aChar >= 'A' && aChar <= 'Z') ||
|
|
||||||
aChar == '_' ||
|
|
||||||
aChar == '\\' ||
|
|
||||||
aChar >= 0x80;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
LooksLikeTypeSelectorRule() const
|
|
||||||
{
|
|
||||||
if (AtEnd() || !StartsPotentialTypeSelector(Peek())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t pos = mPos;
|
|
||||||
int32_t parenDepth = 0;
|
|
||||||
int32_t bracketDepth = 0;
|
|
||||||
bool inComment = false;
|
|
||||||
char16_t stringQuote = 0;
|
|
||||||
|
|
||||||
while (pos < mInput.Length()) {
|
|
||||||
char16_t c = mInput.CharAt(pos);
|
|
||||||
|
|
||||||
if (inComment) {
|
|
||||||
if (c == '*' && pos + 1 < mInput.Length() &&
|
|
||||||
mInput.CharAt(pos + 1) == '/') {
|
|
||||||
inComment = false;
|
|
||||||
++pos;
|
|
||||||
}
|
|
||||||
++pos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stringQuote) {
|
|
||||||
if (c == '\\' && pos + 1 < mInput.Length()) {
|
|
||||||
pos += 2;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == stringQuote) {
|
|
||||||
stringQuote = 0;
|
|
||||||
}
|
|
||||||
++pos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '/' && pos + 1 < mInput.Length() &&
|
|
||||||
mInput.CharAt(pos + 1) == '*') {
|
|
||||||
inComment = true;
|
|
||||||
pos += 2;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '"' || c == '\'') {
|
|
||||||
stringQuote = c;
|
|
||||||
++pos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '(') {
|
|
||||||
++parenDepth;
|
|
||||||
++pos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ')' && parenDepth > 0) {
|
|
||||||
--parenDepth;
|
|
||||||
++pos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '[') {
|
|
||||||
++bracketDepth;
|
|
||||||
++pos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ']' && bracketDepth > 0) {
|
|
||||||
--bracketDepth;
|
|
||||||
++pos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parenDepth == 0 && bracketDepth == 0) {
|
|
||||||
if (c == '{') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (c == ';' || c == '}') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
++pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
IsAtRuleNameChar(char16_t aChar)
|
|
||||||
{
|
|
||||||
return (aChar >= 'a' && aChar <= 'z') ||
|
|
||||||
(aChar >= 'A' && aChar <= 'Z') ||
|
|
||||||
(aChar >= '0' && aChar <= '9') ||
|
|
||||||
aChar == '-';
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
LowercaseASCII(nsACString& aText)
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i < aText.Length(); ++i) {
|
|
||||||
char c = aText.CharAt(i);
|
|
||||||
if (c >= 'A' && c <= 'Z') {
|
|
||||||
aText.BeginWriting()[i] = c - 'A' + 'a';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
ShouldProcessGroupRule(const nsACString& aName)
|
|
||||||
{
|
|
||||||
return aName.EqualsLiteral("media") ||
|
|
||||||
aName.EqualsLiteral("supports") ||
|
|
||||||
aName.EqualsLiteral("document") ||
|
|
||||||
aName.EqualsLiteral("layer");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FlushDeclarations(const SelectorList& aSelectors,
|
|
||||||
nsAString& aDeclarations,
|
|
||||||
nsAString& aOutput)
|
|
||||||
{
|
|
||||||
nsAutoString declarations;
|
|
||||||
declarations.Assign(aDeclarations);
|
|
||||||
TrimWhitespace(declarations);
|
|
||||||
aDeclarations.Truncate();
|
|
||||||
|
|
||||||
if (declarations.IsEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AppendSelectors(aSelectors, aOutput);
|
|
||||||
aOutput.AppendLiteral(" { ");
|
|
||||||
aOutput.Append(declarations);
|
|
||||||
aOutput.AppendLiteral(" }\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ReadRawBlockBody(nsAString& aBody)
|
|
||||||
{
|
|
||||||
uint32_t start = mPos;
|
|
||||||
int32_t depth = 0;
|
|
||||||
|
|
||||||
while (!AtEnd()) {
|
|
||||||
char16_t c = Peek();
|
|
||||||
if (c == '"' || c == '\'') {
|
|
||||||
if (!SkipString(c)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (StartsWithComment()) {
|
|
||||||
if (!SkipComment()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '{') {
|
|
||||||
++depth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '}') {
|
|
||||||
if (depth == 0) {
|
|
||||||
aBody.Assign(Substring(mInput, start, mPos - start));
|
|
||||||
++mPos;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
--depth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
++mPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ReadQualifiedRulePrelude(nsAString& aPrelude)
|
|
||||||
{
|
|
||||||
uint32_t start = mPos;
|
|
||||||
int32_t parenDepth = 0;
|
|
||||||
int32_t bracketDepth = 0;
|
|
||||||
|
|
||||||
while (!AtEnd()) {
|
|
||||||
char16_t c = Peek();
|
|
||||||
if (c == '"' || c == '\'') {
|
|
||||||
if (!SkipString(c)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (StartsWithComment()) {
|
|
||||||
if (!SkipComment()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '(') {
|
|
||||||
++parenDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ')' && parenDepth > 0) {
|
|
||||||
--parenDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '[') {
|
|
||||||
++bracketDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ']' && bracketDepth > 0) {
|
|
||||||
--bracketDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '{' && parenDepth == 0 && bracketDepth == 0) {
|
|
||||||
aPrelude.Assign(Substring(mInput, start, mPos - start));
|
|
||||||
TrimWhitespace(aPrelude);
|
|
||||||
++mPos;
|
|
||||||
return !aPrelude.IsEmpty();
|
|
||||||
}
|
|
||||||
if ((c == ';' || c == '}') && parenDepth == 0 && bracketDepth == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
++mPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ReadAtRulePrelude(nsAString& aPrelude, nsACString& aName, bool& aHasBlock)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(!AtEnd() && Peek() == '@', "expected at-rule");
|
|
||||||
|
|
||||||
uint32_t start = mPos;
|
|
||||||
++mPos;
|
|
||||||
aName.Truncate();
|
|
||||||
while (!AtEnd() && IsAtRuleNameChar(Peek())) {
|
|
||||||
char16_t c = Peek();
|
|
||||||
aName.Append(char(c <= 0x7f ? c : '?'));
|
|
||||||
++mPos;
|
|
||||||
}
|
|
||||||
LowercaseASCII(aName);
|
|
||||||
|
|
||||||
int32_t parenDepth = 0;
|
|
||||||
int32_t bracketDepth = 0;
|
|
||||||
while (!AtEnd()) {
|
|
||||||
char16_t c = Peek();
|
|
||||||
if (c == '"' || c == '\'') {
|
|
||||||
if (!SkipString(c)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (StartsWithComment()) {
|
|
||||||
if (!SkipComment()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '(') {
|
|
||||||
++parenDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ')' && parenDepth > 0) {
|
|
||||||
--parenDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '[') {
|
|
||||||
++bracketDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ']' && bracketDepth > 0) {
|
|
||||||
--bracketDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (parenDepth == 0 && bracketDepth == 0) {
|
|
||||||
if (c == ';') {
|
|
||||||
aPrelude.Assign(Substring(mInput, start, mPos - start));
|
|
||||||
TrimWhitespace(aPrelude);
|
|
||||||
++mPos;
|
|
||||||
aHasBlock = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (c == '{') {
|
|
||||||
aPrelude.Assign(Substring(mInput, start, mPos - start));
|
|
||||||
TrimWhitespace(aPrelude);
|
|
||||||
++mPos;
|
|
||||||
aHasBlock = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++mPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ConsumeDeclaration(nsAString& aDeclaration)
|
|
||||||
{
|
|
||||||
uint32_t start = mPos;
|
|
||||||
int32_t parenDepth = 0;
|
|
||||||
int32_t bracketDepth = 0;
|
|
||||||
int32_t braceDepth = 0;
|
|
||||||
|
|
||||||
while (!AtEnd()) {
|
|
||||||
char16_t c = Peek();
|
|
||||||
if (c == '"' || c == '\'') {
|
|
||||||
if (!SkipString(c)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (StartsWithComment()) {
|
|
||||||
if (!SkipComment()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '(') {
|
|
||||||
++parenDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ')' && parenDepth > 0) {
|
|
||||||
--parenDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '[') {
|
|
||||||
++bracketDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ']' && bracketDepth > 0) {
|
|
||||||
--bracketDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '{') {
|
|
||||||
++braceDepth;
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '}') {
|
|
||||||
if (braceDepth == 0 && parenDepth == 0 && bracketDepth == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (braceDepth > 0) {
|
|
||||||
--braceDepth;
|
|
||||||
}
|
|
||||||
++mPos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == ';' && parenDepth == 0 && bracketDepth == 0 &&
|
|
||||||
braceDepth == 0) {
|
|
||||||
++mPos;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++mPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
aDeclaration.Assign(Substring(mInput, start, mPos - start));
|
|
||||||
TrimWhitespace(aDeclaration);
|
|
||||||
if (aDeclaration.IsEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (aDeclaration.Last() != ';') {
|
|
||||||
aDeclaration.Append(';');
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ParseAtRule(nsAString& aOutput, const SelectorList* aParents)
|
|
||||||
{
|
|
||||||
nsAutoString prelude;
|
|
||||||
nsAutoCString name;
|
|
||||||
bool hasBlock = false;
|
|
||||||
if (!ReadAtRulePrelude(prelude, name, hasBlock)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasBlock) {
|
|
||||||
aOutput.Append(prelude);
|
|
||||||
aOutput.AppendLiteral(";\n");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ShouldProcessGroupRule(name)) {
|
|
||||||
nsAutoString body;
|
|
||||||
if (!ReadRawBlockBody(body)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
aOutput.Append(prelude);
|
|
||||||
aOutput.AppendLiteral(" {");
|
|
||||||
aOutput.Append(body);
|
|
||||||
aOutput.AppendLiteral("}\n");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoString inner;
|
|
||||||
if (aParents) {
|
|
||||||
mSawNesting = true;
|
|
||||||
if (!ProcessStyleContext(*aParents, inner)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!ProcessStylesheet(inner, true)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
aOutput.Append(prelude);
|
|
||||||
aOutput.AppendLiteral(" {\n");
|
|
||||||
aOutput.Append(inner);
|
|
||||||
aOutput.AppendLiteral("}\n");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ParseQualifiedRule(nsAString& aOutput, const SelectorList* aParents)
|
|
||||||
{
|
|
||||||
nsAutoString prelude;
|
|
||||||
if (!ReadQualifiedRulePrelude(prelude)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SelectorList selectors;
|
|
||||||
if (aParents) {
|
|
||||||
mSawNesting = true;
|
|
||||||
if (!ExpandNestedSelectors(*aParents, prelude, selectors)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (!SplitSelectorList(prelude, selectors)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ProcessStyleContext(selectors, aOutput);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ProcessStyleContext(const SelectorList& aSelectors, nsAString& aOutput)
|
|
||||||
{
|
|
||||||
nsAutoString declarations;
|
|
||||||
|
|
||||||
while (!AtEnd()) {
|
|
||||||
SkipWhitespaceAndComments();
|
|
||||||
if (AtEnd()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
char16_t c = Peek();
|
|
||||||
if (c == '}') {
|
|
||||||
++mPos;
|
|
||||||
FlushDeclarations(aSelectors, declarations, aOutput);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '@') {
|
|
||||||
FlushDeclarations(aSelectors, declarations, aOutput);
|
|
||||||
if (!ParseAtRule(aOutput, &aSelectors)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StartsNestedSelector(c) || LooksLikeTypeSelectorRule()) {
|
|
||||||
FlushDeclarations(aSelectors, declarations, aOutput);
|
|
||||||
if (!ParseQualifiedRule(aOutput, &aSelectors)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoString declaration;
|
|
||||||
if (!ConsumeDeclaration(declaration)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!declarations.IsEmpty()) {
|
|
||||||
declarations.Append(' ');
|
|
||||||
}
|
|
||||||
declarations.Append(declaration);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ProcessStylesheet(nsAString& aOutput, bool aStopAtBlockEnd)
|
|
||||||
{
|
|
||||||
while (!AtEnd()) {
|
|
||||||
SkipWhitespaceAndComments();
|
|
||||||
if (AtEnd()) {
|
|
||||||
return !aStopAtBlockEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Peek() == '}') {
|
|
||||||
if (!aStopAtBlockEnd) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
++mPos;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Peek() == '@') {
|
|
||||||
if (!ParseAtRule(aOutput, nullptr)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!ParseQualifiedRule(aOutput, nullptr)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return !aStopAtBlockEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
const nsAString& mInput;
|
|
||||||
uint32_t mPos;
|
|
||||||
bool mSawNesting;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
bool
|
|
||||||
FlattenBasicCSSNesting(const nsAString& aInput, nsAString& aOutput)
|
|
||||||
{
|
|
||||||
CSSNestingFlattener flattener(aInput);
|
|
||||||
return flattener.Flatten(aOutput);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace css
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
#ifndef CSSNestingFlattener_h
|
|
||||||
#define CSSNestingFlattener_h
|
|
||||||
|
|
||||||
class nsAString;
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace css {
|
|
||||||
|
|
||||||
bool FlattenBasicCSSNesting(const nsAString& aInput, nsAString& aOutput);
|
|
||||||
|
|
||||||
} // namespace css
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
#endif // CSSNestingFlattener_h
|
|
||||||
|
|
@ -127,7 +127,6 @@ UNIFIED_SOURCES += [
|
||||||
'CounterStyleManager.cpp',
|
'CounterStyleManager.cpp',
|
||||||
'CSS.cpp',
|
'CSS.cpp',
|
||||||
'CSSLexer.cpp',
|
'CSSLexer.cpp',
|
||||||
'CSSNestingFlattener.cpp',
|
|
||||||
'CSSRuleList.cpp',
|
'CSSRuleList.cpp',
|
||||||
'CSSStyleSheet.cpp',
|
'CSSStyleSheet.cpp',
|
||||||
'CSSVariableDeclarations.cpp',
|
'CSSVariableDeclarations.cpp',
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
#include "mozilla/ArrayUtils.h"
|
#include "mozilla/ArrayUtils.h"
|
||||||
#include "mozilla/DebugOnly.h"
|
#include "mozilla/DebugOnly.h"
|
||||||
#include "mozilla/Maybe.h"
|
|
||||||
#include "mozilla/Move.h"
|
#include "mozilla/Move.h"
|
||||||
#include "mozilla/MathAlgorithms.h"
|
#include "mozilla/MathAlgorithms.h"
|
||||||
#include "mozilla/TypedEnumBits.h"
|
#include "mozilla/TypedEnumBits.h"
|
||||||
|
|
@ -18,7 +17,6 @@
|
||||||
#include <regex> // for std::regex and std::regex_match
|
#include <regex> // for std::regex and std::regex_match
|
||||||
|
|
||||||
#include "nsCSSParser.h"
|
#include "nsCSSParser.h"
|
||||||
#include "CSSNestingFlattener.h"
|
|
||||||
#include "nsAlgorithm.h"
|
#include "nsAlgorithm.h"
|
||||||
#include "nsCSSProps.h"
|
#include "nsCSSProps.h"
|
||||||
#include "nsCSSKeywords.h"
|
#include "nsCSSKeywords.h"
|
||||||
|
|
@ -73,7 +71,6 @@ static bool sMozGradientsEnabled;
|
||||||
static bool sControlCharVisibility;
|
static bool sControlCharVisibility;
|
||||||
static bool sLegacyNegationPseudoClassEnabled;
|
static bool sLegacyNegationPseudoClassEnabled;
|
||||||
static bool sCascadeLayersEnabled;
|
static bool sCascadeLayersEnabled;
|
||||||
static bool sNestingEnabled;
|
|
||||||
|
|
||||||
const uint32_t
|
const uint32_t
|
||||||
nsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands] = {
|
nsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands] = {
|
||||||
|
|
@ -1826,14 +1823,7 @@ CSSParserImpl::ParseSheet(const nsAString& aInput,
|
||||||
"Sheet principal does not match passed principal");
|
"Sheet principal does not match passed principal");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nsAutoString flattenedInput;
|
nsCSSScanner scanner(aInput, aLineNumber);
|
||||||
const nsAString* input = &aInput;
|
|
||||||
if (sNestingEnabled &&
|
|
||||||
mozilla::css::FlattenBasicCSSNesting(aInput, flattenedInput)) {
|
|
||||||
input = &flattenedInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCSSScanner scanner(*input, aLineNumber);
|
|
||||||
css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aSheetURI);
|
css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aSheetURI);
|
||||||
InitScanner(scanner, reporter, aSheetURI, aBaseURI, aSheetPrincipal);
|
InitScanner(scanner, reporter, aSheetURI, aBaseURI, aSheetPrincipal);
|
||||||
|
|
||||||
|
|
@ -18997,8 +18987,6 @@ nsCSSParser::Startup()
|
||||||
"layout.css.legacy-negation-pseudo.enabled");
|
"layout.css.legacy-negation-pseudo.enabled");
|
||||||
Preferences::AddBoolVarCache(&sCascadeLayersEnabled,
|
Preferences::AddBoolVarCache(&sCascadeLayersEnabled,
|
||||||
"layout.css.cascade-layers.enabled");
|
"layout.css.cascade-layers.enabled");
|
||||||
Preferences::AddBoolVarCache(&sNestingEnabled,
|
|
||||||
"layout.css.nesting.enabled");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCSSParser::nsCSSParser(mozilla::css::Loader* aLoader,
|
nsCSSParser::nsCSSParser(mozilla::css::Loader* aLoader,
|
||||||
|
|
|
||||||
|
|
@ -72,9 +72,6 @@ support-files = file_animations_with_disabled_properties.html
|
||||||
[test_attribute_selector_eof_behavior.html]
|
[test_attribute_selector_eof_behavior.html]
|
||||||
[test_aspect_ratio_property.html]
|
[test_aspect_ratio_property.html]
|
||||||
[test_background_blend_mode.html]
|
[test_background_blend_mode.html]
|
||||||
[test_basic_nesting_flattening.html]
|
|
||||||
[test_nesting_flattening_parser_edges.html]
|
|
||||||
[test_nesting_flattening_recovery.html]
|
|
||||||
[test_box_size_keywords.html]
|
[test_box_size_keywords.html]
|
||||||
[test_bug73586.html]
|
[test_bug73586.html]
|
||||||
[test_css_math_functions.html]
|
[test_css_math_functions.html]
|
||||||
|
|
|
||||||
|
|
@ -1,146 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>Test for Basic CSS Nesting Flattening</title>
|
|
||||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
||||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="scope" class="scope order">
|
|
||||||
<span id="desc" class="desc"></span>
|
|
||||||
</div>
|
|
||||||
<div id="button" class="button active"></div>
|
|
||||||
<pre id="standalone-log"></pre>
|
|
||||||
<script>
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function colorOf(win, element, property) {
|
|
||||||
return win.getComputedStyle(element).getPropertyValue(property);
|
|
||||||
}
|
|
||||||
|
|
||||||
function appendTestSheet() {
|
|
||||||
var style = document.createElement("style");
|
|
||||||
style.textContent =
|
|
||||||
".scope {\n" +
|
|
||||||
" color: rgb(1, 2, 3);\n" +
|
|
||||||
" .desc {\n" +
|
|
||||||
" color: rgb(4, 5, 6);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" span {\n" +
|
|
||||||
" border-left-style: solid;\n" +
|
|
||||||
" border-left-color: rgb(19, 20, 21);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" span:first-child, span:last-child {\n" +
|
|
||||||
" border-bottom-style: solid;\n" +
|
|
||||||
" border-bottom-color: rgb(22, 23, 24);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" background-color: rgb(7, 8, 9);\n" +
|
|
||||||
"}\n" +
|
|
||||||
"\n" +
|
|
||||||
".button {\n" +
|
|
||||||
" &.active {\n" +
|
|
||||||
" color: rgb(10, 11, 12);\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}\n" +
|
|
||||||
"\n" +
|
|
||||||
".order {\n" +
|
|
||||||
" border-top-style: solid;\n" +
|
|
||||||
" @media all {\n" +
|
|
||||||
" & {\n" +
|
|
||||||
" border-top-color: rgb(13, 14, 15);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" border-right-style: solid;\n" +
|
|
||||||
" border-right-color: rgb(16, 17, 18);\n" +
|
|
||||||
"}\n";
|
|
||||||
document.head.appendChild(style);
|
|
||||||
return style;
|
|
||||||
}
|
|
||||||
|
|
||||||
function runChecks(style, report) {
|
|
||||||
var scope = document.getElementById("scope");
|
|
||||||
var desc = document.getElementById("desc");
|
|
||||||
var button = document.getElementById("button");
|
|
||||||
|
|
||||||
report(colorOf(window, scope, "color") === "rgb(1, 2, 3)",
|
|
||||||
"outer rule declarations should apply",
|
|
||||||
colorOf(window, scope, "color"),
|
|
||||||
"rgb(1, 2, 3)");
|
|
||||||
report(colorOf(window, desc, "color") === "rgb(4, 5, 6)",
|
|
||||||
"nested descendant rule should be flattened",
|
|
||||||
colorOf(window, desc, "color"),
|
|
||||||
"rgb(4, 5, 6)");
|
|
||||||
report(colorOf(window, desc, "border-left-color") === "rgb(19, 20, 21)",
|
|
||||||
"nested type selector rule should be flattened",
|
|
||||||
colorOf(window, desc, "border-left-color"),
|
|
||||||
"rgb(19, 20, 21)");
|
|
||||||
report(colorOf(window, desc, "border-bottom-color") === "rgb(22, 23, 24)",
|
|
||||||
"nested type selector pseudos should be flattened",
|
|
||||||
colorOf(window, desc, "border-bottom-color"),
|
|
||||||
"rgb(22, 23, 24)");
|
|
||||||
report(colorOf(window, scope, "background-color") === "rgb(7, 8, 9)",
|
|
||||||
"declarations after a nested rule should preserve order",
|
|
||||||
colorOf(window, scope, "background-color"),
|
|
||||||
"rgb(7, 8, 9)");
|
|
||||||
report(colorOf(window, button, "color") === "rgb(10, 11, 12)",
|
|
||||||
"ampersand selectors should be expanded",
|
|
||||||
colorOf(window, button, "color"),
|
|
||||||
"rgb(10, 11, 12)");
|
|
||||||
report(colorOf(window, scope, "border-top-color") === "rgb(13, 14, 15)",
|
|
||||||
"nested group rules should target the parent selector",
|
|
||||||
colorOf(window, scope, "border-top-color"),
|
|
||||||
"rgb(13, 14, 15)");
|
|
||||||
report(colorOf(window, scope, "border-right-color") === "rgb(16, 17, 18)",
|
|
||||||
"declarations after nested group rules should still apply",
|
|
||||||
colorOf(window, scope, "border-right-color"),
|
|
||||||
"rgb(16, 17, 18)");
|
|
||||||
report(style.sheet.cssRules.length === 9,
|
|
||||||
"flattening should produce flat top-level rules",
|
|
||||||
String(style.sheet.cssRules.length),
|
|
||||||
"9");
|
|
||||||
}
|
|
||||||
|
|
||||||
function runStandalone() {
|
|
||||||
var log = document.getElementById("standalone-log");
|
|
||||||
var lines = [
|
|
||||||
"Standalone mode.",
|
|
||||||
"This page only demonstrates nesting if layout.css.nesting.enabled is already true in the browser.",
|
|
||||||
""
|
|
||||||
];
|
|
||||||
var style = appendTestSheet();
|
|
||||||
|
|
||||||
runChecks(style, function(pass, message, actual, expected) {
|
|
||||||
lines.push((pass ? "PASS" : "FAIL") + ": " + message);
|
|
||||||
if (!pass) {
|
|
||||||
lines.push(" expected: " + expected);
|
|
||||||
lines.push(" actual: " + actual);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
log.textContent = lines.join("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
function runMochitest() {
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
|
||||||
SpecialPowers.pushPrefEnv({
|
|
||||||
set: [["layout.css.nesting.enabled", true]]
|
|
||||||
}, function() {
|
|
||||||
var style = appendTestSheet();
|
|
||||||
|
|
||||||
runChecks(style, function(pass, message, actual, expected) {
|
|
||||||
is(actual, expected, message);
|
|
||||||
});
|
|
||||||
|
|
||||||
SimpleTest.finish();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof SimpleTest !== "undefined" && typeof SpecialPowers !== "undefined") {
|
|
||||||
runMochitest();
|
|
||||||
} else {
|
|
||||||
runStandalone();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,161 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>Test CSS Nesting Flattening Parser Edges</title>
|
|
||||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
||||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="scope" class="scope">
|
|
||||||
<span id="firstSpan" class="desc"></span>
|
|
||||||
<span id="middleSpan" class="middle"></span>
|
|
||||||
<span id="escapedSpan" class="1foo"></span>
|
|
||||||
<svg id="svgRoot" xmlns="http://www.w3.org/2000/svg" width="10" height="10">
|
|
||||||
<rect id="nsRect" width="10" height="10"></rect>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<div id="afterMalformed" class="after-malformed"></div>
|
|
||||||
<div id="afterTarget" class="after-target"></div>
|
|
||||||
<pre id="standalone-log"></pre>
|
|
||||||
<script>
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function propOf(win, element, property) {
|
|
||||||
return win.getComputedStyle(element).getPropertyValue(property);
|
|
||||||
}
|
|
||||||
|
|
||||||
function appendTestSheet() {
|
|
||||||
var style = document.createElement("style");
|
|
||||||
style.textContent =
|
|
||||||
"@namespace svg url(http://www.w3.org/2000/svg);\n" +
|
|
||||||
".scope {\n" +
|
|
||||||
" --payload: { alpha: 1; beta: 2; };\n" +
|
|
||||||
" color: rgb(1, 2, 3);\n" +
|
|
||||||
" span:first-of-type, span:last-of-type {\n" +
|
|
||||||
" color: rgb(30, 31, 32);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" .\\31 foo {\n" +
|
|
||||||
" border-left-style: solid;\n" +
|
|
||||||
" border-left-color: rgb(40, 41, 42);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" svg|rect {\n" +
|
|
||||||
" stroke: rgb(50, 51, 52);\n" +
|
|
||||||
" stroke-width: 1px;\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}\n" +
|
|
||||||
"\n" +
|
|
||||||
".after-malformed {\n" +
|
|
||||||
" color: rgb(60, 61, 62);\n" +
|
|
||||||
" : {\n" +
|
|
||||||
" color: rgb(70, 71, 72);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" background-color: rgb(80, 81, 82);\n" +
|
|
||||||
"}\n" +
|
|
||||||
"\n" +
|
|
||||||
".after-target {\n" +
|
|
||||||
" color: rgb(90, 91, 92);\n" +
|
|
||||||
"}\n";
|
|
||||||
document.head.appendChild(style);
|
|
||||||
return style;
|
|
||||||
}
|
|
||||||
|
|
||||||
function runChecks(style, report) {
|
|
||||||
var scope = document.getElementById("scope");
|
|
||||||
var firstSpan = document.getElementById("firstSpan");
|
|
||||||
var middleSpan = document.getElementById("middleSpan");
|
|
||||||
var escapedSpan = document.getElementById("escapedSpan");
|
|
||||||
var rect = document.getElementById("nsRect");
|
|
||||||
var afterMalformed = document.getElementById("afterMalformed");
|
|
||||||
var afterTarget = document.getElementById("afterTarget");
|
|
||||||
|
|
||||||
var payload = propOf(window, scope, "--payload");
|
|
||||||
report(payload.indexOf("alpha") !== -1 && payload.indexOf("beta") !== -1,
|
|
||||||
"custom property payload should survive flattening",
|
|
||||||
payload,
|
|
||||||
"contains alpha and beta");
|
|
||||||
|
|
||||||
report(propOf(window, scope, "color") === "rgb(1, 2, 3)",
|
|
||||||
"base declaration should apply",
|
|
||||||
propOf(window, scope, "color"),
|
|
||||||
"rgb(1, 2, 3)");
|
|
||||||
report(propOf(window, firstSpan, "color") === "rgb(30, 31, 32)",
|
|
||||||
"nested pseudo selector should style first span",
|
|
||||||
propOf(window, firstSpan, "color"),
|
|
||||||
"rgb(30, 31, 32)");
|
|
||||||
report(propOf(window, escapedSpan, "color") === "rgb(30, 31, 32)",
|
|
||||||
"nested pseudo selector should style last span",
|
|
||||||
propOf(window, escapedSpan, "color"),
|
|
||||||
"rgb(30, 31, 32)");
|
|
||||||
report(propOf(window, middleSpan, "color") === "rgb(1, 2, 3)",
|
|
||||||
"middle span should keep inherited scope color",
|
|
||||||
propOf(window, middleSpan, "color"),
|
|
||||||
"rgb(1, 2, 3)");
|
|
||||||
|
|
||||||
report(propOf(window, escapedSpan, "border-left-color") === "rgb(40, 41, 42)",
|
|
||||||
"escaped class selector should match",
|
|
||||||
propOf(window, escapedSpan, "border-left-color"),
|
|
||||||
"rgb(40, 41, 42)");
|
|
||||||
|
|
||||||
report(propOf(window, rect, "stroke") === "rgb(50, 51, 52)",
|
|
||||||
"namespace selector should match nested SVG rect",
|
|
||||||
propOf(window, rect, "stroke"),
|
|
||||||
"rgb(50, 51, 52)");
|
|
||||||
|
|
||||||
report(propOf(window, afterMalformed, "color") === "rgb(60, 61, 62)",
|
|
||||||
"declaration before malformed nested selector should apply",
|
|
||||||
propOf(window, afterMalformed, "color"),
|
|
||||||
"rgb(60, 61, 62)");
|
|
||||||
report(propOf(window, afterMalformed, "background-color") === "rgb(80, 81, 82)",
|
|
||||||
"declaration after malformed nested selector should still apply",
|
|
||||||
propOf(window, afterMalformed, "background-color"),
|
|
||||||
"rgb(80, 81, 82)");
|
|
||||||
report(propOf(window, afterTarget, "color") === "rgb(90, 91, 92)",
|
|
||||||
"subsequent top-level rules should still parse",
|
|
||||||
propOf(window, afterTarget, "color"),
|
|
||||||
"rgb(90, 91, 92)");
|
|
||||||
}
|
|
||||||
|
|
||||||
function runStandalone() {
|
|
||||||
var log = document.getElementById("standalone-log");
|
|
||||||
var lines = [
|
|
||||||
"Standalone mode.",
|
|
||||||
"This page only demonstrates nesting if layout.css.nesting.enabled is already true in the browser.",
|
|
||||||
""
|
|
||||||
];
|
|
||||||
var style = appendTestSheet();
|
|
||||||
|
|
||||||
runChecks(style, function(pass, message, actual, expected) {
|
|
||||||
lines.push((pass ? "PASS" : "FAIL") + ": " + message);
|
|
||||||
if (!pass) {
|
|
||||||
lines.push(" expected: " + expected);
|
|
||||||
lines.push(" actual: " + actual);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
log.textContent = lines.join("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
function runMochitest() {
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
|
||||||
SpecialPowers.pushPrefEnv({
|
|
||||||
set: [["layout.css.nesting.enabled", true]]
|
|
||||||
}, function() {
|
|
||||||
var style = appendTestSheet();
|
|
||||||
|
|
||||||
runChecks(style, function(pass, message, actual, expected) {
|
|
||||||
ok(pass, message + " (expected: " + expected + ", actual: " + actual + ")");
|
|
||||||
});
|
|
||||||
|
|
||||||
SimpleTest.finish();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof SimpleTest !== "undefined" && typeof SpecialPowers !== "undefined") {
|
|
||||||
runMochitest();
|
|
||||||
} else {
|
|
||||||
runStandalone();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,149 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>Test CSS Nesting Flattening Recovery Paths</title>
|
|
||||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
||||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="recBase" class="rec-base"><span id="recBaseChild"></span></div>
|
|
||||||
<div id="recMalformed" class="rec-malformed"></div>
|
|
||||||
<div id="recGroup" class="rec-group"></div>
|
|
||||||
<div id="recTail" class="rec-tail"></div>
|
|
||||||
<pre id="standalone-log"></pre>
|
|
||||||
<script>
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function propOf(win, element, property) {
|
|
||||||
return win.getComputedStyle(element).getPropertyValue(property);
|
|
||||||
}
|
|
||||||
|
|
||||||
function appendTestSheet() {
|
|
||||||
var style = document.createElement("style");
|
|
||||||
style.textContent =
|
|
||||||
".rec-base {\n" +
|
|
||||||
" color: rgb(1, 2, 3);\n" +
|
|
||||||
" |* {\n" +
|
|
||||||
" color: rgb(4, 5, 6);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" background-color: rgb(7, 8, 9);\n" +
|
|
||||||
"}\n" +
|
|
||||||
"\n" +
|
|
||||||
".rec-malformed {\n" +
|
|
||||||
" color: rgb(20, 21, 22);\n" +
|
|
||||||
" : {\n" +
|
|
||||||
" color: rgb(23, 24, 25);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" border-top-style: solid;\n" +
|
|
||||||
" border-top-color: rgb(26, 27, 28);\n" +
|
|
||||||
"}\n" +
|
|
||||||
"\n" +
|
|
||||||
".rec-group {\n" +
|
|
||||||
" color: rgb(32, 33, 34);\n" +
|
|
||||||
" @counter-style rec-counter {\n" +
|
|
||||||
" system: fixed;\n" +
|
|
||||||
" symbols: a;\n" +
|
|
||||||
" }\n" +
|
|
||||||
" background-color: rgb(35, 36, 37);\n" +
|
|
||||||
"}\n" +
|
|
||||||
"\n" +
|
|
||||||
".rec-tail {\n" +
|
|
||||||
" color: rgb(50, 51, 52);\n" +
|
|
||||||
"}\n";
|
|
||||||
document.head.appendChild(style);
|
|
||||||
return style;
|
|
||||||
}
|
|
||||||
|
|
||||||
function runChecks(style, report) {
|
|
||||||
var recBase = document.getElementById("recBase");
|
|
||||||
var recBaseChild = document.getElementById("recBaseChild");
|
|
||||||
var recMalformed = document.getElementById("recMalformed");
|
|
||||||
var recGroup = document.getElementById("recGroup");
|
|
||||||
var recTail = document.getElementById("recTail");
|
|
||||||
|
|
||||||
report(propOf(window, recBase, "color") === "rgb(1, 2, 3)",
|
|
||||||
"unsupported nested selector should not wipe earlier declarations",
|
|
||||||
propOf(window, recBase, "color"),
|
|
||||||
"rgb(1, 2, 3)");
|
|
||||||
report(propOf(window, recBase, "background-color") === "rgb(7, 8, 9)",
|
|
||||||
"unsupported nested selector should not wipe later declarations",
|
|
||||||
propOf(window, recBase, "background-color"),
|
|
||||||
"rgb(7, 8, 9)");
|
|
||||||
report(propOf(window, recBaseChild, "color") === "rgb(1, 2, 3)",
|
|
||||||
"unsupported nested selector should not restyle descendants unexpectedly",
|
|
||||||
propOf(window, recBaseChild, "color"),
|
|
||||||
"rgb(1, 2, 3)");
|
|
||||||
|
|
||||||
report(propOf(window, recMalformed, "color") === "rgb(20, 21, 22)",
|
|
||||||
"malformed nested selector should keep declaration before it",
|
|
||||||
propOf(window, recMalformed, "color"),
|
|
||||||
"rgb(20, 21, 22)");
|
|
||||||
report(propOf(window, recMalformed, "border-top-color") === "rgb(26, 27, 28)",
|
|
||||||
"malformed nested selector should keep declaration after it",
|
|
||||||
propOf(window, recMalformed, "border-top-color"),
|
|
||||||
"rgb(26, 27, 28)");
|
|
||||||
|
|
||||||
report(propOf(window, recGroup, "color") === "rgb(32, 33, 34)",
|
|
||||||
"nested unsupported at-rule should keep declaration before it",
|
|
||||||
propOf(window, recGroup, "color"),
|
|
||||||
"rgb(32, 33, 34)");
|
|
||||||
report(propOf(window, recGroup, "background-color") === "rgb(35, 36, 37)",
|
|
||||||
"nested unsupported at-rule should keep declaration after it",
|
|
||||||
propOf(window, recGroup, "background-color"),
|
|
||||||
"rgb(35, 36, 37)");
|
|
||||||
|
|
||||||
report(propOf(window, recTail, "color") === "rgb(50, 51, 52)",
|
|
||||||
"rules after recovery scenarios should still parse",
|
|
||||||
propOf(window, recTail, "color"),
|
|
||||||
"rgb(50, 51, 52)");
|
|
||||||
|
|
||||||
report(style.sheet.cssRules.length >= 4,
|
|
||||||
"stylesheet should remain parseable after recovery scenarios",
|
|
||||||
String(style.sheet.cssRules.length),
|
|
||||||
">= 4");
|
|
||||||
}
|
|
||||||
|
|
||||||
function runStandalone() {
|
|
||||||
var log = document.getElementById("standalone-log");
|
|
||||||
var lines = [
|
|
||||||
"Standalone mode.",
|
|
||||||
"This page only demonstrates nesting if layout.css.nesting.enabled is already true in the browser.",
|
|
||||||
""
|
|
||||||
];
|
|
||||||
var style = appendTestSheet();
|
|
||||||
|
|
||||||
runChecks(style, function(pass, message, actual, expected) {
|
|
||||||
lines.push((pass ? "PASS" : "FAIL") + ": " + message);
|
|
||||||
if (!pass) {
|
|
||||||
lines.push(" expected: " + expected);
|
|
||||||
lines.push(" actual: " + actual);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
log.textContent = lines.join("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
function runMochitest() {
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
|
||||||
SpecialPowers.pushPrefEnv({
|
|
||||||
set: [["layout.css.nesting.enabled", true]]
|
|
||||||
}, function() {
|
|
||||||
var style = appendTestSheet();
|
|
||||||
|
|
||||||
runChecks(style, function(pass, message, actual, expected) {
|
|
||||||
ok(pass, message + " (expected: " + expected + ", actual: " + actual + ")");
|
|
||||||
});
|
|
||||||
|
|
||||||
SimpleTest.finish();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof SimpleTest !== "undefined" && typeof SpecialPowers !== "undefined") {
|
|
||||||
runMochitest();
|
|
||||||
} else {
|
|
||||||
runStandalone();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -2725,9 +2725,6 @@ pref("layout.css.resizeobserver.enabled", true);
|
||||||
// Is support for cascade layers enabled?
|
// Is support for cascade layers enabled?
|
||||||
pref("layout.css.cascade-layers.enabled", true);
|
pref("layout.css.cascade-layers.enabled", true);
|
||||||
|
|
||||||
// Is support for basic CSS nesting lowering enabled?
|
|
||||||
pref("layout.css.nesting.enabled", true);
|
|
||||||
|
|
||||||
// Should rules in imported style sheets be added based on the order
|
// Should rules in imported style sheets be added based on the order
|
||||||
// of appearance of their respective @import rules in the parent
|
// of appearance of their respective @import rules in the parent
|
||||||
// style sheet? Otherwise, they are added before rules preceding
|
// style sheet? Otherwise, they are added before rules preceding
|
||||||
|
|
@ -3233,7 +3230,7 @@ pref("ui.mouse.radius.inputSource.touchOnly", true);
|
||||||
|
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
|
|
||||||
// Be as uniform as possible, use Twemoji everywhere.
|
// Be as uniform as possible, use Twemoji everywhere.
|
||||||
// Optional: prefix with `Segoe UI Emoji` to use Win8+ Segoe UI font emoji where available.
|
// Optional: prefix with `Segoe UI Emoji` to use Win8+ Segoe UI font emoji where available.
|
||||||
pref("font.name-list.emoji", "Twemoji Mozilla");
|
pref("font.name-list.emoji", "Twemoji Mozilla");
|
||||||
|
|
||||||
|
|
@ -4764,7 +4761,7 @@ pref("media.ondevicechange.fakeDeviceChangeEvent.enabled", false);
|
||||||
// those platforms we don't handle touch events anyway so it's conceptually
|
// those platforms we don't handle touch events anyway so it's conceptually
|
||||||
// a no-op.
|
// a no-op.
|
||||||
pref("layout.css.touch_action.enabled", true);
|
pref("layout.css.touch_action.enabled", true);
|
||||||
|
|
||||||
// WHATWG computed intrinsic aspect ratio for an img element
|
// WHATWG computed intrinsic aspect ratio for an img element
|
||||||
// https://html.spec.whatwg.org/multipage/rendering.html#attributes-for-embedded-content-and-images
|
// https://html.spec.whatwg.org/multipage/rendering.html#attributes-for-embedded-content-and-images
|
||||||
// Are the width and height attributes on image-like elements mapped to the
|
// Are the width and height attributes on image-like elements mapped to the
|
||||||
|
|
@ -5276,7 +5273,7 @@ pref("plugins.navigator_hide_disabled_flash", false);
|
||||||
pref("dom.mozBrowserFramesEnabled", false);
|
pref("dom.mozBrowserFramesEnabled", false);
|
||||||
|
|
||||||
// Thick caret when behind CJK characters
|
// Thick caret when behind CJK characters
|
||||||
pref("layout.cjkthickcaret", true);
|
pref("layout.cjkthickcaret", true);
|
||||||
|
|
||||||
// Is support for 'color-adjust' CSS property enabled?
|
// Is support for 'color-adjust' CSS property enabled?
|
||||||
pref("layout.css.color-adjust.enabled", true);
|
pref("layout.css.color-adjust.enabled", true);
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,5 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
FINAL_TARGET_FILES.fonts += ['TwemojiMozilla.ttf']
|
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3'):
|
||||||
|
FINAL_TARGET_FILES.fonts += ['TwemojiMozilla.ttf']
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue