Commits:
-
56736106
by Pier Angelo Vendrame at 2026-09-01T12:40:48+02:00
Bug 2039206 - Wire WindowDevicePixelRatio to image-set. r=firefox-style-system-reviewers,emilio,layout-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D300449
-
71ecc1ad
by Yury Delendik at 2026-09-01T12:40:53+02:00
Bug 2045435 - Prune dying entries from wasm::Realm::instances_ during sweeping. r=jpages
wasm::Realm::instances_ is a weak list. Readers rely on the
instances()[i]->object() read barrier, but that barrier is a no-op once the
owning zone is being incrementally swept, and entries are otherwise only
removed at Instance finalization (~Instance -> unregisterInstance). So between
marking a zone's instance objects dead and finalizing them, the list could
still hand an about-to-be-finalized instance to a reader.
Prune such entries at the start of zone sweeping via a new
wasm::Realm::traceWeakInstances(), called from beginSweepingSweepGroup
alongside the other per-realm weak-collection sweeps. This makes instances_
behave like the engine's other weak collections, so it never exposes an
about-to-be-finalized instance to the mutator during sweep slices.
Differential Revision: https://phabricator.services.mozilla.com/D314032
-
b5de5efc
by Gela at 2026-09-01T12:40:58+02:00
Bug 2053320 - Part 1: Don't tie Nimbus tooling to `HomeActivity` UI a=RyanVM
Original Revision: https://phabricator.services.mozilla.com/D319628
Differential Revision: https://phabricator.services.mozilla.com/D320784
-
0b475830
by Ting-Yu Lin at 2026-09-01T12:41:02+02:00
Bug 2053578 - Use static_cast in nsSplittableFrame::UpdateFirstContinuationAndFirstInFlowCache(). r=layout-reviewers,jfkthame
`nsSplittableFrame` is a subclass of `nsIFrame`, it is sufficient to use
`static_cast`.
Differential Revision: https://phabricator.services.mozilla.com/D315157
-
2c620a58
by Ting-Yu Lin at 2026-09-01T12:41:07+02:00
Bug 2053578 - Update first-in-flow cache when a continuation is changing from fluid to non-fluid. r=layout-reviewers,jfkthame
The original case in bug 2053578 comment 5 can reproduce an ASAN
use-after-poison with the patch bug 2053578 comment 6 applied. However, with
unpatched code, the best we can do is using a DEBUG-only assertion to catch the
error condition that detect a stale first-in-flow cache in next-in-flow.
`bidi-inline-continuation-first-in-flow.html` is generated with the help of
Claude code, and it can trigger the assertion without other fix in this patch.
Differential Revision: https://phabricator.services.mozilla.com/D315158
-
f14f9f44
by Jan Grulich at 2026-09-01T12:41:11+02:00
Bug 2054625 - WebRTC backport: Video capture: validate PipeWire camera frame size to prevent OOB read r=pehrsons
Check spa_chunk::size is not larger than mmap'ed buffer, which would
lead to an out-of-bounds read when the frame is copied. Validate that
chunk offset + size does not exceed maxsize before processing.
This is a simple backport of an WebRTC upstream change.
Upstream commit: 612430e8266881eaff478b0000cacc90fb71c918
Differential Revision: https://phabricator.services.mozilla.com/D316000
-
6017bf80
by David Parks at 2026-09-01T12:41:16+02:00
Bug 2058006 - Call Destroy() unconditionally in ~StatusBarEntry. a=RyanVM DONTBUILD
Allow Destroy() to tear down mIconLoader, even if Init() does not successfully
complete initialization.
Original Revision: https://phabricator.services.mozilla.com/D318206
Differential Revision: https://phabricator.services.mozilla.com/D319879
-
9cf002cf
by David Parks at 2026-09-01T12:41:20+02:00
Bug 2058013 - Only resolve non-filesystem picker results as shell libraries a=RyanVM DONTBUILD
A genuine shell library is a virtual item with no filesystem path. A
.library-ms file is an ordinary file whose XML can name any local directory.
filedialog::GetFolderResults was passing whatever IFileDialog::GetResult
returned to IShellLibrary::LoadLibraryFromItem and, on success, replacing it
with the library's embedded default save folder.
Gating the resolution on the item being affirmatively not a filesystem object
keeps real libraries selectable and resolving as before, while a .library-ms
file "resolves" to itself -- the .library-ms file, not its target.
Original Revision: https://phabricator.services.mozilla.com/D318246
Differential Revision: https://phabricator.services.mozilla.com/D319957
-
1cec2a2f
by Iain Ireland at 2026-09-01T12:41:25+02:00
Bug 2058626: Check for mutually exclusive flags when deserializing cloned RegExp r=spidermonkey-reviewers,jonco
Differential Revision: https://phabricator.services.mozilla.com/D316904
-
08795680
by Kui-Feng Lee at 2026-09-01T12:41:30+02:00
Bug 2058661 - Clear the drag source window's GdkDragContext pointer synchronously. r=stransky a=RyanVM DONTBUILD
gtk_drag_begin_with_coordinates() returns a borrowed context: GtkDragSourceInfo
holds the only reference, and gtk_drag_source_info_destroy() drops it as soon as
the drag-end handler returns. nsWindow::mSourceDragContext was cleared only from
an async runnable (EndDragSessionMainThread -> EndDragSessionImpl), so between
GTK's unref and that runnable the pointer dangled, and nsWindow::OnUnmap() calls
gtk_drag_cancel() on it. Content can land an unmap in that window with a
window.close() task queued before the drag ended.
EndDragSessionImpl keeps its own clear for drags torn down without a drag-end.
Original Revision: https://phabricator.services.mozilla.com/D315509
Differential Revision: https://phabricator.services.mozilla.com/D319278
-
2f953af5
by Kershaw Chang at 2026-09-01T12:41:34+02:00
Bug 2059199 - Reject NUL bytes in chunked trailer and chunk-size lines a=RyanVM DONTBUILD
A trailer field line whose first byte is NUL would look empty to the
end-of-trailer check, ending the trailer section early. We would then stop
reading the body before the server (or a shared proxy) does, and disagree
with them about where the response ends.
Original Revision: https://phabricator.services.mozilla.com/D317742
Differential Revision: https://phabricator.services.mozilla.com/D319931
-
553036bc
by Sotaro Ikeda at 2026-09-01T12:41:39+02:00
Bug 2061532 a=RyanVM DONTBUILD
ANGLE Metal backend usage is also going to disable RenderExternalTextureHost usage.
Original Revision: https://phabricator.services.mozilla.com/D318624
Differential Revision: https://phabricator.services.mozilla.com/D320769
24 changed files:
Changes:
dom/base/ResponsiveImageSelector.cpp
| ... |
... |
@@ -351,10 +351,6 @@ bool ResponsiveImageSelector::SelectImage(bool aReselect) { |
|
351
|
351
|
if (overrideDPPX > 0) {
|
|
352
|
352
|
displayDensity = overrideDPPX;
|
|
353
|
353
|
}
|
|
354
|
|
- if (doc->ShouldResistFingerprinting(RFPTarget::WindowDevicePixelRatio)) {
|
|
355
|
|
- displayDensity =
|
|
356
|
|
- nsRFPService::GetDevicePixelRatioAtZoom(pctx->GetFullZoom());
|
|
357
|
|
- }
|
|
358
|
354
|
|
|
359
|
355
|
// Per spec, "In a UA-specific manner, choose one image source"
|
|
360
|
356
|
// - For now, select the lowest density greater than displayDensity, otherwise
|
gfx/webrender_bindings/RenderExternalTextureHost.cpp
| ... |
... |
@@ -126,7 +126,14 @@ bool RenderExternalTextureHost::IsReadyForDeletion() { |
|
126
|
126
|
|
|
127
|
127
|
auto& textureSource = mTextureSources[0];
|
|
128
|
128
|
if (textureSource) {
|
|
129
|
|
- return textureSource->Sync(false);
|
|
|
129
|
+ if (textureSource->Sync(/* aBlocking */ true)) {
|
|
|
130
|
+ return true;
|
|
|
131
|
+ }
|
|
|
132
|
+ if (mGL && mGL->MakeCurrent() && !mGL->IsDestroyed()) {
|
|
|
133
|
+ mGL->fFinish();
|
|
|
134
|
+ return true;
|
|
|
135
|
+ }
|
|
|
136
|
+ return false;
|
|
130
|
137
|
}
|
|
131
|
138
|
|
|
132
|
139
|
return true;
|
| ... |
... |
@@ -153,7 +160,11 @@ wr::WrExternalImage RenderExternalTextureHost::Lock(uint8_t aChannelIndex, |
|
153
|
160
|
|
|
154
|
161
|
void RenderExternalTextureHost::PrepareForUse() { mTextureUpdateNeeded = true; }
|
|
155
|
162
|
|
|
156
|
|
-void RenderExternalTextureHost::Unlock() {}
|
|
|
163
|
+void RenderExternalTextureHost::Unlock() {
|
|
|
164
|
+ if (mInitialized && mTextureSources[0]) {
|
|
|
165
|
+ mTextureSources[0]->MaybeFenceTexture();
|
|
|
166
|
+ }
|
|
|
167
|
+}
|
|
157
|
168
|
|
|
158
|
169
|
void RenderExternalTextureHost::UpdateTexture(size_t aIndex) {
|
|
159
|
170
|
MOZ_ASSERT(mSurfaces[aIndex]);
|
js/src/gc/GCRuntime.h
| ... |
... |
@@ -924,6 +924,7 @@ class GCRuntime { |
|
924
|
924
|
void updateAtomsBitmap();
|
|
925
|
925
|
void sweepCCWrappers();
|
|
926
|
926
|
void sweepRealmGlobals();
|
|
|
927
|
+ void sweepWasmInstances();
|
|
927
|
928
|
void sweepEmbeddingWeakPointers(JS::GCContext* gcx);
|
|
928
|
929
|
void sweepMisc();
|
|
929
|
930
|
void sweepCompressionTasks();
|
js/src/gc/Sweeping.cpp
| ... |
... |
@@ -1396,6 +1396,13 @@ void GCRuntime::sweepRealmGlobals() { |
|
1396
|
1396
|
}
|
|
1397
|
1397
|
}
|
|
1398
|
1398
|
|
|
|
1399
|
+void GCRuntime::sweepWasmInstances() {
|
|
|
1400
|
+ for (SweepGroupRealmsIter r(this); !r.done(); r.next()) {
|
|
|
1401
|
+ AutoSetThreadIsSweeping threadIsSweeping(r->zone());
|
|
|
1402
|
+ r->wasm.traceWeakInstances();
|
|
|
1403
|
+ }
|
|
|
1404
|
+}
|
|
|
1405
|
+
|
|
1399
|
1406
|
void GCRuntime::sweepMisc() {
|
|
1400
|
1407
|
SweepingTracer trc(rt);
|
|
1401
|
1408
|
for (SweepGroupRealmsIter r(this); !r.done(); r.next()) {
|
| ... |
... |
@@ -1709,6 +1716,11 @@ IncrementalProgress GCRuntime::beginSweepingSweepGroup(JS::GCContext* gcx, |
|
1709
|
1716
|
// This must happen before updating embedding weak pointers.
|
|
1710
|
1717
|
sweepRealmGlobals();
|
|
1711
|
1718
|
|
|
|
1719
|
+ // Prune dying wasm instances from each realm's weak instance list now, at the
|
|
|
1720
|
+ // start of sweeping, before the mutator can observe them via the (now no-op)
|
|
|
1721
|
+ // instances() read barrier during later incremental slices.
|
|
|
1722
|
+ sweepWasmInstances();
|
|
|
1723
|
+
|
|
1712
|
1724
|
sweepEmbeddingWeakPointers(gcx);
|
|
1713
|
1725
|
|
|
1714
|
1726
|
{
|
js/src/jit-test/tests/structured-clone/bug2058626.js
|
|
1
|
+function forge(pattern, srcFlags, flagsByte) {
|
|
|
2
|
+ var cb = serialize(new RegExp(pattern, srcFlags), undefined, { scope: "DifferentProcess" });
|
|
|
3
|
+ var u8 = new Uint8Array(cb.arraybuffer);
|
|
|
4
|
+ for (var i = 0; i + 8 <= u8.length; i += 4) {
|
|
|
5
|
+ var tag = u8[i+4] | (u8[i+5] << 8) | (u8[i+6] << 16) | (u8[i+7] << 24);
|
|
|
6
|
+ if ((tag >>> 0) === 0xFFFF0006) { u8[i] = flagsByte; break; }
|
|
|
7
|
+ }
|
|
|
8
|
+ cb.clonebuffer = u8.buffer;
|
|
|
9
|
+ return deserialize(cb, { scope: "DifferentProcess" });
|
|
|
10
|
+}
|
|
|
11
|
+try {
|
|
|
12
|
+ var forged = forge("[\\q{abc|de}]", "v", 0x90);
|
|
|
13
|
+ var bad = new RegExp(forged, "u");
|
|
|
14
|
+ try { bad.exec("abc"); } catch {}
|
|
|
15
|
+ var good = new RegExp("[\\q{abc|de}]", "u");
|
|
|
16
|
+} catch {} |
js/src/vm/StructuredClone.cpp
| ... |
... |
@@ -3189,7 +3189,9 @@ bool JSStructuredCloneReader::startRead(MutableHandleValue vp, |
|
3189
|
3189
|
}
|
|
3190
|
3190
|
|
|
3191
|
3191
|
case SCTAG_REGEXP_OBJECT: {
|
|
3192
|
|
- if ((data & RegExpFlag::AllFlags) != data) {
|
|
|
3192
|
+ // Reject invalid flags. /u and /v are mutually exclusive.
|
|
|
3193
|
+ if ((data & RegExpFlag::AllFlags) != data ||
|
|
|
3194
|
+ ((data & RegExpFlag::Unicode) && (data & RegExpFlag::UnicodeSets))) {
|
|
3193
|
3195
|
JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
|
|
3194
|
3196
|
JSMSG_SC_BAD_SERIALIZED_DATA, "regexp");
|
|
3195
|
3197
|
return false;
|
js/src/wasm/WasmRealm.cpp
| ... |
... |
@@ -18,6 +18,7 @@ |
|
18
|
18
|
|
|
19
|
19
|
#include "wasm/WasmRealm.h"
|
|
20
|
20
|
|
|
|
21
|
+#include "gc/Marking.h"
|
|
21
|
22
|
#include "vm/GlobalObject.h"
|
|
22
|
23
|
#include "vm/Realm.h"
|
|
23
|
24
|
#include "wasm/WasmDebug.h"
|
| ... |
... |
@@ -111,6 +112,19 @@ void wasm::Realm::unregisterInstance(Instance& instance) { |
|
111
|
112
|
}
|
|
112
|
113
|
}
|
|
113
|
114
|
|
|
|
115
|
+void wasm::Realm::traceWeakInstances() {
|
|
|
116
|
+ // Registration/unregistration of instances_ is tied to Instance lifetime, so
|
|
|
117
|
+ // an instance whose owning object is about to be finalized is still present
|
|
|
118
|
+ // here until ~Instance runs. Remove such entries now, at the start of zone
|
|
|
119
|
+ // sweeping, because the instances() read barrier that otherwise protects
|
|
|
120
|
+ // readers is a no-op once the zone is being swept. erase order is preserved,
|
|
|
121
|
+ // so the pointer-sorted invariant used by BinarySearchIf holds.
|
|
|
122
|
+ instances_.eraseIf([](Instance* instance) {
|
|
|
123
|
+ return js::gc::IsAboutToBeFinalizedUnbarriered(
|
|
|
124
|
+ instance->objectUnbarriered());
|
|
|
125
|
+ });
|
|
|
126
|
+}
|
|
|
127
|
+
|
|
114
|
128
|
void wasm::Realm::ensureProfilingLabels(bool profilingEnabled) {
|
|
115
|
129
|
for (Instance* instance : instances_) {
|
|
116
|
130
|
instance->ensureProfilingLabels(profilingEnabled);
|
js/src/wasm/WasmRealm.h
| ... |
... |
@@ -53,10 +53,17 @@ class Realm { |
|
53
|
53
|
// Return a vector of all live instances in the realm. The lifetime of
|
|
54
|
54
|
// these Instances is determined by their owning WasmInstanceObject.
|
|
55
|
55
|
// Note that accessing instances()[i]->object() triggers a read barrier
|
|
56
|
|
- // since instances() is effectively a weak list.
|
|
|
56
|
+ // since instances() is effectively a weak list. This read barrier is only
|
|
|
57
|
+ // effective while the owning zone is being marked; traceWeakInstances()
|
|
|
58
|
+ // prunes dying entries at the start of sweeping so that the list never
|
|
|
59
|
+ // exposes an about-to-be-finalized instance to the mutator.
|
|
57
|
60
|
|
|
58
|
61
|
const InstanceVector& instances() const { return instances_; }
|
|
59
|
62
|
|
|
|
63
|
+ // Remove instances whose owning object is about to be finalized. Called at
|
|
|
64
|
+ // the start of zone sweeping, when the instances() read barrier is a no-op.
|
|
|
65
|
+ void traceWeakInstances();
|
|
|
66
|
+
|
|
60
|
67
|
// Ensure all Instances in this Realm have profiling labels created.
|
|
61
|
68
|
|
|
62
|
69
|
void ensureProfilingLabels(bool profilingEnabled);
|
layout/base/nsPresContext.cpp
| ... |
... |
@@ -978,7 +978,11 @@ void nsPresContext::RecomputeBrowsingContextDependentData() { |
|
978
|
978
|
auto systemZoom = LookAndFeel::SystemZoomSettings();
|
|
979
|
979
|
SetFullZoom(browsingContext->FullZoom() * systemZoom.mFullZoom);
|
|
980
|
980
|
SetTextZoom(browsingContext->TextZoom() * systemZoom.mTextZoom);
|
|
981
|
|
- SetOverrideDPPX(browsingContext->OverrideDPPX());
|
|
|
981
|
+ if (doc->ShouldResistFingerprinting(RFPTarget::WindowDevicePixelRatio)) {
|
|
|
982
|
+ SetOverrideDPPX(nsRFPService::GetDevicePixelRatioAtZoom(GetFullZoom()));
|
|
|
983
|
+ } else {
|
|
|
984
|
+ SetOverrideDPPX(browsingContext->OverrideDPPX());
|
|
|
985
|
+ }
|
|
982
|
986
|
}
|
|
983
|
987
|
|
|
984
|
988
|
auto* top = browsingContext->Top();
|
layout/generic/nsSplittableFrame.cpp
| ... |
... |
@@ -214,7 +214,7 @@ void nsSplittableFrame::UpdateFirstContinuationAndFirstInFlowCache() { |
|
214
|
214
|
if (oldCachedFirstContinuation != newFirstContinuation) {
|
|
215
|
215
|
// Update the first-continuation cache for us and our next-continuations.
|
|
216
|
216
|
for (nsSplittableFrame* f = this; f;
|
|
217
|
|
- f = reinterpret_cast<nsSplittableFrame*>(f->GetNextContinuation())) {
|
|
|
217
|
+ f = static_cast<nsSplittableFrame*>(f->GetNextContinuation())) {
|
|
218
|
218
|
f->mFirstContinuation = newFirstContinuation;
|
|
219
|
219
|
}
|
|
220
|
220
|
}
|
| ... |
... |
@@ -227,7 +227,7 @@ void nsSplittableFrame::UpdateFirstContinuationAndFirstInFlowCache() { |
|
227
|
227
|
// behavior when a frame list is destroyed from the front. To avoid that
|
|
228
|
228
|
// pathological behavior, we simply purge the cached values.
|
|
229
|
229
|
for (nsSplittableFrame* f = this; f;
|
|
230
|
|
- f = reinterpret_cast<nsSplittableFrame*>(f->GetNextContinuation())) {
|
|
|
230
|
+ f = static_cast<nsSplittableFrame*>(f->GetNextContinuation())) {
|
|
231
|
231
|
f->mFirstContinuation = nullptr;
|
|
232
|
232
|
}
|
|
233
|
233
|
}
|
| ... |
... |
@@ -239,22 +239,41 @@ void nsSplittableFrame::UpdateFirstContinuationAndFirstInFlowCache() { |
|
239
|
239
|
if (oldCachedFirstInFlow != newFirstInFlow) {
|
|
240
|
240
|
// Update the first-in-flow cache for us and our next-in-flows.
|
|
241
|
241
|
for (nsSplittableFrame* f = this; f;
|
|
242
|
|
- f = reinterpret_cast<nsSplittableFrame*>(f->GetNextInFlow())) {
|
|
|
242
|
+ f = static_cast<nsSplittableFrame*>(f->GetNextInFlow())) {
|
|
243
|
243
|
f->mFirstInFlow = newFirstInFlow;
|
|
244
|
244
|
}
|
|
245
|
245
|
}
|
|
246
|
246
|
} else {
|
|
247
|
|
- // We become the new first-in-flow due to our prev-in-flow being removed.
|
|
248
|
|
- if (oldCachedFirstInFlow) {
|
|
249
|
|
- // It's tempting to update the first-in-flow cache for our
|
|
250
|
|
- // next-in-flows here, but that would result in overall O(n^2)
|
|
251
|
|
- // behavior when a frame list is destroyed from the front. To avoid that
|
|
252
|
|
- // pathological behavior, we simply purge the cached values.
|
|
|
247
|
+ if (GetPrevContinuation()) {
|
|
|
248
|
+ // We become the new first-in-flow after changing from fluid to non-fluid.
|
|
|
249
|
+ // Update the stale first-in-flow cache for us and all next-in-flows.
|
|
|
250
|
+ //
|
|
|
251
|
+ // Note that this has no counterpart in the above mFirstContinuation cache
|
|
|
252
|
+ // since GetPrevContinuation() does not depend on the
|
|
|
253
|
+ // NS_FRAME_IS_FLUID_CONTINUATION bit.
|
|
253
|
254
|
for (nsSplittableFrame* f = this; f;
|
|
254
|
|
- f = reinterpret_cast<nsSplittableFrame*>(f->GetNextInFlow())) {
|
|
255
|
|
- f->mFirstInFlow = nullptr;
|
|
|
255
|
+ f = static_cast<nsSplittableFrame*>(f->GetNextInFlow())) {
|
|
|
256
|
+ f->mFirstInFlow = this;
|
|
|
257
|
+ }
|
|
|
258
|
+ } else {
|
|
|
259
|
+ // We become the new first-in-flow due to our prev-in-flow being removed.
|
|
|
260
|
+ if (oldCachedFirstInFlow) {
|
|
|
261
|
+ // It's tempting to update the first-in-flow cache for our
|
|
|
262
|
+ // next-in-flows here, but that would result in overall O(n^2)
|
|
|
263
|
+ // behavior when a frame list is destroyed from the front. To avoid that
|
|
|
264
|
+ // pathological behavior, we simply purge the cached values.
|
|
|
265
|
+ for (nsSplittableFrame* f = this; f;
|
|
|
266
|
+ f = static_cast<nsSplittableFrame*>(f->GetNextInFlow())) {
|
|
|
267
|
+ f->mFirstInFlow = nullptr;
|
|
|
268
|
+ }
|
|
256
|
269
|
}
|
|
257
|
270
|
}
|
|
|
271
|
+
|
|
|
272
|
+ DebugOnly<nsSplittableFrame*> nextInFlow =
|
|
|
273
|
+ static_cast<nsSplittableFrame*>(GetNextInFlow());
|
|
|
274
|
+ MOZ_ASSERT(!nextInFlow || !nextInFlow->mFirstInFlow ||
|
|
|
275
|
+ nextInFlow->mFirstInFlow == this,
|
|
|
276
|
+ "Our next-in-flow caches a stale first-in-flow!");
|
|
258
|
277
|
}
|
|
259
|
278
|
}
|
|
260
|
279
|
|
mobile/android/fenix/app/src/main/AndroidManifest.xml
| ... |
... |
@@ -770,6 +770,16 @@ |
|
770
|
770
|
android:value="androidx.startup"
|
|
771
|
771
|
tools:node="remove" />
|
|
772
|
772
|
</provider>
|
|
|
773
|
+
|
|
|
774
|
+ <receiver
|
|
|
775
|
+ android:name="org.mozilla.fenix.experiments.QANimbusToolingReceiver"
|
|
|
776
|
+ android:exported="true"
|
|
|
777
|
+ android:enabled="true"
|
|
|
778
|
+ android:permission="android.permission.DUMP">
|
|
|
779
|
+ <intent-filter>
|
|
|
780
|
+ <action android:name="org.mozilla.fenix.NIMBUS_TOOLING" />
|
|
|
781
|
+ </intent-filter>
|
|
|
782
|
+ </receiver>
|
|
773
|
783
|
</application>
|
|
774
|
784
|
|
|
775
|
785
|
</manifest> |
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt
| ... |
... |
@@ -89,7 +89,6 @@ import mozilla.components.support.utils.ext.getParcelableExtraCompat |
|
89
|
89
|
import mozilla.components.support.utils.toSafeIntent
|
|
90
|
90
|
import mozilla.components.support.webextensions.WebExtensionPopupObserver
|
|
91
|
91
|
import mozilla.telemetry.glean.private.NoExtras
|
|
92
|
|
-import org.mozilla.experiments.nimbus.initializeTooling
|
|
93
|
92
|
import org.mozilla.fenix.GleanMetrics.AppIcon
|
|
94
|
93
|
import org.mozilla.fenix.GleanMetrics.Events
|
|
95
|
94
|
import org.mozilla.fenix.GleanMetrics.Metrics
|
| ... |
... |
@@ -330,8 +329,6 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, TorAn |
|
330
|
329
|
// DO NOT MOVE ANYTHING ABOVE THIS getProfilerTime CALL.
|
|
331
|
330
|
val startTimeProfiler = components.core.engine.profiler?.getProfilerTime()
|
|
332
|
331
|
|
|
333
|
|
- // Setup nimbus-cli tooling. This is a NOOP when launching normally.
|
|
334
|
|
- components.nimbus.sdk.initializeTooling(applicationContext, intent)
|
|
335
|
332
|
components.strictMode.attachListenerToDisablePenaltyDeath(supportFragmentManager)
|
|
336
|
333
|
MarkersFragmentLifecycleCallbacks.register(supportFragmentManager, components.core.engine)
|
|
337
|
334
|
|
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/experiments/QANimbusToolingReceiver.kt
|
|
1
|
+/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
2
|
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
3
|
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
4
|
+
|
|
|
5
|
+package org.mozilla.fenix.experiments
|
|
|
6
|
+
|
|
|
7
|
+import android.content.BroadcastReceiver
|
|
|
8
|
+import android.content.Context
|
|
|
9
|
+import android.content.Intent
|
|
|
10
|
+import kotlinx.coroutines.CoroutineDispatcher
|
|
|
11
|
+import kotlinx.coroutines.CoroutineScope
|
|
|
12
|
+import kotlinx.coroutines.Dispatchers
|
|
|
13
|
+import kotlinx.coroutines.launch
|
|
|
14
|
+import mozilla.components.support.base.log.logger.Logger
|
|
|
15
|
+import org.mozilla.experiments.nimbus.initializeTooling
|
|
|
16
|
+import org.mozilla.fenix.ext.components
|
|
|
17
|
+
|
|
|
18
|
+private val logger = Logger("QANimbusToolingReceiver")
|
|
|
19
|
+
|
|
|
20
|
+/**
|
|
|
21
|
+ * Receiver triggered on demand via `nimbus-cli` to manually enroll into Nimbus experiments.
|
|
|
22
|
+ *
|
|
|
23
|
+ * ```
|
|
|
24
|
+ * adb shell am broadcast -a org.mozilla.fenix.NIMBUS_TOOLING \
|
|
|
25
|
+ * -p org.mozilla.fenix
|
|
|
26
|
+ * ```
|
|
|
27
|
+ *
|
|
|
28
|
+ * `-p org.mozilla.fenix` is the package name, so adjust that value for release/beta/nightly/debug.
|
|
|
29
|
+ *
|
|
|
30
|
+ * @param dispatcher the [CoroutineDispatcher] the tooling commands are applied on.
|
|
|
31
|
+ */
|
|
|
32
|
+class QANimbusToolingReceiver(private val dispatcher: CoroutineDispatcher = Dispatchers.IO) : BroadcastReceiver() {
|
|
|
33
|
+ override fun onReceive(context: Context, intent: Intent) {
|
|
|
34
|
+ if (intent.action != ACTION_NIMBUS_TOOLING) return
|
|
|
35
|
+
|
|
|
36
|
+ logger.info("Enqueueing QANimbusToolingReceiver via debug trigger")
|
|
|
37
|
+
|
|
|
38
|
+ val applicationContext = context.applicationContext
|
|
|
39
|
+
|
|
|
40
|
+ val pendingResult: PendingResult? = goAsync()
|
|
|
41
|
+ CoroutineScope(dispatcher).launch {
|
|
|
42
|
+ try {
|
|
|
43
|
+ applicationContext.components.nimbus.sdk.initializeTooling(
|
|
|
44
|
+ applicationContext,
|
|
|
45
|
+ intent,
|
|
|
46
|
+ )
|
|
|
47
|
+ } finally {
|
|
|
48
|
+ logger.info("Nimbus tooling command processed")
|
|
|
49
|
+ pendingResult?.finish()
|
|
|
50
|
+ }
|
|
|
51
|
+ }
|
|
|
52
|
+ }
|
|
|
53
|
+
|
|
|
54
|
+ companion object {
|
|
|
55
|
+ const val ACTION_NIMBUS_TOOLING = "org.mozilla.fenix.NIMBUS_TOOLING"
|
|
|
56
|
+ }
|
|
|
57
|
+} |
mobile/android/fenix/app/src/test/java/org/mozilla/fenix/experiments/QANimbusToolingReceiverTest.kt
|
|
1
|
+/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
2
|
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
3
|
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
4
|
+
|
|
|
5
|
+package org.mozilla.fenix.experiments
|
|
|
6
|
+
|
|
|
7
|
+import android.content.Context
|
|
|
8
|
+import android.content.Intent
|
|
|
9
|
+import io.mockk.every
|
|
|
10
|
+import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
|
11
|
+import kotlinx.coroutines.Job
|
|
|
12
|
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
|
|
13
|
+import mozilla.components.support.test.robolectric.testContext
|
|
|
14
|
+import org.junit.Assert.assertEquals
|
|
|
15
|
+import org.junit.Assert.assertFalse
|
|
|
16
|
+import org.junit.Assert.assertNull
|
|
|
17
|
+import org.junit.Assert.assertTrue
|
|
|
18
|
+import org.junit.Before
|
|
|
19
|
+import org.junit.Test
|
|
|
20
|
+import org.junit.runner.RunWith
|
|
|
21
|
+import org.mozilla.fenix.experiments.QANimbusToolingReceiver.Companion.ACTION_NIMBUS_TOOLING
|
|
|
22
|
+import org.mozilla.fenix.ext.components
|
|
|
23
|
+import org.mozilla.fenix.nimbus.TestNimbusApi
|
|
|
24
|
+import org.robolectric.RobolectricTestRunner
|
|
|
25
|
+
|
|
|
26
|
+@OptIn(ExperimentalCoroutinesApi::class)
|
|
|
27
|
+@RunWith(RobolectricTestRunner::class)
|
|
|
28
|
+class QANimbusToolingReceiverTest {
|
|
|
29
|
+
|
|
|
30
|
+ private val nimbusApi = FakeNimbusApi(testContext)
|
|
|
31
|
+ private val receiver = QANimbusToolingReceiver(UnconfinedTestDispatcher())
|
|
|
32
|
+
|
|
|
33
|
+ @Before
|
|
|
34
|
+ fun setUp() {
|
|
|
35
|
+ every { testContext.components.nimbus.sdk } returns nimbusApi
|
|
|
36
|
+ }
|
|
|
37
|
+
|
|
|
38
|
+ @Test
|
|
|
39
|
+ fun `GIVEN a tooling command WHEN the tooling action is received THEN the command is applied`() {
|
|
|
40
|
+ receiver.onReceive(testContext, toolingIntent(ACTION_NIMBUS_TOOLING))
|
|
|
41
|
+
|
|
|
42
|
+ assertEquals(EXPERIMENTS, nimbusApi.appliedExperiments)
|
|
|
43
|
+ assertEquals(false, nimbusApi.fetchEnabled)
|
|
|
44
|
+ assertTrue(nimbusApi.databaseReset)
|
|
|
45
|
+ assertTrue(nimbusApi.stateDumped)
|
|
|
46
|
+ }
|
|
|
47
|
+
|
|
|
48
|
+ @Test
|
|
|
49
|
+ fun `GIVEN a tooling command WHEN another action is received THEN the command is ignored`() {
|
|
|
50
|
+ receiver.onReceive(testContext, toolingIntent("org.mozilla.fenix.ACTION_PRINT"))
|
|
|
51
|
+
|
|
|
52
|
+ assertNull(nimbusApi.appliedExperiments)
|
|
|
53
|
+ assertNull(nimbusApi.fetchEnabled)
|
|
|
54
|
+ assertFalse(nimbusApi.databaseReset)
|
|
|
55
|
+ assertFalse(nimbusApi.stateDumped)
|
|
|
56
|
+ }
|
|
|
57
|
+
|
|
|
58
|
+ @Test
|
|
|
59
|
+ fun `GIVEN no tooling command WHEN the tooling action is received THEN nothing is applied`() {
|
|
|
60
|
+ receiver.onReceive(testContext, Intent(ACTION_NIMBUS_TOOLING))
|
|
|
61
|
+
|
|
|
62
|
+ assertNull(nimbusApi.appliedExperiments)
|
|
|
63
|
+ assertNull(nimbusApi.fetchEnabled)
|
|
|
64
|
+ assertFalse(nimbusApi.databaseReset)
|
|
|
65
|
+ assertFalse(nimbusApi.stateDumped)
|
|
|
66
|
+ }
|
|
|
67
|
+
|
|
|
68
|
+ @Test
|
|
|
69
|
+ fun `GIVEN a tooling command without the version extra WHEN the tooling action is received THEN nothing is applied`() {
|
|
|
70
|
+ val intent = toolingIntent(ACTION_NIMBUS_TOOLING).apply { removeExtra("version") }
|
|
|
71
|
+
|
|
|
72
|
+ receiver.onReceive(testContext, intent)
|
|
|
73
|
+
|
|
|
74
|
+ assertNull(nimbusApi.appliedExperiments)
|
|
|
75
|
+ assertFalse(nimbusApi.stateDumped)
|
|
|
76
|
+ }
|
|
|
77
|
+
|
|
|
78
|
+ private fun toolingIntent(action: String) =
|
|
|
79
|
+ Intent(action).apply {
|
|
|
80
|
+ putExtra("nimbus-cli", null as String?)
|
|
|
81
|
+ putExtra("version", 1)
|
|
|
82
|
+ putExtra("experiments", EXPERIMENTS)
|
|
|
83
|
+ putExtra("reset-db", true)
|
|
|
84
|
+ putExtra("log-state", true)
|
|
|
85
|
+ }
|
|
|
86
|
+
|
|
|
87
|
+ private class FakeNimbusApi(context: Context) : TestNimbusApi(context) {
|
|
|
88
|
+ var appliedExperiments: String? = null
|
|
|
89
|
+ var fetchEnabled: Boolean? = null
|
|
|
90
|
+ var databaseReset = false
|
|
|
91
|
+ var stateDumped = false
|
|
|
92
|
+
|
|
|
93
|
+ override fun applyLocalExperiments(experimentsJson: String): Job {
|
|
|
94
|
+ appliedExperiments = experimentsJson
|
|
|
95
|
+ return completedJob()
|
|
|
96
|
+ }
|
|
|
97
|
+
|
|
|
98
|
+ override fun resetEnrollmentsDatabase(): Job {
|
|
|
99
|
+ databaseReset = true
|
|
|
100
|
+ return completedJob()
|
|
|
101
|
+ }
|
|
|
102
|
+
|
|
|
103
|
+ override fun setFetchEnabled(enabled: Boolean) {
|
|
|
104
|
+ fetchEnabled = enabled
|
|
|
105
|
+ }
|
|
|
106
|
+
|
|
|
107
|
+ override fun dumpStateToLog() {
|
|
|
108
|
+ stateDumped = true
|
|
|
109
|
+ }
|
|
|
110
|
+
|
|
|
111
|
+ private fun completedJob() = Job().apply { complete() }
|
|
|
112
|
+ }
|
|
|
113
|
+
|
|
|
114
|
+ companion object {
|
|
|
115
|
+ private const val EXPERIMENTS = """{"data":[]}"""
|
|
|
116
|
+ }
|
|
|
117
|
+} |
modules/libpref/init/StaticPrefList.yaml
| ... |
... |
@@ -7834,7 +7834,7 @@ |
|
7834
|
7834
|
#ifdef XP_MACOSX
|
|
7835
|
7835
|
- name: gfx.webrender.enable-client-storage
|
|
7836
|
7836
|
type: bool
|
|
7837
|
|
- value: true
|
|
|
7837
|
+ value: false
|
|
7838
|
7838
|
mirror: once
|
|
7839
|
7839
|
#endif
|
|
7840
|
7840
|
|
netwerk/protocol/http/nsHttpChunkedDecoder.cpp
| ... |
... |
@@ -106,8 +106,15 @@ nsresult nsHttpChunkedDecoder::ParseChunkRemaining(char* buf, uint32_t count, |
|
106
|
106
|
count = mLineBuf.Length();
|
|
107
|
107
|
}
|
|
108
|
108
|
|
|
|
109
|
+ // NUL is illegal in a chunk-size or trailer field line (RFC 9110 section
|
|
|
110
|
+ // 5.5).
|
|
|
111
|
+ if (memchr(buf, '\0', count)) {
|
|
|
112
|
+ LOG(("chunked line contains embedded NUL; rejecting\n"));
|
|
|
113
|
+ return NS_ERROR_UNEXPECTED;
|
|
|
114
|
+ }
|
|
|
115
|
+
|
|
109
|
116
|
if (mWaitEOF) {
|
|
110
|
|
- if (*buf) {
|
|
|
117
|
+ if (count) {
|
|
111
|
118
|
LOG(("got trailer: %s\n", buf));
|
|
112
|
119
|
// allocate a header array for the trailers on demand
|
|
113
|
120
|
if (!mTrailers) {
|
| ... |
... |
@@ -130,7 +137,7 @@ nsresult nsHttpChunkedDecoder::ParseChunkRemaining(char* buf, uint32_t count, |
|
130
|
137
|
mReachedEOF = true;
|
|
131
|
138
|
LOG(("reached end of chunked-body\n"));
|
|
132
|
139
|
}
|
|
133
|
|
- } else if (*buf) {
|
|
|
140
|
+ } else if (count) {
|
|
134
|
141
|
char* endptr;
|
|
135
|
142
|
unsigned long parsedval; // could be 64 bit, could be 32
|
|
136
|
143
|
|
testing/web-platform/tests/css/css-writing-modes/crashtests/bidi-inline-continuation-first-in-flow.html
|
|
1
|
+<!DOCTYPE html>
|
|
|
2
|
+<meta charset="utf-8">
|
|
|
3
|
+<link rel="author" title="Ting-Yu Lin" href="">"mailto:tlin@xxxxxxxxxxx">
|
|
|
4
|
+<link rel="help" href="">"https://bugzilla.mozilla.org/show_bug.cgi?id=2053578">
|
|
|
5
|
+
|
|
|
6
|
+<!-- The operations in <script> are generated from one of the runs from
|
|
|
7
|
+ the original testcase (Bug 2053578 Comment 5) that triggers
|
|
|
8
|
+ the assertion. -->
|
|
|
9
|
+
|
|
|
10
|
+<body></body>
|
|
|
11
|
+
|
|
|
12
|
+<script>
|
|
|
13
|
+var n1 = document.createElement("div");
|
|
|
14
|
+n1.style.width = "50px";
|
|
|
15
|
+var n2 = document.createElement("bdo");
|
|
|
16
|
+n2.setAttribute("dir", "rtl");
|
|
|
17
|
+var n3 = document.createTextNode("كلمة");
|
|
|
18
|
+n2.appendChild(n3);
|
|
|
19
|
+n1.appendChild(n2);
|
|
|
20
|
+var n4 = document.createElement("em");
|
|
|
21
|
+var n5 = document.createElement("span");
|
|
|
22
|
+var n6 = document.createElement("bdo");
|
|
|
23
|
+var n7 = document.createTextNode("word m mix");
|
|
|
24
|
+n6.appendChild(n7);
|
|
|
25
|
+n5.appendChild(n6);
|
|
|
26
|
+var n8 = document.createTextNode("מלל");
|
|
|
27
|
+n5.appendChild(n8);
|
|
|
28
|
+var n9 = document.createElement("b");
|
|
|
29
|
+n9.setAttribute("dir", "ltr");
|
|
|
30
|
+n9.style.unicodeBidi = "bidi-override";
|
|
|
31
|
+var n10 = document.createTextNode("alpha");
|
|
|
32
|
+n9.appendChild(n10);
|
|
|
33
|
+var n11 = document.createTextNode("نص مرحبا كلمة");
|
|
|
34
|
+n9.appendChild(n11);
|
|
|
35
|
+var n12 = document.createTextNode("مرحبا نص نص");
|
|
|
36
|
+n9.appendChild(n12);
|
|
|
37
|
+n5.appendChild(n9);
|
|
|
38
|
+n4.appendChild(n5);
|
|
|
39
|
+var n13 = document.createElement("span");
|
|
|
40
|
+n13.style.unicodeBidi = "bidi-override";
|
|
|
41
|
+var n14 = document.createElement("bdi");
|
|
|
42
|
+var n15 = document.createTextNode("اختبار");
|
|
|
43
|
+n14.appendChild(n15);
|
|
|
44
|
+n13.appendChild(n14);
|
|
|
45
|
+var n16 = document.createElement("em");
|
|
|
46
|
+var n17 = document.createTextNode("בדיקה מלל m نص");
|
|
|
47
|
+n16.appendChild(n17);
|
|
|
48
|
+var n18 = document.createTextNode("كلمة");
|
|
|
49
|
+n16.appendChild(n18);
|
|
|
50
|
+var n19 = document.createTextNode("نص مرحبا كلمة");
|
|
|
51
|
+n16.appendChild(n19);
|
|
|
52
|
+n13.appendChild(n16);
|
|
|
53
|
+var n20 = document.createElement("span");
|
|
|
54
|
+var n21 = document.createTextNode("שלום מלל בדיקה שלום");
|
|
|
55
|
+n20.appendChild(n21);
|
|
|
56
|
+n13.appendChild(n20);
|
|
|
57
|
+n4.appendChild(n13);
|
|
|
58
|
+n1.appendChild(n4);
|
|
|
59
|
+document.body.appendChild(n1);
|
|
|
60
|
+var n22 = document.createElement("bdo");
|
|
|
61
|
+n22.style.unicodeBidi = "plaintext";
|
|
|
62
|
+var n23 = document.createElement("span");
|
|
|
63
|
+var n24 = document.createTextNode("עברית שלום مرحبا alpha");
|
|
|
64
|
+n23.appendChild(n24);
|
|
|
65
|
+n22.appendChild(n23);
|
|
|
66
|
+n14.style.direction = "ltr";
|
|
|
67
|
+var n25 = document.createTextNode("كلمة שלום");
|
|
|
68
|
+n2.insertBefore(n25, n3);
|
|
|
69
|
+n21.remove();
|
|
|
70
|
+n9.setAttribute("dir", "ltr");
|
|
|
71
|
+var n26 = document.createTextNode("בדיקה mm");
|
|
|
72
|
+n4.appendChild(n26);
|
|
|
73
|
+n12.data = "שלום עברית שלום עברית";
|
|
|
74
|
+n7.remove();
|
|
|
75
|
+n2.style.direction = "ltr";
|
|
|
76
|
+n1.style.width = "102px";
|
|
|
77
|
+var n27 = document.createTextNode("עברית mm m");
|
|
|
78
|
+n22.appendChild(n27);
|
|
|
79
|
+n22.setAttribute("dir", "rtl");
|
|
|
80
|
+n4.style.direction = "";
|
|
|
81
|
+n14.style.direction = "rtl";
|
|
|
82
|
+n22.insertBefore(n9, n23);
|
|
|
83
|
+var n28 = document.createElement("br");
|
|
|
84
|
+n9.insertBefore(n28, n12);
|
|
|
85
|
+n14.style.unicodeBidi = "embed";
|
|
|
86
|
+n5.insertBefore(n22, n6);
|
|
|
87
|
+n9.style.direction = "";
|
|
|
88
|
+n9.style.unicodeBidi = "bidi-override";
|
|
|
89
|
+n22.remove();
|
|
|
90
|
+var n29 = document.createTextNode("עברית שלום");
|
|
|
91
|
+n5.insertBefore(n29, n6);
|
|
|
92
|
+n18.data = "mix";
|
|
|
93
|
+n19.data = "alpha m word";
|
|
|
94
|
+n20.style.direction = "ltr";
|
|
|
95
|
+var n30 = document.createTextNode("mm עברית עברית نص");
|
|
|
96
|
+n6.appendChild(n30);
|
|
|
97
|
+n6.style.unicodeBidi = "isolate";
|
|
|
98
|
+n20.style.unicodeBidi = "embed";
|
|
|
99
|
+n16.setAttribute("dir", "rtl");
|
|
|
100
|
+n2.insertBefore(n20, n25);
|
|
|
101
|
+var n31 = document.createTextNode("שלום مرحبا mix mm");
|
|
|
102
|
+n2.insertBefore(n31, n20);
|
|
|
103
|
+var n32 = document.createTextNode("m בדיקה word mix");
|
|
|
104
|
+n20.appendChild(n32);
|
|
|
105
|
+n16.removeAttribute("dir");
|
|
|
106
|
+n16.setAttribute("dir", "auto");
|
|
|
107
|
+n5.remove();
|
|
|
108
|
+n17.remove();
|
|
|
109
|
+n31.data = "בדיקה mm";
|
|
|
110
|
+n14.style.unicodeBidi = "isolate";
|
|
|
111
|
+n4.remove();
|
|
|
112
|
+n20.style.direction = "";
|
|
|
113
|
+n20.style.direction = "rtl";
|
|
|
114
|
+n3.data = "בדיקה שלום word";
|
|
|
115
|
+n25.data = "mm";
|
|
|
116
|
+n25.data = "m mix word";
|
|
|
117
|
+n1.style.direction = "rtl";
|
|
|
118
|
+n31.data = "كلمة اختبار";
|
|
|
119
|
+n20.remove();
|
|
|
120
|
+n3.data = "שלום نص";
|
|
|
121
|
+n31.remove();
|
|
|
122
|
+n2.setAttribute("dir", "ltr");
|
|
|
123
|
+n2.removeAttribute("dir");
|
|
|
124
|
+n1.insertBefore(n4, n2);
|
|
|
125
|
+n19.data = "מלל word";
|
|
|
126
|
+n15.remove();
|
|
|
127
|
+n13.setAttribute("dir", "ltr");
|
|
|
128
|
+n25.remove();
|
|
|
129
|
+n2.setAttribute("dir", "ltr");
|
|
|
130
|
+n14.appendChild(n2);
|
|
|
131
|
+n3.data = "مرحبا اختبار مرحبا";
|
|
|
132
|
+n18.data = "שלום";
|
|
|
133
|
+n16.insertBefore(n20, n18);
|
|
|
134
|
+var n33 = document.createTextNode("كلمة نص mm");
|
|
|
135
|
+n2.appendChild(n33);
|
|
|
136
|
+n19.data = "اختبار مرحبا كلمة كلمة";
|
|
|
137
|
+n18.data = "mm mix mix";
|
|
|
138
|
+var n34 = document.createElement("br");
|
|
|
139
|
+n4.insertBefore(n34, n13);
|
|
|
140
|
+n13.style.unicodeBidi = "isolate-override";
|
|
|
141
|
+n13.remove();
|
|
|
142
|
+n34.remove();
|
|
|
143
|
+n26.data = "كلمة كلمة مرحبا";
|
|
|
144
|
+n4.setAttribute("dir", "rtl");
|
|
|
145
|
+n26.data = "mm word m mm";
|
|
|
146
|
+n26.data = "اختبار نص";
|
|
|
147
|
+n4.setAttribute("dir", "auto");
|
|
|
148
|
+var n35 = document.createTextNode("مرحبا מלל كلمة שלום");
|
|
|
149
|
+n4.insertBefore(n35, n26);
|
|
|
150
|
+n4.style.unicodeBidi = "embed";
|
|
|
151
|
+n4.style.direction = "";
|
|
|
152
|
+var n36 = document.createTextNode("كلمة mix בדיקה نص");
|
|
|
153
|
+n4.insertBefore(n36, n35);
|
|
|
154
|
+n36.remove();
|
|
|
155
|
+n4.removeAttribute("dir");
|
|
|
156
|
+n4.style.unicodeBidi = "";
|
|
|
157
|
+n1.style.width = "87px";
|
|
|
158
|
+n26.data = "שלום מלל מלל עברית";
|
|
|
159
|
+var n37 = document.createElement("br");
|
|
|
160
|
+n4.insertBefore(n37, n35);
|
|
|
161
|
+n35.data = "مرحبا نص اختبار";
|
|
|
162
|
+n4.setAttribute("dir", "rtl");
|
|
|
163
|
+n33.data = "word alpha mm";
|
|
|
164
|
+var n38 = document.createTextNode("שלום word");
|
|
|
165
|
+n16.insertBefore(n38, n20);
|
|
|
166
|
+n2.setAttribute("dir", "auto");
|
|
|
167
|
+n2.remove();
|
|
|
168
|
+n37.remove();
|
|
|
169
|
+var n39 = document.createTextNode("עברית اختبار בדיקה");
|
|
|
170
|
+n13.appendChild(n39);
|
|
|
171
|
+var n40 = document.createTextNode("בדיקה m نص نص");
|
|
|
172
|
+n13.insertBefore(n40, n14);
|
|
|
173
|
+var n41 = document.createElement("br");
|
|
|
174
|
+n20.appendChild(n41);
|
|
|
175
|
+n35.data = "alpha";
|
|
|
176
|
+n16.remove();
|
|
|
177
|
+n39.data = "نص mm בדיקה اختبار";
|
|
|
178
|
+n40.data = "mix mix word m";
|
|
|
179
|
+n35.data = "שלום בדיקה";
|
|
|
180
|
+n35.data = "m mix mm m";
|
|
|
181
|
+n40.data = "مرحبا اختبار";
|
|
|
182
|
+n13.style.unicodeBidi = "embed";
|
|
|
183
|
+n4.insertBefore(n16, n26);
|
|
|
184
|
+var n42 = document.createTextNode("نص");
|
|
|
185
|
+n13.insertBefore(n42, n40);
|
|
|
186
|
+n41.remove();
|
|
|
187
|
+n20.insertBefore(n2, n32);
|
|
|
188
|
+document.body.offsetHeight;
|
|
|
189
|
+n39.data = "مرحبا alpha עברית word";
|
|
|
190
|
+n18.data = "שלום";
|
|
|
191
|
+n2.setAttribute("dir", "auto");
|
|
|
192
|
+document.body.offsetHeight;
|
|
|
193
|
+n20.style.direction = "ltr";
|
|
|
194
|
+</script> |
third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.cc
| ... |
... |
@@ -443,6 +443,14 @@ void VideoCaptureModulePipeWire::ProcessBuffers() { |
|
443
|
443
|
continue;
|
|
444
|
444
|
}
|
|
445
|
445
|
|
|
|
446
|
+ if (static_cast<uint64_t>(spaBuffer->datas[0].chunk->offset) +
|
|
|
447
|
+ spaBuffer->datas[0].chunk->size >
|
|
|
448
|
+ spaBuffer->datas[0].maxsize) {
|
|
|
449
|
+ RTC_LOG(LS_ERROR) << "Dropping frame with invalid size";
|
|
|
450
|
+ pw_stream_queue_buffer(stream_, buffer);
|
|
|
451
|
+ continue;
|
|
|
452
|
+ }
|
|
|
453
|
+
|
|
446
|
454
|
if (spaBuffer->datas[0].type == SPA_DATA_DmaBuf ||
|
|
447
|
455
|
spaBuffer->datas[0].type == SPA_DATA_MemFd) {
|
|
448
|
456
|
ScopedBuf frame;
|
third_party/libwebrtc/moz-patch-stack/612430e826.no-op-cherry-pick-msg
|
|
1
|
+We cherry-picked this in bug 2054625. |
|
|
\ No newline at end of file |
toolkit/components/resistfingerprinting/tests/browser/browser_srcset.js
| ... |
... |
@@ -4,8 +4,20 @@ |
|
4
|
4
|
|
|
5
|
5
|
"use strict";
|
|
6
|
6
|
|
|
|
7
|
+async function precacheAssets(tab, zoom) {
|
|
|
8
|
+ await SpecialPowers.spawn(tab.linkedBrowser, [zoom], async zoom => {
|
|
|
9
|
+ const { Layout } = ChromeUtils.importESModule(
|
|
|
10
|
+ "chrome://mochitests/content/browser/accessible/tests/browser/Layout.sys.mjs"
|
|
|
11
|
+ );
|
|
|
12
|
+ Layout.zoomDocument(content.document, zoom);
|
|
|
13
|
+ const { promise, resolve } = Promise.withResolvers();
|
|
|
14
|
+ content.requestAnimationFrame(resolve);
|
|
|
15
|
+ await promise;
|
|
|
16
|
+ });
|
|
|
17
|
+}
|
|
|
18
|
+
|
|
7
|
19
|
async function runForZoomLevel(tab, zoom) {
|
|
8
|
|
- const [dpr, scale] = await SpecialPowers.spawn(
|
|
|
20
|
+ const [dpr, scale, cssScale] = await SpecialPowers.spawn(
|
|
9
|
21
|
tab.linkedBrowser,
|
|
10
|
22
|
[zoom],
|
|
11
|
23
|
async zoom => {
|
| ... |
... |
@@ -28,9 +40,16 @@ async function runForZoomLevel(tab, zoom) { |
|
28
|
40
|
// Workaround: content.devicePixelRatio has the unspoofed value.
|
|
29
|
41
|
const dpr = content.wrappedJSObject.devicePixelRatio;
|
|
30
|
42
|
const current = img.currentSrc;
|
|
31
|
|
- const scale =
|
|
32
|
|
- current.substring(current.length - 6, current.length - 4) / 10;
|
|
33
|
|
- return [dpr, scale];
|
|
|
43
|
+ const scale = parseFloat(current.match(/.*\/([0-9\.]+)\.png$/)[1]);
|
|
|
44
|
+
|
|
|
45
|
+ const height = content.document
|
|
|
46
|
+ .getElementById("imgset")
|
|
|
47
|
+ .getBoundingClientRect().height;
|
|
|
48
|
+ // The images have been crafted so that it is possible to reverse their
|
|
|
49
|
+ // measured size (altered by the zoom) and find the scale.
|
|
|
50
|
+ const cssScale = Math.round((height * dpr - 50) / 10) / 10 + 0.3;
|
|
|
51
|
+
|
|
|
52
|
+ return [dpr, scale, cssScale];
|
|
34
|
53
|
}
|
|
35
|
54
|
);
|
|
36
|
55
|
|
| ... |
... |
@@ -39,6 +58,11 @@ async function runForZoomLevel(tab, zoom) { |
|
39
|
58
|
true,
|
|
40
|
59
|
`Image scale (${scale}) is within DPR (${dpr})`
|
|
41
|
60
|
);
|
|
|
61
|
+ is(
|
|
|
62
|
+ Math.abs(dpr - cssScale) < 0.1,
|
|
|
63
|
+ true,
|
|
|
64
|
+ `CSS scale (${cssScale}) is within DPR (${dpr})`
|
|
|
65
|
+ );
|
|
42
|
66
|
}
|
|
43
|
67
|
|
|
44
|
68
|
add_task(async () => {
|
| ... |
... |
@@ -53,6 +77,9 @@ add_task(async () => { |
|
53
|
77
|
) + "srcset.html";
|
|
54
|
78
|
const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, testPage);
|
|
55
|
79
|
|
|
|
80
|
+ for (let zoom = 0.3; zoom < 2.09; zoom += 0.1) {
|
|
|
81
|
+ await precacheAssets(tab, zoom);
|
|
|
82
|
+ }
|
|
56
|
83
|
for (let zoom = 0.3; zoom < 2.09; zoom += 0.1) {
|
|
57
|
84
|
await runForZoomLevel(tab, zoom);
|
|
58
|
85
|
}
|
toolkit/components/resistfingerprinting/tests/browser/srcset.html
|
1
|
1
|
<!DOCTYPE html>
|
|
2
|
2
|
<html>
|
|
|
3
|
+ <head>
|
|
|
4
|
+ <style>
|
|
|
5
|
+#imgset {
|
|
|
6
|
+ content: image-set(
|
|
|
7
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50"></svg>') 0.3x,
|
|
|
8
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60"></svg>') 0.4x,
|
|
|
9
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="70" height="70"></svg>') 0.5x,
|
|
|
10
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80"></svg>') 0.6x,
|
|
|
11
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="90" height="90"></svg>') 0.7x,
|
|
|
12
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"></svg>') 0.8x,
|
|
|
13
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="110" height="110"></svg>') 0.9x,
|
|
|
14
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="120" height="120"></svg>') 1.0x,
|
|
|
15
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="130" height="130"></svg>') 1.1x,
|
|
|
16
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="140" height="140"></svg>') 1.2x,
|
|
|
17
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="150" height="150"></svg>') 1.3x,
|
|
|
18
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="160" height="160"></svg>') 1.4x,
|
|
|
19
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="170" height="170"></svg>') 1.5x,
|
|
|
20
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="180" height="180"></svg>') 1.6x,
|
|
|
21
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="190" height="190"></svg>') 1.7x,
|
|
|
22
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200"></svg>') 1.8x,
|
|
|
23
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="210" height="210"></svg>') 1.9x,
|
|
|
24
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="220" height="220"></svg>') 2.0x,
|
|
|
25
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="230" height="230"></svg>') 2.1x,
|
|
|
26
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="240" height="240"></svg>') 2.2x,
|
|
|
27
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="250" height="250"></svg>') 2.3x,
|
|
|
28
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="260" height="260"></svg>') 2.4x,
|
|
|
29
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="270" height="270"></svg>') 2.5x,
|
|
|
30
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="280" height="280"></svg>') 2.6x,
|
|
|
31
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="290" height="290"></svg>') 2.7x,
|
|
|
32
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300"></svg>') 2.8x,
|
|
|
33
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="310" height="310"></svg>') 2.9x,
|
|
|
34
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="320" height="320"></svg>') 3.0x,
|
|
|
35
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="330" height="330"></svg>') 3.1x,
|
|
|
36
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="340" height="340"></svg>') 3.2x,
|
|
|
37
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="350" height="350"></svg>') 3.3x,
|
|
|
38
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="360" height="360"></svg>') 3.4x,
|
|
|
39
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="370" height="370"></svg>') 3.5x,
|
|
|
40
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="380" height="380"></svg>') 3.6x,
|
|
|
41
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="390" height="390"></svg>') 3.7x,
|
|
|
42
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400"></svg>') 3.8x,
|
|
|
43
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="410" height="410"></svg>') 3.9x,
|
|
|
44
|
+ url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="420" height="420"></svg>') 4.0x
|
|
|
45
|
+ );
|
|
|
46
|
+}
|
|
|
47
|
+ </style>
|
|
|
48
|
+ </head>
|
|
3
|
49
|
<body>
|
|
4
|
50
|
<img id="srcset" srcset="
|
|
5
|
|
- 03.png 0.3x, 04.png 0.4x, 05.png 0.5x, 06.png 0.6x, 07.png 0.7x, 08.png 0.8x, 09.png 0.9x,
|
|
6
|
|
- 10.png 1x, 11.png 1.1x, 12.png 1.2x, 13.png 1.3x, 14.png 1.4x, 15.png 1.5x, 16.png 1.6x, 17.png 1.7x, 18.png 1.8x, 19.png 1.9x,
|
|
7
|
|
- 20.png 2x, 21.png 2.1x, 22.png 2.2x, 23.png 2.3x, 24.png 2.4x, 25.png 2.5x, 26.png 2.6x, 27.png 2.7x, 28.png 2.8x, 29.png 2.9x,
|
|
8
|
|
- 30.png 3x, 31.png 3.1x, 32.png 3.2x, 33.png 3.3x, 34.png 3.4x, 35.png 3.5x, 36.png 3.6x, 37.png 3.7x, 38.png 3.8x, 39.png 3.9x,
|
|
9
|
|
- 40.png 4x
|
|
|
51
|
+ 0.65.png 0.65x, 0.85.png 0.85x, 1.05.png 1.05x, 1.25.png 1.25x, 1.45.png 1.45x, 1.65.png 1.65x, 1.85.png 1.85x,
|
|
|
52
|
+ 2.05.png 2.05x, 2.25.png 2.25x, 2.45.png 2.45x, 2.65.png 2.65x, 2.9.png 2.9x, 3.0.png 3.0x, 3.2.png 3.2x,
|
|
|
53
|
+ 3.4.png 3.4x, 3.6.png 3.6x, 3.8.png 3.8x, 4.0.png 4.0x
|
|
10
|
54
|
">
|
|
|
55
|
+ <div id="imgset"></div>
|
|
11
|
56
|
</body>
|
|
12
|
57
|
</html> |
widget/gtk/nsDragService.cpp
| ... |
... |
@@ -1741,6 +1741,14 @@ void nsDragSession::SourceEndDragSession(GdkDragContext* aContext, |
|
1741
|
1741
|
LOGDRAGSERVICE("SourceEndDragSession(%p) result %s\n", aContext,
|
|
1742
|
1742
|
kGtkDragResults[aResult]);
|
|
1743
|
1743
|
|
|
|
1744
|
+ // GTK drops its last reference right after drag-end, so reset ours now.
|
|
|
1745
|
+ //
|
|
|
1746
|
+ // Clearing only from EndDragSessionImpl is not enough (bug 2058661): that
|
|
|
1747
|
+ // runs from an async runnable, by which point the pointer already dangles.
|
|
|
1748
|
+ if (mSourceWindow) {
|
|
|
1749
|
+ mSourceWindow->SetDragSource(nullptr);
|
|
|
1750
|
+ }
|
|
|
1751
|
+
|
|
1744
|
1752
|
// this just releases the list of data items that we provide
|
|
1745
|
1753
|
mSourceDataItems = nullptr;
|
|
1746
|
1754
|
|
widget/windows/SystemStatusBar.cpp
| ... |
... |
@@ -91,10 +91,10 @@ StatusBarEntry::StatusBarEntry(Element* aMenu) : mMenu(aMenu), mInitted(false) { |
|
91
|
91
|
}
|
|
92
|
92
|
|
|
93
|
93
|
StatusBarEntry::~StatusBarEntry() {
|
|
|
94
|
+ Destroy();
|
|
94
|
95
|
if (!mInitted) {
|
|
95
|
96
|
return;
|
|
96
|
97
|
}
|
|
97
|
|
- Destroy();
|
|
98
|
98
|
::Shell_NotifyIconW(NIM_DELETE, &mIconData);
|
|
99
|
99
|
VERIFY(::DestroyWindow(mIconData.hWnd));
|
|
100
|
100
|
}
|
widget/windows/filedialog/WinFileDialogCommands.cpp
| ... |
... |
@@ -233,18 +233,24 @@ mozilla::Result<nsString, Error> GetFolderResults(::IFileDialog* dialog) { |
|
233
|
233
|
}
|
|
234
|
234
|
|
|
235
|
235
|
// If the user chose a Win7 Library, resolve to the library's
|
|
236
|
|
- // default save folder.
|
|
237
|
|
- RefPtr<IShellLibrary> shellLib;
|
|
238
|
|
- RefPtr<IShellItem> folderPath;
|
|
239
|
|
- MOZ_ENSURE_HRESULT_OK(
|
|
240
|
|
- "CoCreateInstance(CLSID_ShellLibrary)",
|
|
241
|
|
- CoCreateInstance(CLSID_ShellLibrary, nullptr, CLSCTX_INPROC_SERVER,
|
|
242
|
|
- IID_IShellLibrary, getter_AddRefs(shellLib)));
|
|
243
|
|
-
|
|
244
|
|
- if (shellLib && SUCCEEDED(shellLib->LoadLibraryFromItem(item, STGM_READ)) &&
|
|
245
|
|
- SUCCEEDED(shellLib->GetDefaultSaveFolder(DSFT_DETECT, IID_IShellItem,
|
|
246
|
|
- getter_AddRefs(folderPath)))) {
|
|
247
|
|
- item.swap(folderPath);
|
|
|
236
|
+ // default save folder. Only do this for items which are known not to be
|
|
|
237
|
+ // filesystem objects, like the user's Documents library (but not .library-ms
|
|
|
238
|
+ // files).
|
|
|
239
|
+ SFGAOF attrs = 0;
|
|
|
240
|
+ if (SUCCEEDED(item->GetAttributes(SFGAO_FILESYSTEM, &attrs)) &&
|
|
|
241
|
+ !(attrs & SFGAO_FILESYSTEM)) {
|
|
|
242
|
+ RefPtr<IShellLibrary> shellLib;
|
|
|
243
|
+ RefPtr<IShellItem> folderPath;
|
|
|
244
|
+ MOZ_ENSURE_HRESULT_OK(
|
|
|
245
|
+ "CoCreateInstance(CLSID_ShellLibrary)",
|
|
|
246
|
+ CoCreateInstance(CLSID_ShellLibrary, nullptr, CLSCTX_INPROC_SERVER,
|
|
|
247
|
+ IID_IShellLibrary, getter_AddRefs(shellLib)));
|
|
|
248
|
+
|
|
|
249
|
+ if (shellLib && SUCCEEDED(shellLib->LoadLibraryFromItem(item, STGM_READ)) &&
|
|
|
250
|
+ SUCCEEDED(shellLib->GetDefaultSaveFolder(DSFT_DETECT, IID_IShellItem,
|
|
|
251
|
+ getter_AddRefs(folderPath)))) {
|
|
|
252
|
+ item.swap(folderPath);
|
|
|
253
|
+ }
|
|
248
|
254
|
}
|
|
249
|
255
|
|
|
250
|
256
|
// get the folder's file system path
|
|