Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsImageFrame.cpp
Warning:line 2463, column 11
Value stored to 'flags' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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