From 8046f8b4aa2bde7bf3273eff7f2cf9814b77a92b Mon Sep 17 00:00:00 2001 From: ownedbywuigi Date: Fri, 27 Mar 2026 17:07:32 +0000 Subject: [PATCH] try to fix the images not rendering on yeezy.com --- dom/html/HTMLImageElement.cpp | 55 +++++++++++++++++++++++-- dom/html/HTMLImageElement.h | 3 ++ dom/performance/PerformanceObserver.cpp | 3 +- dom/security/nsCSPParser.cpp | 7 ++++ dom/webidl/HTMLImageElement.webidl | 2 + image/imgLoader.cpp | 35 ++++++++++++++-- modules/libpref/init/all.js | 12 +++--- 7 files changed, 103 insertions(+), 14 deletions(-) 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