Bug Summary

File:Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/html/HTMLImageElement.cpp
Warning:line 647, column 12
Call argument for 'this' parameter is uncounted and unsafe

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple arm64-apple-ios26.2.0-simulator -O3 -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -Werror=implicit-function-declaration -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name UnifiedSource223.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=osx -analyzer-checker=security.insecureAPI.decodeValueOfObjCType -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 -mframe-pointer=non-leaf -ffp-contract=on -fno-rounding-math -target-sdk-version=26.2 -fdepfile-entry=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/SDKSettings.json -fcompatibility-qualified-id-block-type-checking -fvisibility-inlines-hidden-static-local-var -fno-modulemap-allow-subdirectory-search -fdefine-target-os-macros -enable-tlsdesc -target-cpu apple-m1 -target-feature +v8.4a -target-feature +aes -target-feature +altnzcv -target-feature +ccdp -target-feature +ccpp -target-feature +complxnum -target-feature +crc -target-feature +dotprod -target-feature +flagm -target-feature +fp-armv8 -target-feature +fp16fml -target-feature +fptoint -target-feature +fullfp16 -target-feature +jsconv -target-feature +lse -target-feature +neon -target-feature +pauth -target-feature +perfmon -target-feature +predres -target-feature +ras -target-feature +rcpc -target-feature +rdm -target-feature +sb -target-feature +sha2 -target-feature +sha3 -target-feature +specrestrict -target-feature +ssbs -target-abi darwinpcs -dwarf-ext-refs -fmodule-format=obj -debug-info-kind=standalone -dwarf-version=5 -debugger-tuning=lldb -fdebug-compilation-dir=/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore -target-linker-version 1230.1 -fcoverage-compilation-dir=/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore -resource-dir /Users/buildbot/Library/Developer/Toolchains/swift-webkit.xctoolchain/usr/lib/clang/21 -dependency-file /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/UnifiedSource223.d -skip-unused-modulemap-deps -MT dependencies -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk -iquote /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-generated-files.hmap -iquote /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-project-headers.hmap -isystem /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/PAL/ThirdParty/dav1d/include -isystem /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/SDKAdditions/usr/include -iframework /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/SDKAdditions/System/Library/Frameworks -iframework /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/iphonesimulator26.0-additions.sdk/System/Library/PrivateFrameworks -iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/Frameworks -include-pch /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/PrecompiledHeaders/SharedPrecompiledHeaders/11721353671419897710/WebCorePrefix.h.gch -D _LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE -D NDEBUG -D BUILDING_WEBKIT -D GL_SILENCE_DEPRECATION=1 -D GLES_SILENCE_DEPRECATION=1 -D __clang_analyzer__ -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-own-target-headers.hmap -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-all-target-headers.hmap -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/include -I PAL -I ForwardingHeaders -I /usr/include/libxslt -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include/libxml2 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/DerivedSources/WebCore -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/WebKitAdditions -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/WebKitAdditions -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/iphonesimulator26.0-additions.sdk/usr/local/include -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/webrtc -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/webrtc -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/webm -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/webm -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/PAL.build/PAL.build/DerivedSources -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/PAL.build/Release-iphonesimulator/PAL.build/DerivedSources -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/DerivedSources-normal/arm64 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/DerivedSources/arm64 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/DerivedSources -F/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator -F/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator -I/usr/local/include -stdlib=libc++ -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include/c++/v1 -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include -internal-isystem /Users/buildbot/Library/Developer/Toolchains/swift-webkit.xctoolchain/usr/lib/clang/21/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/Frameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/SubFrameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/Library/Frameworks -Wno-trigraphs -Werror -Wno-missing-field-initializers -Wmissing-prototypes -Wunreachable-code -Wnon-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wno-missing-braces -Wparentheses -Wswitch -Wunused-function -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion -Wint-conversion -Wbool-conversion -Wenum-conversion -Wno-float-conversion -Wnon-literal-null-conversion -Wobjc-literal-conversion -Wsign-compare -Wno-shorten-64-to-32 -Wnewline-eof -Wno-c++11-extensions -Wno-implicit-fallthrough -Wdeprecated-declarations -Winvalid-offsetof -Wno-sign-conversion -Winfinite-recursion -Wmove -Wcomma -Wblock-capture-autoreleasing -Wstrict-prototypes -Wrange-loop-analysis -Wno-semicolon-before-method-body -Wall -Wc99-designator -Wconditional-uninitialized -Wextra -Wdeprecated-enum-enum-conversion -Wdeprecated-enum-float-conversion -Wenum-float-conversion -Wfinal-dtor-non-final-class -Wformat=2 -Wmisleading-indentation -Wpointer-to-int-cast -Wreorder-init-list -Wundef -Wunused-but-set-variable -Wvla -Werror=unguarded-availability -Wno-elaborated-enum-base -Wcast-qual -Wchar-subscripts -Wextra-tokens -Winit-self -Wmissing-noreturn -Wpacked -Wpointer-arith -Wredundant-decls -Wwrite-strings -Wexit-time-destructors -Wglobal-constructors -Wtautological-compare -Wimplicit-fallthrough -Wvla -Wno-unknown-warning-option -Wliteral-conversion -Wthread-safety -Wno-profile-instr-out-of-date -Wno-profile-instr-unprofiled -Wno-backend-plugin -Wunsafe-buffer-usage -std=c++2b -fdeprecated-macro -ferror-limit 19 -fmacro-backtrace-limit=0 -fvisibility=hidden -fvisibility-inlines-hidden -stack-protector 1 -fblocks -fencode-extended-block-signature -fno-rtti -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fno-cxx-modules -fno-implicit-modules -fskip-odr-check-in-gmf -fpascal-strings -fmax-type-align=16 -fdiagnostics-show-note-include-stack -vectorize-loops -vectorize-slp -fsafe-buffer-usage-suggestions -analyzer-output=html -analyzer-config report-in-main-source-file=true -analyzer-config nullability:NoDiagnoseCallsToSystemHeaders=true -analyzer-checker optin.osx.cocoa.localizability.NonLocalizedStringChecker -analyzer-checker security.insecureAPI.UncheckedReturn -analyzer-checker security.insecureAPI.getpw -analyzer-checker security.insecureAPI.gets -analyzer-checker security.insecureAPI.mkstemp -analyzer-checker security.insecureAPI.mktemp -analyzer-disable-checker security.insecureAPI.rand -analyzer-disable-checker security.insecureAPI.strcpy -analyzer-checker security.insecureAPI.vfork -analyzer-disable-checker alpha,apiModeling,core,cplusplus,deadcode,debug,fuchsia,nullability,optin,osx,security,unix,webkit -analyzer-checker alpha.webkit.ForwardDeclChecker,alpha.webkit.MemoryUnsafeCastChecker,alpha.webkit.NoDeleteChecker,alpha.webkit.NoUncheckedPtrMemberChecker,alpha.webkit.NoUnretainedMemberChecker,alpha.webkit.RetainPtrCtorAdoptChecker,alpha.webkit.UncheckedCallArgsChecker,alpha.webkit.UncheckedLocalVarsChecker,alpha.webkit.UncountedCallArgsChecker,alpha.webkit.UncountedLocalVarsChecker,alpha.webkit.UnretainedCallArgsChecker,alpha.webkit.UnretainedLambdaCapturesChecker,alpha.webkit.UnretainedLocalVarsChecker,webkit.NoUncountedMemberChecker,webkit.RefCntblBaseVirtualDtor,webkit.UncountedLambdaCapturesChecker -analyzer-config max-nodes=10000000 -analyzer-config verbose-report-filename=true -fdwarf2-cfi-asm -o /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/UnifiedSource223.plist -x c++ /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/DerivedSources/WebCore/unified-sources/UnifiedSource223.cpp
1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * Copyright (C) 2004-2022 Apple Inc. All rights reserved.
5 * Copyright (C) 2010-2015 Google Inc. All rights reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23#include "config.h"
24#include "HTMLImageElement.h"
25
26#include "CSSPropertyNames.h"
27#include "CSSSerializationContext.h"
28#include "CSSValueKeywords.h"
29#include "CachedImage.h"
30#include "Chrome.h"
31#include "ChromeClient.h"
32#include "CommonAtomStrings.h"
33#include "ContainerNodeInlines.h"
34#include "Editor.h"
35#include "ElementChildIteratorInlines.h"
36#include "ElementRareData.h"
37#include "EventLoop.h"
38#include "EventNames.h"
39#include "HTMLAnchorElement.h"
40#include "HTMLAttachmentElement.h"
41#include "HTMLDocument.h"
42#include "HTMLFormElement.h"
43#include "HTMLImageLoader.h"
44#include "HTMLMapElement.h"
45#include "HTMLParserIdioms.h"
46#include "HTMLPictureElement.h"
47#include "HTMLSourceElement.h"
48#include "HTMLSrcsetParser.h"
49#include "JSRequestPriority.h"
50#include "LazyLoadImageObserver.h"
51#include "LocalFrameView.h"
52#include "Logging.h"
53#include "MIMETypeRegistry.h"
54#include "MediaQueryEvaluator.h"
55#include "MouseEvent.h"
56#include "NodeInlines.h"
57#include "NodeName.h"
58#include "NodeTraversal.h"
59#include "Page.h"
60#include "PlatformMouseEvent.h"
61#include "RenderBoxInlines.h"
62#include "RenderElementStyleInlines.h"
63#include "RenderImage.h"
64#include "RenderView.h"
65#include "RequestPriority.h"
66#include "ScriptController.h"
67#include "Settings.h"
68#include "ShadowRoot.h"
69#include "SizesAttributeParser.h"
70#include "StyleZoomPrimitivesInlines.h"
71#include <wtf/TZoneMallocInlines.h>
72#include <wtf/text/StringBuilder.h>
73
74#if ENABLE(SERVICE_CONTROLS)(defined ENABLE_SERVICE_CONTROLS && ENABLE_SERVICE_CONTROLS
)
75#include "ImageControlsMac.h"
76#endif
77
78#if ENABLE(SPATIAL_IMAGE_CONTROLS)(defined ENABLE_SPATIAL_IMAGE_CONTROLS && ENABLE_SPATIAL_IMAGE_CONTROLS
)
79#include "SpatialImageControls.h"
80#endif
81
82namespace WebCore {
83
84WTF_MAKE_TZONE_ALLOCATED_IMPL(HTMLImageElement)::bmalloc::api::HeapRef HTMLImageElement::s_heapRef; const TZoneSpecification
HTMLImageElement::s_heapSpec = { &HTMLImageElement::s_heapRef
, TZoneSpecification::encodeSize<HTMLImageElement>(), TZoneSpecification
::encodeAlignment<HTMLImageElement>(), TZoneSpecification
::encodeCategory<HTMLImageElement>(), ::bmalloc::api::compactAllocationMode
<HTMLImageElement>(), TZoneSpecification::encodeDescriptor
<HTMLImageElement>(), }; void* HTMLImageElement::operatorNewSlow
(size_t size) { if constexpr (::bmalloc::api::compactAllocationMode
<HTMLImageElement>() == CompactAllocationMode::Compact)
return ::bmalloc::api::tzoneAllocateCompactSlow(size, s_heapSpec
); return ::bmalloc::api::tzoneAllocateNonCompactSlow(size, s_heapSpec
); } using __makeBtzoneMallocedInlineMacroSemicolonifier __attribute__
((unused)) = int
;
85
86using namespace HTMLNames;
87
88HTMLImageElement::HTMLImageElement(const QualifiedName& tagName, Document& document, HTMLFormElement* form)
89 : HTMLElement(tagName, document, { TypeFlag::HasCustomStyleResolveCallbacks, TypeFlag::HasDidMoveToNewDocument })
90 , FormAssociatedElement(form)
91 , ActiveDOMObject(document)
92 , m_imageLoader(makeUniqueWithoutRefCountedCheck<HTMLImageLoader>(*this))
93 , m_imageDevicePixelRatio(1.0f)
94{
95 ASSERT(hasTagName(imgTag))((void)0);
96}
97
98Ref<HTMLImageElement> HTMLImageElement::create(Document& document)
99{
100 auto image = adoptRef(*new HTMLImageElement(imgTag, document));
101 image->suspendIfNeeded();
102 return image;
103}
104
105Ref<HTMLImageElement> HTMLImageElement::create(const QualifiedName& tagName, Document& document, HTMLFormElement* form)
106{
107 auto image = adoptRef(*new HTMLImageElement(tagName, document, form));
108 image->suspendIfNeeded();
109 return image;
110}
111
112HTMLImageElement::~HTMLImageElement()
113{
114 disconnectFromIntersectionObservers();
115 Ref document = this->document();
116 document->removeDynamicMediaQueryDependentImage(*this);
117 setForm(nullptr);
118#if ENABLE(ACCESSIBILITY_ANIMATION_CONTROL)(defined 1 && 1)
119 if (RefPtr page = document->page())
120 page->removeIndividuallyPlayingAnimationElement(*this);
121#endif
122}
123
124void HTMLImageElement::resetFormOwner()
125{
126 setForm(HTMLFormElement::findClosestFormAncestor(*this));
127}
128
129void HTMLImageElement::setFormInternal(RefPtr<HTMLFormElement>&& newForm)
130{
131 if (RefPtr form = FormAssociatedElement::form())
132 form->unregisterImgElement(*this);
133 FormAssociatedElement::setFormInternal(newForm.copyRef());
134 if (newForm)
135 newForm->registerImgElement(*this);
136}
137
138void HTMLImageElement::formOwnerRemovedFromTree(const Node& formRoot)
139{
140 Ref rootNode = traverseToRootNode(); // Do not rely on rootNode() because our IsInTreeScope can be outdated.
141 if (rootNode.ptr() != &formRoot)
142 setForm(nullptr);
143}
144
145Ref<HTMLImageElement> HTMLImageElement::createForLegacyFactoryFunction(Document& document, std::optional<unsigned> width, std::optional<unsigned> height)
146{
147 auto image = adoptRef(*new HTMLImageElement(imgTag, document));
148 if (width)
149 image->setUnsignedIntegralAttribute(widthAttr, width.value());
150 if (height)
151 image->setUnsignedIntegralAttribute(heightAttr, height.value());
152 image->suspendIfNeeded();
153 return image;
154}
155
156bool HTMLImageElement::hasPresentationalHintsForAttribute(const QualifiedName& name) const
157{
158 switch (name.nodeName()) {
159 case AttributeNames::widthAttr:
160 case AttributeNames::heightAttr:
161 case AttributeNames::borderAttr:
162 case AttributeNames::vspaceAttr:
163 case AttributeNames::hspaceAttr:
164 case AttributeNames::valignAttr:
165 return true;
166 default:
167 break;
168 }
169 return HTMLElement::hasPresentationalHintsForAttribute(name);
170}
171
172void HTMLImageElement::collectPresentationalHintsForAttribute(const QualifiedName& name, const AtomString& value, MutableStyleProperties& style)
173{
174 switch (name.nodeName()) {
175 case AttributeNames::widthAttr:
176 addHTMLMultiLengthToStyle(style, CSSPropertyWidth, value);
177 applyAspectRatioFromWidthAndHeightAttributesToStyle(value, attributeWithoutSynchronization(heightAttr), style);
178 break;
179 case AttributeNames::heightAttr:
180 addHTMLMultiLengthToStyle(style, CSSPropertyHeight, value);
181 applyAspectRatioFromWidthAndHeightAttributesToStyle(attributeWithoutSynchronization(widthAttr), value, style);
182 break;
183 case AttributeNames::borderAttr:
184 applyBorderAttributeToStyle(value, style);
185 break;
186 case AttributeNames::vspaceAttr:
187 addHTMLLengthToStyle(style, CSSPropertyMarginTop, value);
188 addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value);
189 break;
190 case AttributeNames::hspaceAttr:
191 addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value);
192 addHTMLLengthToStyle(style, CSSPropertyMarginRight, value);
193 break;
194 case AttributeNames::alignAttr:
195 applyAlignmentAttributeToStyle(value, style);
196 break;
197 case AttributeNames::valignAttr:
198 addPropertyToPresentationalHintStyle(style, CSSPropertyVerticalAlign, value);
199 break;
200 default:
201 HTMLElement::collectPresentationalHintsForAttribute(name, value, style);
202 break;
203 }
204}
205
206void HTMLImageElement::collectExtraStyleForPresentationalHints(MutableStyleProperties& style)
207{
208 RefPtr sourceElement = this->sourceElement();
209 if (!sourceElement)
210 return;
211 auto& widthAttrFromSource = sourceElement->attributeWithoutSynchronization(widthAttr);
212 auto& heightAttrFromSource = sourceElement->attributeWithoutSynchronization(heightAttr);
213 // If both width and height attributes of <source> is undefined, the style's value should not
214 // be overwritten. Otherwise, <souce> will overwrite it. I.e., if <source> only has one attribute
215 // defined, the other one and aspect-ratio shouldn't be set to auto.
216 if (widthAttrFromSource.isNull() && heightAttrFromSource.isNull())
217 return;
218
219 if (!widthAttrFromSource.isNull())
220 addHTMLLengthToStyle(style, CSSPropertyWidth, widthAttrFromSource);
221 else
222 addPropertyToPresentationalHintStyle(style, CSSPropertyWidth, CSSValueAuto);
223
224 if (!heightAttrFromSource.isNull())
225 addHTMLLengthToStyle(style, CSSPropertyHeight, heightAttrFromSource);
226 else
227 addPropertyToPresentationalHintStyle(style, CSSPropertyHeight, CSSValueAuto);
228
229 if (!widthAttrFromSource.isNull() && !heightAttrFromSource.isNull())
230 applyAspectRatioFromWidthAndHeightAttributesToStyle(widthAttrFromSource, heightAttrFromSource, style);
231 else
232 addPropertyToPresentationalHintStyle(style, CSSPropertyAspectRatio, CSSValueAuto);
233}
234
235const AtomString& HTMLImageElement::imageSourceURL() const
236{
237 return m_bestFitImageURL.isEmpty() ? attributeWithoutSynchronization(srcAttr) : m_bestFitImageURL;
238}
239
240const AtomString& HTMLImageElement::currentSrc()
241{
242 if (m_currentSrc.isNull()) {
243 if (!m_currentURL.isEmpty())
244 m_currentSrc = AtomString(m_currentURL.string());
245 }
246 return m_currentSrc;
247}
248
249void HTMLImageElement::setBestFitURLAndDPRFromImageCandidate(const ImageCandidate& candidate)
250{
251 m_bestFitImageURL = candidate.string.toAtomString();
252
253 auto& sourceURL = imageSourceURL();
254 // Only complete the URL if it's non-empty to avoid resolving "" to the document base URL.
255 m_currentURL = sourceURL.isEmpty() ? URL() : protect(document())->completeURL(sourceURL);
256
257 m_currentSrc = { };
258 if (candidate.density >= 0)
259 m_imageDevicePixelRatio = 1 / candidate.density;
260 if (CheckedPtr renderImage = dynamicDowncast<RenderImage>(renderer()))
261 renderImage->setImageDevicePixelRatio(m_imageDevicePixelRatio);
262}
263
264static String extractMIMETypeFromTypeAttributeForLookup(const String& typeAttribute)
265{
266 auto semicolonIndex = typeAttribute.find(';');
267 if (semicolonIndex == notFound)
268 return typeAttribute.trim(isASCIIWhitespace);
269 return StringView(typeAttribute).left(semicolonIndex).trim(isASCIIWhitespace<char16_t>).toStringWithoutCopying();
270}
271
272ImageCandidate HTMLImageElement::bestFitSourceFromPictureElement()
273{
274 RefPtr picture = pictureElement();
275 if (!picture)
276 return { };
277
278 ImageCandidate candidate;
279
280 for (RefPtr<Node> child = picture->firstChild(); child && child != this; child = child->nextSibling()) {
281 auto* source = dynamicDowncast<HTMLSourceElement>(*child);
282 if (!source)
283 continue;
284
285 auto& srcset = source->attributeWithoutSynchronization(srcsetAttr);
286 if (srcset.isEmpty())
287 continue;
288
289 auto& typeAttribute = source->attributeWithoutSynchronization(typeAttr);
290 if (!typeAttribute.isNull()) {
291 auto type = extractMIMETypeFromTypeAttributeForLookup(typeAttribute);
292 if (!type.isEmpty() && !MIMETypeRegistry::isSupportedImageVideoOrSVGMIMEType(type))
293 continue;
294 }
295
296 Ref document = this->document();
297 RefPtr documentElement = document->documentElement();
298 MQ::MediaQueryEvaluator evaluator { document->printing() ? printAtom() : screenAtom(), document.get(), documentElement ? documentElement->computedStyle() : nullptr };
299 auto& queries = source->parsedMediaAttribute(document.get());
300 LOG(MediaQueries, "HTMLImageElement %p bestFitSourceFromPictureElement evaluating media queries", this)((void)0);
301
302 auto result = evaluator.evaluate(queries);
303
304 if (!evaluator.collectDynamicDependencies(queries).isEmpty())
305 m_dynamicMediaQueryResults.append({ queries, result });
306
307 if (!result)
308 continue;
309
310 SizesAttributeParser sizesParser(source->attributeWithoutSynchronization(sizesAttr).string(), document.get());
311
312 m_dynamicMediaQueryResults.appendVector(sizesParser.dynamicMediaQueryResults());
313
314 auto sourceSize = sizesParser.effectiveSize();
315
316 candidate = bestFitSourceForImageAttributes(document->deviceScaleFactor(), nullAtom(), srcset, sourceSize, [&](auto& candidate) {
317 return m_imageLoader->shouldIgnoreCandidateWhenLoadingFromArchive(candidate);
318 });
319
320 if (!candidate.isEmpty()) {
321 setSourceElement(source);
322 break;
323 }
324 }
325
326 return candidate;
327}
328
329void HTMLImageElement::setIsUserAgentShadowRootResource()
330{
331 m_imageLoader->setElementIsUserAgentShadowRootResource(true);
332}
333
334void HTMLImageElement::evaluateDynamicMediaQueryDependencies()
335{
336 RefPtr documentElement = document().documentElement();
337 MQ::MediaQueryEvaluator evaluator { protect(document())->printing() ? printAtom() : screenAtom(), document(), documentElement ? documentElement->computedStyle() : nullptr };
338
339 auto hasChanges = [&] {
340 for (auto& results : m_dynamicMediaQueryResults) {
341 if (results.result != evaluator.evaluate(results.mediaQueryList))
342 return true;
343 }
344 return false;
345 }();
346
347 if (!hasChanges)
348 return;
349
350 selectImageSource(RelevantMutation::No);
351}
352
353void HTMLImageElement::selectImageSource(RelevantMutation relevantMutation)
354{
355 m_dynamicMediaQueryResults = { };
356 Ref document = this->document();
357 document->removeDynamicMediaQueryDependentImage(*this);
358
359 // First look for the best fit source from our <picture> parent if we have one.
360 ImageCandidate candidate = bestFitSourceFromPictureElement();
361 if (candidate.isEmpty()) {
362 setSourceElement(nullptr);
363 auto srcAttribute = attributeWithoutSynchronization(srcAttr);
364 auto srcsetAttribute = attributeWithoutSynchronization(srcsetAttr);
365 // This is extremely common case. We should not invoke SizesAttributeParser at all.
366 if (srcsetAttribute.isNull()) {
367 if (srcAttribute.isNull())
368 candidate = { };
369 else
370 candidate = ImageCandidate(StringViewWithUnderlyingString(srcAttribute, srcAttribute), DescriptorParsingResult(), ImageCandidate::SrcOrigin);
371 } else {
372 // If we don't have a <picture> or didn't find a source, then we use our own attributes.
373 SizesAttributeParser sizesParser(attributeWithoutSynchronization(sizesAttr).string(), document.get());
374 m_dynamicMediaQueryResults.appendVector(sizesParser.dynamicMediaQueryResults());
375 auto sourceSize = sizesParser.effectiveSize();
376 candidate = bestFitSourceForImageAttributes(document->deviceScaleFactor(), srcAttribute, srcsetAttribute, sourceSize, [&](auto& candidate) {
377 return m_imageLoader->shouldIgnoreCandidateWhenLoadingFromArchive(candidate);
378 });
379 }
380 }
381 setBestFitURLAndDPRFromImageCandidate(candidate);
382 m_imageLoader->updateFromElementIgnoringPreviousError(relevantMutation);
383
384 if (!m_dynamicMediaQueryResults.isEmpty())
385 document->addDynamicMediaQueryDependentImage(*this);
386}
387
388bool HTMLImageElement::hasLazyLoadableAttributeValue(StringView attributeValue)
389{
390 return equalLettersIgnoringASCIICase(attributeValue, "lazy"_s);
391}
392
393void HTMLImageElement::attributeChanged(const QualifiedName& name, const AtomString& oldValue, const AtomString& newValue, AttributeModificationReason attributeModificationReason)
394{
395 HTMLElement::attributeChanged(name, oldValue, newValue, attributeModificationReason);
396
397 switch (name.nodeName()) {
398 case AttributeNames::altAttr:
399 if (CheckedPtr renderImage = dynamicDowncast<RenderImage>(renderer()))
400 renderImage->updateAltText();
401 break;
402 case AttributeNames::srcAttr:
403 case AttributeNames::srcsetAttr:
404 case AttributeNames::sizesAttr:
405 if (oldValue != newValue)
406 selectImageSource(RelevantMutation::Yes);
407 else
408 m_imageLoader->updateFromElementIgnoringPreviousErrorToSameValue();
409 break;
410 case AttributeNames::usemapAttr: {
411 Ref treeScope = this->treeScope();
412 if (isInTreeScope() && !m_parsedUsemap.isNull())
413 treeScope->removeImageElementByUsemap(m_parsedUsemap, *this);
414 m_parsedUsemap = parseHTMLHashNameReference(newValue);
415 if (isInTreeScope() && !m_parsedUsemap.isNull())
416 treeScope->addImageElementByUsemap(m_parsedUsemap, *this);
417 break;
418 }
419 case AttributeNames::loadingAttr:
420 // No action needed for eager to lazy transition.
421 if (!hasLazyLoadableAttributeValue(newValue))
422 loadDeferredImage();
423 break;
424 case AttributeNames::referrerpolicyAttr: {
425 auto oldReferrerPolicy = parseReferrerPolicy(oldValue, ReferrerPolicySource::ReferrerPolicyAttribute).value_or(ReferrerPolicy::EmptyString);
426 auto newReferrerPolicy = parseReferrerPolicy(newValue, ReferrerPolicySource::ReferrerPolicyAttribute).value_or(ReferrerPolicy::EmptyString);
427 if (oldReferrerPolicy != newReferrerPolicy)
428 m_imageLoader->updateFromElementIgnoringPreviousError(RelevantMutation::Yes);
429 break;
430 }
431 case AttributeNames::crossoriginAttr:
432 if (parseCORSSettingsAttribute(oldValue) != parseCORSSettingsAttribute(newValue))
433 m_imageLoader->updateFromElementIgnoringPreviousError(RelevantMutation::Yes);
434 break;
435 case AttributeNames::nameAttr: {
436 bool willHaveName = !newValue.isEmpty();
437 if (RefPtr document = dynamicDowncast<HTMLDocument>(this->document()); document && m_hadNameBeforeAttributeChanged != willHaveName && isConnected() && !isInShadowTree()) {
438 const AtomString& id = getIdAttribute();
439 if (!id.isEmpty() && id != getNameAttribute()) {
440 if (willHaveName)
441 document->addDocumentNamedItem(id, *this);
442 else
443 document->removeDocumentNamedItem(id, *this);
444 }
445 }
446 m_hadNameBeforeAttributeChanged = willHaveName;
447 break;
448 }
449#if ENABLE(SPATIAL_IMAGE_CONTROLS)(defined ENABLE_SPATIAL_IMAGE_CONTROLS && ENABLE_SPATIAL_IMAGE_CONTROLS
)
450 case AttributeNames::controlsAttr:
451 SpatialImageControls::updateSpatialImageControls(*this);
452 break;
453#endif
454 default:
455 break;
456 }
457
458#if ENABLE(SERVICE_CONTROLS)(defined ENABLE_SERVICE_CONTROLS && ENABLE_SERVICE_CONTROLS
)
459 if (isImageMenuEnabled())
460 ImageControlsMac::updateImageControls(*this);
461#endif
462}
463
464void HTMLImageElement::loadDeferredImage()
465{
466 m_imageLoader->loadDeferredImage();
467}
468
469const AtomString& HTMLImageElement::altText() const
470{
471 // lets figure out the alt text.. magic stuff
472 // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
473 // also heavily discussed by Hixie on bugzilla
474 const AtomString& alt = attributeWithoutSynchronization(altAttr);
475 if (!alt.isNull())
476 return alt;
477 // fall back to title attribute
478 return attributeWithoutSynchronization(titleAttr);
479}
480
481RenderPtr<RenderElement> HTMLImageElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
482{
483 if (style.content().isData())
484 return RenderElement::createFor(*this, WTF::move(style));
485
486 return createRenderer<RenderImage>(RenderObject::Type::Image, *this, WTF::move(style), nullptr, m_imageDevicePixelRatio);
487}
488
489bool HTMLImageElement::isReplaced(const RenderStyle* style) const
490{
491 return !style || !style->content().isData();
492}
493
494bool HTMLImageElement::canStartSelection() const
495{
496 if (shadowRoot())
497 return HTMLElement::canStartSelection();
498
499 return false;
500}
501
502bool HTMLImageElement::isInteractiveContent() const
503{
504 return hasAttributeWithoutSynchronization(usemapAttr);
505}
506
507void HTMLImageElement::didAttachRenderers()
508{
509 CheckedPtr renderImage = dynamicDowncast<RenderImage>(renderer());
510 if (!renderImage)
511 return;
512 if (m_imageLoader->hasPendingBeforeLoadEvent())
513 return;
514
515#if ENABLE(SERVICE_CONTROLS)(defined ENABLE_SERVICE_CONTROLS && ENABLE_SERVICE_CONTROLS
)
516 ImageControlsMac::updateImageControls(*this);
517#endif
518
519 CheckedRef renderImageResource = renderImage->imageResource();
520 if (renderImageResource->cachedImage())
521 return;
522 renderImageResource->setCachedImage(protect(m_imageLoader->image()));
523
524 // If we have no image at all because we have no src attribute, set
525 // image height and width for the alt text instead.
526 if (!m_imageLoader->image() && !renderImageResource->cachedImage())
527 renderImage->setImageSizeForAltText();
528}
529
530Node::InsertedIntoAncestorResult HTMLImageElement::insertedIntoAncestor(InsertionType insertionType, ContainerNode& parentOfInsertedTree)
531{
532 FormAssociatedElement::elementInsertedIntoAncestor(*this, insertionType);
533 if (!form())
534 resetFormOwner();
535
536 // Insert needs to complete first, before we start updating the loader. Loader dispatches events which could result
537 // in callbacks back to this node.
538 Node::InsertedIntoAncestorResult insertNotificationRequest = HTMLElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
539
540 if (insertionType.treeScopeChanged && !m_parsedUsemap.isNull())
541 protect(treeScope())->addImageElementByUsemap(m_parsedUsemap, *this);
542
543 if (auto* parentPicture = dynamicDowncast<HTMLPictureElement>(parentOfInsertedTree); parentPicture && &parentOfInsertedTree == parentElement()) {
544 // FIXME: When the hack in HTMLConstructionSite::createHTMLElementOrFindCustomElementInterface to eagerly call setPictureElement is removed, we can just assert !pictureElement().
545 ASSERT(!pictureElement() || pictureElement() == &parentOfInsertedTree)((void)0);
546 setPictureElement(parentPicture);
547 selectImageSource(RelevantMutation::Yes);
548 return insertNotificationRequest;
549 }
550
551 // If we have been inserted from a renderer-less document,
552 // our loader may have not fetched the image, so do it now.
553 if (insertionType.connectedToDocument && !m_imageLoader->image())
554 m_imageLoader->updateFromElement();
555
556 return insertNotificationRequest;
557}
558
559void HTMLImageElement::removedFromAncestor(RemovalType removalType, ContainerNode& oldParentOfRemovedTree)
560{
561 if (removalType.treeScopeChanged && !m_parsedUsemap.isNull())
562 protect(oldParentOfRemovedTree.treeScope())->removeImageElementByUsemap(m_parsedUsemap, *this);
563
564 if (is<HTMLPictureElement>(oldParentOfRemovedTree) && !parentElement()) {
565 ASSERT(pictureElement() == &oldParentOfRemovedTree)((void)0);
566 setPictureElement(nullptr);
567 selectImageSource(RelevantMutation::Yes);
568 }
569
570 HTMLElement::removedFromAncestor(removalType, oldParentOfRemovedTree);
571 FormAssociatedElement::elementRemovedFromAncestor(*this, removalType);
572}
573
574HTMLPictureElement* HTMLImageElement::pictureElement() const
575{
576 return m_pictureElement.get();
577}
578
579void HTMLImageElement::setPictureElement(HTMLPictureElement* pictureElement)
580{
581 m_pictureElement = pictureElement;
582}
583
584unsigned HTMLImageElement::width()
585{
586 if (inRenderedDocument())
587 protect(document())->updateLayoutIgnorePendingStylesheets({ LayoutOptions::TreatContentVisibilityHiddenAsVisible, LayoutOptions::TreatContentVisibilityAutoAsVisible }, this);
588
589 if (!renderer()) {
590 // check the attribute first for an explicit pixel value
591 auto optionalWidth = parseHTMLNonNegativeInteger(attributeWithoutSynchronization(widthAttr));
592 if (optionalWidth)
593 return optionalWidth.value();
594
595 // if the image is available, use its width
596 if (m_imageLoader->image())
597 return m_imageLoader->image()->imageSizeForRenderer(nullptr, 1.0f).width().toUnsigned();
598 }
599
600 CheckedPtr box = renderBox();
601 if (!box)
602 return 0;
603 LayoutRect contentRect = box->contentBoxRect();
604 return Style::adjustLayoutUnitForAbsoluteZoom(contentRect.width(), *box).round();
605}
606
607unsigned HTMLImageElement::height()
608{
609 if (inRenderedDocument())
610 protect(document())->updateLayoutIgnorePendingStylesheets({ LayoutOptions::TreatContentVisibilityHiddenAsVisible, LayoutOptions::TreatContentVisibilityAutoAsVisible }, this);
611
612 if (!renderer()) {
613 // check the attribute first for an explicit pixel value
614 auto optionalHeight = parseHTMLNonNegativeInteger(attributeWithoutSynchronization(heightAttr));
615 if (optionalHeight)
616 return optionalHeight.value();
617
618 // if the image is available, use its height
619 if (m_imageLoader->image())
620 return m_imageLoader->image()->imageSizeForRenderer(nullptr, 1.0f).height().toUnsigned();
621 }
622
623 CheckedPtr box = renderBox();
624 if (!box)
625 return 0;
626 LayoutRect contentRect = box->contentBoxRect();
627 return Style::adjustLayoutUnitForAbsoluteZoom(contentRect.height(), *box).round();
628}
629
630float HTMLImageElement::effectiveImageDevicePixelRatio() const
631{
632 if (!m_imageLoader->image())
633 return 1.0f;
634
635 RefPtr image = m_imageLoader->image()->image();
636 if (image && image->drawsSVGImage())
637 return 1.0f;
638
639 return m_imageDevicePixelRatio;
640}
641
642unsigned HTMLImageElement::naturalWidth() const
643{
644 if (!m_imageLoader->image())
645 return 0;
646
647 return m_imageLoader->image()->unclampedImageSizeForRenderer(protect(renderer()).get(), effectiveImageDevicePixelRatio()).width().toUnsigned();
Call argument for 'this' parameter is uncounted and unsafe
648}
649
650unsigned HTMLImageElement::naturalHeight() const
651{
652 if (!m_imageLoader->image())
653 return 0;
654
655 return m_imageLoader->image()->unclampedImageSizeForRenderer(protect(renderer()).get(), effectiveImageDevicePixelRatio()).height().toUnsigned();
656}
657
658bool HTMLImageElement::isURLAttribute(const Attribute& attribute) const
659{
660 return attribute.name() == srcAttr
661 || attribute.name() == lowsrcAttr
662 || attribute.name() == longdescAttr
663 || (attribute.name() == usemapAttr && attribute.value().string()[0] != '#')
664 || HTMLElement::isURLAttribute(attribute);
665}
666
667bool HTMLImageElement::attributeContainsURL(const Attribute& attribute) const
668{
669 return attribute.name() == srcsetAttr
670 || HTMLElement::attributeContainsURL(attribute);
671}
672
673String HTMLImageElement::completeURLsInAttributeValue(const URL& base, const Attribute& attribute, ResolveURLs resolveURLs) const
674{
675 if (attribute.name() == srcsetAttr) {
676 if (resolveURLs == ResolveURLs::No)
677 return attribute.value();
678
679 Vector<ImageCandidate> imageCandidates = parseImageCandidatesFromSrcsetAttribute(StringView(attribute.value()));
680
681 if (resolveURLs == ResolveURLs::NoExcludingURLsForPrivacy) {
682 bool needsToResolveURLs = false;
683 for (const auto& candidate : imageCandidates) {
684 auto urlString = candidate.string.toString();
685 Ref document = this->document();
686 auto completeURL = base.isNull() ? document->completeURL(urlString) : URL(base, urlString);
687 if (document->shouldMaskURLForBindings(completeURL)) {
688 needsToResolveURLs = true;
689 break;
690 }
691 }
692
693 if (!needsToResolveURLs)
694 return attribute.value();
695 }
696
697 StringBuilder result;
698 for (const auto& candidate : imageCandidates) {
699 if (&candidate != &imageCandidates[0])
700 result.append(", "_s);
701 result.append(resolveURLStringIfNeeded(candidate.string.toString(), resolveURLs, base));
702 if (candidate.density != UninitializedDescriptor)
703 result.append(' ', candidate.density, 'x');
704 if (candidate.resourceWidth != UninitializedDescriptor)
705 result.append(' ', candidate.resourceWidth, 'w');
706 }
707
708 return result.toString();
709 }
710
711 return HTMLElement::completeURLsInAttributeValue(base, attribute, resolveURLs);
712}
713
714Attribute HTMLImageElement::replaceURLsInAttributeValue(const Attribute& attribute, const CSS::SerializationContext& serializationContext) const
715{
716 if (attribute.name() != srcsetAttr)
717 return attribute;
718
719 if (serializationContext.replacementURLStrings.isEmpty())
720 return attribute;
721
722 return Attribute { srcsetAttr, AtomString { replaceURLsInSrcsetAttribute(*this, StringView(attribute.value()), serializationContext) } };
723}
724
725bool HTMLImageElement::matchesUsemap(const AtomString& name) const
726{
727 return m_parsedUsemap == name;
728}
729
730RefPtr<HTMLMapElement> HTMLImageElement::associatedMapElement() const
731{
732 return protect(treeScope())->getImageMap(m_parsedUsemap);
733}
734
735int HTMLImageElement::x() const
736{
737 protect(document())->updateLayoutIgnorePendingStylesheets({ LayoutOptions::TreatContentVisibilityHiddenAsVisible, LayoutOptions::TreatContentVisibilityAutoAsVisible }, this);
738 CheckedPtr renderer = this->renderer();
739 if (!renderer)
740 return 0;
741
742 // FIXME: This doesn't work correctly with transforms.
743 return renderer->localToAbsolute().x();
744}
745
746int HTMLImageElement::y() const
747{
748 protect(document())->updateLayoutIgnorePendingStylesheets({ LayoutOptions::TreatContentVisibilityHiddenAsVisible, LayoutOptions::TreatContentVisibilityAutoAsVisible }, this);
749 CheckedPtr renderer = this->renderer();
750 if (!renderer)
751 return 0;
752
753 // FIXME: This doesn't work correctly with transforms.
754 return renderer->localToAbsolute().y();
755}
756
757bool HTMLImageElement::complete() const
758{
759 return m_imageLoader->imageComplete();
760}
761
762String HTMLImageElement::decoding() const
763{
764 switch (decodingMode()) {
765 case DecodingMode::Auto:
766 break;
767 case DecodingMode::Synchronous:
768 return "sync"_s;
769 case DecodingMode::Asynchronous:
770 return "async"_s;
771 }
772 return autoAtom();
773}
774
775DecodingMode HTMLImageElement::decodingMode() const
776{
777 const AtomString& decodingMode = attributeWithoutSynchronization(decodingAttr);
778 if (equalLettersIgnoringASCIICase(decodingMode, "sync"_s))
779 return DecodingMode::Synchronous;
780 if (equalLettersIgnoringASCIICase(decodingMode, "async"_s))
781 return DecodingMode::Asynchronous;
782 return DecodingMode::Auto;
783}
784
785void HTMLImageElement::decode(Ref<DeferredPromise>&& promise)
786{
787 return m_imageLoader->decode(WTF::move(promise));
788}
789
790void HTMLImageElement::addSubresourceAttributeURLs(ListHashSet<URL>& urls) const
791{
792 HTMLElement::addSubresourceAttributeURLs(urls);
793
794 Ref document = this->document();
795 addSubresourceURL(urls, document->completeURL(imageSourceURL()));
796 // FIXME: What about when the usemap attribute begins with "#"?
797 addSubresourceURL(urls, document->completeURL(attributeWithoutSynchronization(usemapAttr)));
798}
799
800void HTMLImageElement::addCandidateSubresourceURLs(ListHashSet<URL>& urls) const
801{
802 auto src = attributeWithoutSynchronization(srcAttr);
803 if (!src.isEmpty()) {
804 URL url { resolveURLStringIfNeeded(src) };
805 if (!url.isNull())
806 urls.add(url);
807 }
808
809 getURLsFromSrcsetAttribute(*this, attributeWithoutSynchronization(srcsetAttr), urls);
810}
811
812void HTMLImageElement::didMoveToNewDocument(Document& oldDocument, Document& newDocument)
813{
814 ActiveDOMObject::didMoveToNewDocument(newDocument);
815 oldDocument.removeDynamicMediaQueryDependentImage(*this);
816
817 selectImageSource(RelevantMutation::No);
818 m_imageLoader->elementDidMoveToNewDocument(oldDocument);
819 HTMLElement::didMoveToNewDocument(oldDocument, newDocument);
820 if (RefPtr element = pictureElement())
821 element->sourcesChanged();
822}
823
824bool HTMLImageElement::isServerMap() const
825{
826 if (!hasAttributeWithoutSynchronization(ismapAttr))
827 return false;
828
829 const AtomString& usemap = attributeWithoutSynchronization(usemapAttr);
830
831 // If the usemap attribute starts with '#', it refers to a map element in the document.
832 if (usemap.string()[0] == '#')
833 return false;
834
835 return protect(document())->completeURL(usemap).isEmpty();
836}
837
838String HTMLImageElement::crossOrigin() const
839{
840 return parseCORSSettingsAttribute(attributeWithoutSynchronization(crossoriginAttr));
841}
842
843bool HTMLImageElement::allowsOrientationOverride() const
844{
845 if (auto* cachedImage = this->cachedImage())
846 return cachedImage->allowsOrientationOverride();
847 return true;
848}
849
850Image* HTMLImageElement::image() const
851{
852 if (auto* cachedImage = this->cachedImage())
853 return cachedImage->image();
854 return nullptr;
855}
856
857bool HTMLImageElement::allowsAnimation() const
858{
859 if (RefPtr image = this->image())
860 return image->allowsAnimation().value_or(document().page() ? document().page()->imageAnimationEnabled() : false);
861 return false;
862}
863
864#if ENABLE(ACCESSIBILITY_ANIMATION_CONTROL)(defined 1 && 1)
865void HTMLImageElement::setAllowsAnimation(std::optional<bool> allowsAnimation)
866{
867 if (RefPtr image = this->image()) {
868 image->setAllowsAnimation(allowsAnimation);
869 if (CheckedPtr renderer = this->renderer())
870 renderer->repaint();
871
872 if (RefPtr page = document().page()) {
873 if (allowsAnimation.value_or(false))
874 page->addIndividuallyPlayingAnimationElement(*this);
875 else
876 page->removeIndividuallyPlayingAnimationElement(*this);
877 }
878 }
879}
880#endif
881
882#if ENABLE(ATTACHMENT_ELEMENT)(defined 1 && 1)
883
884void HTMLImageElement::setAttachmentElement(Ref<HTMLAttachmentElement>&& attachment)
885{
886 AttachmentAssociatedElement::setAttachmentElement(WTF::move(attachment));
887
888#if ENABLE(SERVICE_CONTROLS)(defined ENABLE_SERVICE_CONTROLS && ENABLE_SERVICE_CONTROLS
)
889 bool shouldEnableImageMenu = true;
890#if ENABLE(MULTI_REPRESENTATION_HEIC)(defined ENABLE_MULTI_REPRESENTATION_HEIC && ENABLE_MULTI_REPRESENTATION_HEIC
)
891 shouldEnableImageMenu = !isMultiRepresentationHEIC();
892#endif
893 setImageMenuEnabled(shouldEnableImageMenu);
894#endif // ENABLE(SERVICE_CONTROLS)
895}
896
897#endif // ENABLE(ATTACHMENT_ELEMENT)
898
899#if ENABLE(SERVICE_CONTROLS)(defined ENABLE_SERVICE_CONTROLS && ENABLE_SERVICE_CONTROLS
)
900bool HTMLImageElement::childShouldCreateRenderer(const Node& child) const
901{
902 return hasShadowRootParent(child) && HTMLElement::childShouldCreateRenderer(child);
903}
904#endif
905
906#if ENABLE(CONTENT_CHANGE_OBSERVER)(defined 1 && 1)
907// FIXME: We should find a better place for the touch callout logic. See rdar://problem/48937767.
908bool HTMLImageElement::willRespondToMouseClickEventsWithEditability(Editability editability, IgnoreTouchCallout ignoreTouchCallout) const
909{
910#if ENABLE(WEBKIT_TOUCH_CALLOUT_CSS_PROPERTY)(defined 1 && 1)
911 CheckedPtr renderer = this->renderer();
912 bool touchCalloutIsDefault = !renderer || renderer->style().touchCallout() == Style::WebkitTouchCallout::Default;
913#else
914 bool touchCalloutIsDefault = true;
915#endif
916
917 if (ignoreTouchCallout == IgnoreTouchCallout::No && touchCalloutIsDefault)
918 return true;
919 return HTMLElement::willRespondToMouseClickEventsWithEditability(editability);
920}
921
922bool HTMLImageElement::willRespondToMouseClickEventsWithEditability(Editability editability) const
923{
924 return willRespondToMouseClickEventsWithEditability(editability, IgnoreTouchCallout::No);
925}
926#endif
927
928#if USE(SYSTEM_PREVIEW)(defined 1 && 1)
929bool HTMLImageElement::isSystemPreviewImage() const
930{
931 if (!document().settings().systemPreviewEnabled())
932 return false;
933
934 auto* parent = parentElement();
935 if (auto* anchorElement = dynamicDowncast<HTMLAnchorElement>(parent))
936 return anchorElement->isSystemPreviewLink();
937 if (auto* pictureElement = dynamicDowncast<HTMLPictureElement>(parent))
938 return pictureElement->isSystemPreviewImage();
939 return false;
940}
941#endif
942
943#if ENABLE(MULTI_REPRESENTATION_HEIC)(defined ENABLE_MULTI_REPRESENTATION_HEIC && ENABLE_MULTI_REPRESENTATION_HEIC
)
944bool HTMLImageElement::isMultiRepresentationHEIC() const
945{
946 if (!m_sourceElement)
947 return false;
948
949 auto& typeAttribute = m_sourceElement->attributeWithoutSynchronization(typeAttr);
950 return typeAttribute == "image/x-apple-adaptive-glyph"_s;
951}
952#endif
953
954void HTMLImageElement::copyNonAttributePropertiesFromElement(const Element& source)
955{
956#if ENABLE(ATTACHMENT_ELEMENT)(defined 1 && 1)
957 auto& sourceImage = downcast<HTMLImageElement>(source);
958 copyAttachmentAssociatedPropertiesFromElement(sourceImage);
959#endif
960 Element::copyNonAttributePropertiesFromElement(source);
961}
962
963CachedImage* HTMLImageElement::cachedImage() const
964{
965 return m_imageLoader->image();
966}
967
968void HTMLImageElement::setLoadManually(bool loadManually)
969{
970 m_imageLoader->setLoadManually(loadManually);
971}
972
973bool HTMLImageElement::virtualHasPendingActivity() const
974{
975 return m_imageLoader->hasPendingActivity();
976}
977
978size_t HTMLImageElement::pendingDecodePromisesCountForTesting() const
979{
980 return m_imageLoader->pendingDecodePromisesCountForTesting();
981}
982
983bool HTMLImageElement::usesSrcsetOrPicture() const
984{
985 return !attributeWithoutSynchronization(srcsetAttr).isNull() || !!pictureElement();
986}
987
988AtomString HTMLImageElement::srcsetForBindings() const
989{
990 return getAttributeForBindings(srcsetAttr);
991}
992
993bool HTMLImageElement::isDeferred() const
994{
995 return m_imageLoader->isDeferred();
996}
997
998bool HTMLImageElement::isLazyLoadable() const
999{
1000 if (!document().frame() || !protect(document().frame()->script())->canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript))
1001 return false;
1002 return hasLazyLoadableAttributeValue(attributeWithoutSynchronization(HTMLNames::loadingAttr));
1003}
1004
1005String HTMLImageElement::referrerPolicyForBindings() const
1006{
1007 return referrerPolicyToString(referrerPolicy());
1008}
1009
1010ReferrerPolicy HTMLImageElement::referrerPolicy() const
1011{
1012 return parseReferrerPolicy(attributeWithoutSynchronization(referrerpolicyAttr), ReferrerPolicySource::ReferrerPolicyAttribute).value_or(ReferrerPolicy::EmptyString);
1013}
1014
1015HTMLSourceElement* HTMLImageElement::sourceElement() const
1016{
1017 return m_sourceElement.get();
1018}
1019
1020void HTMLImageElement::setSourceElement(HTMLSourceElement* sourceElement)
1021{
1022 if (m_sourceElement == sourceElement)
1023 return;
1024 m_sourceElement = sourceElement;
1025 invalidateAttributeMapping();
1026}
1027
1028void HTMLImageElement::invalidateAttributeMapping()
1029{
1030 ensureUniqueElementData().setPresentationalHintStyleIsDirty(true);
1031 invalidateStyle();
1032}
1033
1034Ref<Element> HTMLImageElement::cloneElementWithoutAttributesAndChildren(Document& document, CustomElementRegistry*) const
1035{
1036 auto clone = create(document);
1037#if ENABLE(ATTACHMENT_ELEMENT)(defined 1 && 1)
1038 cloneAttachmentAssociatedElementWithoutAttributesAndChildren(clone, document);
1039#endif
1040 return clone;
1041}
1042
1043String HTMLImageElement::fetchPriorityForBindings() const
1044{
1045 return convertEnumerationToString(fetchPriority());
1046}
1047
1048RequestPriority HTMLImageElement::fetchPriority() const
1049{
1050 return parseEnumerationFromString<RequestPriority>(attributeWithoutSynchronization(fetchpriorityAttr)).value_or(RequestPriority::Auto);
1051}
1052
1053bool HTMLImageElement::originClean(const SecurityOrigin& origin) const
1054{
1055 UNUSED_PARAM(origin)(void)origin;
1056
1057 auto* cachedImage = this->cachedImage();
1058 if (!cachedImage)
1059 return true;
1060
1061 RefPtr image = cachedImage->image();
1062 if (!image)
1063 return true;
1064
1065 if (image->renderingTaintsOrigin())
1066 return false;
1067
1068 if (image->sourceURL().protocolIsData())
1069 return true;
1070
1071 if (cachedImage->isCORSCrossOrigin())
1072 return false;
1073
1074 ASSERT(cachedImage->origin())((void)0);
1075 ASSERT(origin.toString() == cachedImage->origin()->toString())((void)0);
1076 return true;
1077}
1078
1079IntersectionObserverData& HTMLImageElement::ensureIntersectionObserverData()
1080{
1081 if (!m_intersectionObserverData)
1082 m_intersectionObserverData = makeUnique<IntersectionObserverData>();
1083 return *m_intersectionObserverData;
1084}
1085
1086IntersectionObserverData* HTMLImageElement::intersectionObserverDataIfExists() const
1087{
1088 return m_intersectionObserverData.get();
1089}
1090
1091}