Bug Summary

File:Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore/page/FrameTree.cpp
Warning:line 421, column 11
Local variable 'child' is uncounted and unsafe

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple arm64-apple-macosx15.5.0 -O2 -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name UnifiedSource298.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=15.5 -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/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore -target-linker-version 1167.5 -fcoverage-compilation-dir=/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore -resource-dir /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/llvm-project/build/lib/clang/21 -dependency-file /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/UnifiedSource298.d -skip-unused-modulemap-deps -MT dependencies -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk -iquote /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-generated-files.hmap -iquote /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-project-headers.hmap -isystem /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore/PAL/ThirdParty/dav1d/include -iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/PrivateFrameworks -iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/Frameworks -include-pch /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/PrecompiledHeaders/SharedPrecompiledHeaders/988383290502741483/WebCorePrefix.h.gch -D _LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE -D CLANG_WEBKIT_BRANCH=1 -D NDEBUG -D BUILDING_WEBKIT -D GL_SILENCE_DEPRECATION=1 -D GLES_SILENCE_DEPRECATION=1 -D __clang_analyzer__ -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-own-target-headers.hmap -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-all-target-headers.hmap -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/include -I PAL -I ForwardingHeaders -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/include/libxslt -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/include/libxml2 -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/DerivedSources/WebCore -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include/WebKitAdditions -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include/WebKitAdditions -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/macosx15.0-additions.sdk/usr/local/include -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include/webrtc -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include/webrtc -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include/webm -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include/webm -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/PAL.build/PAL.build/DerivedSources -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/PAL.build/Release/PAL.build/DerivedSources -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/DerivedSources-normal/arm64 -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/DerivedSources/arm64 -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/DerivedSources -F/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release -I/usr/local/include -stdlib=libc++ -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/include/c++/v1 -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include -internal-isystem /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/llvm-project/build/lib/clang/21/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/include -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/Frameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/SubFrameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.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 -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-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.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/macOS-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/UnifiedSource298.plist -x c++ /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/DerivedSources/WebCore/unified-sources/UnifiedSource298.cpp
1/*
2 * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
3 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#include "config.h"
22#include "FrameTree.h"
23
24#include "Document.h"
25#include "FrameLoader.h"
26#include "HTMLFrameOwnerElement.h"
27#include "LocalFrame.h"
28#include "LocalFrameInlines.h"
29#include "LocalFrameView.h"
30#include "Page.h"
31#include "PageGroup.h"
32#include <stdarg.h>
33#include <wtf/Vector.h>
34#include <wtf/text/CString.h>
35#include <wtf/text/StringBuilder.h>
36
37namespace WebCore {
38
39FrameTree::FrameTree(Frame& thisFrame, Frame* parentFrame)
40 : m_thisFrame(thisFrame)
41 , m_parent(parentFrame)
42{
43}
44
45FrameTree::~FrameTree()
46{
47 for (RefPtr child = firstChild(); child; child = child->tree().nextSibling())
48 child->disconnectView();
49}
50
51void FrameTree::setSpecifiedName(const AtomString& specifiedName)
52{
53 m_specifiedName = specifiedName;
54}
55
56void FrameTree::clearName()
57{
58 m_specifiedName = nullAtom();
59}
60
61Frame* FrameTree::parent() const
62{
63 return m_parent.get();
64}
65
66void FrameTree::appendChild(Frame& child)
67{
68 ASSERT(child.page() == m_thisFrame->page())((void)0);
69 child.tree().m_parent = m_thisFrame.ptr();
70 WeakPtr<Frame> oldLast = m_lastChild;
71 m_lastChild = child;
72
73 if (oldLast) {
74 child.tree().m_previousSibling = oldLast;
75 oldLast->tree().m_nextSibling = child;
76 } else
77 m_firstChild = child;
78
79 m_scopedChildCount = invalidCount;
80
81 ASSERT(!m_lastChild->tree().m_nextSibling)((void)0);
82}
83
84void FrameTree::removeChild(Frame& child)
85{
86 WeakPtr<Frame>& newLocationForPrevious = m_lastChild == &child ? m_lastChild : child.tree().m_nextSibling->tree().m_previousSibling;
87 RefPtr<Frame>& newLocationForNext = m_firstChild == &child ? m_firstChild : child.tree().m_previousSibling->tree().m_nextSibling;
88
89 child.tree().m_parent = nullptr;
90 newLocationForPrevious = std::exchange(child.tree().m_previousSibling, nullptr);
91 newLocationForNext = WTF::move(child.tree().m_nextSibling);
92
93 m_scopedChildCount = invalidCount;
94}
95
96void FrameTree::replaceChild(Frame& oldChild, Frame& newChild)
97{
98 auto& oldTree = oldChild.tree();
99 auto& newTree = newChild.tree();
100 ASSERT(oldTree.parent() == m_thisFrame.ptr())((void)0);
101 ASSERT(!newTree.parent())((void)0);
102 ASSERT(!newTree.nextSibling())((void)0);
103 ASSERT(!newTree.previousSibling())((void)0);
104 ASSERT(!newTree.firstChild())((void)0);
105 ASSERT(!newTree.lastChild())((void)0);
106 ASSERT(newTree.m_scopedChildCount == invalidCount)((void)0);
107 ASSERT(newTree.m_thisFrame.ptr() == &newChild)((void)0);
108 ASSERT(is<LocalFrame>(oldChild) != is<LocalFrame>(newChild))((void)0);
109
110 RefPtr oldNextSibling = oldTree.nextSibling();
111 RefPtr oldPreviousSibling = oldTree.previousSibling();
112 bool oldChildWasFirst = m_firstChild.get() == &oldChild;
113 bool oldChildWasLast = m_lastChild.get() == &oldChild;
114 // Children are intentionally not carried to the new tree because this happens during navigation, when all child frames are removed.
115
116 if (RefPtr oldLocalFrame = dynamicDowncast<LocalFrame>(oldChild))
117 oldLocalFrame->loader().detachFromParent();
118 else
119 removeChild(oldChild);
120
121 newTree.m_parent = m_thisFrame.ptr();
122 newTree.m_nextSibling = oldNextSibling.get();
123 newTree.m_previousSibling = oldPreviousSibling.get();
124
125 if (oldChildWasFirst)
126 m_firstChild = newChild;
127 if (oldChildWasLast)
128 m_lastChild = newChild;
129 if (oldNextSibling)
130 oldNextSibling->tree().m_previousSibling = &newChild;
131 if (oldPreviousSibling)
132 oldPreviousSibling->tree().m_nextSibling = &newChild;
133}
134
135Ref<Frame> FrameTree::protectedThisFrame() const
136{
137 return m_thisFrame.get();
138}
139
140static bool inScope(Frame& frame, TreeScope& scope)
141{
142 RefPtr localFrame = dynamicDowncast<LocalFrame>(frame);
143 if (!localFrame)
144 return true;
145 RefPtr document = localFrame->document();
146 if (!document)
147 return false;
148 RefPtr owner = document->ownerElement();
149 return owner && &owner->treeScope() == &scope;
150}
151
152RefPtr<Frame> FrameTree::scopedChild(unsigned index, TreeScope* scope) const
153{
154 if (!scope)
155 return nullptr;
156
157 unsigned scopedIndex = 0;
158 for (RefPtr frame = firstChild(); frame; frame = frame->tree().nextSibling()) {
159 if (inScope(*frame, *scope)) {
160 if (scopedIndex == index)
161 return frame;
162 ++scopedIndex;
163 }
164 }
165
166 return nullptr;
167}
168
169inline RefPtr<Frame> FrameTree::scopedChild(NOESCAPE[[clang::noescape]] const Function<bool(const FrameTree&)>& isMatch, TreeScope* scope) const
170{
171 if (!scope)
172 return nullptr;
173
174 for (RefPtr child = firstChild(); child; child = child->tree().nextSibling()) {
175 if (isMatch(child->tree()) && inScope(*child, *scope))
176 return child;
177 }
178 return nullptr;
179}
180
181inline unsigned FrameTree::scopedChildCount(TreeScope* scope) const
182{
183 if (!scope)
184 return 0;
185
186 unsigned scopedCount = 0;
187 for (RefPtr result = firstChild(); result; result = result->tree().nextSibling()) {
188 if (inScope(*result, *scope))
189 scopedCount++;
190 }
191
192 return scopedCount;
193}
194
195RefPtr<Frame> FrameTree::scopedChild(unsigned index) const
196{
197 RefPtr localFrame = dynamicDowncast<LocalFrame>(m_thisFrame.get());
198 if (!localFrame)
199 return nullptr;
200 return scopedChild(index, localFrame->protectedDocument().get());
201}
202
203RefPtr<Frame> FrameTree::scopedChildByUniqueName(const AtomString& uniqueName) const
204{
205 RefPtr localFrame = dynamicDowncast<LocalFrame>(m_thisFrame.get());
206 if (!localFrame)
207 return nullptr;
208 return scopedChild([&](auto& frameTree) {
209 return frameTree.uniqueName() == uniqueName;
210 }, localFrame->protectedDocument().get());
211}
212
213RefPtr<Frame> FrameTree::scopedChildBySpecifiedName(const AtomString& specifiedName) const
214{
215 RefPtr localFrame = dynamicDowncast<LocalFrame>(m_thisFrame.get());
216 if (!localFrame)
217 return childBySpecifiedName(specifiedName);
218 return scopedChild([&](auto& frameTree) {
219 return frameTree.specifiedName() == specifiedName;
220 }, localFrame->protectedDocument().get());
221}
222
223unsigned FrameTree::scopedChildCount() const
224{
225 if (m_scopedChildCount == invalidCount) {
226 if (RefPtr localFrame = dynamicDowncast<LocalFrame>(m_thisFrame.get()))
227 m_scopedChildCount = scopedChildCount(localFrame->protectedDocument().get());
228 }
229 return m_scopedChildCount;
230}
231
232unsigned FrameTree::childCount() const
233{
234 unsigned count = 0;
235 for (auto* child = firstChild(); child; child = child->tree().nextSibling())
236 ++count;
237 return count;
238}
239
240unsigned FrameTree::descendantCount() const
241{
242 unsigned count = 0;
243 for (auto* child = firstChild(); child; child = child->tree().nextSibling())
244 count += 1 + child->tree().descendantCount();
245 return count;
246}
247
248Frame* FrameTree::child(unsigned index) const
249{
250 auto* result = firstChild();
251 for (unsigned i = 0; result && i != index; ++i)
252 result = result->tree().nextSibling();
253 return result;
254}
255
256Frame* FrameTree::descendantByFrameID(FrameIdentifier frameID) const
257{
258 for (auto* child = firstChild(); child; child = child->tree().traverseNext()) {
259 if (child->frameID() == frameID)
260 return child;
261 }
262 return nullptr;
263}
264
265Frame* FrameTree::childBySpecifiedName(const AtomString& name) const
266{
267 for (auto* child = firstChild(); child; child = child->tree().nextSibling()) {
268 if (child->tree().specifiedName() == name)
269 return child;
270 }
271 return nullptr;
272}
273
274// FrameTree::find() only returns frames in pages that are related to the active
275// page by an opener <-> openee relationship.
276static bool isFrameFamiliarWith(Frame& frameA, Frame& frameB)
277{
278 if (frameA.page() == frameB.page())
279 return true;
280
281 auto* frameAOpener = frameA.mainFrame().opener();
282 auto* frameBOpener = frameB.mainFrame().opener();
283 return (frameAOpener && frameAOpener->page() == frameB.page())
284 || (frameBOpener && frameBOpener->page() == frameA.page())
285 || (frameAOpener && frameBOpener && frameAOpener->page() == frameBOpener->page());
286}
287
288template<typename F>
289inline RefPtr<Frame> FrameTree::find(const AtomString& name, F&& nameGetter, Frame& activeFrame) const
290{
291 if (isSelfTargetFrameName(name))
292 return m_thisFrame.ptr();
293
294 if (isTopTargetFrameName(name))
295 return &top();
296
297 if (isParentTargetFrameName(name))
298 return parent() ? parent() : m_thisFrame.ptr();
299
300 // Since "_blank" cannot be a frame's name, this check is an optimization, not for correctness.
301 if (isBlankTargetFrameName(name))
302 return nullptr;
303
304 // Search subtree starting with this frame first.
305 Ref thisFrame = m_thisFrame.get();
306 for (RefPtr frame = thisFrame.ptr(); frame; frame = frame->tree().traverseNext(thisFrame.ptr())) {
307 if (nameGetter(frame->tree()) == name)
308 return frame;
309 }
310
311 // Then the rest of the tree.
312 for (RefPtr frame = &thisFrame->mainFrame(); frame; frame = frame->tree().traverseNext()) {
313 if (nameGetter(frame->tree()) == name)
314 return frame;
315 }
316
317 // Search the entire tree of each of the other pages in this namespace.
318 RefPtr page = thisFrame->page();
319 if (!page)
320 return nullptr;
321
322 // FIXME: These pages are searched in random order; that doesn't seem good. Maybe use order of creation?
323 for (RefPtr otherPage : page->group().pages()) {
324 if (otherPage == page || otherPage->isClosing())
325 continue;
326 for (RefPtr frame = &otherPage->mainFrame(); frame; frame = frame->tree().traverseNext()) {
327 if (nameGetter(frame->tree()) == name && isFrameFamiliarWith(activeFrame, *frame))
328 return frame;
329 }
330 }
331
332 return nullptr;
333}
334
335RefPtr<Frame> FrameTree::findByUniqueName(const AtomString& uniqueName, Frame& activeFrame) const
336{
337 return find(uniqueName, [&](auto& frameTree) -> AtomString {
338 return frameTree.uniqueName();
339 }, activeFrame);
340}
341
342RefPtr<Frame> FrameTree::findBySpecifiedName(const AtomString& specifiedName, Frame& activeFrame) const
343{
344 return find(specifiedName, [&](auto& frameTree) -> const AtomString& {
345 return frameTree.specifiedName();
346 }, activeFrame);
347}
348
349bool FrameTree::isDescendantOf(const Frame* ancestor) const
350{
351 if (!ancestor)
352 return false;
353
354 if (m_thisFrame->page() != ancestor->page())
355 return false;
356
357 for (Frame* frame = m_thisFrame.ptr(); frame; frame = frame->tree().parent()) {
358 if (frame == ancestor)
359 return true;
360 }
361 return false;
362}
363
364Frame* FrameTree::traverseNext(const Frame* stayWithin) const
365{
366 auto* child = firstChild();
367 if (child) {
368 ASSERT(!stayWithin || child->tree().isDescendantOf(stayWithin))((void)0);
369 return child;
370 }
371
372 if (m_thisFrame.ptr() == stayWithin)
373 return nullptr;
374
375 auto* sibling = nextSibling();
376 if (sibling) {
377 ASSERT(!stayWithin || sibling->tree().isDescendantOf(stayWithin))((void)0);
378 return sibling;
379 }
380
381 auto* frame = m_thisFrame.ptr();
382 while (!sibling && (!stayWithin || frame->tree().parent() != stayWithin)) {
383 frame = frame->tree().parent();
384 if (!frame)
385 return nullptr;
386 sibling = frame->tree().nextSibling();
387 }
388
389 if (frame) {
390 ASSERT(!stayWithin || !sibling || sibling->tree().isDescendantOf(stayWithin))((void)0);
391 return sibling;
392 }
393
394 return nullptr;
395}
396
397Frame* FrameTree::traverseNextSkippingChildren(const Frame* stayWithin) const
398{
399 if (m_thisFrame.ptr() == stayWithin)
400 return nullptr;
401 if (auto* sibling = nextSibling())
402 return sibling;
403 return nextAncestorSibling(stayWithin);
404}
405
406Frame* FrameTree::nextAncestorSibling(const Frame* stayWithin) const
407{
408 ASSERT(!nextSibling())((void)0);
409 ASSERT(m_thisFrame.ptr() != stayWithin)((void)0);
410 for (auto* ancestor = parent(); ancestor; ancestor = ancestor->tree().parent()) {
411 if (ancestor == stayWithin)
412 return nullptr;
413 if (auto ancestorSibling = ancestor->tree().nextSibling())
414 return ancestorSibling;
415 }
416 return nullptr;
417}
418
419Frame* FrameTree::firstRenderedChild() const
420{
421 auto* child = firstChild();
Local variable 'child' is uncounted and unsafe
422 if (!child)
423 return nullptr;
424
425 if (auto* localChild = dynamicDowncast<LocalFrame>(child); localChild && localChild->ownerRenderer())
426 return child;
427
428 while ((child = child->tree().nextSibling())) {
429 if (auto* localChild = dynamicDowncast<LocalFrame>(child); localChild && localChild->ownerRenderer())
430 return child;
431 }
432
433 return nullptr;
434}
435
436Frame* FrameTree::nextRenderedSibling() const
437{
438 auto* sibling = m_thisFrame.ptr();
439
440 while ((sibling = sibling->tree().nextSibling())) {
441 if (auto* localSibling = dynamicDowncast<LocalFrame>(sibling); localSibling && localSibling->ownerRenderer())
442 return sibling;
443 }
444
445 return nullptr;
446}
447
448LocalFrame* FrameTree::firstLocalDescendant() const
449{
450 for (auto* child = firstChild(); child; child = child->tree().traverseNext()) {
451 if (auto* localChild = dynamicDowncast<LocalFrame>(child))
452 return localChild;
453 }
454 return nullptr;
455}
456
457LocalFrame* FrameTree::nextLocalSibling() const
458{
459 for (auto* sibling = nextSibling(); sibling; sibling = sibling->tree().nextSibling()) {
460 if (auto* localSibling = dynamicDowncast<LocalFrame>(sibling))
461 return localSibling;
462 }
463 return nullptr;
464}
465
466Frame* FrameTree::traverseNextRendered(const Frame* stayWithin) const
467{
468 auto* child = firstRenderedChild();
469 if (child) {
470 ASSERT(!stayWithin || child->tree().isDescendantOf(stayWithin))((void)0);
471 return child;
472 }
473
474 if (m_thisFrame.ptr() == stayWithin)
475 return nullptr;
476
477 auto* sibling = nextRenderedSibling();
478 if (sibling) {
479 ASSERT(!stayWithin || sibling->tree().isDescendantOf(stayWithin))((void)0);
480 return sibling;
481 }
482
483 auto* frame = m_thisFrame.ptr();
484 while (!sibling && (!stayWithin || frame->tree().parent() != stayWithin)) {
485 frame = frame->tree().parent();
486 if (!frame)
487 return nullptr;
488 sibling = frame->tree().nextRenderedSibling();
489 }
490
491 if (frame) {
492 ASSERT(!stayWithin || !sibling || sibling->tree().isDescendantOf(stayWithin))((void)0);
493 return sibling;
494 }
495
496 return nullptr;
497}
498
499Frame* FrameTree::traverseNext(CanWrap canWrap, DidWrap* didWrap) const
500{
501 if (auto* result = traverseNext())
502 return result;
503
504 if (canWrap == CanWrap::Yes) {
505 if (didWrap)
506 *didWrap = DidWrap::Yes;
507 return &m_thisFrame->mainFrame();
508 }
509
510 return nullptr;
511}
512
513Frame* FrameTree::traversePrevious(CanWrap canWrap, DidWrap* didWrap) const
514{
515 // FIXME: besides the wrap feature, this is just the traversePreviousNode algorithm
516
517 if (auto* prevSibling = previousSibling())
518 return prevSibling->tree().deepLastChild();
519 if (auto* parentFrame = parent())
520 return parentFrame;
521
522 // no siblings, no parent, self==top
523 if (canWrap == CanWrap::Yes) {
524 if (didWrap)
525 *didWrap = DidWrap::Yes;
526 return deepLastChild();
527 }
528
529 // top view is always the last one in this ordering, so prev is nil without wrap
530 return nullptr;
531}
532
533Frame* FrameTree::traverseNextInPostOrder(CanWrap canWrap) const
534{
535 if (m_nextSibling)
536 return m_nextSibling->tree().deepFirstChild();
537 if (m_parent)
538 return m_parent.get();
539 if (canWrap == CanWrap::Yes)
540 return deepFirstChild();
541 return nullptr;
542}
543
544Frame* FrameTree::deepFirstChild() const
545{
546 auto* result = m_thisFrame.ptr();
547 while (auto* next = result->tree().firstChild())
548 result = next;
549 return result;
550}
551
552Frame* FrameTree::deepLastChild() const
553{
554 auto* result = m_thisFrame.ptr();
555 for (auto* last = lastChild(); last; last = last->tree().lastChild())
556 result = last;
557
558 return result;
559}
560
561Frame& FrameTree::top() const
562{
563 return m_thisFrame->mainFrame();
564}
565
566Ref<Frame> FrameTree::protectedTop() const
567{
568 return top();
569}
570
571unsigned FrameTree::depth() const
572{
573 unsigned depth = 0;
574 for (auto* parent = m_thisFrame.ptr(); parent; parent = parent->tree().parent())
575 depth++;
576 return depth;
577}
578
579AtomString FrameTree::uniqueName() const
580{
581 if (!parent())
582 return m_specifiedName;
583
584 auto frameIndex { 0u };
585 for (RefPtr frame = top().tree().firstChild(); frame; frame = frame->tree().traverseNext()) {
586 bool frameMatch = frame->frameID() == m_thisFrame->frameID();
587 auto frameName = frame->tree().specifiedName();
588 if (frameName.isEmpty() || isBlankTargetFrameName(frameName) || frame->tree().childBySpecifiedName(frameName)) {
589 frameIndex++;
590 if (frameMatch)
591 return makeAtomString("<!--frame"_s, frameIndex, "-->"_s);
592 }
593 if (frameMatch)
594 return frameName;
595 }
596 return nullAtom();
597}
598
599ASCIILiteral blankTargetFrameName()
600{
601 return "_blank"_s;
602}
603
604// FIXME: Is it important to have this? Can't we just use the empty string everywhere this is used, instead?
605ASCIILiteral selfTargetFrameName()
606{
607 return "_self"_s;
608}
609
610bool isBlankTargetFrameName(StringView name)
611{
612 return equalIgnoringASCIICase(name, "_blank"_s);
613}
614
615bool isParentTargetFrameName(StringView name)
616{
617 return equalIgnoringASCIICase(name, "_parent"_s);
618}
619
620bool isSelfTargetFrameName(StringView name)
621{
622 // FIXME: Some day we should remove _current, which is not part of the HTML specification.
623 return name.isEmpty() || equalIgnoringASCIICase(name, "_self"_s) || name == "_current"_s;
624}
625
626bool isTopTargetFrameName(StringView name)
627{
628 return equalIgnoringASCIICase(name, "_top"_s);
629}
630
631} // namespace WebCore
632
633#ifndef NDEBUG1
634
635static void printIndent(int indent)
636{
637 for (int i = 0; i < indent; ++i)
638 printf(" ");
639}
640
641static void printFrames(const WebCore::Frame& frame, const WebCore::Frame* targetFrame, int indent)
642{
643 if (&frame == targetFrame) {
644 printf("--> ");
645 printIndent(indent - 1);
646 } else
647 printIndent(indent);
648
649 auto* localFrame = dynamicDowncast<WebCore::LocalFrame>(frame);
650 if (!localFrame)
651 printf("RemoteFrame %p\n", &frame);
652 else {
653 auto* view = localFrame->view();
654 printf("Frame %p %dx%d\n", &frame, view ? view->width() : 0, view ? view->height() : 0);
655 printIndent(indent);
656 printf(" ownerElement=%p\n", localFrame->ownerElement());
657 printIndent(indent);
658 printf(" frameView=%p (needs layout %d)\n", view, view ? view->needsLayout() : false);
659 printIndent(indent);
660 printf(" renderView=%p\n", view ? view->renderView() : nullptr);
661 printIndent(indent);
662 printf(" ownerRenderer=%p\n", localFrame->ownerRenderer());
663 printIndent(indent);
664 printf(" document=%p (needs style recalc %d)\n", localFrame->document(), localFrame->document() ? localFrame->document()->childNeedsStyleRecalc() : false);
665 printIndent(indent);
666 SAFE_PRINTF(" uri=%s\n", localFrame->document()->documentURI().utf8())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" printf(" uri=%s\n"
, WTF::safePrintfType(localFrame->document()->documentURI
().utf8())) clang diagnostic pop
;
667 }
668 for (auto* child = frame.tree().firstChild(); child; child = child->tree().nextSibling())
669 printFrames(*child, targetFrame, indent + 1);
670}
671
672void showFrameTree(const WebCore::Frame* frame)
673{
674 if (!frame) {
675 printf("Null input frame\n");
676 return;
677 }
678
679 printFrames(frame->tree().protectedTop(), frame, 0);
680}
681
682#endif