Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/layout/generic/./../../../layout/generic/nsImageFrame.cpp
Warning:line 2350, column 7
Value stored to 'result' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_layout_generic2.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/layout/generic -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/layout/generic -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/layout/generic -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/layout/generic -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/toolkit/components/telemetry -I /root/firefox-clang/xpcom/base -I /root/firefox-clang/layout/base -I /root/firefox-clang/layout/forms -I /root/firefox-clang/layout/painting -I /root/firefox-clang/layout/style -I /root/firefox-clang/layout/tables -I /root/firefox-clang/layout/xul -I /root/firefox-clang/docshell/base -I /root/firefox-clang/dom/base -I /root/firefox-clang/dom/html -I /root/firefox-clang/dom/xul -I /root/firefox-clang/gfx/cairo/cairo/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -I /usr/include/gtk-3.0/unix-print -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cloudproviders -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/fribidi -I /usr/include/harfbuzz -I /usr/include/atk-1.0 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/glycin-2 -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/gio-unix-2.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ Unified_cpp_layout_generic2.cpp
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/* rendering object for replaced elements with image data */
6
7#include "nsImageFrame.h"
8
9#include <algorithm>
10
11#include "TextDrawTarget.h"
12#include "gfx2DGlue.h"
13#include "gfxContext.h"
14#include "gfxUtils.h"
15#include "mozilla/ComputedStyle.h"
16#include "mozilla/DebugOnly.h"
17#include "mozilla/Encoding.h"
18#include "mozilla/HTMLEditor.h"
19#include "mozilla/MouseEvents.h"
20#include "mozilla/PresShell.h"
21#include "mozilla/PresShellInlines.h"
22#include "mozilla/ReflowInput.h"
23#include "mozilla/SVGImageContext.h"
24#include "mozilla/StaticPrefs_browser.h"
25#include "mozilla/StaticPrefs_image.h"
26#include "mozilla/StaticPrefs_layout.h"
27#include "mozilla/dom/Document.h"
28#include "mozilla/dom/FetchPriority.h"
29#include "mozilla/dom/GeneratedImageContent.h"
30#include "mozilla/dom/HTMLAreaElement.h"
31#include "mozilla/dom/HTMLImageElement.h"
32#include "mozilla/dom/LargestContentfulPaint.h"
33#include "mozilla/dom/NameSpaceConstants.h"
34#include "mozilla/dom/PerformanceContainerTiming.h"
35#include "mozilla/dom/ReferrerInfo.h"
36#include "mozilla/dom/ResponsiveImageSelector.h"
37#include "mozilla/dom/ViewTransition.h"
38#include "mozilla/gfx/2D.h"
39#include "mozilla/gfx/Helpers.h"
40#include "mozilla/gfx/PathHelpers.h"
41#include "mozilla/image/WebRenderImageProvider.h"
42#include "mozilla/intl/BidiEmbeddingLevel.h"
43#include "mozilla/layers/RenderRootStateManager.h"
44#include "mozilla/layers/WebRenderLayerManager.h"
45#include "nsCOMPtr.h"
46#include "nsCSSRendering.h"
47#include "nsContentUtils.h"
48#include "nsFontMetrics.h"
49#include "nsGkAtoms.h"
50#include "nsIFrameInlines.h"
51#include "nsIImageLoadingContent.h"
52#include "nsILoadGroup.h"
53#include "nsImageLoadingContent.h"
54#include "nsImageMap.h"
55#include "nsImageRenderer.h"
56#include "nsNameSpaceManager.h"
57#include "nsNetCID.h"
58#include "nsNetUtil.h"
59#include "nsObjectLoadingContent.h"
60#include "nsPresContext.h"
61#include "nsPrintfCString.h"
62#include "nsString.h"
63#include "nsStyleConsts.h"
64#include "nsStyleUtil.h"
65#include "nsTransform2D.h"
66#ifdef ACCESSIBILITY1
67# include "nsAccessibilityService.h"
68#endif
69#include "DisplayListClipState.h"
70#include "ImageContainer.h"
71#include "ImageRegion.h"
72#include "gfxRect.h"
73#include "imgIContainer.h"
74#include "imgLoader.h"
75#include "imgRequestProxy.h"
76#include "mozilla/ServoStyleSet.h"
77#include "mozilla/dom/BrowserChild.h"
78#include "mozilla/dom/HTMLAnchorElement.h"
79#include "mozilla/dom/Link.h"
80#include "mozilla/dom/Selection.h"
81#include "nsBidiPresUtils.h"
82#include "nsBidiUtils.h"
83#include "nsBlockFrame.h"
84#include "nsCSSFrameConstructor.h"
85#include "nsDisplayList.h"
86#include "nsError.h"
87#include "nsIContent.h"
88#include "nsIURIMutator.h"
89#include "nsLayoutUtils.h"
90#include "nsRange.h"
91#include "nsStyleStructInlines.h"
92
93using namespace mozilla;
94using namespace mozilla::dom;
95using namespace mozilla::gfx;
96using namespace mozilla::image;
97using namespace mozilla::layers;
98
99using mozilla::layout::TextDrawTarget;
100
101static constexpr wr::ImageKey kNoKey{{0}, 0};
102
103class nsDisplayGradient final : public nsPaintedDisplayItem {
104 public:
105 nsDisplayGradient(nsDisplayListBuilder* aBuilder, nsImageFrame* aFrame)
106 : nsPaintedDisplayItem(aBuilder, aFrame) {
107 MOZ_COUNT_CTOR(nsDisplayGradient)do { static_assert(std::is_class_v<nsDisplayGradient>, "Token '"
"nsDisplayGradient" "' is not a class type."); static_assert
(!std::is_base_of_v<nsISupports, nsDisplayGradient>, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "nsDisplayGradient"
, sizeof(*this)); } while (0)
;
108 }
109
110 MOZ_COUNTED_DTOR_FINAL(nsDisplayGradient)~nsDisplayGradient() final { do { static_assert(std::is_class_v
<nsDisplayGradient>, "Token '" "nsDisplayGradient" "' is not a class type."
); static_assert(!std::is_base_of_v<nsISupports, nsDisplayGradient
>, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "nsDisplayGradient"
, sizeof(*this)); } while (0); }
111
112 nsRect GetBounds(bool* aSnap) const {
113 *aSnap = true;
114 return Frame()->GetContentRectRelativeToSelf() + ToReferenceFrame();
115 }
116
117 nsRect GetBounds(nsDisplayListBuilder*, bool* aSnap) const final {
118 return GetBounds(aSnap);
119 }
120
121 void Paint(nsDisplayListBuilder*, gfxContext* aCtx) final;
122
123 WebRenderCommandsResult CreateWebRenderCommands(
124 wr::DisplayListBuilder&, wr::IpcResourceUpdateQueue&,
125 const StackingContextHelper&, layers::RenderRootStateManager*,
126 nsDisplayListBuilder*) final;
127
128 NS_DISPLAY_DECL_NAME("Gradient", TYPE_GRADIENT)const char* Name() const override { return "Gradient"; } constexpr
static DisplayItemType ItemType() { return DisplayItemType::
TYPE_GRADIENT; } private: void* operator new(size_t aSize, nsDisplayListBuilder
* aBuilder) { return aBuilder->Allocate(aSize, DisplayItemType
::TYPE_GRADIENT); } template <typename T, typename F, typename
... Args> friend T* mozilla::MakeDisplayItemWithIndex( nsDisplayListBuilder
* aBuilder, F* aFrame, const uint16_t aIndex, Args&&...
aArgs); public:
129};
130
131void nsDisplayGradient::Paint(nsDisplayListBuilder* aBuilder,
132 gfxContext* aCtx) {
133 auto* frame = static_cast<nsImageFrame*>(Frame());
134 nsImageRenderer imageRenderer(frame, frame->GetImageFromStyle(),
135 aBuilder->GetImageRendererFlags());
136 nsSize size = frame->GetSize();
137 imageRenderer.SetPreferredSize({}, size);
138
139 ImgDrawResult result;
140 if (!imageRenderer.PrepareImage()) {
141 result = imageRenderer.PrepareResult();
142 } else {
143 nsRect dest(ToReferenceFrame(), size);
144 result = imageRenderer.DrawLayer(
145 frame->PresContext(), *aCtx, dest, dest, dest.TopLeft(),
146 GetPaintRect(aBuilder, aCtx), dest.Size(), /* aOpacity = */ 1.0f);
147 }
148 (void)result;
149}
150
151WebRenderCommandsResult nsDisplayGradient::CreateWebRenderCommands(
152 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
153 const StackingContextHelper& aSc, layers::RenderRootStateManager* aManager,
154 nsDisplayListBuilder* aDisplayListBuilder) {
155 auto* frame = static_cast<nsImageFrame*>(Frame());
156 nsImageRenderer imageRenderer(frame, frame->GetImageFromStyle(),
157 aDisplayListBuilder->GetImageRendererFlags());
158 nsSize size = frame->GetSize();
159 imageRenderer.SetPreferredSize({}, size);
160
161 ImgDrawResult result;
162 if (!imageRenderer.PrepareImage()) {
163 result = imageRenderer.PrepareResult();
164 } else {
165 nsRect dest(ToReferenceFrame(), size);
166 result = imageRenderer.BuildWebRenderDisplayItemsForLayer(
167 frame->PresContext(), aBuilder, aResources, aSc, aManager, this, dest,
168 dest, dest.TopLeft(), dest, dest.Size(),
169 /* aOpacity = */ 1.0f);
170 if (result == ImgDrawResult::NOT_SUPPORTED) {
171 return Err("gradient image layer is not supported");
172 }
173 }
174 return Ok();
175}
176
177// sizes (pixels) for image icon, padding and border frame
178#define ICON_SIZE(16) (16)
179#define ICON_PADDING(3) (3)
180#define ALT_BORDER_WIDTH(1) (1)
181
182// Default alignment value (so we can tell an unset value from a set value)
183#define ALIGN_UNSETuint8_t(-1) uint8_t(-1)
184
185class BrokenImageIcon final : public imgINotificationObserver {
186 // private class that wraps the data and logic needed for
187 // broken image and loading image icons
188 public:
189 explicit BrokenImageIcon(const nsImageFrame& aFrame);
190 static void Shutdown();
191
192 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
193 NS_DECL_IMGINOTIFICATIONOBSERVERvirtual void Notify(imgIRequest *aProxy, int32_t aType, const
nsIntRect * aRect) override;
194
195 static imgRequestProxy* GetImage(nsImageFrame* aFrame) {
196 return Get(*aFrame).mImage.get();
197 }
198
199 static void AddObserver(nsImageFrame* aFrame) {
200 auto& instance = Get(*aFrame);
201 MOZ_ASSERT(!instance.mObservers.Contains(aFrame),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!instance.mObservers.Contains(aFrame))>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(!instance.mObservers.Contains(aFrame)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!instance.mObservers.Contains(aFrame)"
" (" "Observer shouldn't aleady be in array" ")", "./../../../layout/generic/nsImageFrame.cpp"
, 202); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!instance.mObservers.Contains(aFrame)"
") (" "Observer shouldn't aleady be in array" ")"); do { MOZ_CrashSequence
(__null, 202); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
202 "Observer shouldn't aleady be in array")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!instance.mObservers.Contains(aFrame))>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(!instance.mObservers.Contains(aFrame)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!instance.mObservers.Contains(aFrame)"
" (" "Observer shouldn't aleady be in array" ")", "./../../../layout/generic/nsImageFrame.cpp"
, 202); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!instance.mObservers.Contains(aFrame)"
") (" "Observer shouldn't aleady be in array" ")"); do { MOZ_CrashSequence
(__null, 202); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
203 instance.mObservers.AppendElement(aFrame);
204 }
205
206 static void RemoveObserver(nsImageFrame* aFrame) {
207 auto& instance = Get(*aFrame);
208 DebugOnly<bool> didRemove = instance.mObservers.RemoveElement(aFrame);
209 MOZ_ASSERT(didRemove, "Observer not in array")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(didRemove)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(didRemove))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("didRemove" " (" "Observer not in array"
")", "./../../../layout/generic/nsImageFrame.cpp", 209); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "didRemove" ") (" "Observer not in array" ")"
); do { MOZ_CrashSequence(__null, 209); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
210 }
211
212 private:
213 static BrokenImageIcon& Get(const nsImageFrame& aFrame) {
214 if (!gSingleton) {
215 gSingleton = MakeRefPtr<BrokenImageIcon>(aFrame);
216 }
217 return *gSingleton;
218 }
219
220 ~BrokenImageIcon() = default;
221
222 nsTObserverArray<nsImageFrame*> mObservers;
223 RefPtr<imgRequestProxy> mImage;
224
225 static StaticRefPtr<BrokenImageIcon> gSingleton;
226};
227
228StaticRefPtr<BrokenImageIcon> BrokenImageIcon::gSingleton;
229
230NS_IMPL_ISUPPORTS(BrokenImageIcon, imgINotificationObserver)MozExternalRefCountType BrokenImageIcon::AddRef(void) { static_assert
(!std::is_destructible_v<BrokenImageIcon>, "Reference-counted class "
"BrokenImageIcon" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../layout/generic/nsImageFrame.cpp"
, 230); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 230
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("BrokenImageIcon" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("BrokenImageIcon" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"BrokenImageIcon\" != nullptr" " (" "Must specify a name" ")"
, "./../../../layout/generic/nsImageFrame.cpp", 230); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "\"BrokenImageIcon\" != nullptr" ") (" "Must specify a name"
")"); do { MOZ_CrashSequence(__null, 230); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); if (!mRefCnt
.isThreadSafe) _mOwningThread.AssertOwnership("BrokenImageIcon"
" not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef
((this), (count), ("BrokenImageIcon"), (uint32_t)(sizeof(*this
))); return count; } MozExternalRefCountType BrokenImageIcon::
Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../layout/generic/nsImageFrame.cpp"
, 230); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 230
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("BrokenImageIcon" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("BrokenImageIcon" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"BrokenImageIcon\" != nullptr" " (" "Must specify a name" ")"
, "./../../../layout/generic/nsImageFrame.cpp", 230); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "\"BrokenImageIcon\" != nullptr" ") (" "Must specify a name"
")"); do { MOZ_CrashSequence(__null, 230); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); if (!mRefCnt
.isThreadSafe) _mOwningThread.AssertOwnership("BrokenImageIcon"
" not thread-safe"); const char* const nametmp = "BrokenImageIcon"
; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (
nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return
0; } return count; } nsresult BrokenImageIcon::QueryInterface
(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../layout/generic/nsImageFrame.cpp"
, 230); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<BrokenImageIcon, imgINotificationObserver
>, int32_t( reinterpret_cast<char*>(static_cast<imgINotificationObserver
*>((BrokenImageIcon*)0x1000)) - reinterpret_cast<char*>
((BrokenImageIcon*)0x1000))}, {&mozilla::detail::kImplementedIID
<BrokenImageIcon, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
imgINotificationObserver*>((BrokenImageIcon*)0x1000))) - reinterpret_cast
<char*>((BrokenImageIcon*)0x1000))}, { nullptr, 0 } } ;
static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
231
232BrokenImageIcon::BrokenImageIcon(const nsImageFrame& aFrame) {
233 constexpr auto brokenSrc = u"resource://gre-resources/broken-image.png"_ns;
234 nsCOMPtr<nsIURI> realURI;
235 NS_NewURI(getter_AddRefs(realURI), brokenSrc);
236
237 MOZ_ASSERT(realURI, "how?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(realURI)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(realURI))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("realURI" " (" "how?" ")"
, "./../../../layout/generic/nsImageFrame.cpp", 237); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "realURI" ") (" "how?" ")"); do { MOZ_CrashSequence
(__null, 237); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
238 if (NS_WARN_IF(!realURI)NS_warn_if_impl(!realURI, "!realURI", "./../../../layout/generic/nsImageFrame.cpp"
, 238)
) {
239 return;
240 }
241
242 nsPresContext* pc = aFrame.PresContext();
243 Document* doc = pc->Document();
244 RefPtr<imgLoader> il = nsContentUtils::GetImgLoaderForDocument(doc);
245
246 nsCOMPtr<nsILoadGroup> loadGroup = doc->GetDocumentLoadGroup();
247
248 // For icon loads, we don't need to merge with the loadgroup flags
249 const nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
250 const nsContentPolicyType contentPolicyType =
251 nsIContentPolicy::TYPE_INTERNAL_IMAGE;
252
253 nsresult rv =
254 il->LoadImage(realURI, /* icon URI */
255 nullptr, /* initial document URI; this is only
256 relevant for cookies, so does not
257 apply to icons. */
258 nullptr, /* referrer (not relevant for icons) */
259 nullptr, /* principal (not relevant for icons) */
260 0, loadGroup, this, nullptr, /* No context */
261 nullptr, /* Not associated with any particular document */
262 loadFlags, nullptr, contentPolicyType, u""_ns,
263 false, /* aUseUrgentStartForChannel */
264 false, /* aLinkPreload */
265 0, FetchPriority::Auto, getter_AddRefs(mImage));
266 (void)NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../layout/generic/nsImageFrame.cpp"
, 266)
;
267}
268
269void BrokenImageIcon::Shutdown() {
270 if (!gSingleton) {
271 return;
272 }
273 if (gSingleton->mImage) {
274 gSingleton->mImage->CancelAndForgetObserver(NS_ERROR_FAILURE);
275 gSingleton->mImage = nullptr;
276 }
277 gSingleton = nullptr;
278}
279
280void BrokenImageIcon::Notify(imgIRequest* aRequest, int32_t aType,
281 const nsIntRect* aData) {
282 MOZ_ASSERT(aRequest)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRequest)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRequest))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aRequest", "./../../../layout/generic/nsImageFrame.cpp"
, 282); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRequest" ")"
); do { MOZ_CrashSequence(__null, 282); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
283
284 if (aType != imgINotificationObserver::LOAD_COMPLETE &&
285 aType != imgINotificationObserver::FRAME_UPDATE) {
286 return;
287 }
288
289 if (aType == imgINotificationObserver::LOAD_COMPLETE) {
290 nsCOMPtr<imgIContainer> image;
291 aRequest->GetImage(getter_AddRefs(image));
292 if (!image) {
293 return;
294 }
295
296 // Retrieve the image's intrinsic size.
297 int32_t width = 0;
298 int32_t height = 0;
299 image->GetWidth(&width);
300 image->GetHeight(&height);
301
302 // Request a decode at that size.
303 image->RequestDecodeForSize(IntSize(width, height),
304 imgIContainer::DECODE_FLAGS_DEFAULT |
305 imgIContainer::FLAG_HIGH_QUALITY_SCALING);
306 }
307
308 for (nsImageFrame* frame : mObservers.ForwardRange()) {
309 frame->InvalidateFrame();
310 }
311}
312
313// test if the width and height are fixed, looking at the style data
314// This is used by nsImageFrame::ImageFrameTypeFor and should not be used for
315// layout decisions.
316static bool HaveSpecifiedSize(const nsStylePosition* aStylePosition,
317 const AnchorPosResolutionParams& aParams) {
318 // check the width and height values in the reflow input's style struct
319 // - if width and height are specified as either coord or percentage, then
320 // the size of the image frame is constrained
321 return aStylePosition->GetWidth(aParams)->IsLengthPercentage() &&
322 aStylePosition->GetHeight(aParams)->IsLengthPercentage();
323}
324
325template <typename SizeOrMaxSize>
326static bool DependsOnIntrinsicSize(const SizeOrMaxSize& aMinOrMaxSize) {
327 auto length = nsIFrame::ToExtremumLength(aMinOrMaxSize);
328 if (!length) {
329 return false;
330 }
331 switch (*length) {
332 case nsIFrame::ExtremumLength::MinContent:
333 case nsIFrame::ExtremumLength::MaxContent:
334 case nsIFrame::ExtremumLength::FitContent:
335 case nsIFrame::ExtremumLength::FitContentFunction:
336 return true;
337 case nsIFrame::ExtremumLength::MozAvailable:
338 case nsIFrame::ExtremumLength::Stretch:
339 return false;
340 }
341 MOZ_ASSERT_UNREACHABLE("Unknown sizing keyword?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Unknown sizing keyword?" ")", "./../../../layout/generic/nsImageFrame.cpp"
, 341); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unknown sizing keyword?" ")"); do
{ MOZ_CrashSequence(__null, 341); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
342 return false;
343}
344
345// Decide whether we can optimize away reflows that result from the
346// image's intrinsic size changing.
347static bool SizeDependsOnIntrinsicSize(const ReflowInput& aReflowInput) {
348 const auto& position = *aReflowInput.mStylePosition;
349 const auto anchorResolutionParams =
350 AnchorPosResolutionParams::From(&aReflowInput);
351 WritingMode wm = aReflowInput.GetWritingMode();
352 // Don't try to make this optimization when an image has percentages
353 // in its 'width' or 'height'. The percentages might be treated like
354 // auto (especially for intrinsic width calculations and for heights).
355 //
356 // min-width: min-content and such can also affect our intrinsic size.
357 // but note that those keywords on the block axis behave like auto, so we
358 // don't need to check them.
359 //
360 // Flex item's min-[width|height]:auto resolution depends on intrinsic size.
361 return !position.GetHeight(anchorResolutionParams)->ConvertsToLength() ||
362 !position.GetWidth(anchorResolutionParams)->ConvertsToLength() ||
363 DependsOnIntrinsicSize(
364 *position.MinISize(wm, anchorResolutionParams)) ||
365 DependsOnIntrinsicSize(
366 *position.MaxISize(wm, anchorResolutionParams)) ||
367 aReflowInput.mFrame->IsFlexItem();
368}
369
370nsIFrame* NS_NewImageFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
371 return new (aPresShell) nsImageFrame(aStyle, aPresShell->GetPresContext(),
372 nsImageFrame::Kind::ImageLoadingContent);
373}
374
375static bool ShouldCreateImageFrameForContentProperty(
376 const ComputedStyle& aStyle) {
377 Span<const StyleContentItem> items =
378 aStyle.StyleContent()->NonAltContentItems();
379 return items.Length() == 1 && items[0].IsImage();
380}
381
382nsIFrame* NS_NewXULImageFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
383 auto kind = ShouldCreateImageFrameForContentProperty(*aStyle)
384 ? nsImageFrame::Kind::ContentProperty
385 : nsImageFrame::Kind::XULImage;
386 return new (aPresShell)
387 nsImageFrame(aStyle, aPresShell->GetPresContext(), kind);
388}
389
390nsIFrame* NS_NewImageFrameForContentProperty(PresShell* aPresShell,
391 ComputedStyle* aStyle) {
392 return new (aPresShell) nsImageFrame(aStyle, aPresShell->GetPresContext(),
393 nsImageFrame::Kind::ContentProperty);
394}
395
396nsIFrame* NS_NewImageFrameForGeneratedContentIndex(PresShell* aPresShell,
397 ComputedStyle* aStyle) {
398 return new (aPresShell)
399 nsImageFrame(aStyle, aPresShell->GetPresContext(),
400 nsImageFrame::Kind::ContentPropertyAtIndex);
401}
402
403nsIFrame* NS_NewImageFrameForListStyleImage(PresShell* aPresShell,
404 ComputedStyle* aStyle) {
405 return new (aPresShell) nsImageFrame(aStyle, aPresShell->GetPresContext(),
406 nsImageFrame::Kind::ListStyleImage);
407}
408
409nsIFrame* NS_NewImageFrameForViewTransition(PresShell* aPresShell,
410 ComputedStyle* aStyle) {
411 return new (aPresShell) nsImageFrame(aStyle, aPresShell->GetPresContext(),
412 nsImageFrame::Kind::ViewTransition);
413}
414
415bool nsImageFrame::ShouldShowBrokenImageIcon() const {
416 // NOTE(emilio, https://github.com/w3c/csswg-drafts/issues/2832): WebKit and
417 // Blink behave differently here for content: url(..), for now adapt to
418 // Blink's behavior.
419 if (mKind != Kind::ImageLoadingContent) {
420 return false;
421 }
422
423 if (!StaticPrefs::browser_display_show_image_placeholders()) {
424 return false;
425 }
426
427 // <img alt=""> is special, and it shouldn't draw the broken image icon,
428 // unlike the no-alt attribute or non-empty-alt-attribute case.
429 if (auto* image = HTMLImageElement::FromNode(mContent)) {
430 const nsAttrValue* alt = image->GetParsedAttr(nsGkAtoms::alt);
431 if (alt && alt->IsEmptyString()) {
432 return false;
433 }
434 }
435
436 // check for broken images. valid null images (eg. img src="") are
437 // not considered broken because they have no image requests
438 if (nsCOMPtr<imgIRequest> currentRequest = GetCurrentRequest()) {
439 uint32_t imageStatus;
440 return NS_SUCCEEDED(currentRequest->GetImageStatus(&imageStatus))((bool)(__builtin_expect(!!(!NS_FAILED_impl(currentRequest->
GetImageStatus(&imageStatus))), 1)))
&&
441 (imageStatus & imgIRequest::STATUS_ERROR);
442 }
443
444 nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
445 MOZ_ASSERT(imageLoader)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(imageLoader)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(imageLoader))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("imageLoader", "./../../../layout/generic/nsImageFrame.cpp"
, 445); AnnotateMozCrashReason("MOZ_ASSERT" "(" "imageLoader"
")"); do { MOZ_CrashSequence(__null, 445); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
446 // Show the broken image icon only if we've tried to perform a load at all
447 // (that is, if we have a current uri).
448 nsCOMPtr<nsIURI> currentURI = imageLoader->GetCurrentURI();
449 return !!currentURI;
450}
451
452nsImageFrame* nsImageFrame::CreateContinuingFrame(
453 mozilla::PresShell* aPresShell, ComputedStyle* aStyle) const {
454 return new (aPresShell)
455 nsImageFrame(aStyle, aPresShell->GetPresContext(), mKind);
456}
457
458NS_IMPL_FRAMEARENA_HELPERS(nsImageFrame)void* nsImageFrame ::operator new(size_t sz, mozilla::PresShell
* aShell) { return aShell->AllocateFrame(nsQueryFrame::nsImageFrame_id
, sz); }
459
460nsImageFrame::nsImageFrame(ComputedStyle* aStyle, nsPresContext* aPresContext,
461 ClassID aID, Kind aKind)
462 : nsAtomicContainerFrame(aStyle, aPresContext, aID),
463 mIntrinsicSize(0, 0),
464 mKind(aKind) {
465 EnableVisibilityTracking();
466}
467
468nsImageFrame::~nsImageFrame() = default;
469
470NS_QUERYFRAME_HEAD(nsImageFrame)void* nsImageFrame ::QueryFrame(FrameIID id) const { switch (
id) {
471 NS_QUERYFRAME_ENTRY(nsImageFrame)case nsImageFrame ::kFrameIID: { static_assert( std::is_same_v
<nsImageFrame, nsImageFrame ::Has_NS_DECL_QUERYFRAME_TARGET
>, "nsImageFrame" " must declare itself as a queryframe target"
); return const_cast<nsImageFrame*>(static_cast<const
nsImageFrame*>(this)); }
472NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame)default: break; } return nsAtomicContainerFrame ::QueryFrame(
id); }
473
474#ifdef ACCESSIBILITY1
475a11y::AccType nsImageFrame::AccessibleType() {
476 if (mKind == Kind::ListStyleImage) {
477 // This is an HTMLListBulletAccessible.
478 return a11y::eNoType;
479 }
480
481 if (mKind == Kind::ViewTransition) {
482 // View transitions don't show up in the a11y tree.
483 return a11y::eNoType;
484 }
485
486 // Don't use GetImageMap() to avoid reentrancy into accessibility.
487 if (HasImageMap()) {
488 return a11y::eHTMLImageMapType;
489 }
490
491 return a11y::eImageType;
492}
493#endif
494
495void nsImageFrame::DisconnectMap() {
496 if (!mImageMap) {
497 return;
498 }
499
500 mImageMap->Destroy();
501 mImageMap = nullptr;
502
503#ifdef ACCESSIBILITY1
504 if (nsAccessibilityService* accService = GetAccService()) {
505 accService->RecreateAccessible(PresShell(), mContent);
506 }
507#endif
508}
509
510void nsImageFrame::Destroy(DestroyContext& aContext) {
511 MaybeSendIntrinsicSizeAndRatioToEmbedder(Nothing(), Nothing());
512
513 if (mReflowCallbackPosted) {
514 PresShell()->CancelReflowCallback(this);
515 mReflowCallbackPosted = false;
516 }
517
518 // Tell our image map, if there is one, to clean up
519 // This causes the nsImageMap to unregister itself as
520 // a DOM listener.
521 DisconnectMap();
522
523 MOZ_ASSERT(mListener)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mListener)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mListener))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mListener", "./../../../layout/generic/nsImageFrame.cpp"
, 523); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mListener" ")"
); do { MOZ_CrashSequence(__null, 523); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
524
525 if (mKind == Kind::ImageLoadingContent) {
526 MOZ_ASSERT(!mOwnedRequest)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mOwnedRequest)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mOwnedRequest))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mOwnedRequest"
, "./../../../layout/generic/nsImageFrame.cpp", 526); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mOwnedRequest" ")"); do { MOZ_CrashSequence
(__null, 526); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
527 MOZ_ASSERT(!mOwnedRequestRegistered)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mOwnedRequestRegistered)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mOwnedRequestRegistered))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!mOwnedRequestRegistered"
, "./../../../layout/generic/nsImageFrame.cpp", 527); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mOwnedRequestRegistered" ")"); do { MOZ_CrashSequence
(__null, 527); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
528 nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
529 MOZ_ASSERT(imageLoader)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(imageLoader)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(imageLoader))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("imageLoader", "./../../../layout/generic/nsImageFrame.cpp"
, 529); AnnotateMozCrashReason("MOZ_ASSERT" "(" "imageLoader"
")"); do { MOZ_CrashSequence(__null, 529); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
530
531 // Notify our image loading content that we are going away so it can
532 // deregister with our refresh driver.
533 imageLoader->FrameDestroyed(this);
534 imageLoader->RemoveNativeObserver(mListener);
535 } else {
536 DeinitOwnedRequest();
537 }
538
539 // set the frame to null so we don't send messages to a dead object.
540 mListener->SetFrame(nullptr);
541 mListener = nullptr;
542
543 // If we were displaying an icon, take ourselves off the list
544 if (mDisplayingIcon) {
545 BrokenImageIcon::RemoveObserver(this);
546 }
547
548 nsAtomicContainerFrame::Destroy(aContext);
549}
550
551void nsImageFrame::DeinitOwnedRequest() {
552 MOZ_ASSERT(mKind != Kind::ImageLoadingContent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mKind != Kind::ImageLoadingContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mKind != Kind::ImageLoadingContent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mKind != Kind::ImageLoadingContent", "./../../../layout/generic/nsImageFrame.cpp"
, 552); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mKind != Kind::ImageLoadingContent"
")"); do { MOZ_CrashSequence(__null, 552); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
553 if (!mOwnedRequest) {
554 return;
555 }
556 PresContext()->Document()->UntrackImage(mOwnedRequest);
557 nsLayoutUtils::DeregisterImageRequest(PresContext(), mOwnedRequest,
558 &mOwnedRequestRegistered);
559 mOwnedRequest->CancelAndForgetObserver(NS_BINDING_ABORTED);
560 mOwnedRequest = nullptr;
561}
562
563void nsImageFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) {
564 nsAtomicContainerFrame::DidSetComputedStyle(aOldStyle);
565
566 // A list-style-image ::marker default size is calculated from the font's
567 // em-size, which might have changed here.
568 if (mKind == Kind::ListStyleImage) {
569 UpdateIntrinsicSize();
570 }
571
572 // Normal "owned" images reframe when `content` or `list-style-image` change,
573 // but XUL images don't (and we don't really need to). So deal with the
574 // dynamic list-style-image change in that case.
575 //
576 // TODO(emilio): We might want to do the same for regular list-style-image or
577 // even simple content: url() changes.
578 if (mKind == Kind::XULImage && aOldStyle) {
579 if (!mContent->AsElement()->HasNonEmptyAttr(nsGkAtoms::src) &&
580 aOldStyle->StyleList()->mListStyleImage !=
581 StyleList()->mListStyleImage) {
582 UpdateXULImage();
583 }
584 // If we have no image our intrinsic size might be themed. We need to
585 // update the size even if the effective appearance hasn't changed to
586 // deal correctly with theme changes.
587 if (!mOwnedRequest) {
588 UpdateIntrinsicSize();
589 }
590 }
591
592 // We need to update our orientation either if we had no ComputedStyle before
593 // because this is the first time it's been set, or if the image-orientation
594 // property changed from its previous value.
595 bool shouldUpdateOrientation = false;
596 nsCOMPtr<imgIRequest> currentRequest = GetCurrentRequest();
597 const auto newOrientation =
598 StyleVisibility()->UsedImageOrientation(currentRequest);
599 if (mImage) {
600 if (aOldStyle) {
601 auto oldOrientation =
602 aOldStyle->StyleVisibility()->UsedImageOrientation(currentRequest);
603 shouldUpdateOrientation = oldOrientation != newOrientation;
604 } else {
605 shouldUpdateOrientation = true;
606 }
607 }
608
609 if (shouldUpdateOrientation) {
610 nsCOMPtr<imgIContainer> image(mImage->Unwrap());
611 mImage = nsLayoutUtils::OrientImage(image, newOrientation);
612
613 UpdateIntrinsicSize();
614 UpdateIntrinsicRatio();
615 } else if (!aOldStyle || aOldStyle->StylePosition()->mAspectRatio !=
616 StylePosition()->mAspectRatio) {
617 UpdateIntrinsicRatio();
618 }
619}
620
621static bool SizeIsAvailable(imgIRequest* aRequest) {
622 if (!aRequest) {
623 return false;
624 }
625
626 uint32_t imageStatus = 0;
627 nsresult rv = aRequest->GetImageStatus(&imageStatus);
628 return NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && (imageStatus & imgIRequest::STATUS_SIZE_AVAILABLE);
629}
630
631const StyleImage* nsImageFrame::GetImageFromStyle() const {
632 switch (mKind) {
633 case Kind::ViewTransition:
634 break;
635 case Kind::ImageLoadingContent:
636 break;
637 case Kind::ListStyleImage:
638 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(GetParent()->GetContent()->IsGeneratedContentContainerForMarker
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(GetParent()->GetContent()->IsGeneratedContentContainerForMarker
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("GetParent()->GetContent()->IsGeneratedContentContainerForMarker()"
, "./../../../layout/generic/nsImageFrame.cpp", 639); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "GetParent()->GetContent()->IsGeneratedContentContainerForMarker()"
")"); do { MOZ_CrashSequence(__null, 639); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
639 GetParent()->GetContent()->IsGeneratedContentContainerForMarker())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(GetParent()->GetContent()->IsGeneratedContentContainerForMarker
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(GetParent()->GetContent()->IsGeneratedContentContainerForMarker
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("GetParent()->GetContent()->IsGeneratedContentContainerForMarker()"
, "./../../../layout/generic/nsImageFrame.cpp", 639); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "GetParent()->GetContent()->IsGeneratedContentContainerForMarker()"
")"); do { MOZ_CrashSequence(__null, 639); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
640 MOZ_ASSERT(mContent->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mContent->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mContent->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mContent->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage)"
, "./../../../layout/generic/nsImageFrame.cpp", 640); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mContent->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage)"
")"); do { MOZ_CrashSequence(__null, 640); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
641 return &StyleList()->mListStyleImage;
642 case Kind::XULImage:
643 MOZ_ASSERT(!mContent->AsElement()->HasNonEmptyAttr(nsGkAtoms::src))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mContent->AsElement()->HasNonEmptyAttr(nsGkAtoms
::src))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!mContent->AsElement()->HasNonEmptyAttr(nsGkAtoms
::src)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mContent->AsElement()->HasNonEmptyAttr(nsGkAtoms::src)"
, "./../../../layout/generic/nsImageFrame.cpp", 643); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mContent->AsElement()->HasNonEmptyAttr(nsGkAtoms::src)"
")"); do { MOZ_CrashSequence(__null, 643); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
644 return &StyleList()->mListStyleImage;
645 case Kind::ContentProperty:
646 case Kind::ContentPropertyAtIndex: {
647 uint32_t contentIndex = 0;
648 const nsStyleContent* styleContent = StyleContent();
649 if (mKind == Kind::ContentPropertyAtIndex) {
650 MOZ_RELEASE_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mContent->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mContent->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mContent->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage)"
, "./../../../layout/generic/nsImageFrame.cpp", 651); AnnotateMozCrashReason
("MOZ_RELEASE_ASSERT" "(" "mContent->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage)"
")"); do { MOZ_CrashSequence(__null, 651); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
651 mContent->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mContent->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mContent->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mContent->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage)"
, "./../../../layout/generic/nsImageFrame.cpp", 651); AnnotateMozCrashReason
("MOZ_RELEASE_ASSERT" "(" "mContent->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage)"
")"); do { MOZ_CrashSequence(__null, 651); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
652 contentIndex =
653 static_cast<GeneratedImageContent*>(mContent.get())->Index();
654
655 // TODO(emilio): Consider inheriting the `content` property instead of
656 // doing this parent traversal?
657 nsIFrame* parent = GetParent();
658 MOZ_DIAGNOSTIC_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(parent->GetContent()->IsGeneratedContentContainerForMarker
() || parent->GetContent()->IsGeneratedContentContainerForAfter
() || parent->GetContent()->IsGeneratedContentContainerForBefore
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(parent->GetContent()->IsGeneratedContentContainerForMarker
() || parent->GetContent()->IsGeneratedContentContainerForAfter
() || parent->GetContent()->IsGeneratedContentContainerForBefore
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("parent->GetContent()->IsGeneratedContentContainerForMarker() || parent->GetContent()->IsGeneratedContentContainerForAfter() || parent->GetContent()->IsGeneratedContentContainerForBefore()"
, "./../../../layout/generic/nsImageFrame.cpp", 661); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "parent->GetContent()->IsGeneratedContentContainerForMarker() || parent->GetContent()->IsGeneratedContentContainerForAfter() || parent->GetContent()->IsGeneratedContentContainerForBefore()"
")"); do { MOZ_CrashSequence(__null, 661); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
659 parent->GetContent()->IsGeneratedContentContainerForMarker() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(parent->GetContent()->IsGeneratedContentContainerForMarker
() || parent->GetContent()->IsGeneratedContentContainerForAfter
() || parent->GetContent()->IsGeneratedContentContainerForBefore
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(parent->GetContent()->IsGeneratedContentContainerForMarker
() || parent->GetContent()->IsGeneratedContentContainerForAfter
() || parent->GetContent()->IsGeneratedContentContainerForBefore
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("parent->GetContent()->IsGeneratedContentContainerForMarker() || parent->GetContent()->IsGeneratedContentContainerForAfter() || parent->GetContent()->IsGeneratedContentContainerForBefore()"
, "./../../../layout/generic/nsImageFrame.cpp", 661); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "parent->GetContent()->IsGeneratedContentContainerForMarker() || parent->GetContent()->IsGeneratedContentContainerForAfter() || parent->GetContent()->IsGeneratedContentContainerForBefore()"
")"); do { MOZ_CrashSequence(__null, 661); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
660 parent->GetContent()->IsGeneratedContentContainerForAfter() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(parent->GetContent()->IsGeneratedContentContainerForMarker
() || parent->GetContent()->IsGeneratedContentContainerForAfter
() || parent->GetContent()->IsGeneratedContentContainerForBefore
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(parent->GetContent()->IsGeneratedContentContainerForMarker
() || parent->GetContent()->IsGeneratedContentContainerForAfter
() || parent->GetContent()->IsGeneratedContentContainerForBefore
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("parent->GetContent()->IsGeneratedContentContainerForMarker() || parent->GetContent()->IsGeneratedContentContainerForAfter() || parent->GetContent()->IsGeneratedContentContainerForBefore()"
, "./../../../layout/generic/nsImageFrame.cpp", 661); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "parent->GetContent()->IsGeneratedContentContainerForMarker() || parent->GetContent()->IsGeneratedContentContainerForAfter() || parent->GetContent()->IsGeneratedContentContainerForBefore()"
")"); do { MOZ_CrashSequence(__null, 661); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
661 parent->GetContent()->IsGeneratedContentContainerForBefore())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(parent->GetContent()->IsGeneratedContentContainerForMarker
() || parent->GetContent()->IsGeneratedContentContainerForAfter
() || parent->GetContent()->IsGeneratedContentContainerForBefore
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(parent->GetContent()->IsGeneratedContentContainerForMarker
() || parent->GetContent()->IsGeneratedContentContainerForAfter
() || parent->GetContent()->IsGeneratedContentContainerForBefore
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("parent->GetContent()->IsGeneratedContentContainerForMarker() || parent->GetContent()->IsGeneratedContentContainerForAfter() || parent->GetContent()->IsGeneratedContentContainerForBefore()"
, "./../../../layout/generic/nsImageFrame.cpp", 661); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "parent->GetContent()->IsGeneratedContentContainerForMarker() || parent->GetContent()->IsGeneratedContentContainerForAfter() || parent->GetContent()->IsGeneratedContentContainerForBefore()"
")"); do { MOZ_CrashSequence(__null, 661); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
662 nsIFrame* nonAnonymousParent = parent;
663 while (nonAnonymousParent->Style()->IsAnonBox()) {
664 nonAnonymousParent = nonAnonymousParent->GetParent();
665 }
666 MOZ_DIAGNOSTIC_ASSERT(parent->GetContent() ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(parent->GetContent() == nonAnonymousParent->GetContent
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(parent->GetContent() == nonAnonymousParent->GetContent
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("parent->GetContent() == nonAnonymousParent->GetContent()"
, "./../../../layout/generic/nsImageFrame.cpp", 667); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "parent->GetContent() == nonAnonymousParent->GetContent()"
")"); do { MOZ_CrashSequence(__null, 667); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
667 nonAnonymousParent->GetContent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(parent->GetContent() == nonAnonymousParent->GetContent
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(parent->GetContent() == nonAnonymousParent->GetContent
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("parent->GetContent() == nonAnonymousParent->GetContent()"
, "./../../../layout/generic/nsImageFrame.cpp", 667); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "parent->GetContent() == nonAnonymousParent->GetContent()"
")"); do { MOZ_CrashSequence(__null, 667); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
668 styleContent = nonAnonymousParent->StyleContent();
669 }
670 auto items = styleContent->NonAltContentItems();
671 MOZ_RELEASE_ASSERT(contentIndex < items.Length())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentIndex < items.Length())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(contentIndex < items.Length
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("contentIndex < items.Length()", "./../../../layout/generic/nsImageFrame.cpp"
, 671); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "contentIndex < items.Length()"
")"); do { MOZ_CrashSequence(__null, 671); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
672 const auto& contentItem = items[contentIndex];
673 MOZ_RELEASE_ASSERT(contentItem.IsImage())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentItem.IsImage())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(contentItem.IsImage()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("contentItem.IsImage()"
, "./../../../layout/generic/nsImageFrame.cpp", 673); AnnotateMozCrashReason
("MOZ_RELEASE_ASSERT" "(" "contentItem.IsImage()" ")"); do { MOZ_CrashSequence
(__null, 673); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
674 return &contentItem.AsImage();
675 }
676 }
677 MOZ_ASSERT_UNREACHABLE("Don't call me")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Don't call me" ")", "./../../../layout/generic/nsImageFrame.cpp"
, 677); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Don't call me" ")"); do { MOZ_CrashSequence
(__null, 677); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
678 return nullptr;
679}
680
681void nsImageFrame::UpdateXULImage() {
682 MOZ_ASSERT(mKind == Kind::XULImage)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mKind == Kind::XULImage)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mKind == Kind::XULImage))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mKind == Kind::XULImage"
, "./../../../layout/generic/nsImageFrame.cpp", 682); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mKind == Kind::XULImage" ")"); do { MOZ_CrashSequence
(__null, 682); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
683 DeinitOwnedRequest();
684
685 nsAutoString src;
686 nsPresContext* pc = PresContext();
687 if (mContent->AsElement()->GetAttr(nsGkAtoms::src, src) && !src.IsEmpty()) {
688 nsContentPolicyType contentPolicyType;
689 nsCOMPtr<nsIPrincipal> triggeringPrincipal;
690 uint64_t requestContextID = 0;
691 nsContentUtils::GetContentPolicyTypeForUIImageLoading(
692 mContent, getter_AddRefs(triggeringPrincipal), contentPolicyType,
693 &requestContextID);
694 nsCOMPtr<nsIURI> uri;
695 nsContentUtils::NewURIWithDocumentCharset(
696 getter_AddRefs(uri), src, pc->Document(), mContent->GetBaseURI());
697 if (uri) {
698 auto referrerInfo = MakeRefPtr<ReferrerInfo>(*mContent->AsElement());
699 nsContentUtils::LoadImage(
700 uri, mContent, pc->Document(), triggeringPrincipal, requestContextID,
701 referrerInfo, mListener, nsIRequest::LOAD_NORMAL, u""_ns,
702 getter_AddRefs(mOwnedRequest), contentPolicyType);
703 SetupOwnedRequest();
704 }
705 } else {
706 const auto* image = GetImageFromStyle();
707 if (image->IsImageRequestType()) {
708 if (imgRequestProxy* proxy = image->GetImageRequest()) {
709 proxy->Clone(mListener, pc->Document(), getter_AddRefs(mOwnedRequest));
710 SetupOwnedRequest();
711 }
712 }
713 }
714
715 if (!mOwnedRequest) {
716 UpdateImage(nullptr, nullptr);
717 }
718}
719
720void nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
721 nsIFrame* aPrevInFlow) {
722 MOZ_ASSERT_IF(aPrevInFlow,do { if (aPrevInFlow) { do { static_assert( mozilla::detail::
AssertionConditionType<decltype(aPrevInFlow->Type() == Type
() && static_cast<nsImageFrame*>(aPrevInFlow)->
mKind == mKind)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aPrevInFlow->Type() == Type
() && static_cast<nsImageFrame*>(aPrevInFlow)->
mKind == mKind))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aPrevInFlow->Type() == Type() && static_cast<nsImageFrame*>(aPrevInFlow)->mKind == mKind"
, "./../../../layout/generic/nsImageFrame.cpp", 724); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aPrevInFlow->Type() == Type() && static_cast<nsImageFrame*>(aPrevInFlow)->mKind == mKind"
")"); do { MOZ_CrashSequence(__null, 724); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
723 aPrevInFlow->Type() == Type() &&do { if (aPrevInFlow) { do { static_assert( mozilla::detail::
AssertionConditionType<decltype(aPrevInFlow->Type() == Type
() && static_cast<nsImageFrame*>(aPrevInFlow)->
mKind == mKind)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aPrevInFlow->Type() == Type
() && static_cast<nsImageFrame*>(aPrevInFlow)->
mKind == mKind))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aPrevInFlow->Type() == Type() && static_cast<nsImageFrame*>(aPrevInFlow)->mKind == mKind"
, "./../../../layout/generic/nsImageFrame.cpp", 724); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aPrevInFlow->Type() == Type() && static_cast<nsImageFrame*>(aPrevInFlow)->mKind == mKind"
")"); do { MOZ_CrashSequence(__null, 724); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
724 static_cast<nsImageFrame*>(aPrevInFlow)->mKind == mKind)do { if (aPrevInFlow) { do { static_assert( mozilla::detail::
AssertionConditionType<decltype(aPrevInFlow->Type() == Type
() && static_cast<nsImageFrame*>(aPrevInFlow)->
mKind == mKind)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aPrevInFlow->Type() == Type
() && static_cast<nsImageFrame*>(aPrevInFlow)->
mKind == mKind))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aPrevInFlow->Type() == Type() && static_cast<nsImageFrame*>(aPrevInFlow)->mKind == mKind"
, "./../../../layout/generic/nsImageFrame.cpp", 724); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aPrevInFlow->Type() == Type() && static_cast<nsImageFrame*>(aPrevInFlow)->mKind == mKind"
")"); do { MOZ_CrashSequence(__null, 724); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
725
726 nsAtomicContainerFrame::Init(aContent, aParent, aPrevInFlow);
727
728 mListener = MakeRefPtr<nsImageListener>(this);
729
730 GetImageMap(); // Ensure to init the image map asap. This is important to
731 // make <area> elements focusable.
732
733 if (StaticPrefs::layout_image_eager_broken_image_icon()) {
734 (void)BrokenImageIcon::GetImage(this);
735 }
736
737 nsPresContext* pc = PresContext();
738 if (mKind == Kind::ImageLoadingContent) {
739 nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(aContent);
740 MOZ_ASSERT(imageLoader)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(imageLoader)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(imageLoader))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("imageLoader", "./../../../layout/generic/nsImageFrame.cpp"
, 740); AnnotateMozCrashReason("MOZ_ASSERT" "(" "imageLoader"
")"); do { MOZ_CrashSequence(__null, 740); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
741 imageLoader->AddNativeObserver(mListener);
742 // We have a PresContext now, so we need to notify the image content node
743 // that it can register images.
744 imageLoader->FrameCreated(this);
745 AssertSyncDecodingHintIsInSync();
746 if (nsIDocShell* docShell = pc->GetDocShell()) {
747 RefPtr<BrowsingContext> bc = docShell->GetBrowsingContext();
748 mIsInObjectOrEmbed = bc->IsEmbedderTypeObjectOrEmbed() &&
749 pc->Document()->IsImageDocument();
750 }
751 } else if (mKind == Kind::XULImage) {
752 UpdateXULImage();
753 } else if (mKind == Kind::ViewTransition) {
754 // View transitions have a surface directly.
755 } else {
756 const StyleImage* image = GetImageFromStyle();
757 if (image->IsImageRequestType()) {
758 if (imgRequestProxy* proxy = image->GetImageRequest()) {
759 proxy->Clone(mListener, pc->Document(), getter_AddRefs(mOwnedRequest));
760 SetupOwnedRequest();
761 }
762 }
763 }
764
765 // Give image loads associated with an image frame a small priority boost.
766 if (nsCOMPtr<imgIRequest> currentRequest = GetCurrentRequest()) {
767 uint32_t categoryToBoostPriority = imgIRequest::CATEGORY_FRAME_INIT;
768
769 // Increase load priority further if intrinsic size might be important for
770 // layout.
771 if (!HaveSpecifiedSize(StylePosition(),
772 AnchorPosResolutionParams::From(this))) {
773 categoryToBoostPriority |= imgIRequest::CATEGORY_SIZE_QUERY;
774 }
775
776 currentRequest->BoostPriority(categoryToBoostPriority);
777 }
778
779 MaybeSendIntrinsicSizeAndRatioToEmbedder();
780}
781
782void nsImageFrame::SetupOwnedRequest() {
783 MOZ_ASSERT(mKind != Kind::ImageLoadingContent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mKind != Kind::ImageLoadingContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mKind != Kind::ImageLoadingContent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mKind != Kind::ImageLoadingContent", "./../../../layout/generic/nsImageFrame.cpp"
, 783); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mKind != Kind::ImageLoadingContent"
")"); do { MOZ_CrashSequence(__null, 783); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
784 if (!mOwnedRequest) {
785 return;
786 }
787
788 // We're not using AssociateRequestToFrame for the content property, so we
789 // need to add it to the image tracker manually.
790 PresContext()->Document()->TrackImage(mOwnedRequest);
791
792 uint32_t status = 0;
793 nsresult rv = mOwnedRequest->GetImageStatus(&status);
794 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
795 return;
796 }
797
798 if (status & imgIRequest::STATUS_SIZE_AVAILABLE) {
799 nsCOMPtr<imgIContainer> image;
800 mOwnedRequest->GetImage(getter_AddRefs(image));
801 OnSizeAvailable(mOwnedRequest, image);
802 }
803
804 if (status & imgIRequest::STATUS_FRAME_COMPLETE) {
805 mFirstFrameComplete = true;
806 }
807
808 if (status & imgIRequest::STATUS_IS_ANIMATED) {
809 nsLayoutUtils::RegisterImageRequest(PresContext(), mOwnedRequest,
810 &mOwnedRequestRegistered);
811 }
812}
813
814static void ScaleIntrinsicSizeForDensity(IntrinsicSize& aSize,
815 const ImageResolution& aResolution) {
816 if (aSize.width) {
817 aResolution.ApplyXTo(aSize.width.ref());
818 }
819 if (aSize.height) {
820 aResolution.ApplyYTo(aSize.height.ref());
821 }
822}
823
824static void ScaleIntrinsicSizeForDensity(imgIContainer* aImage,
825 nsIContent& aContent,
826 IntrinsicSize& aSize) {
827 ImageResolution resolution = aImage->GetResolution();
828 if (auto* image = HTMLImageElement::FromNode(aContent)) {
829 if (auto* selector = image->GetResponsiveImageSelector()) {
830 resolution.ScaleBy(selector->GetSelectedImageDensity());
831 }
832 }
833 ScaleIntrinsicSizeForDensity(aSize, resolution);
834}
835
836static nscoord ListImageDefaultLength(const nsImageFrame& aFrame) {
837 // https://drafts.csswg.org/css-lists-3/#image-markers
838 // The spec says we should use 1em x 1em, but that seems too large.
839 // See disussion in https://github.com/w3c/csswg-drafts/issues/4207
840 auto* pc = aFrame.PresContext();
841 RefPtr<nsFontMetrics> fm =
842 nsLayoutUtils::GetFontMetricsForComputedStyle(aFrame.Style(), pc);
843 RefPtr<gfxFont> font = fm->GetThebesFontGroup()->GetFirstValidFont();
844 auto emAU =
845 font->GetMetrics(fm->Orientation()).emHeight * pc->AppUnitsPerDevPixel();
846 return std::max(NSToCoordRound(0.4f * emAU),
847 nsPresContext::CSSPixelsToAppUnits(1));
848}
849
850IntrinsicSize nsImageFrame::ComputeIntrinsicSize(
851 bool aIgnoreContainment) const {
852 const auto containAxes =
853 aIgnoreContainment ? ContainSizeAxes(false, false) : GetContainSizeAxes();
854 if (containAxes.IsBoth()) {
855 return FinishIntrinsicSize(containAxes, IntrinsicSize(0, 0));
856 }
857
858 nsSize size;
859 if (mImage && NS_SUCCEEDED(mImage->GetIntrinsicSizeInAppUnits(&size))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mImage->GetIntrinsicSizeInAppUnits
(&size))), 1)))
) {
860 IntrinsicSize intrinsicSize;
861 intrinsicSize.width = size.width == -1 ? Nothing() : Some(size.width);
862 intrinsicSize.height = size.height == -1 ? Nothing() : Some(size.height);
863 if (mKind == nsImageFrame::Kind::ListStyleImage) {
864 if (intrinsicSize.width.isNothing() || intrinsicSize.height.isNothing()) {
865 nscoord defaultLength = ListImageDefaultLength(*this);
866 if (intrinsicSize.width.isNothing()) {
867 intrinsicSize.width = Some(defaultLength);
868 }
869 if (intrinsicSize.height.isNothing()) {
870 intrinsicSize.height = Some(defaultLength);
871 }
872 }
873 }
874 if (mKind == nsImageFrame::Kind::ImageLoadingContent ||
875 (mKind == nsImageFrame::Kind::XULImage &&
876 GetContent()->AsElement()->HasNonEmptyAttr(nsGkAtoms::src))) {
877 ScaleIntrinsicSizeForDensity(mImage, *GetContent(), intrinsicSize);
878 } else {
879 // We don't include zoom here because FinishIntrinsicSize already does it
880 // for us.
881 ScaleIntrinsicSizeForDensity(
882 intrinsicSize,
883 GetImageFromStyle()->GetResolution(/* aStyleForZoom = */ nullptr));
884 }
885 return FinishIntrinsicSize(containAxes, intrinsicSize);
886 }
887
888 if (auto size = GetViewTransitionBorderBoxSize()) {
889 IntrinsicSize intrinsicSize;
890 intrinsicSize.width.emplace(size->width);
891 intrinsicSize.height.emplace(size->height);
892 return FinishIntrinsicSize(containAxes, intrinsicSize);
893 }
894
895 if (mKind == nsImageFrame::Kind::ListStyleImage) {
896 // Note: images are handled above, this handles gradients etc.
897 const nscoord defaultLength = ListImageDefaultLength(*this);
898 return FinishIntrinsicSize(containAxes,
899 IntrinsicSize(defaultLength, defaultLength));
900 }
901
902 if (mKind == nsImageFrame::Kind::XULImage && IsThemed()) {
903 nsPresContext* pc = PresContext();
904 // FIXME: const_cast here is a bit evil but IsThemed and so does the same.
905 const auto widgetSize = pc->Theme()->GetMinimumWidgetSize(
906 pc, const_cast<nsImageFrame*>(this),
907 StyleDisplay()->EffectiveAppearance());
908 const IntrinsicSize intrinsicSize(
909 LayoutDeviceIntSize::ToAppUnits(widgetSize, pc->AppUnitsPerDevPixel()));
910 return FinishIntrinsicSize(containAxes, intrinsicSize);
911 }
912
913 if (ShouldShowBrokenImageIcon()) {
914 nscoord edgeLengthToUse = nsPresContext::CSSPixelsToAppUnits(
915 ICON_SIZE(16) + (2 * (ICON_PADDING(3) + ALT_BORDER_WIDTH(1))));
916 return FinishIntrinsicSize(containAxes,
917 IntrinsicSize(edgeLengthToUse, edgeLengthToUse));
918 }
919
920 if (ShouldUseMappedAspectRatio() &&
921 StylePosition()->mAspectRatio.HasRatio()) {
922 return IntrinsicSize();
923 }
924
925 // XXX: No FinishIntrinsicSize?
926 return IntrinsicSize(0, 0);
927}
928
929// For compat reasons, see bug 1602047, we don't use the intrinsic ratio from
930// width="" and height="" for images with no src attribute (no request).
931//
932// But we shouldn't get fooled by <img loading=lazy>. We do want to apply the
933// ratio then...
934bool nsImageFrame::ShouldUseMappedAspectRatio() const {
935 if (mKind != Kind::ImageLoadingContent) {
936 return true;
937 }
938 nsCOMPtr<imgIRequest> currentRequest = GetCurrentRequest();
939 if (currentRequest) {
940 return true;
941 }
942 // TODO(emilio): Investigate the compat situation of the above check, maybe we
943 // can just check for empty src attribute or something...
944 auto* image = HTMLImageElement::FromNode(mContent);
945 return image && image->IsAwaitingLoadOrLazyLoading();
946}
947
948bool nsImageFrame::UpdateIntrinsicSize() {
949 IntrinsicSize oldIntrinsicSize = mIntrinsicSize;
950 mIntrinsicSize = ComputeIntrinsicSize();
951 return mIntrinsicSize != oldIntrinsicSize;
952}
953
954nsAtom* nsImageFrame::GetViewTransitionName() const {
955 if (mKind != Kind::ViewTransition) {
956 return nullptr;
957 }
958 MOZ_ASSERT(GetContent()->AsElement()->HasName())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(GetContent()->AsElement()->HasName())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(GetContent()->AsElement()->HasName()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("GetContent()->AsElement()->HasName()"
, "./../../../layout/generic/nsImageFrame.cpp", 958); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "GetContent()->AsElement()->HasName()"
")"); do { MOZ_CrashSequence(__null, 958); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
959 return GetContent()
960 ->AsElement()
961 ->GetParsedAttr(nsGkAtoms::name)
962 ->GetAtomValue();
963}
964
965Maybe<nsSize> nsImageFrame::GetViewTransitionBorderBoxSize() const {
966 auto* name = GetViewTransitionName();
967 if (!name) {
968 return {};
969 }
970 auto* vt = PresContext()->Document()->GetActiveViewTransition();
971 if (NS_WARN_IF(!vt)NS_warn_if_impl(!vt, "!vt", "./../../../layout/generic/nsImageFrame.cpp"
, 971)
) {
972 return {};
973 }
974 return Style()->GetPseudoType() == PseudoStyleType::ViewTransitionOld
975 ? vt->GetOldBorderBoxSize(name)
976 : vt->GetNewBorderBoxSize(name);
977}
978
979wr::ImageKey nsImageFrame::GetViewTransitionImageKey(
980 layers::RenderRootStateManager* aManager,
981 wr::IpcResourceUpdateQueue& aResources) const {
982 auto* name = GetViewTransitionName();
983 if (!name) {
984 return kNoKey;
985 }
986 auto* vt = PresContext()->Document()->GetActiveViewTransition();
987 if (NS_WARN_IF(!vt)NS_warn_if_impl(!vt, "!vt", "./../../../layout/generic/nsImageFrame.cpp"
, 987)
) {
988 return kNoKey;
989 }
990 const auto* key =
991 Style()->GetPseudoType() == PseudoStyleType::ViewTransitionOld
992 ? vt->ReadOldImageKey(name, aManager, aResources)
993 : vt->GetNewImageKey(name);
994 return key ? *key : kNoKey;
995}
996
997AspectRatio nsImageFrame::ComputeIntrinsicRatioForImage(
998 imgIContainer* aImage, bool aIgnoreContainment) const {
999 if (!aIgnoreContainment && GetContainSizeAxes().IsAny()) {
1000 return AspectRatio();
1001 }
1002
1003 if (aImage) {
1004 if (AspectRatio fromImage = aImage->GetIntrinsicRatio()) {
1005 return fromImage;
1006 }
1007 }
1008
1009 if (auto size = GetViewTransitionBorderBoxSize()) {
1010 return AspectRatio::FromSize(*size);
1011 }
1012
1013 if (ShouldUseMappedAspectRatio()) {
1014 const StyleAspectRatio& ratio = StylePosition()->mAspectRatio;
1015 if (ratio.auto_ && ratio.HasRatio()) {
1016 // Return the mapped intrinsic aspect ratio stored in
1017 // nsStylePosition::mAspectRatio.
1018 return ratio.ratio.AsRatio().ToLayoutRatio(UseBoxSizing::Yes);
1019 }
1020 }
1021 if (ShouldShowBrokenImageIcon()) {
1022 return AspectRatio(1.0f);
1023 }
1024 return AspectRatio();
1025}
1026
1027bool nsImageFrame::UpdateIntrinsicRatio() {
1028 AspectRatio oldIntrinsicRatio = mIntrinsicRatio;
1029 mIntrinsicRatio = ComputeIntrinsicRatioForImage(mImage);
1030 return mIntrinsicRatio != oldIntrinsicRatio;
1031}
1032
1033bool nsImageFrame::GetSourceToDestTransform(nsTransform2D& aTransform) {
1034 nsRect destRect = GetDestRect(GetContentRectRelativeToSelf());
1035 // Set the translation components, based on destRect
1036 // XXXbz does this introduce rounding errors because of the cast to
1037 // float? Should we just manually add that stuff in every time
1038 // instead?
1039 aTransform.SetToTranslate(float(destRect.x), float(destRect.y));
1040
1041 // NOTE(emilio): This intrinsicSize is not the same as the layout intrinsic
1042 // size (mIntrinsicSize), which can be scaled due to ResponsiveImageSelector,
1043 // see ScaleIntrinsicSizeForDensity.
1044 nsSize intrinsicSize;
1045 if (!mImage ||
1046 !NS_SUCCEEDED(mImage->GetIntrinsicSizeInAppUnits(&intrinsicSize))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mImage->GetIntrinsicSizeInAppUnits
(&intrinsicSize))), 1)))
||
1047 intrinsicSize.IsEmpty()) {
1048 return false;
1049 }
1050
1051 aTransform.SetScale(float(destRect.width) / float(intrinsicSize.width),
1052 float(destRect.height) / float(intrinsicSize.height));
1053 return true;
1054}
1055
1056// This function checks whether the given request is the current request for our
1057// mContent.
1058bool nsImageFrame::IsPendingLoad(imgIRequest* aRequest) const {
1059 // Default to pending load in case of errors
1060 if (mKind != Kind::ImageLoadingContent) {
1061 MOZ_ASSERT(aRequest == mOwnedRequest)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRequest == mOwnedRequest)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRequest == mOwnedRequest)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("aRequest == mOwnedRequest"
, "./../../../layout/generic/nsImageFrame.cpp", 1061); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aRequest == mOwnedRequest" ")"); do { MOZ_CrashSequence
(__null, 1061); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1062 return false;
1063 }
1064
1065 nsCOMPtr<nsIImageLoadingContent> imageLoader(do_QueryInterface(mContent));
1066 MOZ_ASSERT(imageLoader)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(imageLoader)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(imageLoader))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("imageLoader", "./../../../layout/generic/nsImageFrame.cpp"
, 1066); AnnotateMozCrashReason("MOZ_ASSERT" "(" "imageLoader"
")"); do { MOZ_CrashSequence(__null, 1066); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1067
1068 int32_t requestType = nsIImageLoadingContent::UNKNOWN_REQUEST;
1069 imageLoader->GetRequestType(aRequest, &requestType);
1070
1071 return requestType != nsIImageLoadingContent::CURRENT_REQUEST;
1072}
1073
1074nsRect nsImageFrame::SourceRectToDest(const nsIntRect& aRect) {
1075 // When scaling the image, row N of the source image may (depending on
1076 // the scaling function) be used to draw any row in the destination image
1077 // between floor(F * (N-1)) and ceil(F * (N+1)), where F is the
1078 // floating-point scaling factor. The same holds true for columns.
1079 // So, we start by computing that bound without the floor and ceiling.
1080
1081 nsRect r(nsPresContext::CSSPixelsToAppUnits(aRect.x - 1),
1082 nsPresContext::CSSPixelsToAppUnits(aRect.y - 1),
1083 nsPresContext::CSSPixelsToAppUnits(aRect.width + 2),
1084 nsPresContext::CSSPixelsToAppUnits(aRect.height + 2));
1085
1086 nsTransform2D sourceToDest;
1087 if (!GetSourceToDestTransform(sourceToDest)) {
1088 // Failed to generate transform matrix. Return our whole content area,
1089 // to be on the safe side (since this method is used for generating
1090 // invalidation rects).
1091 return GetContentRectRelativeToSelf();
1092 }
1093
1094 sourceToDest.TransformCoord(&r.x, &r.y, &r.width, &r.height);
1095
1096 // Now, round the edges out to the pixel boundary.
1097 nscoord scale = nsPresContext::CSSPixelsToAppUnits(1);
1098 nscoord right = r.x + r.width;
1099 nscoord bottom = r.y + r.height;
1100
1101 r.x -= (scale + (r.x % scale)) % scale;
1102 r.y -= (scale + (r.y % scale)) % scale;
1103 r.width = right + ((scale - (right % scale)) % scale) - r.x;
1104 r.height = bottom + ((scale - (bottom % scale)) % scale) - r.y;
1105
1106 return r;
1107}
1108
1109static bool ImageOk(ElementState aState) {
1110 return !aState.HasState(ElementState::BROKEN);
1111}
1112
1113static bool HasAltText(const Element& aElement) {
1114 // We always return some alternate text for <input>, see
1115 // nsCSSFrameConstructor::GetAlternateTextFor.
1116 if (aElement.IsHTMLElement(nsGkAtoms::input)) {
1117 return true;
1118 }
1119
1120 MOZ_ASSERT(aElement.IsHTMLElement(nsGkAtoms::img))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aElement.IsHTMLElement(nsGkAtoms::img))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aElement.IsHTMLElement(nsGkAtoms::img)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aElement.IsHTMLElement(nsGkAtoms::img)"
, "./../../../layout/generic/nsImageFrame.cpp", 1120); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aElement.IsHTMLElement(nsGkAtoms::img)" ")"
); do { MOZ_CrashSequence(__null, 1120); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1121 return aElement.HasNonEmptyAttr(nsGkAtoms::alt);
1122}
1123
1124bool nsImageFrame::ShouldCreateImageFrameForContentProperty(
1125 const Element& aElement, const ComputedStyle& aStyle) {
1126 if (aElement.IsRootOfNativeAnonymousSubtree()) {
1127 return false;
1128 }
1129 return ::ShouldCreateImageFrameForContentProperty(aStyle);
1130}
1131
1132// Check if we want to use an image frame or just let the frame constructor make
1133// us into an inline, and if so, which kind of image frame should we create.
1134/* static */
1135auto nsImageFrame::ImageFrameTypeFor(const Element& aElement,
1136 const ComputedStyle& aStyle)
1137 -> ImageFrameType {
1138 if (ShouldCreateImageFrameForContentProperty(aElement, aStyle)) {
1139 // Prefer the content property, for compat reasons, see bug 1484928.
1140 return ImageFrameType::ForContentProperty;
1141 }
1142
1143 if (ImageOk(aElement.State())) {
1144 // Image is fine or loading; do the image frame thing
1145 return ImageFrameType::ForElementRequest;
1146 }
1147
1148 if (aStyle.StyleUIReset()->mMozForceBrokenImageIcon) {
1149 return ImageFrameType::ForElementRequest;
1150 }
1151
1152 if (!HasAltText(aElement)) {
1153 return ImageFrameType::ForElementRequest;
1154 }
1155
1156 // FIXME(emilio, bug 1788767): We definitely don't reframe when
1157 // HaveSpecifiedSize changes...
1158 if (aElement.OwnerDoc()->GetCompatibilityMode() == eCompatibility_NavQuirks &&
1159 HaveSpecifiedSize(aStyle.StylePosition(),
1160 {nullptr, aStyle.StyleDisplay()->mPosition})) {
1161 return ImageFrameType::ForElementRequest;
1162 }
1163
1164 return ImageFrameType::None;
1165}
1166
1167void nsImageFrame::Notify(imgIRequest* aRequest, int32_t aType,
1168 const nsIntRect* aRect) {
1169 if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
1170 nsCOMPtr<imgIContainer> image;
1171 aRequest->GetImage(getter_AddRefs(image));
1172 return OnSizeAvailable(aRequest, image);
1173 }
1174
1175 if (aType == imgINotificationObserver::FRAME_UPDATE) {
1176 return OnFrameUpdate(aRequest, aRect);
1177 }
1178
1179 if (aType == imgINotificationObserver::FRAME_COMPLETE) {
1180 mFirstFrameComplete = true;
1181 }
1182
1183 if (aType == imgINotificationObserver::IS_ANIMATED &&
1184 mKind != Kind::ImageLoadingContent) {
1185 nsLayoutUtils::RegisterImageRequest(PresContext(), mOwnedRequest,
1186 &mOwnedRequestRegistered);
1187 }
1188
1189 if (aType == imgINotificationObserver::LOAD_COMPLETE) {
1190 LargestContentfulPaint::MaybeProcessImageForElementTiming(
1191 static_cast<imgRequestProxy*>(aRequest), GetContent()->AsElement());
1192 return OnLoadComplete(aRequest);
1193 }
1194}
1195
1196void nsImageFrame::OnSizeAvailable(imgIRequest* aRequest,
1197 imgIContainer* aImage) {
1198 if (!aImage) {
1199 return;
1200 }
1201
1202 /* Get requested animation policy from the pres context:
1203 * normal = 0
1204 * one frame = 1
1205 * one loop = 2
1206 */
1207 aImage->SetAnimationMode(PresContext()->ImageAnimationMode());
1208
1209 if (IsPendingLoad(aRequest)) {
1210 // We don't care
1211 return;
1212 }
1213
1214 UpdateImage(aRequest, aImage);
1215}
1216
1217void nsImageFrame::UpdateImage(imgIRequest* aRequest, imgIContainer* aImage) {
1218 if (SizeIsAvailable(aRequest)) {
1219 StyleImageOrientation orientation =
1220 StyleVisibility()->UsedImageOrientation(aRequest);
1221 // This is valid and for the current request, so update our stored image
1222 // container, orienting according to our style.
1223 mImage = nsLayoutUtils::OrientImage(aImage, orientation);
1224 MOZ_ASSERT(mImage)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mImage)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(mImage))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mImage", "./../../../layout/generic/nsImageFrame.cpp"
, 1224); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mImage" ")"
); do { MOZ_CrashSequence(__null, 1224); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1225 } else {
1226 // We no longer have a valid image, so release our stored image container.
1227 mImage = mPrevImage = nullptr;
1228 if (mKind == Kind::ListStyleImage) {
1229 auto* genContent = static_cast<GeneratedImageContent*>(GetContent());
1230 genContent->NotifyLoadFailed();
1231 // No need to continue below since the above state change will destroy
1232 // this frame.
1233 return;
1234 }
1235 }
1236
1237 UpdateIntrinsicSizeAndRatio();
1238
1239 if (!GotInitialReflow()) {
1240 return;
1241 }
1242
1243 // We're going to need to repaint now either way.
1244 InvalidateFrame();
1245}
1246
1247void nsImageFrame::OnFrameUpdate(imgIRequest* aRequest,
1248 const nsIntRect* aRect) {
1249 if (NS_WARN_IF(!aRect)NS_warn_if_impl(!aRect, "!aRect", "./../../../layout/generic/nsImageFrame.cpp"
, 1249)
) {
1250 return;
1251 }
1252
1253 if (!GotInitialReflow()) {
1254 // Don't bother to do anything; we have a reflow coming up!
1255 return;
1256 }
1257
1258 if (mFirstFrameComplete && !StyleVisibility()->IsVisible()) {
1259 return;
1260 }
1261
1262 if (IsPendingLoad(aRequest)) {
1263 // We don't care
1264 return;
1265 }
1266
1267 nsIntRect layerInvalidRect =
1268 mImage ? mImage->GetImageSpaceInvalidationRect(*aRect) : *aRect;
1269
1270 if (layerInvalidRect.IsEqualInterior(GetMaxSizedIntRect())) {
1271 // Invalidate our entire area.
1272 InvalidateSelf(nullptr, nullptr);
1273 return;
1274 }
1275
1276 nsRect frameInvalidRect = SourceRectToDest(layerInvalidRect);
1277 InvalidateSelf(&layerInvalidRect, &frameInvalidRect);
1278}
1279
1280void nsImageFrame::InvalidateSelf(const nsIntRect* aLayerInvalidRect,
1281 const nsRect* aFrameInvalidRect) {
1282 // Check if WebRender has interacted with this frame. If it has
1283 // we need to let it know that things have changed.
1284 const auto type = DisplayItemType::TYPE_IMAGE;
1285 const auto providerId = mImage ? mImage->GetProviderId() : 0;
1286 if (WebRenderUserData::ProcessInvalidateForImage(this, type, providerId)) {
1287 return;
1288 }
1289
1290 InvalidateLayer(type, aLayerInvalidRect, aFrameInvalidRect);
1291
1292 if (!mFirstFrameComplete) {
1293 InvalidateLayer(DisplayItemType::TYPE_ALT_FEEDBACK, aLayerInvalidRect,
1294 aFrameInvalidRect);
1295 }
1296}
1297
1298void nsImageFrame::MaybeSendIntrinsicSizeAndRatioToEmbedder() {
1299 MaybeSendIntrinsicSizeAndRatioToEmbedder(Some(GetIntrinsicSize()),
1300 Some(GetAspectRatio()));
1301}
1302
1303void nsImageFrame::MaybeSendIntrinsicSizeAndRatioToEmbedder(
1304 Maybe<IntrinsicSize> aIntrinsicSize, Maybe<AspectRatio> aIntrinsicRatio) {
1305 if (!mIsInObjectOrEmbed || !mImage) {
1306 return;
1307 }
1308
1309 nsCOMPtr<nsIDocShell> docShell = PresContext()->GetDocShell();
1310 if (!docShell) {
1311 return;
1312 }
1313
1314 BrowsingContext* bc = docShell->GetBrowsingContext();
1315 if (!bc) {
1316 return;
1317 }
1318 MOZ_ASSERT(bc->IsContentSubframe())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bc->IsContentSubframe())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bc->IsContentSubframe()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("bc->IsContentSubframe()"
, "./../../../layout/generic/nsImageFrame.cpp", 1318); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "bc->IsContentSubframe()" ")"); do { MOZ_CrashSequence
(__null, 1318); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1319
1320 if (bc->GetParent()->IsInProcess()) {
1321 if (Element* embedder = bc->GetEmbedderElement()) {
1322 if (nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(embedder)) {
1323 static_cast<nsObjectLoadingContent*>(olc.get())
1324 ->SubdocumentIntrinsicSizeOrRatioChanged(aIntrinsicSize,
1325 aIntrinsicRatio);
1326 } else {
1327 MOZ_ASSERT_UNREACHABLE("Got out of sync?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Got out of sync?" ")", "./../../../layout/generic/nsImageFrame.cpp"
, 1327); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Got out of sync?" ")"); do { MOZ_CrashSequence
(__null, 1327); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1328 }
1329 return;
1330 }
1331 }
1332
1333 if (BrowserChild* browserChild = BrowserChild::GetFrom(docShell)) {
1334 (void)browserChild->SendIntrinsicSizeOrRatioChanged(aIntrinsicSize,
1335 aIntrinsicRatio);
1336 }
1337}
1338
1339void nsImageFrame::OnLoadComplete(imgIRequest* aRequest) {
1340 NotifyNewCurrentRequest(aRequest);
1341}
1342
1343void nsImageFrame::ElementStateChanged(ElementState aStates) {
1344 if (!(aStates & ElementState::BROKEN)) {
1345 return;
1346 }
1347 if (mKind != Kind::ImageLoadingContent) {
1348 return;
1349 }
1350 if (!ImageOk(mContent->AsElement()->State())) {
1351 UpdateImage(nullptr, nullptr);
1352 }
1353}
1354
1355void nsImageFrame::ResponsiveContentDensityChanged() {
1356 UpdateIntrinsicSizeAndRatio();
1357}
1358
1359void nsImageFrame::UpdateIntrinsicSizeAndRatio() {
1360 bool intrinsicSizeOrRatioChanged = [&] {
1361 // NOTE(emilio): We intentionally want to call both functions and avoid
1362 // short-circuiting.
1363 bool intrinsicSizeChanged = UpdateIntrinsicSize();
1364 bool intrinsicRatioChanged = UpdateIntrinsicRatio();
1365 return intrinsicSizeChanged || intrinsicRatioChanged;
1366 }();
1367
1368 if (!intrinsicSizeOrRatioChanged) {
1369 return;
1370 }
1371
1372 // Our aspect-ratio property value changed, and an embedding <object> or
1373 // <embed> might care about that.
1374 MaybeSendIntrinsicSizeAndRatioToEmbedder();
1375
1376 if (!GotInitialReflow()) {
1377 return;
1378 }
1379
1380 // Now we need to reflow if we have an unconstrained size and have
1381 // already gotten the initial reflow.
1382 if (!HasAnyStateBits(IMAGE_SIZECONSTRAINED)) {
1383 PresShell()->FrameNeedsReflow(
1384 this, IntrinsicDirty::FrameAncestorsAndDescendants, NS_FRAME_IS_DIRTY);
1385 } else if (PresShell()->IsActive()) {
1386 // We've already gotten the initial reflow, and our size hasn't changed,
1387 // so we're ready to request a decode.
1388 MaybeDecodeForPredictedSize();
1389 }
1390}
1391
1392void nsImageFrame::NotifyNewCurrentRequest(imgIRequest* aRequest) {
1393 nsCOMPtr<imgIContainer> image;
1394 aRequest->GetImage(getter_AddRefs(image));
1395#ifdef DEBUG1
1396 uint32_t imgStatus;
1397 aRequest->GetImageStatus(&imgStatus);
1398 NS_ASSERTION(image || (imgStatus & imgIRequest::STATUS_ERROR),do { if (!(image || (imgStatus & imgIRequest::STATUS_ERROR
))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Successful load with no container?"
, "image || (imgStatus & imgIRequest::STATUS_ERROR)", "./../../../layout/generic/nsImageFrame.cpp"
, 1399); MOZ_PretendNoReturn(); } } while (0)
1399 "Successful load with no container?")do { if (!(image || (imgStatus & imgIRequest::STATUS_ERROR
))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Successful load with no container?"
, "image || (imgStatus & imgIRequest::STATUS_ERROR)", "./../../../layout/generic/nsImageFrame.cpp"
, 1399); MOZ_PretendNoReturn(); } } while (0)
;
1400#endif
1401 UpdateImage(aRequest, image);
1402}
1403
1404void nsImageFrame::MaybeDecodeForPredictedSize() {
1405 // Check that we're ready to decode.
1406 if (!mImage) {
1407 return; // Nothing to do yet.
1408 }
1409
1410 if (mComputedSize.IsEmpty()) {
1411 return; // We won't draw anything, so no point in decoding.
1412 }
1413
1414 if (GetVisibility() != Visibility::ApproximatelyVisible) {
1415 return; // We're not visible, so don't decode.
1416 }
1417
1418 // OK, we're ready to decode. Compute the scale to the screen...
1419 mozilla::PresShell* presShell = PresShell();
1420 MatrixScales scale =
1421 ScaleFactor<UnknownUnits, UnknownUnits>(
1422 presShell->GetCumulativeResolution()) *
1423 nsLayoutUtils::GetTransformToAncestorScaleExcludingAnimated(this);
1424 auto resolutionToScreen = ViewAs<LayoutDeviceToScreenScale2D>(scale);
1425
1426 // If we are in a remote browser, then apply scaling from ancestor browsers
1427 if (BrowserChild* browserChild = BrowserChild::GetFrom(presShell)) {
1428 resolutionToScreen =
1429 resolutionToScreen * ViewAs<ScreenToScreenScale2D>(
1430 browserChild->GetEffectsInfo().mRasterScale);
1431 }
1432
1433 // ...and this frame's content box...
1434 const nsPoint offset =
1435 GetOffsetToCrossDoc(nsLayoutUtils::GetReferenceFrame(this));
1436 const nsRect frameContentBox = GetContentRectRelativeToSelf() + offset;
1437
1438 // ...and our predicted dest rect...
1439 const int32_t factor = PresContext()->AppUnitsPerDevPixel();
1440 const LayoutDeviceRect destRect =
1441 LayoutDeviceRect::FromAppUnits(GetDestRect(frameContentBox), factor);
1442
1443 // ...and use them to compute our predicted size in screen pixels.
1444 const ScreenSize predictedScreenSize = destRect.Size() * resolutionToScreen;
1445 const ScreenIntSize predictedScreenIntSize =
1446 RoundedToInt(predictedScreenSize);
1447 if (predictedScreenIntSize.IsEmpty()) {
1448 return;
1449 }
1450
1451 // Determine the optimal image size to use.
1452 uint32_t flags = imgIContainer::FLAG_HIGH_QUALITY_SCALING |
1453 imgIContainer::FLAG_ASYNC_NOTIFY;
1454 SamplingFilter samplingFilter =
1455 nsLayoutUtils::GetSamplingFilterForFrame(this);
1456 gfxSize gfxPredictedScreenSize =
1457 gfxSize(predictedScreenIntSize.width, predictedScreenIntSize.height);
1458 nsIntSize predictedImageSize = mImage->OptimalImageSizeForDest(
1459 gfxPredictedScreenSize, imgIContainer::FRAME_CURRENT, samplingFilter,
1460 flags);
1461
1462 // Request a decode.
1463 mImage->RequestDecodeForSize(predictedImageSize, flags);
1464}
1465
1466nsRect nsImageFrame::GetDestRect(const nsRect& aFrameContentBox,
1467 nsPoint* aAnchorPoint) {
1468 // Note: To get the "dest rect", we have to provide the "constraint rect"
1469 // (which is the content-box, with the effects of fragmentation undone).
1470 nsRect constraintRect(aFrameContentBox.TopLeft(), mComputedSize);
1471 constraintRect.y -= GetContinuationOffset();
1472
1473 auto intrinsicSize = mIntrinsicSize;
1474 auto intrinsicRatio = mIntrinsicRatio;
1475 if (GetContainSizeAxes().IsAny()) {
1476 // Ignore containment for object-fit computations.
1477 const bool ignoreContainment = true;
1478 intrinsicSize = ComputeIntrinsicSize(ignoreContainment);
1479 intrinsicRatio = ComputeIntrinsicRatioForImage(mImage, ignoreContainment);
1480 }
1481 return nsLayoutUtils::ComputeObjectDestRect(constraintRect, intrinsicSize,
1482 intrinsicRatio, StylePosition(),
1483 aAnchorPoint);
1484}
1485
1486void nsImageFrame::EnsureIntrinsicSizeAndRatio(bool aConsiderIntrinsicsDirty) {
1487 const auto containAxes = GetContainSizeAxes();
1488 if (containAxes.IsBoth()) {
1489 // If we have 'contain:size', then we have no intrinsic aspect ratio,
1490 // and the intrinsic size is determined by contain-intrinsic-size,
1491 // regardless of what our underlying image may think.
1492 mIntrinsicSize = FinishIntrinsicSize(containAxes, IntrinsicSize(0, 0));
1493 mIntrinsicRatio = AspectRatio();
1494 return;
1495 }
1496
1497 // If mIntrinsicSize is set (i.e. anything besides (0,0)), then we assume that
1498 // our intrinsic size/ratio have been already computed and don't need
1499 // recomputing, *unless* the aConsiderIntrinsicsDirty param is set to true
1500 // (in which case our intrinsic size/ratio might be invalid).
1501 //
1502 // The fallback list-style-image marker size might have been set in
1503 // DidSetComputedStyle, and it might have changed since then.
1504 // TODO(emilio): We should remove that special case and add missing
1505 // invalidation if/where needed.
1506 if (!aConsiderIntrinsicsDirty && mIntrinsicSize != IntrinsicSize(0, 0) &&
1507 mKind != Kind::ListStyleImage) {
1508 return;
1509 }
1510
1511 bool intrinsicSizeOrRatioChanged = UpdateIntrinsicSize();
1512 intrinsicSizeOrRatioChanged =
1513 UpdateIntrinsicRatio() || intrinsicSizeOrRatioChanged;
1514
1515 if (intrinsicSizeOrRatioChanged) {
1516 // Our aspect-ratio property value changed, and an embedding <object> or
1517 // <embed> might care about that.
1518 MaybeSendIntrinsicSizeAndRatioToEmbedder();
1519 }
1520}
1521
1522nsIFrame::SizeComputationResult nsImageFrame::ComputeSize(
1523 const SizeComputationInput& aSizingInput, WritingMode aWM,
1524 const LogicalSize& aCBSize, nscoord aAvailableISize,
1525 const LogicalSize& aMargin, const LogicalSize& aBorderPadding,
1526 const StyleSizeOverrides& aSizeOverrides, ComputeSizeFlags aFlags) {
1527 EnsureIntrinsicSizeAndRatio();
1528 return {
1529 ComputeSizeWithIntrinsicDimensions(
1530 aSizingInput.mRenderingContext, aWM, mIntrinsicSize, GetAspectRatio(),
1531 aCBSize, aMargin, aBorderPadding, aSizeOverrides, aFlags),
1532 AspectRatioUsage::None};
1533}
1534
1535Element* nsImageFrame::GetMapElement() const {
1536 return IsForImageLoadingContent()
1537 ? nsImageLoadingContent::FindImageMap(mContent->AsElement())
1538 : nullptr;
1539}
1540
1541// get the offset into the content area of the image where aImg starts if it is
1542// a continuation.
1543nscoord nsImageFrame::GetContinuationOffset() const {
1544 nscoord offset = 0;
1545 for (nsIFrame* f = GetPrevInFlow(); f; f = f->GetPrevInFlow()) {
1546 offset += f->GetContentRect().height;
1547 }
1548 NS_ASSERTION(offset >= 0, "bogus GetContentRect")do { if (!(offset >= 0)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "bogus GetContentRect", "offset >= 0", "./../../../layout/generic/nsImageFrame.cpp"
, 1548); MOZ_PretendNoReturn(); } } while (0)
;
1549 return offset;
1550}
1551
1552nscoord nsImageFrame::IntrinsicISize(const IntrinsicSizeInput& aInput,
1553 IntrinsicISizeType aType) {
1554 EnsureIntrinsicSizeAndRatio();
1555 return mIntrinsicSize.ISize(GetWritingMode()).valueOr(0);
1556}
1557
1558void nsImageFrame::ReflowChildren(nsPresContext* aPresContext,
1559 const ReflowInput& aReflowInput,
1560 const LogicalSize& aImageSize) {
1561 const WritingMode wm = GetWritingMode();
1562 for (nsIFrame* child : mFrames) {
1563 ReflowOutput childDesiredSize(aReflowInput);
1564 const WritingMode childWm = child->GetWritingMode();
1565 ReflowInput childReflowInput(aPresContext, aReflowInput, child,
1566 aImageSize.ConvertTo(childWm, wm));
1567 LogicalPoint childOffset(wm);
1568 const nsSize containerSize = aImageSize.GetPhysicalSize(wm);
1569 nsReflowStatus childStatus;
1570 ReflowChild(child, aPresContext, childDesiredSize, childReflowInput, wm,
1571 childOffset, containerSize, ReflowChildFlags::Default,
1572 childStatus);
1573 FinishReflowChild(child, aPresContext, childDesiredSize, &childReflowInput,
1574 wm, childOffset, containerSize,
1575 ReflowChildFlags::Default);
1576 }
1577}
1578
1579void nsImageFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
1580 const ReflowInput& aReflowInput,
1581 nsReflowStatus& aStatus) {
1582 MarkInReflow();
1583 DO_GLOBAL_REFLOW_COUNT("nsImageFrame")aPresContext->CountReflows(("nsImageFrame"), (nsIFrame*)this
);
;
1584 MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus.IsEmpty()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aStatus.IsEmpty()"
" (" "Caller should pass a fresh reflow status!" ")", "./../../../layout/generic/nsImageFrame.cpp"
, 1584); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus.IsEmpty()"
") (" "Caller should pass a fresh reflow status!" ")"); do {
MOZ_CrashSequence(__null, 1584); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1585 NS_FRAME_TRACE(do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { TraceMsg ("enter nsImageFrame::Reflow: availSize=%d,%d"
, aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight
()); } } while (0)
1586 NS_FRAME_TRACE_CALLS,do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { TraceMsg ("enter nsImageFrame::Reflow: availSize=%d,%d"
, aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight
()); } } while (0)
1587 ("enter nsImageFrame::Reflow: availSize=%d,%d",do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { TraceMsg ("enter nsImageFrame::Reflow: availSize=%d,%d"
, aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight
()); } } while (0)
1588 aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight()))do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { TraceMsg ("enter nsImageFrame::Reflow: availSize=%d,%d"
, aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight
()); } } while (0)
;
1589
1590 MOZ_ASSERT(HasAnyStateBits(NS_FRAME_IN_REFLOW), "frame is not in reflow")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(HasAnyStateBits(NS_FRAME_IN_REFLOW))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(HasAnyStateBits(NS_FRAME_IN_REFLOW
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("HasAnyStateBits(NS_FRAME_IN_REFLOW)" " (" "frame is not in reflow"
")", "./../../../layout/generic/nsImageFrame.cpp", 1590); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "HasAnyStateBits(NS_FRAME_IN_REFLOW)" ") ("
"frame is not in reflow" ")"); do { MOZ_CrashSequence(__null
, 1590); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
1591
1592 // see if we have a frozen size (i.e. a fixed width and height)
1593 if (!SizeDependsOnIntrinsicSize(aReflowInput)) {
1594 AddStateBits(IMAGE_SIZECONSTRAINED);
1595 } else {
1596 RemoveStateBits(IMAGE_SIZECONSTRAINED);
1597 }
1598
1599 mComputedSize = aReflowInput.ComputedPhysicalSize();
1600
1601 const auto wm = GetWritingMode();
1602 aMetrics.SetSize(wm, aReflowInput.ComputedSizeWithBorderPadding(wm));
1603
1604 if (GetPrevInFlow()) {
1605 aMetrics.Width() = GetPrevInFlow()->GetSize().width;
1606 nscoord y = GetContinuationOffset();
1607 aMetrics.Height() -= y + aReflowInput.ComputedPhysicalBorderPadding().top;
1608 aMetrics.Height() = std::max(0, aMetrics.Height());
1609 }
1610
1611 // we have to split images if we are:
1612 // in Paginated mode, we need to have a constrained height, and have a height
1613 // larger than our available height
1614 uint32_t loadStatus = imgIRequest::STATUS_NONE;
1615 if (nsCOMPtr<imgIRequest> currentRequest = GetCurrentRequest()) {
1616 currentRequest->GetImageStatus(&loadStatus);
1617 }
1618
1619 const bool haveSize = loadStatus & imgIRequest::STATUS_SIZE_AVAILABLE;
1620
1621 // Printing an image frame in vertical writing mode is not properly supported
1622 // yet (Bug 1751260). In this case, don't split it, and let the display-list
1623 // slicing fallback (layout.display-list.improve-fragmentation) handle
1624 // fragmentation.
1625 if (aPresContext->IsPaginated() && !wm.IsVertical() &&
1626 (haveSize || HasAnyStateBits(IMAGE_SIZECONSTRAINED)) &&
1627 NS_UNCONSTRAINEDSIZE != aReflowInput.AvailableHeight() &&
1628 aMetrics.Height() > aReflowInput.AvailableHeight()) {
1629 // our desired height was greater than 0, so to avoid infinite
1630 // splitting, use 1 pixel as the min
1631 aMetrics.Height() = std::max(nsPresContext::CSSPixelsToAppUnits(1),
1632 aReflowInput.AvailableHeight());
1633 aStatus.SetIncomplete();
1634 }
1635
1636 aMetrics.SetOverflowAreasToDesiredBounds();
1637 const bool imageOK = mKind != Kind::ImageLoadingContent ||
1638 ImageOk(mContent->AsElement()->State());
1639 if (!imageOK || !haveSize) {
1640 nsRect altFeedbackSize(
1641 0, 0,
1642 nsPresContext::CSSPixelsToAppUnits(
1643 ICON_SIZE(16) + 2 * (ICON_PADDING(3) + ALT_BORDER_WIDTH(1))),
1644 nsPresContext::CSSPixelsToAppUnits(
1645 ICON_SIZE(16) + 2 * (ICON_PADDING(3) + ALT_BORDER_WIDTH(1))));
1646 // We include the altFeedbackSize in our ink overflow, but not in our
1647 // scrollable overflow, since it doesn't really need to be scrolled to
1648 // outside the image.
1649 nsRect& inkOverflow = aMetrics.InkOverflow();
1650 inkOverflow.UnionRect(inkOverflow, altFeedbackSize);
1651 } else {
1652 // Union with our dest rect (note that it will most likely get clipped in
1653 // FinishAndStoreOverflow). Only do this if we're not fragmented, since in
1654 // that case overflow goes into our continuation.
1655 if (aStatus.IsComplete()) {
1656 aMetrics.mOverflowAreas.UnionAllWith(
1657 GetDestRect(aReflowInput.ComputedPhysicalContentBoxRelativeToSelf()));
1658 }
1659 if (PresShell()->IsActive()) {
1660 // We've just reflowed and we should have an accurate size, so we're ready
1661 // to request a decode.
1662 MaybeDecodeForPredictedSize();
1663 }
1664 }
1665 FinishAndStoreOverflow(&aMetrics, aReflowInput.mStyleDisplay);
1666
1667 // Reflow the child frames. Our children can't affect our size in any way.
1668 ReflowChildren(aPresContext, aReflowInput, aMetrics.Size(GetWritingMode()));
1669
1670 if (HasAnyStateBits(NS_FRAME_FIRST_REFLOW) && !mReflowCallbackPosted) {
1671 mReflowCallbackPosted = true;
1672 PresShell()->PostReflowCallback(this);
1673 }
1674
1675 NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("exit nsImageFrame::Reflow: size=%d,%d",do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { TraceMsg ("exit nsImageFrame::Reflow: size=%d,%d"
, aMetrics.Width(), aMetrics.Height()); } } while (0)
1676 aMetrics.Width(), aMetrics.Height()))do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { TraceMsg ("exit nsImageFrame::Reflow: size=%d,%d"
, aMetrics.Width(), aMetrics.Height()); } } while (0)
;
1677}
1678
1679bool nsImageFrame::ReflowFinished() {
1680 mReflowCallbackPosted = false;
1681
1682 // XXX(seth): We don't need this. The purpose of updating visibility
1683 // synchronously is to ensure that animated images start animating
1684 // immediately. In the short term, however,
1685 // nsImageLoadingContent::OnUnlockedDraw() is enough to ensure that
1686 // animations start as soon as the image is painted for the first time, and in
1687 // the long term we want to update visibility information from the display
1688 // list whenever we paint, so we don't actually need to do this. However, to
1689 // avoid behavior changes during the transition from the old image visibility
1690 // code, we'll leave it in for now.
1691 UpdateVisibilitySynchronously();
1692
1693 return false;
1694}
1695
1696void nsImageFrame::ReflowCallbackCanceled() { mReflowCallbackPosted = false; }
1697
1698// Computes the width of the specified string. aMaxWidth specifies the maximum
1699// width available. Once this limit is reached no more characters are measured.
1700// The number of characters that fit within the maximum width are returned in
1701// aMaxFit. NOTE: it is assumed that the fontmetrics have already been selected
1702// into the rendering context before this is called (for performance). MMP
1703nscoord nsImageFrame::MeasureString(const char16_t* aString, int32_t aLength,
1704 nscoord aMaxWidth, uint32_t& aMaxFit,
1705 gfxContext& aContext,
1706 nsFontMetrics& aFontMetrics) {
1707 nscoord totalWidth = 0;
1708 aFontMetrics.SetTextRunRTL(false);
1709 nscoord spaceWidth = aFontMetrics.SpaceWidth();
1710
1711 aMaxFit = 0;
1712 while (aLength > 0) {
1713 // Find the next place we can line break
1714 uint32_t len = aLength;
1715 bool trailingSpace = false;
1716 for (int32_t i = 0; i < aLength; i++) {
1717 if (dom::IsSpaceCharacter(aString[i]) && (i > 0)) {
1718 len = i; // don't include the space when measuring
1719 trailingSpace = true;
1720 break;
1721 }
1722 }
1723
1724 // Measure this chunk of text, and see if it fits
1725 nscoord width = nsLayoutUtils::AppUnitWidthOfStringBidi(
1726 aString, len, this, aFontMetrics, aContext);
1727 bool fits = (totalWidth + width) <= aMaxWidth;
1728
1729 // If it fits on the line, or it's the first word we've processed then
1730 // include it
1731 if (fits || (0 == totalWidth)) {
1732 // New piece fits
1733 totalWidth += width;
1734
1735 // If there's a trailing space then see if it fits as well
1736 if (trailingSpace) {
1737 if ((totalWidth + spaceWidth) <= aMaxWidth) {
1738 totalWidth += spaceWidth;
1739 } else {
1740 // Space won't fit. Leave it at the end but don't include it in
1741 // the width
1742 fits = false;
1743 }
1744
1745 len++;
1746 }
1747
1748 aMaxFit += len;
1749 aString += len;
1750 aLength -= len;
1751 }
1752
1753 if (!fits) {
1754 break;
1755 }
1756 }
1757 return totalWidth;
1758}
1759
1760// Formats the alt-text to fit within the specified rectangle. Breaks lines
1761// between words if a word would extend past the edge of the rectangle
1762void nsImageFrame::DisplayAltText(nsPresContext* aPresContext,
1763 gfxContext& aRenderingContext,
1764 const nsString& aAltText,
1765 const nsRect& aRect) {
1766 // Set font and color
1767 aRenderingContext.SetColor(
1768 sRGBColor::FromABGR(StyleText()->mColor.ToColor()));
1769 RefPtr<nsFontMetrics> fm =
1770 nsLayoutUtils::GetInflatedFontMetricsForFrame(this);
1771
1772 // Format the text to display within the formatting rect
1773
1774 nscoord maxAscent = fm->MaxAscent();
1775 nscoord maxDescent = fm->MaxDescent();
1776 nscoord lineHeight = fm->MaxHeight(); // line-relative, so an x-coordinate
1777 // length if writing mode is vertical
1778
1779 WritingMode wm = GetWritingMode();
1780 bool isVertical = wm.IsVertical();
1781
1782 fm->SetVertical(isVertical);
1783 fm->SetTextOrientation(StyleVisibility()->mTextOrientation);
1784
1785 // XXX It would be nice if there was a way to have the font metrics tell
1786 // use where to break the text given a maximum width. At a minimum we need
1787 // to be able to get the break character...
1788 const char16_t* str = aAltText.get();
1789 int32_t strLen = aAltText.Length();
1790 nsPoint pt = wm.IsVerticalRL() ? aRect.TopRight() - nsPoint(lineHeight, 0)
1791 : aRect.TopLeft();
1792 nscoord iSize = isVertical ? aRect.height : aRect.width;
1793
1794 if (!aPresContext->BidiEnabled() && HasRTLChars(aAltText)) {
1795 aPresContext->SetBidiEnabled();
1796 }
1797
1798 // Always show the first line, even if we have to clip it below
1799 bool firstLine = true;
1800 while (strLen > 0) {
1801 if (!firstLine) {
1802 // If we've run out of space, break out of the loop
1803 if ((!isVertical && (pt.y + maxDescent) >= aRect.YMost()) ||
1804 (wm.IsVerticalRL() && (pt.x + maxDescent < aRect.x)) ||
1805 (wm.IsVerticalLR() && (pt.x + maxDescent >= aRect.XMost()))) {
1806 break;
1807 }
1808 }
1809
1810 // Determine how much of the text to display on this line
1811 uint32_t maxFit; // number of characters that fit
1812 nscoord strWidth =
1813 MeasureString(str, strLen, iSize, maxFit, aRenderingContext, *fm);
1814
1815 // Display the text
1816 nsresult rv = NS_ERROR_FAILURE;
1817
1818 if (aPresContext->BidiEnabled()) {
1819 mozilla::intl::BidiEmbeddingLevel level;
1820 nscoord x, y;
1821
1822 if (isVertical) {
1823 x = pt.x + maxDescent;
1824 if (wm.IsBidiLTR()) {
1825 y = aRect.y;
1826 level = mozilla::intl::BidiEmbeddingLevel::LTR();
1827 } else {
1828 y = aRect.YMost() - strWidth;
1829 level = mozilla::intl::BidiEmbeddingLevel::RTL();
1830 }
1831 } else {
1832 y = pt.y + maxAscent;
1833 if (wm.IsBidiLTR()) {
1834 x = aRect.x;
1835 level = mozilla::intl::BidiEmbeddingLevel::LTR();
1836 } else {
1837 x = aRect.XMost() - strWidth;
1838 level = mozilla::intl::BidiEmbeddingLevel::RTL();
1839 }
1840 }
1841
1842 rv = nsBidiPresUtils::RenderText(
1843 str, maxFit, level, aPresContext, aRenderingContext,
1844 aRenderingContext.GetDrawTarget(), *fm, x, y);
1845 }
1846 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1847 nsLayoutUtils::DrawUniDirString(str, maxFit,
1848 isVertical
1849 ? nsPoint(pt.x + maxDescent, pt.y)
1850 : nsPoint(pt.x, pt.y + maxAscent),
1851 *fm, aRenderingContext);
1852 }
1853
1854 // Move to the next line
1855 str += maxFit;
1856 strLen -= maxFit;
1857 if (wm.IsVerticalRL()) {
1858 pt.x -= lineHeight;
1859 } else if (wm.IsVerticalLR()) {
1860 pt.x += lineHeight;
1861 } else {
1862 pt.y += lineHeight;
1863 }
1864
1865 firstLine = false;
1866 }
1867}
1868
1869struct nsRecessedBorder : public nsStyleBorder {
1870 explicit nsRecessedBorder(nscoord aBorderWidth) {
1871 for (const auto side : AllPhysicalSides()) {
1872 BorderColorFor(side) = StyleColor::Black();
1873 mBorder.Get(side) = aBorderWidth;
1874 mBorderStyle.Get(side) = StyleBorderStyle::Inset;
1875 }
1876 }
1877};
1878
1879class nsDisplayAltFeedback final : public nsPaintedDisplayItem {
1880 public:
1881 nsDisplayAltFeedback(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
1882 : nsPaintedDisplayItem(aBuilder, aFrame) {}
1883
1884 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const final {
1885 *aSnap = false;
1886 return mFrame->InkOverflowRectRelativeToSelf() + ToReferenceFrame();
1887 }
1888
1889 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) final {
1890 // Always sync decode, because these icons are UI, and since they're not
1891 // discardable we'll pay the price of sync decoding at most once.
1892 uint32_t flags = imgIContainer::FLAG_SYNC_DECODE;
1893
1894 nsImageFrame* f = static_cast<nsImageFrame*>(mFrame);
1895 (void)f->DisplayAltFeedback(*aCtx, GetPaintRect(aBuilder, aCtx),
1896 ToReferenceFrame(), flags);
1897 }
1898
1899 WebRenderCommandsResult CreateWebRenderCommands(
1900 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
1901 const StackingContextHelper& aSc,
1902 layers::RenderRootStateManager* aManager,
1903 nsDisplayListBuilder* aDisplayListBuilder) final {
1904 // Always sync decode, because these icons are UI, and since they're not
1905 // discardable we'll pay the price of sync decoding at most once.
1906 uint32_t flags =
1907 imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY;
1908 nsImageFrame* f = static_cast<nsImageFrame*>(mFrame);
1909 ImgDrawResult result = f->DisplayAltFeedbackWithoutLayer(
1910 this, aBuilder, aResources, aSc, aManager, aDisplayListBuilder,
1911 ToReferenceFrame(), flags);
1912
1913 if (result != ImgDrawResult::SUCCESS) {
1914 return Err("alt feedback could not be fully drawn");
1915 }
1916 return Ok();
1917 }
1918
1919 NS_DISPLAY_DECL_NAME("AltFeedback", TYPE_ALT_FEEDBACK)const char* Name() const override { return "AltFeedback"; } constexpr
static DisplayItemType ItemType() { return DisplayItemType::
TYPE_ALT_FEEDBACK; } private: void* operator new(size_t aSize
, nsDisplayListBuilder* aBuilder) { return aBuilder->Allocate
(aSize, DisplayItemType::TYPE_ALT_FEEDBACK); } template <typename
T, typename F, typename... Args> friend T* mozilla::MakeDisplayItemWithIndex
( nsDisplayListBuilder* aBuilder, F* aFrame, const uint16_t aIndex
, Args&&... aArgs); public:
1920};
1921
1922ImgDrawResult nsImageFrame::DisplayAltFeedback(gfxContext& aRenderingContext,
1923 const nsRect& aDirtyRect,
1924 nsPoint aPt, uint32_t aFlags) {
1925 // Whether we draw the broken or loading icon.
1926 bool isLoading = mKind != Kind::ImageLoadingContent ||
1927 ImageOk(mContent->AsElement()->State());
1928
1929 // Calculate the content area.
1930 nsRect inner = GetContentRectRelativeToSelf() + aPt;
1931
1932 // Display a recessed one pixel border
1933 nscoord borderEdgeWidth =
1934 nsPresContext::CSSPixelsToAppUnits(ALT_BORDER_WIDTH(1));
1935
1936 // if inner area is empty, then make it big enough for at least the icon
1937 if (inner.IsEmpty()) {
1938 inner.SizeTo(2 * (nsPresContext::CSSPixelsToAppUnits(
1939 ICON_SIZE(16) + ICON_PADDING(3) + ALT_BORDER_WIDTH(1))),
1940 2 * (nsPresContext::CSSPixelsToAppUnits(
1941 ICON_SIZE(16) + ICON_PADDING(3) + ALT_BORDER_WIDTH(1))));
1942 }
1943
1944 // Make sure we have enough room to actually render the border within
1945 // our frame bounds
1946 if ((inner.width < 2 * borderEdgeWidth) ||
1947 (inner.height < 2 * borderEdgeWidth)) {
1948 return ImgDrawResult::SUCCESS;
1949 }
1950
1951 // Paint the border
1952 if (!isLoading) {
1953 nsRecessedBorder recessedBorder(borderEdgeWidth);
1954
1955 // Assert that we're not drawing a border-image here; if we were, we
1956 // couldn't ignore the ImgDrawResult that PaintBorderWithStyleBorder
1957 // returns.
1958 MOZ_ASSERT(recessedBorder.mBorderImageSource.IsNone())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(recessedBorder.mBorderImageSource.IsNone())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(recessedBorder.mBorderImageSource.IsNone()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("recessedBorder.mBorderImageSource.IsNone()"
, "./../../../layout/generic/nsImageFrame.cpp", 1958); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "recessedBorder.mBorderImageSource.IsNone()"
")"); do { MOZ_CrashSequence(__null, 1958); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1959
1960 (void)nsCSSRendering::PaintBorderWithStyleBorder(
1961 PresContext(), aRenderingContext, this, inner, inner, recessedBorder,
1962 mComputedStyle, PaintBorderFlags::SyncDecodeImages);
1963 }
1964
1965 // Adjust the inner rect to account for the one pixel recessed border,
1966 // and a six pixel padding on each edge
1967 inner.Deflate(
1968 nsPresContext::CSSPixelsToAppUnits(ICON_PADDING(3) + ALT_BORDER_WIDTH(1)),
1969 nsPresContext::CSSPixelsToAppUnits(ICON_PADDING(3) + ALT_BORDER_WIDTH(1)));
1970 if (inner.IsEmpty()) {
1971 return ImgDrawResult::SUCCESS;
1972 }
1973
1974 DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
1975
1976 // Clip so we don't render outside the inner rect
1977 aRenderingContext.Save();
1978 aRenderingContext.Clip(NSRectToSnappedRect(
1979 inner, PresContext()->AppUnitsPerDevPixel(), *drawTarget));
1980
1981 ImgDrawResult result = ImgDrawResult::SUCCESS;
1982
1983 // Check if we should display image placeholders
1984 if (ShouldShowBrokenImageIcon()) {
1985 result = ImgDrawResult::NOT_READY;
1986 nscoord size = nsPresContext::CSSPixelsToAppUnits(ICON_SIZE(16));
1987 imgIRequest* request = BrokenImageIcon::GetImage(this);
1988
1989 // If we weren't previously displaying an icon, register ourselves
1990 // as an observer for load and animation updates and flag that we're
1991 // doing so now.
1992 if (request && !mDisplayingIcon) {
1993 BrokenImageIcon::AddObserver(this);
1994 mDisplayingIcon = true;
1995 }
1996
1997 WritingMode wm = GetWritingMode();
1998 bool flushRight = wm.IsPhysicalRTL();
1999
2000 // If the icon in question is loaded, draw it.
2001 uint32_t imageStatus = 0;
2002 if (request) {
2003 request->GetImageStatus(&imageStatus);
2004 }
2005 if (imageStatus & imgIRequest::STATUS_LOAD_COMPLETE &&
2006 !(imageStatus & imgIRequest::STATUS_ERROR)) {
2007 nsCOMPtr<imgIContainer> imgCon;
2008 request->GetImage(getter_AddRefs(imgCon));
2009 MOZ_ASSERT(imgCon, "Load complete, but no image container?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(imgCon)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(imgCon))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("imgCon" " (" "Load complete, but no image container?"
")", "./../../../layout/generic/nsImageFrame.cpp", 2009); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "imgCon" ") (" "Load complete, but no image container?"
")"); do { MOZ_CrashSequence(__null, 2009); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2010 nsRect dest(flushRight ? inner.XMost() - size : inner.x, inner.y, size,
2011 size);
2012 result = nsLayoutUtils::DrawSingleImage(
2013 aRenderingContext, PresContext(), imgCon,
2014 nsLayoutUtils::GetSamplingFilterForFrame(this), dest, aDirtyRect,
2015 SVGImageContext(), aFlags);
2016 }
2017
2018 // If we could not draw the icon, just draw some graffiti in the mean time.
2019 if (result == ImgDrawResult::NOT_READY) {
2020 ColorPattern color(ToDeviceColor(sRGBColor(1.f, 0.f, 0.f, 1.f)));
2021
2022 nscoord iconXPos = flushRight ? inner.XMost() - size : inner.x;
2023
2024 // stroked rect:
2025 nsRect rect(iconXPos, inner.y, size, size);
2026 Rect devPxRect = ToRect(nsLayoutUtils::RectToGfxRect(
2027 rect, PresContext()->AppUnitsPerDevPixel()));
2028 drawTarget->StrokeRect(devPxRect, color);
2029
2030 // filled circle in bottom right quadrant of stroked rect:
2031 nscoord twoPX = nsPresContext::CSSPixelsToAppUnits(2);
2032 rect = nsRect(iconXPos + size / 2, inner.y + size / 2, size / 2 - twoPX,
2033 size / 2 - twoPX);
2034 devPxRect = ToRect(nsLayoutUtils::RectToGfxRect(
2035 rect, PresContext()->AppUnitsPerDevPixel()));
2036 RefPtr<PathBuilder> builder = drawTarget->CreatePathBuilder();
2037 AppendEllipseToPath(builder, devPxRect.Center(), devPxRect.Size());
2038 RefPtr<Path> ellipse = builder->Finish();
2039 drawTarget->Fill(ellipse, color);
2040 }
2041
2042 // Reduce the inner rect by the width of the icon, and leave an
2043 // additional ICON_PADDING pixels for padding
2044 int32_t paddedIconSize =
2045 nsPresContext::CSSPixelsToAppUnits(ICON_SIZE(16) + ICON_PADDING(3));
2046 if (wm.IsVertical()) {
2047 inner.y += paddedIconSize;
2048 inner.height -= paddedIconSize;
2049 } else {
2050 if (!flushRight) {
2051 inner.x += paddedIconSize;
2052 }
2053 inner.width -= paddedIconSize;
2054 }
2055 }
2056
2057 // If there's still room, display the alt-text
2058 if (!inner.IsEmpty()) {
2059 nsAutoString altText;
2060 nsCSSFrameConstructor::GetAlternateTextFor(*mContent->AsElement(), altText);
2061 DisplayAltText(PresContext(), aRenderingContext, altText, inner);
2062 }
2063
2064 aRenderingContext.Restore();
2065
2066 return result;
2067}
2068
2069ImgDrawResult nsImageFrame::DisplayAltFeedbackWithoutLayer(
2070 nsDisplayItem* aItem, wr::DisplayListBuilder& aBuilder,
2071 wr::IpcResourceUpdateQueue& aResources, const StackingContextHelper& aSc,
2072 layers::RenderRootStateManager* aManager,
2073 nsDisplayListBuilder* aDisplayListBuilder, nsPoint aPt, uint32_t aFlags) {
2074 // Whether we draw the broken or loading icon.
2075 bool isLoading = mKind != Kind::ImageLoadingContent ||
2076 ImageOk(mContent->AsElement()->State());
2077
2078 // Calculate the content area.
2079 nsRect inner = GetContentRectRelativeToSelf() + aPt;
2080
2081 // Display a recessed one pixel border
2082 nscoord borderEdgeWidth =
2083 nsPresContext::CSSPixelsToAppUnits(ALT_BORDER_WIDTH(1));
2084
2085 // if inner area is empty, then make it big enough for at least the icon
2086 if (inner.IsEmpty()) {
2087 inner.SizeTo(2 * (nsPresContext::CSSPixelsToAppUnits(
2088 ICON_SIZE(16) + ICON_PADDING(3) + ALT_BORDER_WIDTH(1))),
2089 2 * (nsPresContext::CSSPixelsToAppUnits(
2090 ICON_SIZE(16) + ICON_PADDING(3) + ALT_BORDER_WIDTH(1))));
2091 }
2092
2093 // Make sure we have enough room to actually render the border within
2094 // our frame bounds
2095 if ((inner.width < 2 * borderEdgeWidth) ||
2096 (inner.height < 2 * borderEdgeWidth)) {
2097 return ImgDrawResult::SUCCESS;
2098 }
2099
2100 // If the TextDrawTarget requires fallback we need to rollback everything we
2101 // may have added to the display list, but we don't find that out until the
2102 // end.
2103 bool textDrawResult = true;
2104 class AutoSaveRestore {
2105 public:
2106 explicit AutoSaveRestore(wr::DisplayListBuilder& aBuilder,
2107 bool& aTextDrawResult)
2108 : mBuilder(aBuilder), mTextDrawResult(aTextDrawResult) {
2109 mBuilder.Save();
2110 }
2111 ~AutoSaveRestore() {
2112 // If we have to use fallback for the text restore the builder and remove
2113 // anything else we added to the display list, we need to use fallback.
2114 if (mTextDrawResult) {
2115 mBuilder.ClearSave();
2116 } else {
2117 mBuilder.Restore();
2118 }
2119 }
2120
2121 private:
2122 wr::DisplayListBuilder& mBuilder;
2123 bool& mTextDrawResult;
2124 };
2125
2126 AutoSaveRestore autoSaveRestore(aBuilder, textDrawResult);
2127
2128 // Paint the border
2129 if (!isLoading) {
2130 nsRecessedBorder recessedBorder(borderEdgeWidth);
2131 // Assert that we're not drawing a border-image here; if we were, we
2132 // couldn't ignore the ImgDrawResult that PaintBorderWithStyleBorder
2133 // returns.
2134 MOZ_ASSERT(recessedBorder.mBorderImageSource.IsNone())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(recessedBorder.mBorderImageSource.IsNone())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(recessedBorder.mBorderImageSource.IsNone()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("recessedBorder.mBorderImageSource.IsNone()"
, "./../../../layout/generic/nsImageFrame.cpp", 2134); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "recessedBorder.mBorderImageSource.IsNone()"
")"); do { MOZ_CrashSequence(__null, 2134); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2135
2136 nsRect rect = nsRect(aPt, GetSize());
2137 (void)nsCSSRendering::CreateWebRenderCommandsForBorderWithStyleBorder(
2138 aItem, this, rect, aBuilder, aResources, aSc, aManager,
2139 aDisplayListBuilder, recessedBorder);
2140 }
2141
2142 // Adjust the inner rect to account for the one pixel recessed border,
2143 // and a six pixel padding on each edge
2144 inner.Deflate(
2145 nsPresContext::CSSPixelsToAppUnits(ICON_PADDING(3) + ALT_BORDER_WIDTH(1)),
2146 nsPresContext::CSSPixelsToAppUnits(ICON_PADDING(3) + ALT_BORDER_WIDTH(1)));
2147 if (inner.IsEmpty()) {
2148 return ImgDrawResult::SUCCESS;
2149 }
2150
2151 // Clip to this rect so we don't render outside the inner rect
2152 const auto bounds = LayoutDeviceRect::FromAppUnits(
2153 inner, PresContext()->AppUnitsPerDevPixel());
2154 auto wrBounds = wr::ToLayoutRect(bounds);
2155
2156 // Check if we should display image placeholders
2157 if (ShouldShowBrokenImageIcon()) {
2158 ImgDrawResult result = ImgDrawResult::NOT_READY;
2159 nscoord size = nsPresContext::CSSPixelsToAppUnits(ICON_SIZE(16));
2160 imgIRequest* request = BrokenImageIcon::GetImage(this);
2161
2162 // If we weren't previously displaying an icon, register ourselves
2163 // as an observer for load and animation updates and flag that we're
2164 // doing so now.
2165 if (request && !mDisplayingIcon) {
2166 BrokenImageIcon::AddObserver(this);
2167 mDisplayingIcon = true;
2168 }
2169
2170 WritingMode wm = GetWritingMode();
2171 const bool flushRight = wm.IsPhysicalRTL();
2172
2173 // If the icon in question is loaded, draw it.
2174 uint32_t imageStatus = 0;
2175 if (request) {
2176 request->GetImageStatus(&imageStatus);
2177 }
2178 if (imageStatus & imgIRequest::STATUS_LOAD_COMPLETE &&
2179 !(imageStatus & imgIRequest::STATUS_ERROR)) {
2180 nsCOMPtr<imgIContainer> imgCon;
2181 request->GetImage(getter_AddRefs(imgCon));
2182 MOZ_ASSERT(imgCon, "Load complete, but no image container?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(imgCon)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(imgCon))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("imgCon" " (" "Load complete, but no image container?"
")", "./../../../layout/generic/nsImageFrame.cpp", 2182); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "imgCon" ") (" "Load complete, but no image container?"
")"); do { MOZ_CrashSequence(__null, 2182); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2183
2184 nsRect dest(flushRight ? inner.XMost() - size : inner.x, inner.y, size,
2185 size);
2186
2187 const int32_t factor = PresContext()->AppUnitsPerDevPixel();
2188 const auto destRect = LayoutDeviceRect::FromAppUnits(dest, factor);
2189
2190 SVGImageContext svgContext;
2191 Maybe<ImageIntRegion> region;
2192 IntSize decodeSize =
2193 nsLayoutUtils::ComputeImageContainerDrawingParameters(
2194 imgCon, this, destRect, destRect, aSc, aFlags, svgContext,
2195 region);
2196 RefPtr<image::WebRenderImageProvider> provider;
2197 result = imgCon->GetImageProvider(aManager->LayerManager(), decodeSize,
2198 svgContext, region, aFlags,
2199 getter_AddRefs(provider));
2200 if (provider) {
2201 bool wrResult = aManager->CommandBuilder().PushImageProvider(
2202 aItem, provider, result, aBuilder, aResources, destRect, bounds);
2203 result &= wrResult ? ImgDrawResult::SUCCESS : ImgDrawResult::NOT_READY;
2204 } else {
2205 // We don't use &= here because we want the result to be NOT_READY so
2206 // the next block executes.
2207 result = ImgDrawResult::NOT_READY;
2208 }
2209 }
2210
2211 // If we could not draw the icon, just draw some graffiti in the mean time.
2212 if (result == ImgDrawResult::NOT_READY) {
2213 auto color = wr::ColorF{1.0f, 0.0f, 0.0f, 1.0f};
2214 bool isBackfaceVisible = !aItem->BackfaceIsHidden();
2215
2216 nscoord iconXPos = flushRight ? inner.XMost() - size : inner.x;
2217
2218 // stroked rect:
2219 nsRect rect(iconXPos, inner.y, size, size);
2220 auto devPxRect = LayoutDeviceRect::FromAppUnits(
2221 rect, PresContext()->AppUnitsPerDevPixel());
2222 auto dest = wr::ToLayoutRect(devPxRect);
2223
2224 auto borderWidths = wr::ToBorderWidths(1.0, 1.0, 1.0, 1.0);
2225 wr::BorderSide side = {color, wr::BorderStyle::Solid};
2226 wr::BorderSide sides[4] = {side, side, side, side};
2227 Range<const wr::BorderSide> sidesRange(sides, 4);
2228 aBuilder.PushBorder(dest, wrBounds, isBackfaceVisible, borderWidths,
2229 sidesRange, wr::EmptyBorderRadius());
2230
2231 // filled circle in bottom right quadrant of stroked rect:
2232 nscoord twoPX = nsPresContext::CSSPixelsToAppUnits(2);
2233 rect = nsRect(iconXPos + size / 2, inner.y + size / 2, size / 2 - twoPX,
2234 size / 2 - twoPX);
2235 devPxRect = LayoutDeviceRect::FromAppUnits(
2236 rect, PresContext()->AppUnitsPerDevPixel());
2237 dest = wr::ToLayoutRect(devPxRect);
2238
2239 aBuilder.PushRoundedRect(dest, wrBounds, isBackfaceVisible, color);
2240 }
2241
2242 // Reduce the inner rect by the width of the icon, and leave an
2243 // additional ICON_PADDING pixels for padding
2244 int32_t paddedIconSize =
2245 nsPresContext::CSSPixelsToAppUnits(ICON_SIZE(16) + ICON_PADDING(3));
2246 if (wm.IsVertical()) {
2247 inner.y += paddedIconSize;
2248 inner.height -= paddedIconSize;
2249 } else {
2250 if (!flushRight) {
2251 inner.x += paddedIconSize;
2252 }
2253 inner.width -= paddedIconSize;
2254 }
2255 }
2256
2257 // Draw text
2258 if (!inner.IsEmpty()) {
2259 auto textDrawer = MakeRefPtr<TextDrawTarget>(
2260 aBuilder, aResources, aSc, aManager, aItem, inner,
2261 /* aCallerDoesSaveRestore = */ true);
2262 MOZ_ASSERT(textDrawer->IsValid())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(textDrawer->IsValid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(textDrawer->IsValid()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("textDrawer->IsValid()"
, "./../../../layout/generic/nsImageFrame.cpp", 2262); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "textDrawer->IsValid()" ")"); do { MOZ_CrashSequence
(__null, 2262); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2263 if (textDrawer->IsValid()) {
2264 gfxContext captureCtx(textDrawer);
2265
2266 nsAutoString altText;
2267 nsCSSFrameConstructor::GetAlternateTextFor(*mContent->AsElement(),
2268 altText);
2269 DisplayAltText(PresContext(), captureCtx, altText, inner);
2270
2271 textDrawer->TerminateShadows();
2272 textDrawResult = !textDrawer->CheckHasUnsupportedFeatures();
2273 }
2274 }
2275
2276 // Purposely ignore local DrawResult because we handled it not being success
2277 // already.
2278 return textDrawResult ? ImgDrawResult::SUCCESS : ImgDrawResult::NOT_READY;
2279}
2280
2281// We want to sync-decode in this case, as otherwise we either need to flash
2282// white while waiting to decode the new image, or paint the old image with a
2283// different aspect-ratio, which would be bad as it'd be stretched.
2284//
2285// See bug 1589955.
2286static bool OldImageHasDifferentRatio(const nsImageFrame& aFrame,
2287 imgIContainer& aImage,
2288 imgIContainer* aPrevImage) {
2289 if (!aPrevImage || aPrevImage == &aImage) {
2290 return false;
2291 }
2292
2293 // If we don't depend on our intrinsic image size / ratio, we're good.
2294 //
2295 // FIXME(emilio): There's the case of the old image being painted
2296 // intrinsically, and src and styles changing at the same time... Maybe we
2297 // should keep track of the old GetPaintRect()'s ratio and the image's ratio,
2298 // instead of checking this bit?
2299 if (aFrame.HasAnyStateBits(IMAGE_SIZECONSTRAINED)) {
2300 return false;
2301 }
2302
2303 auto currentRatio = aFrame.GetIntrinsicRatio();
2304 auto oldRatio = aFrame.ComputeIntrinsicRatioForImage(aPrevImage);
2305 return oldRatio != currentRatio;
2306}
2307
2308#ifdef DEBUG1
2309void nsImageFrame::AssertSyncDecodingHintIsInSync() const {
2310 if (!IsForImageLoadingContent()) {
2311 return;
2312 }
2313 nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
2314 MOZ_ASSERT(imageLoader)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(imageLoader)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(imageLoader))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("imageLoader", "./../../../layout/generic/nsImageFrame.cpp"
, 2314); AnnotateMozCrashReason("MOZ_ASSERT" "(" "imageLoader"
")"); do { MOZ_CrashSequence(__null, 2314); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2315
2316 // The opposite is not true, we might have some other heuristics which force
2317 // sync-decoding of images.
2318 MOZ_ASSERT_IF(imageLoader->GetSyncDecodingHint(), mForceSyncDecoding)do { if (imageLoader->GetSyncDecodingHint()) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(mForceSyncDecoding
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mForceSyncDecoding))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mForceSyncDecoding", "./../../../layout/generic/nsImageFrame.cpp"
, 2318); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mForceSyncDecoding"
")"); do { MOZ_CrashSequence(__null, 2318); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2319}
2320#endif
2321
2322void nsDisplayImage::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
2323 auto* frame = Frame();
2324 frame->AssertSyncDecodingHintIsInSync();
2325
2326 auto* image = frame->mImage.get();
2327 auto* prevImage = frame->mPrevImage.get();
2328 if (!image) {
2329 return;
2330 }
2331
2332 const bool oldImageIsDifferent =
2333 OldImageHasDifferentRatio(*frame, *image, prevImage);
2334
2335 uint32_t flags = aBuilder->GetImageDecodeFlags();
2336 if (oldImageIsDifferent || frame->mForceSyncDecoding ||
2337 frame->UsedImageDecoding() == StyleImageDecoding::Sync) {
2338 flags |= imgIContainer::FLAG_SYNC_DECODE;
2339 }
2340
2341 ImgDrawResult result = frame->PaintImage(
2342 *aCtx, ToReferenceFrame(), GetPaintRect(aBuilder, aCtx), image, flags);
2343
2344 if (result == ImgDrawResult::NOT_READY ||
2345 result == ImgDrawResult::INCOMPLETE ||
2346 result == ImgDrawResult::TEMPORARY_ERROR) {
2347 // If the current image failed to paint because it's still loading or
2348 // decoding, try painting the previous image.
2349 if (prevImage) {
2350 result =
Value stored to 'result' is never read
2351 frame->PaintImage(*aCtx, ToReferenceFrame(),
2352 GetPaintRect(aBuilder, aCtx), prevImage, flags);
2353 }
2354 }
2355}
2356
2357nsRect nsDisplayImage::GetDestRect() const {
2358 auto* f = static_cast<nsImageFrame*>(mFrame);
2359 return f->GetDestRect(f->GetContentRectRelativeToSelf() + ToReferenceFrame());
2360}
2361
2362nsRect nsDisplayImage::GetDestRectViewTransition() const {
2363 nsRect destRect = GetDestRect();
2364 auto* image = static_cast<nsImageFrame*>(mFrame);
2365
2366 auto* name = image->GetViewTransitionName();
2367 auto* vt = image->PresContext()->Document()->GetActiveViewTransition();
2368
2369 if (!name || !vt) {
2370 return destRect;
2371 }
2372
2373 // In view transitions, the snapshot images natural dimension is the captured
2374 // elements principal border box. In order to render the captured overflow to
2375 // its appropiate position and scale, we must internally map and scale the
2376 // destRect with respect to the captured element's inkOverflowRect.
2377 nsRect inkOverflowRect;
2378 nsSize borderBoxSize;
2379 Maybe<nsRect> activeRect;
2380
2381 if (image->Style()->GetPseudoType() == PseudoStyleType::ViewTransitionOld) {
2382 inkOverflowRect = vt->GetOldInkOverflowRect(name).value();
2383 borderBoxSize = vt->GetOldBorderBoxSize(name).value();
2384 activeRect = vt->GetOldActiveRect(name);
2385 } else {
2386 inkOverflowRect = vt->GetNewInkOverflowRect(name).value();
2387 borderBoxSize = vt->GetNewBorderBoxSize(name).value();
2388 activeRect = vt->GetNewActiveRect(name);
2389 }
2390
2391 if (borderBoxSize.IsEmpty()) {
2392 return destRect;
2393 }
2394
2395 // Scale the ink overflow offset to maintain its position relative to
2396 // the destination border box, as if the offset scaled with the element.
2397 auto xRatio = static_cast<float>(inkOverflowRect.X()) / borderBoxSize.Width();
2398 auto yRatio =
2399 static_cast<float>(inkOverflowRect.Y()) / borderBoxSize.Height();
2400 auto scaledX = std::round(xRatio * destRect.Width());
2401 auto scaledY = std::round(yRatio * destRect.Height());
2402
2403 const nsPoint scaledInkOverflowOffset(scaledX, scaledY);
2404
2405 // Scale destRect’s size to match the captured element’s relative ink overflow
2406 // size.
2407 auto widthRatio =
2408 static_cast<float>(inkOverflowRect.Width()) / borderBoxSize.Width();
2409 auto heightRatio =
2410 static_cast<float>(inkOverflowRect.Height()) / borderBoxSize.Height();
2411 const nsSize scaledInkOverflowSize(
2412 std::round(widthRatio * destRect.Width()),
2413 std::round(heightRatio * destRect.Height()));
2414
2415 destRect = nsRect(destRect.TopLeft() + scaledInkOverflowOffset,
2416 scaledInkOverflowSize);
2417
2418 if (activeRect) {
2419 destRect = destRect.Intersect(activeRect.value());
2420 }
2421
2422 return destRect;
2423}
2424
2425nsRegion nsDisplayImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
2426 bool* aSnap) const {
2427 *aSnap = false;
2428 auto* image = Frame()->mImage.get();
2429 if (image && image->WillDrawOpaqueNow()) {
2430 const nsRect frameContentBox = GetBounds(aSnap);
2431 return GetDestRect().Intersect(frameContentBox);
2432 }
2433 return nsRegion();
2434}
2435
2436void nsDisplayImage::MaybeCreateWebRenderCommandsForViewTransition(
2437 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
2438 const StackingContextHelper& aSc, RenderRootStateManager* aManager,
2439 nsDisplayListBuilder* aDisplayListBuilder) {
2440 auto* frame = Frame();
2441 MOZ_ASSERT(!frame->mImage)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!frame->mImage)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!frame->mImage))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!frame->mImage"
, "./../../../layout/generic/nsImageFrame.cpp", 2441); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!frame->mImage" ")"); do { MOZ_CrashSequence
(__null, 2441); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2442 auto key = frame->GetViewTransitionImageKey(aManager, aResources);
2443 if (NS_WARN_IF(key == kNoKey)NS_warn_if_impl(key == kNoKey, "key == kNoKey", "./../../../layout/generic/nsImageFrame.cpp"
, 2443)
) {
2444 return;
2445 }
2446 VT_LOG_DEBUG("GetViewTransitionImageKey(%s) = %s", frame->ListTag().get(),do { const ::mozilla::LogModule* moz_real_module = mozilla::dom
::gViewTransitionsLog; if ((__builtin_expect(!!(mozilla::detail
::log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, mozilla::LogLevel
::Debug, "GetViewTransitionImageKey(%s) = %s", frame->ListTag
().get(), ToString(key).c_str()); } } while (0)
2447 ToString(key).c_str())do { const ::mozilla::LogModule* moz_real_module = mozilla::dom
::gViewTransitionsLog; if ((__builtin_expect(!!(mozilla::detail
::log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, mozilla::LogLevel
::Debug, "GetViewTransitionImageKey(%s) = %s", frame->ListTag
().get(), ToString(key).c_str()); } } while (0)
;
2448 nsRect destAppUnits = GetDestRectViewTransition();
2449 const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
2450 const auto destRect =
2451 wr::ToLayoutRect(LayoutDeviceRect::FromAppUnits(destAppUnits, factor));
2452 auto rendering = wr::ToImageRendering(frame->UsedImageRendering());
2453 aBuilder.PushDebug(1);
2454 aBuilder.PushImage(destRect, destRect, !BackfaceIsHidden(),
2455 /* aForceAntiAliasing = */ false, rendering, key);
2456}
2457
2458WebRenderCommandsResult nsDisplayImage::CreateWebRenderCommands(
2459 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
2460 const StackingContextHelper& aSc, RenderRootStateManager* aManager,
2461 nsDisplayListBuilder* aDisplayListBuilder) {
2462 auto* frame = Frame();
2463 auto* image = frame->mImage.get();
2464 if (!image) {
2465 MaybeCreateWebRenderCommandsForViewTransition(
2466 aBuilder, aResources, aSc, aManager, aDisplayListBuilder);
2467 return Ok();
2468 }
2469
2470 if (nsImageMap* map = frame->GetImageMap(); map && map->HasFocus()) {
2471 // We can't draw some of the focus areas (in particular, PolyArea would be
2472 // somewhat hard to do).
2473 return Err("focused image map area cannot be drawn");
2474 }
2475
2476 auto* prevImage = frame->mPrevImage.get();
2477
2478 frame->AssertSyncDecodingHintIsInSync();
2479 const bool oldImageIsDifferent =
2480 OldImageHasDifferentRatio(*frame, *image, prevImage);
2481
2482 uint32_t flags = aDisplayListBuilder->GetImageDecodeFlags();
2483 if (oldImageIsDifferent || frame->mForceSyncDecoding ||
2484 frame->UsedImageDecoding() == StyleImageDecoding::Sync) {
2485 flags |= imgIContainer::FLAG_SYNC_DECODE;
2486 }
2487 if (StaticPrefs::image_svg_blob_image() &&
2488 image->GetType() == imgIContainer::TYPE_VECTOR) {
2489 flags |= imgIContainer::FLAG_RECORD_BLOB;
2490 }
2491
2492 const nsRect destAppUnits = GetDestRect();
2493 const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
2494 const auto destRect = LayoutDeviceRect::FromAppUnits(destAppUnits, factor);
2495
2496 SVGImageContext svgContext;
2497 Maybe<ImageIntRegion> region;
2498 IntSize decodeSize = nsLayoutUtils::ComputeImageContainerDrawingParameters(
2499 image, mFrame, destRect, destRect, aSc, flags, svgContext, region);
2500
2501 RefPtr<image::WebRenderImageProvider> provider;
2502 ImgDrawResult drawResult =
2503 image->GetImageProvider(aManager->LayerManager(), decodeSize, svgContext,
2504 region, flags, getter_AddRefs(provider));
2505
2506 if (nsCOMPtr<imgIRequest> currentRequest = frame->GetCurrentRequest()) {
2507 Element* element = frame->GetContent()->AsElement();
2508 nsRect rectRelativeToSelf = destAppUnits - ToReferenceFrame();
2509
2510 ContainerTimingHelpers::MaybeProcessPaintForContainer(element, frame,
2511 rectRelativeToSelf);
2512 LCPHelpers::FinalizeLCPEntryForImage(
2513 element, static_cast<imgRequestProxy*>(currentRequest.get()),
2514 rectRelativeToSelf);
2515 }
2516
2517 // While we got a container, it may not contain a fully decoded surface. If
2518 // that is the case, and we have an image we were previously displaying which
2519 // has a fully decoded surface, then we should prefer the previous image.
2520 bool updatePrevImage = false;
2521 switch (drawResult) {
2522 case ImgDrawResult::NOT_READY:
2523 case ImgDrawResult::INCOMPLETE:
2524 case ImgDrawResult::TEMPORARY_ERROR:
2525 if (prevImage && prevImage != image) {
2526 // The current image and the previous image might be switching between
2527 // rasterized surfaces and blob recordings, so we need to update the
2528 // flags appropriately.
2529 uint32_t prevFlags = flags;
2530 if (StaticPrefs::image_svg_blob_image() &&
2531 prevImage->GetType() == imgIContainer::TYPE_VECTOR) {
2532 prevFlags |= imgIContainer::FLAG_RECORD_BLOB;
2533 } else {
2534 prevFlags &= ~imgIContainer::FLAG_RECORD_BLOB;
2535 }
2536
2537 RefPtr<image::WebRenderImageProvider> prevProvider;
2538 ImgDrawResult prevDrawResult = prevImage->GetImageProvider(
2539 aManager->LayerManager(), decodeSize, svgContext, region, prevFlags,
2540 getter_AddRefs(prevProvider));
2541 if (prevProvider && (prevDrawResult == ImgDrawResult::SUCCESS ||
2542 prevDrawResult == ImgDrawResult::WRONG_SIZE)) {
2543 // We use WRONG_SIZE here to ensure that when the frame next tries to
2544 // invalidate due to a frame update from the current image, we don't
2545 // consider the result from the previous image to be a valid result to
2546 // avoid redrawing.
2547 drawResult = ImgDrawResult::WRONG_SIZE;
2548 provider = std::move(prevProvider);
2549 flags = prevFlags;
2550 break;
2551 }
2552
2553 // Previous image was unusable; we can forget about it.
2554 updatePrevImage = true;
2555 }
2556 break;
2557 case ImgDrawResult::NOT_SUPPORTED:
2558 return Err("image provider is not supported");
2559 default:
2560 updatePrevImage = prevImage != image;
2561 break;
2562 }
2563
2564 // The previous image was not used, and is different from the current image.
2565 // We should forget about it. We need to update the frame as well because the
2566 // display item may get recreated.
2567 if (updatePrevImage) {
2568 frame->mPrevImage = frame->mImage;
2569 }
2570
2571 // If the image provider is null, we don't want to fallback. Any other
2572 // failure will be due to resource constraints and fallback is unlikely to
2573 // help us. Hence we can ignore the return value from PushImage.
2574 aManager->CommandBuilder().PushImageProvider(
2575 this, provider, drawResult, aBuilder, aResources, destRect, destRect);
2576 return Ok();
2577}
2578
2579ImgDrawResult nsImageFrame::PaintImage(gfxContext& aRenderingContext,
2580 nsPoint aPt, const nsRect& aDirtyRect,
2581 imgIContainer* aImage, uint32_t aFlags) {
2582 DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
2583
2584 // Render the image into our content area (the area inside
2585 // the borders and padding)
2586 NS_ASSERTION(GetContentRectRelativeToSelf().width == mComputedSize.width,do { if (!(GetContentRectRelativeToSelf().width == mComputedSize
.width)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad width", "GetContentRectRelativeToSelf().width == mComputedSize.width"
, "./../../../layout/generic/nsImageFrame.cpp", 2587); MOZ_PretendNoReturn
(); } } while (0)
2587 "bad width")do { if (!(GetContentRectRelativeToSelf().width == mComputedSize
.width)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad width", "GetContentRectRelativeToSelf().width == mComputedSize.width"
, "./../../../layout/generic/nsImageFrame.cpp", 2587); MOZ_PretendNoReturn
(); } } while (0)
;
2588
2589 nsPoint anchorPoint;
2590 const nsRect dest =
2591 GetDestRect(GetContentRectRelativeToSelf() + aPt, &anchorPoint);
2592
2593 SVGImageContext svgContext;
2594 SVGImageContext::MaybeStoreContextPaint(svgContext, this, aImage);
2595
2596 ImgDrawResult result = nsLayoutUtils::DrawSingleImage(
2597 aRenderingContext, PresContext(), aImage,
2598 nsLayoutUtils::GetSamplingFilterForFrame(this), dest, aDirtyRect,
2599 svgContext, aFlags, &anchorPoint);
2600
2601 if (nsImageMap* map = GetImageMap(); map && map->HasFocus()) {
2602 gfxPoint devPixelOffset = nsLayoutUtils::PointToGfxPoint(
2603 dest.TopLeft(), PresContext()->AppUnitsPerDevPixel());
2604 AutoRestoreTransform autoRestoreTransform(drawTarget);
2605 drawTarget->SetTransform(
2606 drawTarget->GetTransform().PreTranslate(ToPoint(devPixelOffset)));
2607
2608 // solid white stroke:
2609 ColorPattern white(ToDeviceColor(sRGBColor::OpaqueWhite()));
2610 map->DrawFocus(this, *drawTarget, white);
2611
2612 // then dashed black stroke over the top:
2613 ColorPattern black(ToDeviceColor(sRGBColor::OpaqueBlack()));
2614 StrokeOptions strokeOptions;
2615 nsLayoutUtils::InitDashPattern(strokeOptions, StyleBorderStyle::Dotted);
2616 map->DrawFocus(this, *drawTarget, black, strokeOptions);
2617 }
2618
2619 if (result == ImgDrawResult::SUCCESS) {
2620 mPrevImage = aImage;
2621 } else if (result == ImgDrawResult::BAD_IMAGE) {
2622 mPrevImage = nullptr;
2623 }
2624
2625 return result;
2626}
2627
2628already_AddRefed<imgIRequest> nsImageFrame::GetCurrentRequest() const {
2629 if (mKind != Kind::ImageLoadingContent) {
2630 return do_AddRef(mOwnedRequest);
2631 }
2632
2633 MOZ_ASSERT(!mOwnedRequest)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mOwnedRequest)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mOwnedRequest))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mOwnedRequest"
, "./../../../layout/generic/nsImageFrame.cpp", 2633); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mOwnedRequest" ")"); do { MOZ_CrashSequence
(__null, 2633); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2634
2635 nsCOMPtr<imgIRequest> request;
2636 nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
2637 MOZ_ASSERT(imageLoader)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(imageLoader)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(imageLoader))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("imageLoader", "./../../../layout/generic/nsImageFrame.cpp"
, 2637); AnnotateMozCrashReason("MOZ_ASSERT" "(" "imageLoader"
")"); do { MOZ_CrashSequence(__null, 2637); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2638 imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
2639 getter_AddRefs(request));
2640 return request.forget();
2641}
2642
2643void nsImageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
2644 const nsDisplayListSet& aLists) {
2645 if (!IsVisibleForPainting()) {
2646 return;
2647 }
2648
2649 DisplayBorderBackgroundOutline(aBuilder, aLists);
2650
2651 if (HidesContent()) {
2652 DisplaySelectionOverlay(aBuilder, aLists.Content(),
2653 nsISelectionDisplay::DISPLAY_IMAGES);
2654 return;
2655 }
2656
2657 DisplayListClipState::AutoSaveRestore clipState(aBuilder);
2658 auto clipAxes = ShouldApplyOverflowClipping(StyleDisplay());
2659 if (!clipAxes.isEmpty()) {
2660 nsRect clipRect;
2661 nsRectCornerRadii radii;
2662 nsMargin inset;
2663 bool haveRadii =
2664 ComputeOverflowClipRectRelativeToSelf(clipAxes, clipRect, radii, inset);
2665 clipState.ClipContainingBlockDescendants(
2666 clipRect + aBuilder->ToReferenceFrame(this),
2667 haveRadii ? &radii : nullptr, haveRadii ? &inset : nullptr);
2668 }
2669
2670 if (!mComputedSize.IsEmpty()) {
2671 const bool imageOK = mKind != Kind::ImageLoadingContent ||
2672 ImageOk(mContent->AsElement()->State());
2673
2674 nsCOMPtr<imgIRequest> currentRequest = GetCurrentRequest();
2675
2676 const bool isViewTransition = mKind == Kind::ViewTransition;
2677 const bool isImageFromStyle = mKind != Kind::ImageLoadingContent &&
2678 mKind != Kind::XULImage && !isViewTransition;
2679 const bool drawAltFeedback = [&] {
2680 if (!imageOK) {
2681 return true;
2682 }
2683 if (isImageFromStyle && !GetImageFromStyle()->IsImageRequestType()) {
2684 // If we're a gradient, we don't need to draw alt feedback.
2685 return false;
2686 }
2687 if (isViewTransition) {
2688 // Same for view transitions.
2689 return false;
2690 }
2691 // XXX(seth): The SizeIsAvailable check here should not be necessary - the
2692 // intention is that a non-null mImage means we have a size, but there is
2693 // currently some code that violates this invariant.
2694 return !mImage || !SizeIsAvailable(currentRequest);
2695 }();
2696
2697 if (drawAltFeedback) {
2698 // No image yet, or image load failed. Draw the alt-text and an icon
2699 // indicating the status
2700 aLists.Content()->AppendNewToTop<nsDisplayAltFeedback>(aBuilder, this);
2701
2702 // This image is visible (we are being asked to paint it) but it's not
2703 // decoded yet. And we are not going to ask the image to draw, so this
2704 // may be the only chance to tell it that it should decode.
2705 if (currentRequest) {
2706 uint32_t status = 0;
2707 currentRequest->GetImageStatus(&status);
2708 if (!(status & imgIRequest::STATUS_DECODE_COMPLETE)) {
2709 MaybeDecodeForPredictedSize();
2710 }
2711 // Increase loading priority if the image is ready to be displayed.
2712 if (!(status & imgIRequest::STATUS_LOAD_COMPLETE)) {
2713 currentRequest->BoostPriority(imgIRequest::CATEGORY_DISPLAY);
2714 }
2715 }
2716 } else {
2717 if (mImage || isViewTransition) {
2718 aLists.Content()->AppendNewToTop<nsDisplayImage>(aBuilder, this);
2719 } else if (isImageFromStyle) {
2720 aLists.Content()->AppendNewToTop<nsDisplayGradient>(aBuilder, this);
2721 }
2722
2723 // If we were previously displaying an icon, we're not anymore
2724 if (mDisplayingIcon) {
2725 BrokenImageIcon::RemoveObserver(this);
2726 mDisplayingIcon = false;
2727 }
2728 }
2729 }
2730
2731 if (ShouldDisplaySelection()) {
2732 DisplaySelectionOverlay(aBuilder, aLists.Content(),
2733 nsISelectionDisplay::DISPLAY_IMAGES);
2734 }
2735
2736 BuildDisplayListForNonBlockChildren(aBuilder, aLists);
2737}
2738
2739bool nsImageFrame::ShouldDisplaySelection() {
2740 int16_t displaySelection = PresShell()->GetSelectionFlags();
2741 if (!(displaySelection & nsISelectionDisplay::DISPLAY_IMAGES)) {
2742 // no need to check the blue border, we cannot be drawn selected.
2743 return false;
2744 }
2745
2746 if (displaySelection != nsISelectionDisplay::DISPLAY_ALL) {
2747 return true;
2748 }
2749
2750 // If the image is currently resize target of the editor, don't draw the
2751 // selection overlay.
2752 HTMLEditor* htmlEditor = nsContentUtils::GetHTMLEditor(PresContext());
2753 if (!htmlEditor) {
2754 return true;
2755 }
2756
2757 return htmlEditor->GetResizerTarget() != mContent;
2758}
2759
2760nsImageMap* nsImageFrame::GetImageMap() {
2761 if (!mImageMap) {
2762 if (nsIContent* map = GetMapElement()) {
2763 mImageMap = MakeRefPtr<nsImageMap>();
2764 mImageMap->Init(this, map);
2765 }
2766 }
2767
2768 return mImageMap;
2769}
2770
2771bool nsImageFrame::IsServerImageMap() {
2772 return mContent->AsElement()->HasAttr(nsGkAtoms::ismap);
2773}
2774
2775CSSIntPoint nsImageFrame::TranslateEventCoords(const nsPoint& aPoint) const {
2776 const nsRect contentRect = GetContentRectRelativeToSelf();
2777 // Subtract out border and padding here so that the coordinates are
2778 // now relative to the content area of this frame.
2779 return CSSPixel::FromAppUnitsRounded(aPoint - contentRect.TopLeft());
2780}
2781
2782bool nsImageFrame::GetAnchorHREFTargetAndNode(nsIURI** aHref, nsString& aTarget,
2783 nsIContent** aNode) {
2784 aTarget.Truncate();
2785 *aHref = nullptr;
2786 *aNode = nullptr;
2787
2788 // Walk up the content tree, looking for an nsIDOMAnchorElement
2789 for (nsIContent* content = mContent->GetParent(); content;
2790 content = content->GetParent()) {
2791 nsCOMPtr<dom::Link> link = do_QueryInterface(content);
2792 if (!link) {
2793 continue;
2794 }
2795 if (nsCOMPtr<nsIURI> href = link->GetURI()) {
2796 href.forget(aHref);
2797 }
2798
2799 if (auto* anchor = HTMLAnchorElement::FromNode(content)) {
2800 anchor->GetLinkTarget(aTarget);
2801 }
2802 NS_ADDREF(*aNode = content)(*aNode = content)->AddRef();
2803 return *aHref != nullptr;
2804 }
2805 return false;
2806}
2807
2808bool nsImageFrame::IsLeafDynamic() const {
2809 if (mKind != Kind::ImageLoadingContent) {
2810 // Image frames created for "content: url()" could have an author-controlled
2811 // shadow root, we want to be a regular leaf for those.
2812 return true;
2813 }
2814 // For elements that create image frames, calling attachShadow() will throw,
2815 // so the only ShadowRoot we could ever have is a UA widget.
2816 const auto* shadow = mContent->AsElement()->GetShadowRoot();
2817 MOZ_ASSERT_IF(shadow, shadow->IsUAWidget())do { if (shadow) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(shadow->IsUAWidget())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(shadow->IsUAWidget()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("shadow->IsUAWidget()"
, "./../../../layout/generic/nsImageFrame.cpp", 2817); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "shadow->IsUAWidget()" ")"); do { MOZ_CrashSequence
(__null, 2817); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false); } } while (false)
;
2818 return !shadow;
2819}
2820
2821nsIContent* nsImageFrame::GetExplicitEventTargetContent(
2822 const WidgetEvent* aEvent /* = nullptr */) const {
2823 if (mImageMap && aEvent) {
2824 // XXX We need to make this special check for area element's capturing the
2825 // mouse due to bug 135040. Remove it once that's fixed.
2826 nsIContent* capturingContent = aEvent->HasMouseEventMessage()
2827 ? PresShell::GetCapturingContent()
2828 : nullptr;
2829 if (capturingContent && capturingContent->GetPrimaryFrame() == this) {
2830 return capturingContent;
2831 }
2832 const CSSIntPoint p = TranslateEventCoords(
2833 nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, RelativeTo{this}));
2834 if (auto* area = mImageMap->GetArea(p)) {
2835 return area;
2836 }
2837 }
2838 return nsIFrame::GetExplicitEventTargetContent(aEvent);
2839}
2840
2841// XXX what should clicks on transparent pixels do?
2842nsresult nsImageFrame::HandleEvent(nsPresContext* aPresContext,
2843 WidgetGUIEvent* aEvent,
2844 nsEventStatus* aEventStatus) {
2845 NS_ENSURE_ARG_POINTER(aEventStatus)do { if ((__builtin_expect(!!(!(aEventStatus)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aEventStatus" ") failed"
, nullptr, "./../../../layout/generic/nsImageFrame.cpp", 2845
); return NS_ERROR_INVALID_POINTER; } } while (false)
;
2846
2847 if ((aEvent->mMessage == ePointerClick &&
2848 aEvent->AsMouseEvent()->mButton == MouseButton::ePrimary) ||
2849 aEvent->mMessage == eMouseMove) {
2850 nsImageMap* map = GetImageMap();
2851 bool isServerMap = IsServerImageMap();
2852 if (map || isServerMap) {
2853 CSSIntPoint p =
2854 TranslateEventCoords(nsLayoutUtils::GetEventCoordinatesRelativeTo(
2855 aEvent, RelativeTo{this}));
2856
2857 // Even though client-side image map triggering happens
2858 // through content, we need to make sure we're not inside
2859 // (in case we deal with a case of both client-side and
2860 // sever-side on the same image - it happens!)
2861 const bool inside = map && map->GetArea(p);
2862
2863 if (!inside && isServerMap) {
2864 // Server side image maps use the href in a containing anchor
2865 // element to provide the basis for the destination url.
2866 nsCOMPtr<nsIURI> uri;
2867 nsAutoString target;
2868 nsCOMPtr<nsIContent> anchorNode;
2869 if (GetAnchorHREFTargetAndNode(getter_AddRefs(uri), target,
2870 getter_AddRefs(anchorNode))) {
2871 // XXX if the mouse is over/clicked in the border/padding area
2872 // we should probably just pretend nothing happened. Nav4
2873 // keeps the x,y coordinates positive as we do; IE doesn't
2874 // bother. Both of them send the click through even when the
2875 // mouse is over the border.
2876 if (p.x < 0) {
2877 p.x = 0;
2878 }
2879 if (p.y < 0) {
2880 p.y = 0;
2881 }
2882
2883 nsAutoCString spec;
2884 nsresult rv = uri->GetSpec(spec);
2885 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../layout/generic/nsImageFrame.cpp"
, 2885); return rv; } } while (false)
;
2886
2887 spec += nsPrintfCString("?%d,%d", p.x.value, p.y.value);
2888 rv = NS_MutateURI(uri).SetSpec(spec).Finalize(uri);
2889 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../layout/generic/nsImageFrame.cpp"
, 2889); return rv; } } while (false)
;
2890
2891 if (aEvent->mMessage == ePointerClick &&
2892 !aEvent->DefaultPrevented()) {
2893 *aEventStatus = nsEventStatus_eConsumeDoDefault;
2894 nsContentUtils::TriggerLinkClick(
2895 anchorNode, uri, target,
2896 aEvent->IsTrusted() ? UserNavigationInvolvement::Activation
2897 : UserNavigationInvolvement::None);
2898 } else {
2899 nsContentUtils::TriggerLinkMouseOver(anchorNode, uri, target);
2900 }
2901 }
2902 }
2903 }
2904 }
2905
2906 return nsAtomicContainerFrame::HandleEvent(aPresContext, aEvent,
2907 aEventStatus);
2908}
2909
2910nsIFrame::Cursor nsImageFrame::GetCursor(const nsPoint& aPoint) {
2911 nsImageMap* map = GetImageMap();
2912 if (!map) {
2913 return nsIFrame::GetCursor(aPoint);
2914 }
2915 const CSSIntPoint p = TranslateEventCoords(aPoint);
2916 HTMLAreaElement* area = map->GetArea(p);
2917 if (!area) {
2918 return nsIFrame::GetCursor(aPoint);
2919 }
2920
2921 // Use the cursor from the style of the *area* element.
2922 RefPtr<ComputedStyle> areaStyle =
2923 PresShell()->StyleSet()->ResolveStyleLazily(*area);
2924
2925 // This is one of the cases, like the <xul:tree> pseudo-style stuff, where we
2926 // get styles out of the blue and expect to trigger image loads for those.
2927 areaStyle->StartImageLoads(*PresContext()->Document());
2928
2929 StyleCursorKind kind = areaStyle->StyleUI()->Cursor().keyword;
2930 if (kind == StyleCursorKind::Auto) {
2931 kind = StyleCursorKind::Default;
2932 }
2933 return Cursor{kind, AllowCustomCursorImage::Yes, std::move(areaStyle)};
2934}
2935
2936nsresult nsImageFrame::AttributeChanged(int32_t aNameSpaceID,
2937 nsAtom* aAttribute,
2938 AttrModType aModType) {
2939 nsresult rv = nsAtomicContainerFrame::AttributeChanged(aNameSpaceID,
2940 aAttribute, aModType);
2941 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2942 return rv;
2943 }
2944 if (nsGkAtoms::alt == aAttribute) {
2945 PresShell()->FrameNeedsReflow(
2946 this, IntrinsicDirty::FrameAncestorsAndDescendants, NS_FRAME_IS_DIRTY);
2947 }
2948 if (mKind == Kind::XULImage && aAttribute == nsGkAtoms::src &&
2949 aNameSpaceID == kNameSpaceID_None) {
2950 UpdateXULImage();
2951 }
2952 return NS_OK;
2953}
2954
2955void nsImageFrame::OnVisibilityChange(
2956 Visibility aNewVisibility, const Maybe<OnNonvisible>& aNonvisibleAction) {
2957 if (mKind == Kind::ImageLoadingContent) {
2958 nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
2959 imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction);
2960 }
2961
2962 if (aNewVisibility == Visibility::ApproximatelyVisible &&
2963 PresShell()->IsActive()) {
2964 MaybeDecodeForPredictedSize();
2965 }
2966
2967 nsAtomicContainerFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
2968}
2969
2970void nsImageFrame::MarkIntrinsicISizesDirty() {
2971 // Recompute our intrinsic size and ratio. It's important that we pass 'true'
2972 // here -- that makes us recompute the intrinsic size *and* ratio, regardless
2973 // of their current value. Without that, EnsureIntrinsicSizeAndRatio assumes
2974 // the intrinsic ratio can't have changed in some cases; but if we're a
2975 // "content-visibility:auto" image that's being scrolled back into view, our
2976 // ratio may have changed from not-existing to existing, per spec text[1]
2977 // about suppressing the natural aspect ratio when size-contained.
2978 // [1] https://drafts.csswg.org/css-contain-2/#containment-size
2979 EnsureIntrinsicSizeAndRatio(true);
2980
2981 // Call superclass method:
2982 nsAtomicContainerFrame::MarkIntrinsicISizesDirty();
2983}
2984
2985#ifdef DEBUG_FRAME_DUMP1
2986nsresult nsImageFrame::GetFrameName(nsAString& aResult) const {
2987 return MakeFrameName(u"ImageFrame"_ns, aResult);
2988}
2989
2990void nsImageFrame::List(FILE* out, const char* aPrefix,
2991 ListFlags aFlags) const {
2992 nsCString str;
2993 ListGeneric(str, aPrefix, aFlags);
2994
2995 // output the img src url
2996 if (nsCOMPtr<imgIRequest> currentRequest = GetCurrentRequest()) {
2997 nsCOMPtr<nsIURI> uri = currentRequest->GetURI();
2998 nsAutoCString uristr;
2999 uri->GetAsciiSpec(uristr);
3000 str += nsPrintfCString(" [src=%s]", uristr.get());
3001 }
3002 fprintf_stderr(out, "%s\n", str.get());
3003}
3004#endif
3005
3006LogicalSides nsImageFrame::GetLogicalSkipSides() const {
3007 LogicalSides skip(mWritingMode);
3008 if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==(__builtin_expect(!!(StyleBorder()->mBoxDecorationBreak ==
StyleBoxDecorationBreak::Clone), 0))
3009 StyleBoxDecorationBreak::Clone)(__builtin_expect(!!(StyleBorder()->mBoxDecorationBreak ==
StyleBoxDecorationBreak::Clone), 0))
) {
3010 return skip;
3011 }
3012 if (GetPrevInFlow()) {
3013 skip += LogicalSide::BStart;
3014 }
3015 if (GetNextInFlow()) {
3016 skip += LogicalSide::BEnd;
3017 }
3018 return skip;
3019}
3020NS_IMPL_ISUPPORTS(nsImageListener, imgINotificationObserver)MozExternalRefCountType nsImageListener::AddRef(void) { static_assert
(!std::is_destructible_v<nsImageListener>, "Reference-counted class "
"nsImageListener" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../layout/generic/nsImageFrame.cpp"
, 3020); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 3020
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsImageListener" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsImageListener" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsImageListener\" != nullptr" " (" "Must specify a name" ")"
, "./../../../layout/generic/nsImageFrame.cpp", 3020); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "\"nsImageListener\" != nullptr" ") (" "Must specify a name"
")"); do { MOZ_CrashSequence(__null, 3020); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); if (!mRefCnt
.isThreadSafe) _mOwningThread.AssertOwnership("nsImageListener"
" not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef
((this), (count), ("nsImageListener"), (uint32_t)(sizeof(*this
))); return count; } MozExternalRefCountType nsImageListener::
Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../layout/generic/nsImageFrame.cpp"
, 3020); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 3020
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsImageListener" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsImageListener" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsImageListener\" != nullptr" " (" "Must specify a name" ")"
, "./../../../layout/generic/nsImageFrame.cpp", 3020); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "\"nsImageListener\" != nullptr" ") (" "Must specify a name"
")"); do { MOZ_CrashSequence(__null, 3020); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); if (!mRefCnt
.isThreadSafe) _mOwningThread.AssertOwnership("nsImageListener"
" not thread-safe"); const char* const nametmp = "nsImageListener"
; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (
nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return
0; } return count; } nsresult nsImageListener::QueryInterface
(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../layout/generic/nsImageFrame.cpp"
, 3020); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsImageListener, imgINotificationObserver
>, int32_t( reinterpret_cast<char*>(static_cast<imgINotificationObserver
*>((nsImageListener*)0x1000)) - reinterpret_cast<char*>
((nsImageListener*)0x1000))}, {&mozilla::detail::kImplementedIID
<nsImageListener, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
imgINotificationObserver*>((nsImageListener*)0x1000))) - reinterpret_cast
<char*>((nsImageListener*)0x1000))}, { nullptr, 0 } } ;
static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
3021
3022nsImageListener::nsImageListener(nsImageFrame* aFrame) : mFrame(aFrame) {}
3023
3024nsImageListener::~nsImageListener() = default;
3025
3026void nsImageListener::Notify(imgIRequest* aRequest, int32_t aType,
3027 const nsIntRect* aData) {
3028 if (!mFrame) {
3029 return;
3030 }
3031
3032 return mFrame->Notify(aRequest, aType, aData);
3033}
3034
3035static bool IsInAutoWidthTableCellForQuirk(nsIFrame* aFrame) {
3036 if (eCompatibility_NavQuirks != aFrame->PresContext()->CompatibilityMode()) {
3037 return false;
3038 }
3039 // Check if the parent of the closest nsBlockFrame has auto width.
3040 nsBlockFrame* ancestor = nsLayoutUtils::FindNearestBlockAncestor(aFrame);
3041 if (ancestor->Style()->GetPseudoType() == PseudoStyleType::MozCellContent) {
3042 // Assume direct parent is a table cell frame.
3043 nsIFrame* grandAncestor = static_cast<nsIFrame*>(ancestor->GetParent());
3044 return grandAncestor &&
3045 grandAncestor->StylePosition()
3046 ->GetWidth(AnchorPosResolutionParams::From(grandAncestor))
3047 ->IsAuto();
3048 }
3049 return false;
3050}
3051
3052void nsImageFrame::AddInlineMinISize(const IntrinsicSizeInput& aInput,
3053 InlineMinISizeData* aData) {
3054 // Note: we are one of the children that mPercentageBasisForChildren was
3055 // prepared for (i.e. our parent frame prepares the percentage basis for us,
3056 // not for our own children). Hence it's fine that we're resolving our
3057 // percentages sizes against this basis in IntrinsicForContainer().
3058 nscoord isize = nsLayoutUtils::IntrinsicForContainer(
3059 aInput.mContext, this, IntrinsicISizeType::MinISize,
3060 aInput.mPercentageBasisForChildren);
3061 bool canBreak = !IsInAutoWidthTableCellForQuirk(this);
3062 aData->DefaultAddInlineMinISize(this, isize, canBreak);
3063}
3064
3065void nsImageFrame::ReleaseGlobals() { BrokenImageIcon::Shutdown(); }