Bug Summary

File:Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/rendering/LegacyLineLayout.cpp
Warning:line 602, column 5
A function 'layoutContext' has [[clang::annotate_type("webkit.nodelete")]] but it contains code that could destruct an object

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 UnifiedSource408.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/UnifiedSource408.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/UnifiedSource408.plist -x c++ /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/DerivedSources/WebCore/unified-sources/UnifiedSource408.cpp
1/*
2 * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2003-2023 Apple Inc. All right reserved.
4 * Copyright (C) 2010 Google Inc. All rights reserved.
5 * Copyright (C) 2013 ChangSeok Oh <shivamidow@gmail.com>
6 * Copyright (C) 2013 Adobe Systems Inc. All right reserved.
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 "LegacyLineLayout.h"
27
28#include "AXObjectCache.h"
29#include "BidiResolver.h"
30#include "BreakingContext.h"
31#include "DocumentView.h"
32#include "FloatingObjects.h"
33#include "InlineIteratorBoxInlines.h"
34#include "InlineIteratorTextBox.h"
35#include "InlineTextBoxStyle.h"
36#include "InlineWalker.h"
37#include "LegacyInlineIterator.h"
38#include "LegacyInlineTextBox.h"
39#include "LineInfo.h"
40#include "LineInlineHeaders.h"
41#include "Logging.h"
42#include "RenderBlockFlowInlines.h"
43#include "RenderFragmentContainer.h"
44#include "RenderFragmentedFlow.h"
45#include "RenderLayoutState.h"
46#include "RenderLineBreak.h"
47#include "RenderObjectInlines.h"
48#include "RenderSVGText.h"
49#include "RenderView.h"
50#include "SVGElementTypeHelpers.h"
51#include "SVGRootInlineBox.h"
52#include "Settings.h"
53#include <wtf/StdLibExtras.h>
54#include <wtf/TZoneMallocInlines.h>
55
56namespace WebCore {
57
58WTF_MAKE_TZONE_ALLOCATED_IMPL(LegacyLineLayout)::bmalloc::api::HeapRef LegacyLineLayout::s_heapRef; const TZoneSpecification
LegacyLineLayout::s_heapSpec = { &LegacyLineLayout::s_heapRef
, TZoneSpecification::encodeSize<LegacyLineLayout>(), TZoneSpecification
::encodeAlignment<LegacyLineLayout>(), TZoneSpecification
::encodeCategory<LegacyLineLayout>(), ::bmalloc::api::compactAllocationMode
<LegacyLineLayout>(), TZoneSpecification::encodeDescriptor
<LegacyLineLayout>(), }; void* LegacyLineLayout::operatorNewSlow
(size_t size) { if constexpr (::bmalloc::api::compactAllocationMode
<LegacyLineLayout>() == CompactAllocationMode::Compact)
return ::bmalloc::api::tzoneAllocateCompactSlow(size, s_heapSpec
); return ::bmalloc::api::tzoneAllocateNonCompactSlow(size, s_heapSpec
); } using __makeBtzoneMallocedInlineMacroSemicolonifier __attribute__
((unused)) = int
;
59
60LegacyLineLayout::LegacyLineLayout(RenderBlockFlow& flow)
61 : m_flow(flow)
62{
63}
64
65LegacyLineLayout::~LegacyLineLayout()
66{
67 deleteLegacyRootBox(true);
68}
69
70static void determineDirectionality(TextDirection& dir, LegacyInlineIterator iter)
71{
72 while (!iter.atEnd()) {
73 if (iter.atParagraphSeparator())
74 return;
75 if (char16_t current = iter.current()) {
76 UCharDirection charDirection = u_charDirection(current);
77 if (charDirection == U_LEFT_TO_RIGHT) {
78 dir = TextDirection::LTR;
79 return;
80 }
81 if (charDirection == U_RIGHT_TO_LEFT || charDirection == U_RIGHT_TO_LEFT_ARABIC) {
82 dir = TextDirection::RTL;
83 return;
84 }
85 }
86 iter.increment();
87 }
88}
89
90inline std::unique_ptr<BidiRun> createRun(int start, int end, RenderObject& obj, InlineBidiResolver& resolver)
91{
92 return makeUnique<BidiRun>(start, end, obj, resolver.context(), resolver.dir());
93}
94
95bool LegacyLineLayout::shouldSkipCreatingRunsForObject(RenderObject& object)
96{
97 if (is<RenderText>(object))
98 return false;
99 auto& renderElement = downcast<RenderElement>(object);
100 if (renderElement.isFloating())
101 return true;
102 if (renderElement.isOutOfFlowPositioned() && !renderElement.style().originalDisplay().isInlineType() && !renderElement.container()->isRenderInline())
103 return true;
104 return false;
105}
106
107void LegacyLineLayout::appendRunsForObject(BidiRunList<BidiRun>* runs, int start, int end, RenderObject& obj, InlineBidiResolver& resolver)
108{
109 if (start > end || shouldSkipCreatingRunsForObject(obj))
110 return;
111
112 LineWhitespaceCollapsingState& lineWhitespaceCollapsingState = resolver.whitespaceCollapsingState();
113 bool haveNextTransition = (lineWhitespaceCollapsingState.currentTransition() < lineWhitespaceCollapsingState.numTransitions());
114 LegacyInlineIterator nextTransition;
115 if (haveNextTransition)
116 nextTransition = lineWhitespaceCollapsingState.transitions()[lineWhitespaceCollapsingState.currentTransition()];
117 if (lineWhitespaceCollapsingState.betweenTransitions()) {
118 if (!haveNextTransition || (&obj != nextTransition.renderer()))
119 return;
120 // This is a new start point. Stop ignoring objects and
121 // adjust our start.
122 start = nextTransition.offset();
123 lineWhitespaceCollapsingState.incrementCurrentTransition();
124 if (start < end) {
125 appendRunsForObject(runs, start, end, obj, resolver);
126 return;
127 }
128 } else {
129 if (!haveNextTransition || (&obj != nextTransition.renderer())) {
130 if (runs)
131 runs->appendRun(createRun(start, end, obj, resolver));
132 return;
133 }
134
135 // An end transition has been encountered within our object. We need to append a run with our endpoint.
136 if (static_cast<int>(nextTransition.offset() + 1) <= end) {
137 lineWhitespaceCollapsingState.incrementCurrentTransition();
138 // The end of the line is before the object we're inspecting. Skip everything and return
139 if (nextTransition.refersToEndOfPreviousNode())
140 return;
141 if (static_cast<int>(nextTransition.offset() + 1) > start && runs)
142 runs->appendRun(createRun(start, nextTransition.offset() + 1, obj, resolver));
143 appendRunsForObject(runs, nextTransition.offset() + 1, end, obj, resolver);
144 } else if (runs)
145 runs->appendRun(createRun(start, end, obj, resolver));
146 }
147}
148
149std::unique_ptr<LegacyRootInlineBox> LegacyLineLayout::createRootInlineBox()
150{
151 if (CheckedPtr svgText = dynamicDowncast<RenderSVGText>(m_flow)) {
152 auto box = makeUnique<SVGRootInlineBox>(*svgText);
153 box->setHasVirtualLogicalHeight();
154 return box;
155 }
156
157 return makeUnique<LegacyRootInlineBox>(m_flow);
158}
159
160LegacyRootInlineBox* LegacyLineLayout::createAndAppendRootInlineBox()
161{
162 m_legacyRootInlineBox = createRootInlineBox();
163 if (AXObjectCache::accessibilityEnabled()) [[unlikely]] {
164 if (AXObjectCache* cache = m_flow.document().existingAXObjectCache())
165 cache->deferRecomputeIsIgnored(m_flow.element());
166 }
167
168 return m_legacyRootInlineBox.get();
169}
170
171LegacyInlineBox* LegacyLineLayout::createInlineBoxForRenderer(RenderObject* renderer)
172{
173 if (renderer == &m_flow)
174 return createAndAppendRootInlineBox();
175
176 if (auto* textRenderer = dynamicDowncast<RenderSVGInlineText>(*renderer))
177 return textRenderer->createInlineTextBox();
178
179 if (auto* renderInline = dynamicDowncast<RenderInline>(*renderer))
180 return renderInline->createAndAppendInlineFlowBox();
181
182 ASSERT_NOT_REACHED()((void)0);
183 return nullptr;
184}
185
186static inline void dirtyLineBoxesForRenderer(RenderObject& renderer)
187{
188 if (CheckedPtr renderText = dynamicDowncast<RenderSVGInlineText>(renderer))
189 renderText->deleteLegacyLineBoxes();
190 else if (CheckedPtr renderInline = dynamicDowncast<RenderInline>(renderer))
191 renderInline->deleteLegacyLineBoxes();
192}
193
194static bool NODELETE[[clang::annotate_type("webkit.nodelete")]] parentIsConstructedOrHaveNext(LegacyInlineFlowBox* parentBox)
195{
196 do {
197 if (parentBox->isConstructed() || parentBox->nextOnLine())
198 return true;
199 parentBox = parentBox->parent();
200 } while (parentBox);
201 return false;
202}
203
204LegacyInlineFlowBox* LegacyLineLayout::createLineBoxes(RenderObject* obj, const LineInfo& lineInfo, LegacyInlineBox* childBox)
205{
206 // See if we have an unconstructed line box for this object that is also
207 // the last item on the line.
208 unsigned lineDepth = 1;
209 LegacyInlineFlowBox* parentBox = nullptr;
210 LegacyInlineFlowBox* result = nullptr;
211 do {
212 RenderInline* inlineFlow = obj != &m_flow ? &downcast<RenderInline>(*obj) : nullptr;
213
214 // Get the last box we made for this render object.
215 parentBox = inlineFlow ? inlineFlow->lastLegacyInlineBox() : downcast<RenderBlockFlow>(*obj).legacyRootBox();
216
217 // If this box or its ancestor is constructed then it is from a previous line, and we need
218 // to make a new box for our line. If this box or its ancestor is unconstructed but it has
219 // something following it on the line, then we know we have to make a new box
220 // as well. In this situation our inline has actually been split in two on
221 // the same line (this can happen with very fancy language mixtures).
222 bool constructedNewBox = false;
223 bool canUseExistingParentBox = parentBox && !parentIsConstructedOrHaveNext(parentBox);
224 if (!canUseExistingParentBox) {
225 // We need to make a new box for this render object. Once
226 // made, we need to place it at the end of the current line.
227 LegacyInlineBox* newBox = createInlineBoxForRenderer(obj);
228 parentBox = downcast<LegacyInlineFlowBox>(newBox);
229 parentBox->setIsFirstLine(lineInfo.isFirstLine());
230 parentBox->setIsHorizontal(m_flow.isHorizontalWritingMode());
231 constructedNewBox = true;
232 }
233
234 if (constructedNewBox || canUseExistingParentBox) {
235 if (!result)
236 result = parentBox;
237
238 // If we have hit the block itself, then |box| represents the root
239 // inline box for the line, and it doesn't have to be appended to any parent
240 // inline.
241 if (childBox)
242 parentBox->addToLine(childBox);
243
244 if (!constructedNewBox || obj == &m_flow)
245 break;
246
247 childBox = parentBox;
248 }
249
250 // If we've exceeded our line depth, then jump straight to the root and skip all the remaining
251 // intermediate inline flows.
252 obj = (++lineDepth >= cMaxLineDepth) ? &m_flow : obj->parent();
253
254 } while (true);
255
256 return result;
257}
258
259LegacyRootInlineBox* LegacyLineLayout::constructLine(BidiRunList<BidiRun>& bidiRuns, const LineInfo& lineInfo)
260{
261 if (legacyRootBox()) {
262 // Refuse to create multiple lines for svg content. There should not need to be more than one.
263 ASSERT_NOT_REACHED()((void)0);
264 return nullptr;
265 }
266
267 ASSERT(bidiRuns.firstRun())((void)0);
268 LegacyInlineFlowBox* parentBox = 0;
269 for (BidiRun* r = bidiRuns.firstRun(); r; r = r->next()) {
270 if (lineInfo.isEmpty())
271 continue;
272
273 LegacyInlineBox* box = createInlineBoxForRenderer(&r->renderer());
274 r->setBox(box);
275
276 // If we have no parent box yet, or if the run is not simply a sibling,
277 // then we need to construct inline boxes as necessary to properly enclose the
278 // run's inline box. Segments can only be siblings at the root level, as
279 // they are positioned separately.
280 if (!parentBox || &parentBox->renderer() != r->renderer().parent()) {
281 // Create new inline boxes all the way back to the appropriate insertion point.
282 RenderObject* parentToUse = r->renderer().parent();
283 parentBox = createLineBoxes(parentToUse, lineInfo, box);
284 } else {
285 // Append the inline box to this line.
286 parentBox->addToLine(box);
287 }
288
289 box->setBidiLevel(r->level());
290
291 if (auto* textBox = dynamicDowncast<LegacyInlineTextBox>(*box)) {
292 textBox->setStart(r->m_start);
293 textBox->setLen(r->m_stop - r->m_start);
294 }
295 }
296
297 // We should have a root inline box. It should be unconstructed and
298 // be the last continuation of our line list.
299 ASSERT(legacyRootBox() && !legacyRootBox()->isConstructed())((void)0);
300
301 // Now mark the line boxes as being constructed.
302 legacyRootBox()->setConstructed();
303 return legacyRootBox();
304}
305
306void LegacyLineLayout::removeInlineBox(BidiRun& run, const LegacyRootInlineBox& rootLineBox) const
307{
308 auto* inlineBox = run.box();
309#if ASSERT_ENABLED0
310 auto* inlineParent = inlineBox->parent();
311 while (inlineParent && inlineParent != &rootLineBox) {
312 ASSERT(!inlineParent->isDirty())((void)0);
313 inlineParent = inlineParent->parent();
314 }
315 ASSERT(!rootLineBox.isDirty())((void)0);
316#endif
317 auto* parent = inlineBox->parent();
318 inlineBox->removeFromParent();
319
320 auto& renderer = run.renderer();
321 if (CheckedPtr textRenderer = dynamicDowncast<RenderSVGInlineText>(renderer))
322 textRenderer->removeTextBox(downcast<LegacyInlineTextBox>(*inlineBox));
323 delete inlineBox;
324 run.setBox(nullptr);
325 // removeFromParent() unnecessarily dirties the ancestor subtree.
326 auto* ancestor = parent;
327 while (ancestor) {
328 ancestor->markDirty(false);
329 if (ancestor == &rootLineBox)
330 break;
331 ancestor = ancestor->parent();
332 }
333}
334
335void LegacyLineLayout::removeEmptyTextBoxesAndUpdateVisualReordering(LegacyRootInlineBox* lineBox, BidiRun* firstRun)
336{
337 for (auto* run = firstRun; run; run = run->next()) {
338 if (auto* inlineTextBox = dynamicDowncast<LegacyInlineTextBox>(*run->box())) {
339 auto& renderer = inlineTextBox->renderer();
340 if (!inlineTextBox->hasTextContent()) {
341 removeInlineBox(*run, *lineBox);
342 continue;
343 }
344 if (!inlineTextBox->isLeftToRightDirection())
345 renderer.setNeedsVisualReordering();
346 }
347 }
348}
349
350static inline void notifyResolverToResumeInIsolate(InlineBidiResolver& resolver, const RenderInline* root, RenderObject* startObject)
351{
352 if (root != startObject) {
353 RenderObject* parent = startObject->parent();
354 notifyResolverToResumeInIsolate(resolver, root, parent);
355 notifyObserverEnteredObject(&resolver, startObject);
356 }
357}
358
359static inline void setUpResolverToResumeInIsolate(InlineBidiResolver& resolver, InlineBidiResolver& topResolver, BidiRun& isolatedRun, const RenderInline* root, RenderObject* startObject)
360{
361 // Set up m_whitespaceCollapsingState
362 resolver.whitespaceCollapsingState() = topResolver.whitespaceCollapsingState();
363 resolver.whitespaceCollapsingState().setCurrentTransition(topResolver.whitespaceCollapsingTransitionForIsolatedRun(isolatedRun));
364
365 // Set up m_nestedIsolateCount
366 notifyResolverToResumeInIsolate(resolver, root, startObject);
367}
368
369// FIXME: BidiResolver should have this logic.
370static inline void constructBidiRunsForSegment(InlineBidiResolver& topResolver, BidiRunList<BidiRun>& bidiRuns, const LegacyInlineIterator& endOfRuns, VisualDirectionOverride override)
371{
372 // FIXME: We should pass a BidiRunList into createBidiRunsForLine instead
373 // of the resolver owning the runs.
374 ASSERT(&topResolver.runs() == &bidiRuns)((void)0);
375 ASSERT(topResolver.position() != endOfRuns)((void)0);
376 topResolver.createBidiRunsForLine(endOfRuns, override);
377
378 while (!topResolver.isolatedRuns().isEmpty()) {
379 // It does not matter which order we resolve the runs as long as we resolve them all.
380 auto isolatedRun = WTF::move(topResolver.isolatedRuns().last());
381 topResolver.isolatedRuns().removeLast();
382
383 RenderObject& startObject = isolatedRun.object;
384
385 // Only inlines make sense with unicode-bidi: isolate (blocks are already isolated).
386 // FIXME: Because enterIsolate is not passed a RenderObject, we have to crawl up the
387 // tree to see which parent inline is the isolate. We could change enterIsolate
388 // to take a RenderObject and do this logic there, but that would be a layering
389 // violation for BidiResolver (which knows nothing about RenderObject).
390 RenderInline* isolatedInline = downcast<RenderInline>(highestContainingIsolateWithinRoot(startObject, &isolatedRun.root));
391 ASSERT(isolatedInline)((void)0);
392
393 InlineBidiResolver isolatedResolver;
394 auto unicodeBidi = isolatedInline->style().unicodeBidi();
395 TextDirection direction;
396 if (unicodeBidi == UnicodeBidi::Plaintext)
397 determineDirectionality(direction, LegacyInlineIterator(isolatedInline, &isolatedRun.object, 0));
398 else {
399 ASSERT(unicodeBidi == UnicodeBidi::Isolate || unicodeBidi == UnicodeBidi::IsolateOverride)((void)0);
400 direction = isolatedInline->writingMode().bidiDirection();
401 }
402 isolatedResolver.setStatus(BidiStatus(direction, isOverride(unicodeBidi)));
403
404 setUpResolverToResumeInIsolate(isolatedResolver, topResolver, isolatedRun.runToReplace, isolatedInline, &startObject);
405
406 // The starting position is the beginning of the first run within the isolate that was identified
407 // during the earlier call to createBidiRunsForLine. This can be but is not necessarily the
408 // first run within the isolate.
409 LegacyInlineIterator iter = LegacyInlineIterator(isolatedInline, &startObject, isolatedRun.position);
410 isolatedResolver.setPositionIgnoringNestedIsolates(iter);
411
412 // We stop at the next end of line; we may re-enter this isolate in the next call to constructBidiRuns().
413 isolatedResolver.createBidiRunsForLine(endOfRuns, NoVisualOverride);
414 // Note that we do not delete the runs from the resolver.
415 // We're not guaranteed to get any BidiRuns in the previous step. If we don't, we allow the placeholder
416 // itself to be turned into an InlineBox. We can't remove it here without potentially losing track of
417 // the logically last run.
418 if (isolatedResolver.runs().runCount())
419 bidiRuns.replaceRunWithRuns(&isolatedRun.runToReplace, isolatedResolver.runs());
420
421 // If we encountered any nested isolate runs, just move them
422 // to the top resolver's list for later processing.
423 while (!isolatedResolver.isolatedRuns().isEmpty()) {
424 auto runWithContext = WTF::move(isolatedResolver.isolatedRuns().last());
425 isolatedResolver.isolatedRuns().removeLast();
426 topResolver.setWhitespaceCollapsingTransitionForIsolatedRun(runWithContext.runToReplace, isolatedResolver.whitespaceCollapsingTransitionForIsolatedRun(runWithContext.runToReplace));
427 topResolver.isolatedRuns().append(WTF::move(runWithContext));
428 }
429 }
430}
431
432// This function constructs line boxes for all of the text runs in the resolver and computes their position.
433LegacyRootInlineBox* LegacyLineLayout::createLineBoxesFromBidiRuns(unsigned bidiLevel, BidiRunList<BidiRun>& bidiRuns, const LegacyInlineIterator& end, LineInfo& lineInfo)
434{
435 if (!bidiRuns.runCount())
436 return nullptr;
437
438 // FIXME: Why is this only done when we had runs?
439 lineInfo.setLastLine(!end.renderer());
440
441 LegacyRootInlineBox* lineBox = constructLine(bidiRuns, lineInfo);
442 if (!lineBox)
443 return nullptr;
444
445 lineBox->setBidiLevel(bidiLevel);
446
447 removeEmptyTextBoxesAndUpdateVisualReordering(lineBox, bidiRuns.firstRun());
448
449 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
450 lineBox->computeOverflow(lineBox->lineTop(), lineBox->lineBottom(), textBoxDataMap);
451
452 return lineBox;
453}
454
455static void repaintSelfPaintInlineBoxes(const LegacyRootInlineBox& rootInlineBox)
456{
457 if (rootInlineBox.hasSelfPaintInlineBox()) {
458 for (auto* inlineBox = rootInlineBox.firstChild(); inlineBox; inlineBox = inlineBox->nextOnLine()) {
459 if (auto* renderer = dynamicDowncast<RenderLayerModelObject>(inlineBox->renderer()); renderer && renderer->hasSelfPaintingLayer())
460 renderer->repaint();
461 }
462 }
463}
464
465void LegacyLineLayout::layoutRunsAndFloats(bool hasInlineChild)
466{
467 deleteLegacyRootBox(true);
468
469 TextDirection direction = style().writingMode().bidiDirection();
470 if (style().unicodeBidi() == UnicodeBidi::Plaintext)
471 determineDirectionality(direction, LegacyInlineIterator(&m_flow, firstInlineRendererSkippingEmpty(m_flow), 0));
472
473 InlineBidiResolver resolver;
474 resolver.setStatus(BidiStatus(direction, isOverride(style().unicodeBidi())));
475 LegacyInlineIterator iter = LegacyInlineIterator(&m_flow, firstInlineRendererSkippingEmpty(m_flow, &resolver), 0);
476 resolver.setPosition(iter, numberOfIsolateAncestors(iter));
477
478 if (hasInlineChild && !m_flow.selfNeedsLayout()) {
479 m_flow.setNeedsLayout(MarkOnlyThis); // Mark as needing a full layout to force us to repaint.
480 if (!layoutContext().needsFullRepaint() && m_flow.cachedLayerClippedOverflowRect()) {
481 // Because we waited until we were already inside layout to discover
482 // that the block really needed a full layout, we missed our chance to repaint the layer
483 // before layout started. Luckily the layer has cached the repaint rect for its original
484 // position and size, and so we can use that to make a repaint happen now.
485 m_flow.repaintUsingContainer(m_flow.containerForRepaint().renderer.get(), *m_flow.cachedLayerClippedOverflowRect());
486 }
487 }
488
489 layoutRunsAndFloatsInRange(resolver);
490 if (legacyRootBox())
491 repaintSelfPaintInlineBoxes(*legacyRootBox());
492}
493
494void LegacyLineLayout::layoutRunsAndFloatsInRange(InlineBidiResolver& resolver)
495{
496 const RenderStyle& styleToUse = style();
497 LineWhitespaceCollapsingState& lineWhitespaceCollapsingState = resolver.whitespaceCollapsingState();
498 LegacyInlineIterator end = resolver.position();
499 RenderTextInfo renderTextInfo;
500
501 LineInfo lineInfo { };
502 LineBreaker lineBreaker(m_flow);
503
504 while (!end.atEnd()) {
505 lineWhitespaceCollapsingState.reset();
506
507 lineInfo.setEmpty(true);
508 lineInfo.resetRunsFromLeadingWhitespace();
509
510 end = lineBreaker.nextLineBreak(resolver, lineInfo, renderTextInfo);
511 renderTextInfo.lineBreakIteratorFactory.priorContext().reset();
512 if (resolver.position().atEnd()) {
513 // FIXME: We shouldn't be creating any runs in nextLineBreak to begin with!
514 // Once BidiRunList is separated from BidiResolver this will not be needed.
515 resolver.runs().clear();
516 resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed).
517 resolver.setPosition(LegacyInlineIterator(resolver.position().root(), 0, 0), 0);
518 break;
519 }
520
521 ASSERT(end != resolver.position())((void)0);
522
523 if (!lineInfo.isEmpty()) {
524 VisualDirectionOverride override = (styleToUse.rtlOrdering() == Order::Visual ? (styleToUse.writingMode().isBidiLTR() ? VisualLeftToRightOverride : VisualRightToLeftOverride) : NoVisualOverride);
525
526 if (styleToUse.unicodeBidi() == UnicodeBidi::Plaintext && !resolver.context()->parent()) {
527 TextDirection direction = styleToUse.writingMode().bidiDirection();
528 determineDirectionality(direction, resolver.position());
529 resolver.setStatus(BidiStatus(direction, isOverride(styleToUse.unicodeBidi())));
530 }
531 // FIXME: This ownership is reversed. We should own the BidiRunList and pass it to createBidiRunsForLine.
532 BidiRunList<BidiRun>& bidiRuns = resolver.runs();
533 constructBidiRunsForSegment(resolver, bidiRuns, end, override);
534 ASSERT(resolver.position() == end)((void)0);
535
536 // Now that the runs have been ordered, we create the line boxes.
537
538 createLineBoxesFromBidiRuns(resolver.status().context->level(), bidiRuns, end, lineInfo);
539
540 bidiRuns.clear();
541 resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed).
542 }
543
544 if (!lineInfo.isEmpty())
545 lineInfo.setFirstLine(false);
546
547 lineWhitespaceCollapsingState.reset();
548 resolver.setPosition(end, numberOfIsolateAncestors(end));
549 }
550}
551
552void LegacyLineLayout::layoutLineBoxes()
553{
554 m_flow.setLogicalHeight(0_lu);
555
556 deleteLegacyRootBox();
557
558 if (m_flow.firstChild()) {
559 // In full layout mode, clear the line boxes of children upfront. Otherwise,
560 // siblings can run into stale root lineboxes during layout. Then layout
561 // the replaced elements later. In partial layout mode, line boxes are not
562 // deleted and only dirtied. In that case, we can layout the replaced
563 // elements at the same time.
564 bool hasInlineChild = false;
565 for (InlineWalker walker(m_flow); !walker.atEnd(); walker.advance()) {
566 RenderObject& o = *walker.current();
567
568 if (!hasInlineChild && o.isInline())
569 hasInlineChild = true;
570
571 dirtyLineBoxesForRenderer(o);
572 o.clearNeedsLayout();
573 }
574
575 layoutRunsAndFloats(hasInlineChild);
576 }
577
578 if (!legacyRootBox() && m_flow.hasLineIfEmpty())
579 m_flow.setLogicalHeight(m_flow.logicalHeight() + m_flow.lineHeight());
580}
581
582void LegacyLineLayout::addOverflowFromInlineChildren()
583{
584 if (auto* rootBox = legacyRootBox()) {
585 LayoutRect childVisualOverflowRect = rootBox->visualOverflowRect(rootBox->lineTop(), rootBox->lineBottom());
586 m_flow.addVisualOverflow(childVisualOverflowRect);
587 }
588}
589
590size_t LegacyLineLayout::lineCount() const
591{
592 return legacyRootBox() ? 1 : 0;
593}
594
595const RenderStyle& LegacyLineLayout::style() const
596{
597 return m_flow.style();
598}
599
600const LocalFrameViewLayoutContext& LegacyLineLayout::layoutContext() const
601{
602 return m_flow.view().frameView().layoutContext();
A function 'layoutContext' has [[clang::annotate_type("webkit.nodelete")]] but it contains code that could destruct an object
603}
604
605void LegacyLineLayout::shiftLineBy(LayoutUnit shiftX, LayoutUnit shiftY)
606{
607 if (m_legacyRootInlineBox)
608 m_legacyRootInlineBox->adjustPosition(shiftX, shiftY);
609}
610
611void LegacyLineLayout::deleteLegacyRootBox(bool runCleanup)
612{
613 if (!m_legacyRootInlineBox)
614 return;
615
616 if (!runCleanup) {
617 m_legacyRootInlineBox = { };
618 return;
619 }
620
621 auto* rootInlineBoxToDestroy = m_legacyRootInlineBox.release();
622 rootInlineBoxToDestroy->deleteLine();
623}
624
625}