Bug Summary

File:Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/rendering/RenderInline.cpp
Warning:line 884, column 82
Call argument 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 UnifiedSource413.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/UnifiedSource413.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/UnifiedSource413.plist -x c++ /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/DerivedSources/WebCore/unified-sources/UnifiedSource413.cpp
1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * Copyright (C) 2003-2025 Apple Inc. All rights reserved.
5 * Copyright (C) 2014 Google Inc. All rights reserved.
6 * Copyright (C) 2025 Samuel Weinig <sam@webkit.org>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25#include "config.h"
26#include "RenderInline.h"
27
28#include "Chrome.h"
29#include "FloatQuad.h"
30#include "FrameSelection.h"
31#include "GraphicsContext.h"
32#include "HitTestResult.h"
33#include "InlineIteratorBoxInlines.h"
34#include "InlineIteratorInlineBox.h"
35#include "InlineIteratorLineBox.h"
36#include "LayoutIntegrationLineLayout.h"
37#include "LegacyInlineTextBox.h"
38#include "OutlinePainter.h"
39#include "RenderBlock.h"
40#include "RenderBoxInlines.h"
41#include "RenderChildIterator.h"
42#include "RenderElementStyleInlines.h"
43#include "RenderElementInlines.h"
44#include "RenderFragmentedFlow.h"
45#include "RenderGeometryMap.h"
46#include "RenderIterator.h"
47#include "RenderLayer.h"
48#include "RenderLayoutState.h"
49#include "RenderLineBreak.h"
50#include "RenderListMarker.h"
51#include "RenderObjectInlines.h"
52#include "RenderTable.h"
53#include "RenderTheme.h"
54#include "RenderTreeBuilder.h"
55#include "RenderView.h"
56#include "Settings.h"
57#include "TransformState.h"
58#include "VisiblePosition.h"
59#include <wtf/SetForScope.h>
60#include <wtf/TZoneMallocInlines.h>
61
62namespace WebCore {
63
64WTF_MAKE_TZONE_ALLOCATED_IMPL(RenderInline)::bmalloc::api::HeapRef RenderInline::s_heapRef; const TZoneSpecification
RenderInline::s_heapSpec = { &RenderInline::s_heapRef, TZoneSpecification
::encodeSize<RenderInline>(), TZoneSpecification::encodeAlignment
<RenderInline>(), TZoneSpecification::encodeCategory<
RenderInline>(), ::bmalloc::api::compactAllocationMode<
RenderInline>(), TZoneSpecification::encodeDescriptor<RenderInline
>(), }; void* RenderInline::operatorNewSlow(size_t size) {
if constexpr (::bmalloc::api::compactAllocationMode<RenderInline
>() == CompactAllocationMode::Compact) return ::bmalloc::api
::tzoneAllocateCompactSlow(size, s_heapSpec); return ::bmalloc
::api::tzoneAllocateNonCompactSlow(size, s_heapSpec); } using
__makeBtzoneMallocedInlineMacroSemicolonifier __attribute__(
(unused)) = int
;
65
66RenderInline::RenderInline(Type type, Element& element, RenderStyle&& style)
67 : RenderBoxModelObject(type, element, WTF::move(style), TypeFlag::IsRenderInline, { })
68{
69 setChildrenInline(true);
70 ASSERT(isRenderInline())((void)0);
71}
72
73RenderInline::RenderInline(Type type, Document& document, RenderStyle&& style)
74 : RenderBoxModelObject(type, document, WTF::move(style), TypeFlag::IsRenderInline, { })
75{
76 setChildrenInline(true);
77 ASSERT(isRenderInline())((void)0);
78}
79
80RenderInline::~RenderInline() = default;
81
82void RenderInline::willBeDestroyed()
83{
84#if ASSERT_ENABLED0
85 // Make sure we do not retain "this" in the continuation outline table map of our containing blocks.
86 if (parent() && style().usedVisibility() == Visibility::Visible && hasOutline()) {
87 bool containingBlockPaintsContinuationOutline = continuation() || isContinuation();
88 if (containingBlockPaintsContinuationOutline) {
89 if (RenderBlock* cb = containingBlock()) {
90 if (RenderBlock* cbCb = cb->containingBlock())
91 ASSERT(!cbCb->paintsContinuationOutline(*this))((void)0);
92 }
93 }
94 }
95#endif // ASSERT_ENABLED
96
97 if (!renderTreeBeingDestroyed()) {
98 if (auto* inlineBox = firstLegacyInlineBox()) {
99 // We can't wait for RenderBoxModelObject::destroy to clear the selection,
100 // because by then we will have nuked the line boxes.
101 if (isSelectionBorder())
102 frame().selection().setNeedsSelectionUpdate();
103
104 // If line boxes are contained inside a root, that means we're an inline.
105 // In that case, we need to remove all the line boxes so that the parent
106 // lines aren't pointing to deleted children. If the first line box does
107 // not have a parent that means they are either already disconnected or
108 // root lines that can just be destroyed without disconnecting.
109 if (inlineBox->parent()) {
110 for (auto* box = inlineBox; box; box = box->nextLineBox())
111 box->removeFromParent();
112 }
113 } else if (auto* parent = this->parent(); parent && parent->isSVGRenderer())
114 parent->dirtyLineFromChangedChild();
115 }
116
117 m_legacyLineBoxes.deleteLineBoxes();
118
119 RenderBoxModelObject::willBeDestroyed();
120}
121
122void RenderInline::updateFromStyle()
123{
124 RenderBoxModelObject::updateFromStyle();
125
126 // FIXME: Support transforms and reflections on inline flows someday.
127 setHasTransformRelatedProperty(false);
128 setHasReflection(false);
129}
130
131static RenderElement* NODELETE[[clang::annotate_type("webkit.nodelete")]] inFlowPositionedInlineAncestor(RenderElement* p)
132{
133 while (p && p->isRenderInline()) {
134 if (p->isInFlowPositioned())
135 return p;
136 p = p->parent();
137 }
138 return nullptr;
139}
140
141static void updateStyleOfAnonymousBlockContinuations(const RenderBlock& block, const RenderStyle* newStyle, const RenderStyle* oldStyle)
142{
143 // If any descendant blocks exist then they will be in the next anonymous block and its siblings.
144 for (RenderBox* box = block.nextSiblingBox(); box && box->isAnonymousBlock(); box = box->nextSiblingBox()) {
145 if (box->style().position() == newStyle->position())
146 continue;
147
148 CheckedPtr block = dynamicDowncast<RenderBlock>(*box);
149 if (!block)
150 continue;
151
152 if (!block->isContinuation())
153 continue;
154
155 // If we are no longer in-flow positioned but our descendant block(s) still have an in-flow positioned ancestor then
156 // their containing anonymous block should keep its in-flow positioning.
157 RenderInline* continuation = block->inlineContinuation();
158 if (oldStyle->hasInFlowPosition() && inFlowPositionedInlineAncestor(continuation))
159 continue;
160 auto blockStyle = RenderStyle::createAnonymousStyleWithDisplay(block->style(), Style::DisplayType::BlockFlow);
161 blockStyle.setPosition(newStyle->position());
162 block->setStyle(WTF::move(blockStyle));
163 }
164}
165
166void RenderInline::styleWillChange(Style::Difference diff, const RenderStyle& newStyle)
167{
168 RenderBoxModelObject::styleWillChange(diff, newStyle);
169
170 // RenderInlines forward their absolute positioned descendants to their (non-anonymous) containing block.
171 // Check if this non-anonymous containing block can hold the absolute positioned elements when the inline is no longer positioned.
172 CheckedPtr container = containingBlock();
173 if (!container)
174 return;
175
176 const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr;
177 if (oldStyle)
178 removeOutOfFlowBoxesIfNeededOnStyleChange(*container, *oldStyle, newStyle);
179}
180
181void RenderInline::styleDidChange(Style::Difference diff, const RenderStyle* oldStyle)
182{
183 RenderBoxModelObject::styleDidChange(diff, oldStyle);
184
185 // Ensure that all of the split inlines pick up the new style. We
186 // only do this if we're an inline, since we don't want to propagate
187 // a block's style to the other inlines.
188 // e.g., <font>foo <h4>goo</h4> moo</font>. The <font> inlines before
189 // and after the block share the same style, but the block doesn't
190 // need to pass its style on to anyone else.
191 auto& newStyle = style();
192 RenderInline* continuation = inlineContinuation();
193 if (continuation && !isContinuation()) {
194 for (RenderInline* currCont = continuation; currCont; currCont = currCont->inlineContinuation())
195 currCont->setStyle(RenderStyle::clone(newStyle));
196 // If an inline's in-flow positioning has changed and it is part of an active continuation as a descendant of an anonymous containing block,
197 // then any descendant blocks will need to change their in-flow positioning accordingly.
198 // Do this by updating the position of the descendant blocks' containing anonymous blocks - there may be more than one.
199 if (containingBlock()->isAnonymousBlock() && oldStyle && newStyle.position() != oldStyle->position() && (newStyle.hasInFlowPosition() || oldStyle->hasInFlowPosition()))
200 updateStyleOfAnonymousBlockContinuations(*containingBlock(), &newStyle, oldStyle);
201 }
202
203 propagateStyleToAnonymousChildren(StylePropagationType::AllChildren);
204}
205
206bool RenderInline::mayAffectLayout() const
207{
208 auto* parentStyle = &parent()->style();
209 auto* parentRenderInline = dynamicDowncast<RenderInline>(*parent());
210 auto hasHardLineBreakChildOnly = firstChild() && firstChild() == lastChild() && firstChild()->isBR();
211 bool checkFonts = document().inNoQuirksMode();
212 auto mayAffectLayout = (parentRenderInline && parentRenderInline->mayAffectLayout())
213 || (parentRenderInline && !WTF::holdsAlternative<CSS::Keyword::Baseline>(parentStyle->verticalAlign()))
214 || !WTF::holdsAlternative<CSS::Keyword::Baseline>(style().verticalAlign())
215 || !style().textEmphasisStyle().isNone()
216 || (checkFonts && (!parentStyle->fontCascade().metricsOfPrimaryFont().hasIdenticalAscentDescentAndLineGap(style().fontCascade().metricsOfPrimaryFont())
217 || parentStyle->lineHeight() != style().lineHeight()))
218 || hasHardLineBreakChildOnly;
219
220 if (!mayAffectLayout && checkFonts) {
221 // Have to check the first line style as well.
222 parentStyle = &parent()->firstLineStyle();
223 auto& childStyle = firstLineStyle();
224 mayAffectLayout = !parentStyle->fontCascade().metricsOfPrimaryFont().hasIdenticalAscentDescentAndLineGap(childStyle.fontCascade().metricsOfPrimaryFont())
225 || !WTF::holdsAlternative<CSS::Keyword::Baseline>(childStyle.verticalAlign())
226 || parentStyle->lineHeight() != childStyle.lineHeight();
227 }
228 return mayAffectLayout;
229}
230
231void RenderInline::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
232{
233 if (auto* lineLayout = LayoutIntegration::LineLayout::containing(*this))
234 lineLayout->paint(paintInfo, paintOffset, this);
235}
236
237template<typename GeneratorContext>
238void RenderInline::generateLineBoxRects(GeneratorContext& context) const
239{
240 if (auto* lineLayout = LayoutIntegration::LineLayout::containing(*this)) {
241 auto inlineBoxRects = lineLayout->collectInlineBoxRects(*this);
242 if (inlineBoxRects.isEmpty()) {
243 context.addRect({ });
244 return;
245 }
246 for (auto inlineRect : inlineBoxRects)
247 context.addRect(inlineRect);
248 return;
249 }
250 if (auto* curr = firstLegacyInlineBox()) {
251 for (; curr; curr = curr->nextLineBox())
252 context.addRect(FloatRect(curr->topLeft(), curr->size()));
253 } else
254 context.addRect(FloatRect());
255}
256
257class AbsoluteRectsGeneratorContext {
258public:
259 AbsoluteRectsGeneratorContext(Vector<LayoutRect>& rects, const LayoutPoint& accumulatedOffset)
260 : m_rects(rects)
261 , m_accumulatedOffset(accumulatedOffset) { }
262
263 void addRect(const FloatRect& rect)
264 {
265 LayoutRect adjustedRect = LayoutRect(rect);
266 adjustedRect.moveBy(m_accumulatedOffset);
267 m_rects.append(adjustedRect);
268 }
269private:
270 Vector<LayoutRect>& m_rects;
271 const LayoutPoint& m_accumulatedOffset;
272};
273
274void RenderInline::boundingRects(Vector<LayoutRect>& rects, const LayoutPoint& accumulatedOffset) const
275{
276 AbsoluteRectsGeneratorContext context(rects, accumulatedOffset);
277 generateLineBoxRects(context);
278
279 if (auto* continuation = this->continuation()) {
280 if (auto* box = dynamicDowncast<RenderBox>(*continuation)) {
281 continuation->boundingRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location() + box->locationOffset()));
282 } else
283 continuation->boundingRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location()));
284 }
285}
286
287namespace {
288
289class AbsoluteQuadsGeneratorContext {
290public:
291 AbsoluteQuadsGeneratorContext(const RenderInline* renderer, Vector<FloatQuad>& quads)
292 : m_quads(quads)
293 , m_geometryMap()
294 {
295 m_geometryMap.pushMappingsToAncestor(renderer, nullptr);
296 }
297
298 void addRect(const FloatRect& rect)
299 {
300 m_quads.append(m_geometryMap.absoluteRect(rect));
301 }
302private:
303 Vector<FloatQuad>& m_quads;
304 RenderGeometryMap m_geometryMap;
305};
306
307} // unnamed namespace
308
309void RenderInline::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
310{
311 absoluteQuadsIgnoringContinuation({ }, quads, wasFixed);
312 if (continuation())
313 collectAbsoluteQuadsForContinuation(quads, wasFixed);
314}
315
316void RenderInline::absoluteQuadsIgnoringContinuation(const FloatRect&, Vector<FloatQuad>& quads, bool*) const
317{
318 AbsoluteQuadsGeneratorContext context(this, quads);
319 generateLineBoxRects(context);
320}
321
322#if PLATFORM(IOS_FAMILY)(defined 1 && 1)
323void RenderInline::absoluteQuadsForSelection(Vector<FloatQuad>& quads) const
324{
325 AbsoluteQuadsGeneratorContext context(this, quads);
326 generateLineBoxRects(context);
327}
328#endif
329
330LayoutUnit RenderInline::offsetLeft() const
331{
332 return adjustedPositionRelativeToOffsetParent(firstInlineBoxTopLeft()).x();
333}
334
335LayoutUnit RenderInline::offsetTop() const
336{
337 return adjustedPositionRelativeToOffsetParent(firstInlineBoxTopLeft()).y();
338}
339
340LayoutPoint RenderInline::firstInlineBoxTopLeft() const
341{
342 if (auto* lineLayout = LayoutIntegration::LineLayout::containing(*this))
343 return lineLayout->firstInlineBoxRect(*this).location();
344 if (auto* inlineBox = firstLegacyInlineBox())
345 return flooredLayoutPoint(inlineBox->locationIncludingFlipping());
346 return { };
347}
348
349static LayoutUnit computeMargin(const RenderInline* renderer, const Style::MarginEdge& margin, const Style::ZoomFactor& zoomFactor)
350{
351 return Style::evaluateMinimum<LayoutUnit>(margin, [&] ALWAYS_INLINE_LAMBDA__attribute__((__always_inline__)) {
352 return std::max<LayoutUnit>(0, renderer->containingBlock()->contentBoxLogicalWidth());
353 }, zoomFactor);
354}
355
356LayoutUnit RenderInline::marginLeft() const
357{
358 return computeMargin(this, style().marginLeft(), style().usedZoomForLength());
359}
360
361LayoutUnit RenderInline::marginRight() const
362{
363 return computeMargin(this, style().marginRight(), style().usedZoomForLength());
364}
365
366LayoutUnit RenderInline::marginTop() const
367{
368 return computeMargin(this, style().marginTop(), style().usedZoomForLength());
369}
370
371LayoutUnit RenderInline::marginBottom() const
372{
373 return computeMargin(this, style().marginBottom(), style().usedZoomForLength());
374}
375
376LayoutUnit RenderInline::marginStart(const WritingMode writingMode) const
377{
378 return computeMargin(this, style().marginStart(writingMode), style().usedZoomForLength());
379}
380
381LayoutUnit RenderInline::marginEnd(const WritingMode writingMode) const
382{
383 return computeMargin(this, style().marginEnd(writingMode), style().usedZoomForLength());
384}
385
386LayoutUnit RenderInline::marginBefore(const WritingMode writingMode) const
387{
388 return computeMargin(this, style().marginBefore(writingMode), style().usedZoomForLength());
389}
390
391LayoutUnit RenderInline::marginAfter(const WritingMode writingMode) const
392{
393 return computeMargin(this, style().marginAfter(writingMode), style().usedZoomForLength());
394}
395
396ASCIILiteral RenderInline::renderName() const
397{
398 if (isRelativelyPositioned())
399 return "RenderInline (relative positioned)"_s;
400 if (isStickilyPositioned())
401 return "RenderInline (sticky positioned)"_s;
402 // FIXME: Temporary hack while the new generated content system is being implemented.
403 if (isPseudoElement())
404 return "RenderInline (generated)"_s;
405 if (isAnonymous())
406 return "RenderInline (generated)"_s;
407 return "RenderInline"_s;
408}
409
410bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
411 const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
412{
413 ASSERT(layer())((void)0);
414 if (auto* lineLayout = LayoutIntegration::LineLayout::containing(*this))
415 return lineLayout->hitTest(request, result, locationInContainer, accumulatedOffset, hitTestAction, this);
416 return false;
417}
418
419PositionWithAffinity RenderInline::positionForPoint(const LayoutPoint& point, HitTestSource source, const RenderFragmentContainer* fragment)
420{
421 auto& containingBlock = *this->containingBlock();
422
423 if (auto* continuation = this->continuation()) {
424 // Translate the coords from the pre-anonymous block to the post-anonymous block.
425 LayoutPoint parentBlockPoint = containingBlock.location() + point;
426 while (continuation) {
427 RenderBlock* currentBlock = continuation->isInline() ? continuation->containingBlock() : downcast<RenderBlock>(continuation);
428 if (continuation->isInline() || continuation->firstChild())
429 return continuation->positionForPoint(parentBlockPoint - currentBlock->locationOffset(), source, fragment);
430 continuation = continuation->inlineContinuation();
431 }
432 return RenderBoxModelObject::positionForPoint(point, source, fragment);
433 }
434
435 return containingBlock.positionForPoint(point, source, fragment);
436}
437
438LayoutUnit RenderInline::innerPaddingBoxWidth() const
439{
440 auto firstInlineBoxPaddingBoxLeft = LayoutUnit { };
441 auto lastInlineBoxPaddingBoxRight = LayoutUnit { };
442
443 if (LayoutIntegration::LineLayout::containing(*this)) {
444 if (auto inlineBox = InlineIterator::lineLeftmostInlineBoxFor(*this)) {
445 if (writingMode().isBidiLTR()) {
446 firstInlineBoxPaddingBoxLeft = inlineBox->logicalLeftIgnoringInlineDirection() + borderStart();
447 for (; inlineBox->nextInlineBoxLineRightward(); inlineBox.traverseInlineBoxLineRightward()) { }
448 ASSERT(inlineBox)((void)0);
449 lastInlineBoxPaddingBoxRight = inlineBox->logicalRightIgnoringInlineDirection() - borderEnd();
450 } else {
451 lastInlineBoxPaddingBoxRight = inlineBox->logicalRightIgnoringInlineDirection() - borderStart();
452 for (; inlineBox->nextInlineBoxLineRightward(); inlineBox.traverseInlineBoxLineRightward()) { }
453 ASSERT(inlineBox)((void)0);
454 firstInlineBoxPaddingBoxLeft = inlineBox->logicalLeftIgnoringInlineDirection() + borderEnd();
455 }
456 return std::max(0_lu, lastInlineBoxPaddingBoxRight - firstInlineBoxPaddingBoxLeft);
457 }
458 return { };
459 }
460
461 auto* firstInlineBox = firstLegacyInlineBox();
462 auto* lastInlineBox = lastLegacyInlineBox();
463 if (!firstInlineBox || !lastInlineBox)
464 return { };
465
466 if (writingMode().isBidiLTR()) {
467 firstInlineBoxPaddingBoxLeft = firstInlineBox->logicalLeft();
468 lastInlineBoxPaddingBoxRight = lastInlineBox->logicalRight();
469 } else {
470 lastInlineBoxPaddingBoxRight = firstInlineBox->logicalRight();
471 firstInlineBoxPaddingBoxLeft = lastInlineBox->logicalLeft();
472 }
473 return std::max(0_lu, lastInlineBoxPaddingBoxRight - firstInlineBoxPaddingBoxLeft);
474}
475
476LayoutUnit RenderInline::innerPaddingBoxHeight() const
477{
478 auto innerPaddingBoxLogicalHeight = LayoutUnit { isHorizontalWritingMode() ? linesBoundingBox().height() : linesBoundingBox().width() };
479 innerPaddingBoxLogicalHeight -= (borderBefore() + borderAfter());
480 return innerPaddingBoxLogicalHeight;
481}
482
483IntRect RenderInline::linesBoundingBox() const
484{
485 if (auto* layout = LayoutIntegration::LineLayout::containing(*this)) {
486 if (!layoutBox() || !layout->contains(*this)) {
487 // Repaint may be issued on subtrees during content mutation with newly inserted renderers
488 // (or we just forgot to initiate layout before querying geometry on stale content after moving inline boxes between blocks).
489 ASSERT(needsLayout())((void)0);
490 return { };
491 }
492 if (isRenderSVGInline()) {
493 // FIXME: Always build the bounding box like this. LineLayouyt::enclosingBorderBoxRectFor does not include
494 // any post-layout box adjustments.
495 FloatRect result;
496 for (auto box = InlineIterator::lineLeftmostInlineBoxFor(*this); box; box.traverseInlineBoxLineRightward()) {
497 auto rect = box->visualRectIgnoringBlockDirection();
498 result.unite(rect);
499 }
500 return enclosingIntRect(result);
501 }
502 return enclosingIntRect(layout->enclosingBorderBoxRectFor(*this));
503 }
504
505 // See <rdar://problem/5289721>, for an unknown reason the linked list here is sometimes inconsistent, first is non-zero and last is zero. We have been
506 // unable to reproduce this at all (and consequently unable to figure ot why this is happening). The assert will hopefully catch the problem in debug
507 // builds and help us someday figure out why. We also put in a redundant check of lastLineBox() to avoid the crash for now.
508 ASSERT(!firstLegacyInlineBox() == !lastLegacyInlineBox())((void)0); // Either both are null or both exist.
509 IntRect result;
510 if (firstLegacyInlineBox() && lastLegacyInlineBox()) {
511 // Return the width of the minimal left side and the maximal right side.
512 float logicalLeftSide = 0;
513 float logicalRightSide = 0;
514 for (auto* curr = firstLegacyInlineBox(); curr; curr = curr->nextLineBox()) {
515 if (curr == firstLegacyInlineBox() || curr->logicalLeft() < logicalLeftSide)
516 logicalLeftSide = curr->logicalLeft();
517 if (curr == firstLegacyInlineBox() || curr->logicalRight() > logicalRightSide)
518 logicalRightSide = curr->logicalRight();
519 }
520
521 bool isHorizontal = writingMode().isHorizontal();
522
523 float x = isHorizontal ? logicalLeftSide : firstLegacyInlineBox()->x();
524 float y = isHorizontal ? firstLegacyInlineBox()->y() : logicalLeftSide;
525 float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLegacyInlineBox()->logicalBottom() - x;
526 float height = isHorizontal ? lastLegacyInlineBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
527 result = enclosingIntRect(FloatRect(x, y, width, height));
528 }
529
530 return result;
531}
532
533LayoutRect RenderInline::linesVisualOverflowBoundingBox() const
534{
535 if (auto* layout = LayoutIntegration::LineLayout::containing(*this)) {
536 if (!layoutBox()) {
537 // Repaint may be issued on subtrees during content mutation with newly inserted renderers.
538 ASSERT(needsLayout())((void)0);
539 return { };
540 }
541 return layout->inkOverflowBoundingBoxRectFor(*this);
542 }
543
544 if (!firstLegacyInlineBox() || !lastLegacyInlineBox())
545 return { };
546
547 // Return the width of the minimal left side and the maximal right side.
548 LayoutUnit logicalLeftSide = LayoutUnit::max();
549 LayoutUnit logicalRightSide = LayoutUnit::min();
550 for (auto* curr = firstLegacyInlineBox(); curr; curr = curr->nextLineBox()) {
551 logicalLeftSide = std::min(logicalLeftSide, curr->logicalLeftVisualOverflow());
552 logicalRightSide = std::max(logicalRightSide, curr->logicalRightVisualOverflow());
553 }
554
555 const LegacyRootInlineBox& firstRootBox = firstLegacyInlineBox()->root();
556 const LegacyRootInlineBox& lastRootBox = lastLegacyInlineBox()->root();
557
558 LayoutUnit logicalTop = firstLegacyInlineBox()->logicalTopVisualOverflow(firstRootBox.lineTop());
559 LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
560 LayoutUnit logicalHeight = lastLegacyInlineBox()->logicalBottomVisualOverflow(lastRootBox.lineBottom()) - logicalTop;
561
562 LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
563 if (!writingMode().isHorizontal())
564 rect = rect.transposedRect();
565 return rect;
566}
567
568LayoutRect RenderInline::clippedOverflowRect(const RenderLayerModelObject* repaintContainer, VisibleRectContext context) const
569{
570 // Only first-letter renderers are allowed in here during layout. They mutate the tree triggering repaints.
571#ifndef NDEBUG1
572 auto insideSelfPaintingInlineBox = [&] {
573 if (hasSelfPaintingLayer())
574 return true;
575 auto* containingBlock = this->containingBlock();
576 for (auto* ancestor = this->parent(); ancestor && ancestor != containingBlock; ancestor = ancestor->parent()) {
577 if (ancestor->hasSelfPaintingLayer())
578 return true;
579 }
580 return false;
581 };
582 ASSERT_UNUSED(insideSelfPaintingInlineBox, !view().frameView().layoutContext().isPaintOffsetCacheEnabled() || style().pseudoElementType() == PseudoElementType::FirstLetter || insideSelfPaintingInlineBox())((void)insideSelfPaintingInlineBox);
583#endif
584
585 auto knownEmpty = [&] {
586 if (firstLegacyInlineBox())
587 return false;
588 if (continuation())
589 return false;
590 if (LayoutIntegration::LineLayout::containing(*this))
591 return false;
592 return true;
593 };
594
595 if (knownEmpty())
596 return LayoutRect();
597
598 auto repaintRect = linesVisualOverflowBoundingBox();
599 bool hitRepaintContainer = false;
600
601 // We need to add in the in-flow position offsets of any inlines (including us) up to our
602 // containing block.
603 RenderBlock* containingBlock = this->containingBlock();
604 for (const RenderElement* inlineFlow = this; inlineFlow; inlineFlow = inlineFlow->parent()) {
605 auto* renderInline = dynamicDowncast<RenderInline>(*inlineFlow);
606 if (!renderInline || inlineFlow == containingBlock)
607 break;
608 if (inlineFlow == repaintContainer) {
609 hitRepaintContainer = true;
610 break;
611 }
612 if (inlineFlow->style().hasInFlowPosition() && inlineFlow->hasLayer())
613 repaintRect.move(renderInline->layer()->offsetForInFlowPosition());
614 }
615
616 LayoutUnit outlineSize { style().usedOutlineSize() };
617 repaintRect.inflate(outlineSize);
618
619 if (hitRepaintContainer || !containingBlock)
620 return repaintRect;
621
622 auto rects = RepaintRects { repaintRect };
623
624 if (containingBlock->hasNonVisibleOverflow())
625 containingBlock->applyCachedClipAndScrollPosition(rects, repaintContainer, context);
626
627 rects = containingBlock->computeRects(rects, repaintContainer, context);
628 repaintRect = rects.clippedOverflowRect;
629
630 if (outlineSize) {
631 for (auto& child : childrenOfType<RenderElement>(*this))
632 repaintRect.unite(child.rectWithOutlineForRepaint(repaintContainer, outlineSize));
633
634 if (RenderBoxModelObject* continuation = this->continuation()) {
635 if (!continuation->isInline() && continuation->parent())
636 repaintRect.unite(continuation->rectWithOutlineForRepaint(repaintContainer, outlineSize));
637 }
638 }
639
640 return repaintRect;
641}
642
643auto RenderInline::rectsForRepaintingAfterLayout(const RenderLayerModelObject* repaintContainer, RepaintOutlineBounds) const -> RepaintRects
644{
645 // RepaintOutlineBounds is unused for inlines.
646 return { clippedOverflowRect(repaintContainer, visibleRectContextForRepaint()) };
647}
648
649LayoutRect RenderInline::rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const
650{
651 LayoutRect r(RenderBoxModelObject::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
652 for (auto& child : childrenOfType<RenderElement>(*this))
653 r.unite(child.rectWithOutlineForRepaint(repaintContainer, outlineWidth));
654 return r;
655}
656
657auto RenderInline::computeVisibleRectsUsingPaintOffset(const RepaintRects& rects) const -> RepaintRects
658{
659 auto adjustedRects = rects;
660 auto* layoutState = view().frameView().layoutContext().layoutState();
661 if (style().hasInFlowPosition() && layer())
662 adjustedRects.move(layer()->offsetForInFlowPosition());
663 adjustedRects.move(layoutState->paintOffset());
664 if (layoutState->isClipped())
665 adjustedRects.clippedOverflowRect.intersect(layoutState->clipRect());
666 return adjustedRects;
667}
668
669auto RenderInline::computeVisibleRectsInContainer(const RepaintRects& rects, const RenderLayerModelObject* container, VisibleRectContext context) const -> std::optional<RepaintRects>
670{
671 // Repaint offset cache is only valid for root-relative repainting
672 if (view().frameView().layoutContext().isPaintOffsetCacheEnabled() && !container && !context.options.contains(VisibleRectContext::Option::UseEdgeInclusiveIntersection))
673 return computeVisibleRectsUsingPaintOffset(rects);
674
675 if (container == this)
676 return rects;
677
678 bool containerSkipped;
679 RenderElement* localContainer = this->container(container, containerSkipped);
680 if (!localContainer)
681 return rects;
682
683 auto adjustedRects = rects;
684 if (style().hasInFlowPosition() && layer()) {
685 // Apply the in-flow position offset when invalidating a rectangle. The layer
686 // is translated, but the render box isn't, so we need to do this to get the
687 // right dirty rect. Since this is called from RenderObject::setStyle, the relative or sticky position
688 // flag on the RenderObject has been cleared, so use the one on the style().
689 auto offsetForInFlowPosition = layer()->offsetForInFlowPosition();
690 adjustedRects.move(offsetForInFlowPosition);
691 }
692
693 if (localContainer->hasNonVisibleOverflow()) {
694 // FIXME: Respect the value of context.options.
695 SetForScope change(context.options, context.options | VisibleRectContext::Option::ApplyCompositedContainerScrolls);
696 bool isEmpty = !downcast<RenderLayerModelObject>(*localContainer).applyCachedClipAndScrollPosition(adjustedRects, container, context);
697 if (isEmpty) {
698 if (context.options.contains(VisibleRectContext::Option::UseEdgeInclusiveIntersection))
699 return std::nullopt;
700 return adjustedRects;
701 }
702 }
703
704 if (containerSkipped) {
705 // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
706 auto containerOffset = container->offsetFromAncestorContainer(*localContainer);
707 adjustedRects.move(-containerOffset);
708 return adjustedRects;
709 }
710
711 return localContainer->computeVisibleRectsInContainer(adjustedRects, container, context);
712}
713
714LayoutSize RenderInline::offsetFromContainer(const RenderElement& container, const LayoutPoint&, bool* offsetDependsOnPoint) const
715{
716 ASSERT(&container == this->container())((void)0);
717
718 LayoutSize offset;
719 if (isInFlowPositioned())
720 offset += offsetForInFlowPosition();
721
722 if (auto* box = dynamicDowncast<RenderBox>(container))
723 offset -= toLayoutSize(box->scrollPosition());
724
725 if (offsetDependsOnPoint)
726 *offsetDependsOnPoint = (is<RenderBox>(container) && container.writingMode().isBlockFlipped()) || is<RenderFragmentedFlow>(container);
727
728 return offset;
729}
730
731void RenderInline::mapLocalToContainer(const RenderLayerModelObject* ancestorContainer, TransformState& transformState, OptionSet<MapCoordinatesMode> mode, bool* wasFixed) const
732{
733 if (ancestorContainer == this)
734 return;
735
736 if (view().frameView().layoutContext().isPaintOffsetCacheEnabled() && !ancestorContainer) {
737 auto* layoutState = view().frameView().layoutContext().layoutState();
738 LayoutSize offset = layoutState->paintOffset();
739 if (style().hasInFlowPosition() && layer())
740 offset += layer()->offsetForInFlowPosition();
741 transformState.move(offset);
742 return;
743 }
744
745 bool containerSkipped;
746 RenderElement* container = this->container(ancestorContainer, containerSkipped);
747 if (!container)
748 return;
749
750 if (mode.contains(ApplyContainerFlip)) {
751 if (CheckedPtr box = dynamicDowncast<RenderBox>(*container)) {
752 if (container->writingMode().isBlockFlipped()) {
753 LayoutPoint centerPoint(transformState.mappedPoint());
754 transformState.move(box->flipForWritingMode(centerPoint) - centerPoint);
755 }
756 mode.remove(ApplyContainerFlip);
757 }
758 }
759
760 LayoutSize containerOffset = offsetFromContainer(*container, LayoutPoint(transformState.mappedPoint()));
761
762 pushOntoTransformState(transformState, mode, ancestorContainer, container, containerOffset, containerSkipped);
763 if (containerSkipped)
764 return;
765
766 container->mapLocalToContainer(ancestorContainer, transformState, mode, wasFixed);
767}
768
769const RenderElement* RenderInline::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
770{
771 ASSERT(ancestorToStopAt != this)((void)0);
772
773 bool ancestorSkipped;
774 RenderElement* container = this->container(ancestorToStopAt, ancestorSkipped);
775 if (!container)
776 return nullptr;
777
778 pushOntoGeometryMap(geometryMap, ancestorToStopAt, container, ancestorSkipped);
779
780 return ancestorSkipped ? ancestorToStopAt : container;
781}
782
783void RenderInline::updateHitTestResult(HitTestResult& result, const LayoutPoint& point) const
784{
785 if (result.innerNode())
786 return;
787
788 LayoutPoint localPoint(point);
789 if (RefPtr node = nodeForHitTest()) {
790 if (isContinuation()) {
791 // We're in the continuation of a split inline. Adjust our local point to be in the coordinate space
792 // of the principal renderer's containing block. This will end up being the innerNonSharedNode.
793 auto* firstBlock = node->renderer()->containingBlock();
794 localPoint.moveBy(containingBlock()->location() - firstBlock->locationOffset());
795 }
796
797 result.setInnerNode(node.get());
798 if (!result.innerNonSharedNode())
799 result.setInnerNonSharedNode(node.get());
800 result.setPseudoElementIdentifier(style().pseudoElementIdentifier());
801 result.setLocalPoint(localPoint);
802 }
803}
804
805void RenderInline::deleteLegacyLineBoxes()
806{
807 m_legacyLineBoxes.deleteLineBoxes();
808}
809
810std::unique_ptr<LegacyInlineFlowBox> RenderInline::createInlineFlowBox()
811{
812 return makeUnique<LegacyInlineFlowBox>(*this);
813}
814
815LegacyInlineFlowBox* RenderInline::createAndAppendInlineFlowBox()
816{
817 auto newFlowBox = createInlineFlowBox();
818 auto flowBox = newFlowBox.get();
819 m_legacyLineBoxes.appendLineBox(WTF::move(newFlowBox));
820 return flowBox;
821}
822
823LayoutSize RenderInline::offsetForInFlowPositionedInline(const RenderBox* child) const
824{
825 // FIXME: This function isn't right with mixed writing modes.
826 if (!isInFlowPositioned()) {
827 ASSERT_NOT_REACHED()((void)0);
828 return { };
829 }
830
831 if (!hasLayer()) {
832 // It looks like we are inflow positioned but no layer created yet. It essentially means we don't have an position offset yet.
833 return { };
834 }
835
836 // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
837 // box from the rest of the content, but only in the cases where we know we're positioned
838 // relative to the inline itself.
839 auto inlinePosition = layer()->staticInlinePosition();
840 auto blockPosition = layer()->staticBlockPosition();
841 if (auto* inlineBox = firstLegacyInlineBox()) {
842 inlinePosition = LayoutUnit::fromFloatRound(inlineBox->logicalLeft());
843 blockPosition = inlineBox->logicalTop();
844 } else if (LayoutIntegration::LineLayout::containing(*this)) {
845 if (!layoutBox()) {
846 // Repaint may be issued on subtrees during content mutation with newly inserted renderers.
847 ASSERT(needsLayout())((void)0);
848 return { };
849 }
850 if (auto inlineBox = InlineIterator::lineLeftmostInlineBoxFor(*this)) {
851 inlinePosition = LayoutUnit::fromFloatRound(inlineBox->logicalLeftIgnoringInlineDirection());
852 blockPosition = inlineBox->logicalTop();
853 } else if (auto* blockContainer = containingBlock()) {
854 // This must be a block with no in-flow content e.g. <div><span><abs pos box></span></div> where we don't construct any display box at all.
855 auto contentBoxLocation = blockContainer->contentBoxLocation();
856 inlinePosition = contentBoxLocation.x();
857 blockPosition = contentBoxLocation.y();
858 }
859 }
860
861 // Per http://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-width an absolute positioned box with a static position
862 // should locate itself as though it is a normal flow box in relation to its containing block.
863 LayoutSize logicalOffset;
864 if (!child->style().hasStaticInlinePosition(writingMode().isHorizontal())
865 || !child->style().positionArea().isNone() || child->style().justifySelf().isAnchorCenter())
866 logicalOffset.setWidth(inlinePosition);
867
868 if (!child->style().hasStaticBlockPosition(writingMode().isHorizontal())
869 || !child->style().positionArea().isNone() || child->style().alignSelf().isAnchorCenter())
870 logicalOffset.setHeight(blockPosition);
871
872 return writingMode().isHorizontal() ? logicalOffset : logicalOffset.transposedSize();
873}
874
875void RenderInline::imageChanged(WrappedImagePtr image, const IntRect*)
876{
877 if (!parent())
878 return;
879
880 bool isNonEmpty;
881 RefPtr styleImage = Style::findLayerUsedImage(style().backgroundLayers(), image, isNonEmpty);
882 if (styleImage && isNonEmpty) {
883 if (auto styleable = Styleable::fromRenderer(*this))
884 protect(document())->didLoadImage(protect(styleable->element).get(), styleImage->cachedImage());
Call argument is uncounted and unsafe
885 }
886
887 // FIXME: We can do better.
888 repaint();
889}
890
891namespace {
892 class AbsoluteRectsIgnoringEmptyGeneratorContext : public AbsoluteRectsGeneratorContext {
893 public:
894 AbsoluteRectsIgnoringEmptyGeneratorContext(Vector<LayoutRect>& rects, const LayoutPoint& accumulatedOffset)
895 : AbsoluteRectsGeneratorContext(rects, accumulatedOffset) { }
896
897 void addRect(const FloatRect& rect)
898 {
899 if (!rect.isEmpty())
900 AbsoluteRectsGeneratorContext::addRect(rect);
901 }
902 };
903} // unnamed namespace
904
905void RenderInline::collectLineBoxRects(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset) const
906{
907 AbsoluteRectsIgnoringEmptyGeneratorContext context(rects, additionalOffset);
908 generateLineBoxRects(context);
909}
910
911bool isEmptyInline(const RenderInline& renderer)
912{
913 for (auto& current : childrenOfType<RenderObject>(renderer)) {
914 if (current.isFloatingOrOutOfFlowPositioned())
915 continue;
916 if (auto* text = dynamicDowncast<RenderText>(current)) {
917 if (!text->containsOnlyCollapsibleWhitespace())
918 return false;
919 continue;
920 }
921 auto* renderInline = dynamicDowncast<RenderInline>(current);
922 if (!renderInline || !isEmptyInline(*renderInline))
923 return false;
924 }
925 return true;
926}
927
928bool RenderInline::requiresLayer() const
929{
930 return isInFlowPositioned()
931 || createsGroup()
932 || hasClipPath()
933 || style().willChange().canCreateStackingContext()
934 || hasRunningAcceleratedAnimations()
935 || requiresRenderingConsolidationForViewTransition();
936}
937
938} // namespace WebCore