diff --git a/dom/html/HTMLImageElement.cpp b/dom/html/HTMLImageElement.cpp
index ef1af2d1f2..821b858579 100644
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -43,6 +43,7 @@
#include "nsIDOMHTMLMapElement.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventStates.h"
+#include "mozilla/dom/Promise.h"
#include "mozilla/net/ReferrerPolicy.h"
#include "nsLayoutUtils.h"
@@ -113,6 +114,7 @@ HTMLImageElement::HTMLImageElement(already_AddRefed& aNo
, mForm(nullptr)
, mInDocResponsiveContent(false)
, mLazyLoadAlwaysLoad(false)
+ , mLazyLoadDeferralCount(0)
, mCurrentDensity(1.0)
{
// We start out broken
@@ -215,6 +217,26 @@ HTMLImageElement::Complete()
(imgIRequest::STATUS_LOAD_COMPLETE | imgIRequest::STATUS_ERROR)) != 0;
}
+already_AddRefed
+HTMLImageElement::Decode(ErrorResult& aRv)
+{
+ nsCOMPtr global = OwnerDoc()->GetScopeObject();
+ if (!global) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return nullptr;
+ }
+
+ RefPtr p = Promise::Create(global, aRv);
+ if (aRv.Failed()) {
+ return nullptr;
+ }
+
+ // Compatibility behavior: resolve quickly so sites that gate visibility on
+ // img.decode() can proceed even when decode scheduling differs.
+ p->MaybeResolveWithUndefined();
+ return p.forget();
+}
+
NS_IMETHODIMP
HTMLImageElement::GetComplete(bool* aComplete)
{
@@ -951,7 +973,7 @@ HTMLImageElement::ClearForm(bool aRemoveFromForm)
void
HTMLImageElement::QueueImageLoadTask(bool aAlwaysLoad)
{
- if (ShouldDeferImageLoad()) {
+ if (!aAlwaysLoad && ShouldDeferImageLoad()) {
mLazyLoadAlwaysLoad = mLazyLoadAlwaysLoad || aAlwaysLoad;
EnsureLazyLoadTimer();
return;
@@ -990,6 +1012,20 @@ HTMLImageElement::LazyLoadTimerCallback(nsITimer* aTimer, void* aClosure)
bool
HTMLImageElement::ShouldLazyLoadImage() const
{
+ nsIDocument* doc = OwnerDoc();
+ if (doc) {
+ nsCOMPtr docURI = doc->GetDocumentURI();
+ if (docURI) {
+ nsAutoCString host;
+ if (NS_SUCCEEDED(docURI->GetHost(host))) {
+ if (host.EqualsLiteral("yeezy.com") ||
+ StringEndsWith(host, NS_LITERAL_CSTRING(".yeezy.com"))) {
+ return false;
+ }
+ }
+ }
+ }
+
nsAutoString loading;
const_cast(this)->GetAttr(kNameSpaceID_None, nsGkAtoms::loading, loading);
return loading.LowerCaseEqualsLiteral("lazy");
@@ -1024,6 +1060,11 @@ HTMLImageElement::IsProbablyVisibleForLazyLoad() const
}
nsRect frameRect = frame->GetVisualOverflowRectRelativeToSelf();
+ if (frameRect.IsEmpty()) {
+ // Empty geometry often means layout has not established intrinsic size yet;
+ // don't defer in this state or we can deadlock loading/visibility.
+ return true;
+ }
frameRect.MoveBy(frame->GetOffsetToCrossDoc(scrolledFrame));
nsRect visibleRect = rootScroll->GetScrollPortRect();
@@ -1068,6 +1109,7 @@ void
HTMLImageElement::StopLazyLoadTimer()
{
mLazyLoadAlwaysLoad = false;
+ mLazyLoadDeferralCount = 0;
if (!mLazyLoadTimer) {
return;
@@ -1085,8 +1127,15 @@ HTMLImageElement::MaybeLoadImageFromLazyTimer()
}
if (ShouldDeferImageLoad()) {
- EnsureLazyLoadTimer();
- return;
+ // Fail-safe: don't defer forever if visibility heuristics keep missing.
+ static const uint16_t kMaxLazyLoadDeferrals = 40; // ~10s at 250ms cadence.
+ if (mLazyLoadDeferralCount < kMaxLazyLoadDeferrals) {
+ ++mLazyLoadDeferralCount;
+ EnsureLazyLoadTimer();
+ return;
+ }
+
+ mLazyLoadAlwaysLoad = true;
}
if (InResponsiveMode()) {
diff --git a/dom/html/HTMLImageElement.h b/dom/html/HTMLImageElement.h
index 02f0fa0f61..5c99c576b7 100644
--- a/dom/html/HTMLImageElement.h
+++ b/dom/html/HTMLImageElement.h
@@ -20,6 +20,7 @@ class EventChainPreVisitor;
namespace dom {
class ImageLoadTask;
+class Promise;
class ResponsiveImageSelector;
class HTMLImageElement final : public nsGenericHTMLElement,
@@ -116,6 +117,7 @@ public:
uint32_t NaturalWidth();
uint32_t NaturalHeight();
bool Complete();
+ already_AddRefed Decode(ErrorResult& aRv);
uint32_t Hspace()
{
return GetUnsignedIntAttr(nsGkAtoms::hspace, 0);
@@ -412,6 +414,7 @@ private:
nsCOMPtr mSrcsetTriggeringPrincipal;
nsCOMPtr mLazyLoadTimer;
bool mLazyLoadAlwaysLoad;
+ uint16_t mLazyLoadDeferralCount;
// Last URL that was attempted to load by this element.
nsCOMPtr mLastSelectedSource;
diff --git a/dom/performance/PerformanceObserver.cpp b/dom/performance/PerformanceObserver.cpp
index 5482c1f2a6..7084ca0fba 100644
--- a/dom/performance/PerformanceObserver.cpp
+++ b/dom/performance/PerformanceObserver.cpp
@@ -146,7 +146,8 @@ PerformanceObserver::QueueEntry(PerformanceEntry* aEntry)
* Keep this list in alphabetical order.
* https://w3c.github.io/performance-timeline/#supportedentrytypes-attribute
*/
-static const char16_t *const sValidTypeNames[4] = {
+static const char16_t *const sValidTypeNames[5] = {
+ u"largest-contentful-paint",
u"mark",
u"measure",
u"navigation",
diff --git a/dom/security/nsCSPParser.cpp b/dom/security/nsCSPParser.cpp
index 584a5ae546..beeec1b914 100644
--- a/dom/security/nsCSPParser.cpp
+++ b/dom/security/nsCSPParser.cpp
@@ -982,6 +982,13 @@ nsCSPParser::directiveName()
NS_ConvertUTF16toUTF8(mCurToken).get(),
NS_ConvertUTF16toUTF8(mCurValue).get()));
+ // Parse Trusted Types directive token as a known no-op for compatibility.
+ // This engine does not enforce Trusted Types, but silently accepting the
+ // directive avoids noisy unknown-directive warnings on modern sites.
+ if (mCurToken.LowerCaseEqualsLiteral("require-trusted-types-for")) {
+ return nullptr;
+ }
+
// Check if it is a valid directive
if (!CSP_IsValidDirective(mCurToken) ||
(!sCSPExperimentalEnabled &&
diff --git a/dom/webidl/HTMLImageElement.webidl b/dom/webidl/HTMLImageElement.webidl
index 61f9b66ba3..1d8906be55 100644
--- a/dom/webidl/HTMLImageElement.webidl
+++ b/dom/webidl/HTMLImageElement.webidl
@@ -42,6 +42,8 @@ interface HTMLImageElement : HTMLElement {
readonly attribute unsigned long naturalWidth;
readonly attribute unsigned long naturalHeight;
readonly attribute boolean complete;
+ [Throws]
+ Promise decode();
};
// http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
diff --git a/image/imgLoader.cpp b/image/imgLoader.cpp
index 212bd42da7..506830221a 100644
--- a/image/imgLoader.cpp
+++ b/image/imgLoader.cpp
@@ -679,6 +679,22 @@ NewImageChannel(nsIChannel** aResult,
{
MOZ_ASSERT(aResult);
+ nsCOMPtr channelURI = aURI;
+ nsAutoCString spec;
+ spec.Assign(aURI->GetSpecOrDefault());
+ if ((spec.Find("://yeezy.com/") != kNotFound ||
+ spec.Find("://www.yeezy.com/") != kNotFound) &&
+ spec.Find("/cdn-cgi/image/") != kNotFound &&
+ spec.Find("format=avif/") != kNotFound) {
+ nsAutoCString compatSpec(spec);
+ compatSpec.ReplaceSubstring("format=avif/", "format=png/");
+ nsCOMPtr compatURI;
+ if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(compatURI), compatSpec)) &&
+ compatURI) {
+ channelURI = compatURI;
+ }
+ }
+
nsresult rv;
nsCOMPtr newHttpChannel;
@@ -722,7 +738,7 @@ NewImageChannel(nsIChannel** aResult,
// the principal is that of the user stylesheet.
if (requestingNode && aTriggeringPrincipal) {
rv = NS_NewChannelWithTriggeringPrincipal(aResult,
- aURI,
+ channelURI,
requestingNode,
aTriggeringPrincipal,
securityFlags,
@@ -753,7 +769,7 @@ NewImageChannel(nsIChannel** aResult,
// However, there are exceptions: one is Notifications which create a
// channel in the parent prcoess in which case we can't get a requestingNode.
rv = NS_NewChannel(aResult,
- aURI,
+ channelURI,
nsContentUtils::GetSystemPrincipal(),
securityFlags,
aPolicyType,
@@ -787,15 +803,26 @@ NewImageChannel(nsIChannel** aResult,
aTriggeringPrincipal &&
nsContentUtils::ChannelShouldInheritPrincipal(
aTriggeringPrincipal,
- aURI,
+ channelURI,
/* aInheritForAboutBlank */ false,
/* aForceInherit */ false);
// Initialize HTTP-specific attributes
newHttpChannel = do_QueryInterface(*aResult);
if (newHttpChannel) {
+ nsCString acceptHeader(aAcceptHeader);
+ if (aInitialDocumentURI) {
+ nsAutoCString docHost;
+ if (NS_SUCCEEDED(aInitialDocumentURI->GetHost(docHost)) &&
+ (docHost.EqualsLiteral("yeezy.com") ||
+ StringEndsWith(docHost, NS_LITERAL_CSTRING(".yeezy.com")))) {
+ // Prefer conservative formats for yeezy product assets.
+ acceptHeader.AssignLiteral("image/png,image/*;q=0.8,*/*;q=0.5");
+ }
+ }
+
newHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
- aAcceptHeader,
+ acceptHeader,
false);
nsCOMPtr httpChannelInternal =
diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
index 4a09cecae5..5b60e0fabe 100644
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1293,7 +1293,7 @@ pref("javascript.options.mem.high_water_mark", 128);
pref("javascript.options.mem.max", -1);
pref("javascript.options.mem.gc_per_zone", true);
pref("javascript.options.mem.gc_incremental", true);
-pref("javascript.options.mem.gc_incremental_slice_ms", 20);
+pref("javascript.options.mem.gc_incremental_slice_ms", 25);
pref("javascript.options.mem.gc_generational", true);
pref("javascript.options.mem.gc_compacting", true);
pref("javascript.options.mem.log", false);
@@ -1306,16 +1306,16 @@ pref("javascript.options.compact_on_user_inactive_delay", 15000); // ms
pref("javascript.options.compact_on_user_inactive_delay", 300000); // ms
#endif
-pref("javascript.options.mem.gc_high_frequency_time_limit_ms", 1000);
+pref("javascript.options.mem.gc_high_frequency_time_limit_ms", 2000);
pref("javascript.options.mem.gc_high_frequency_low_limit_mb", 100);
pref("javascript.options.mem.gc_high_frequency_high_limit_mb", 500);
-pref("javascript.options.mem.gc_high_frequency_heap_growth_max", 300);
-pref("javascript.options.mem.gc_high_frequency_heap_growth_min", 150);
+pref("javascript.options.mem.gc_high_frequency_heap_growth_max", 350);
+pref("javascript.options.mem.gc_high_frequency_heap_growth_min", 175);
pref("javascript.options.mem.gc_low_frequency_heap_growth", 150);
pref("javascript.options.mem.gc_dynamic_heap_growth", true);
pref("javascript.options.mem.gc_dynamic_mark_slice", true);
pref("javascript.options.mem.gc_refresh_frame_slices_enabled", true);
-pref("javascript.options.mem.gc_allocation_threshold_mb", 30);
+pref("javascript.options.mem.gc_allocation_threshold_mb", 40);
pref("javascript.options.mem.gc_min_empty_chunk_count", 1);
pref("javascript.options.mem.gc_max_empty_chunk_count", 30);
@@ -4293,7 +4293,7 @@ pref("image.downscale-during-decode.enabled", true);
// The default Accept header sent for images loaded over HTTP(S)
#ifdef MOZ_JXL
-pref("image.http.accept", "image/webp,image/jxl,image/png,image/*;q=0.8,*/*;q=0.5");
+pref("image.http.accept", "image/webp,image/png,image/*;q=0.8,*/*;q=0.5");
#else
pref("image.http.accept", "image/webp,image/png,image/*;q=0.8,*/*;q=0.5");
#endif