Bug Summary

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