Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/TimeStamp.h
Warning:line 420, column 49
The left operand of '==' is a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name nsContentUtils.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/base -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/base -resource-dir /usr/lib/llvm-19/lib/clang/19 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/battery -I /var/lib/jenkins/workspace/firefox-scan-build/dom/events -I /var/lib/jenkins/workspace/firefox-scan-build/dom/media -I /var/lib/jenkins/workspace/firefox-scan-build/dom/network -I /var/lib/jenkins/workspace/firefox-scan-build/caps -I /var/lib/jenkins/workspace/firefox-scan-build/docshell/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/file -I /var/lib/jenkins/workspace/firefox-scan-build/dom/geolocation -I /var/lib/jenkins/workspace/firefox-scan-build/dom/html -I /var/lib/jenkins/workspace/firefox-scan-build/dom/ipc -I /var/lib/jenkins/workspace/firefox-scan-build/dom/storage -I /var/lib/jenkins/workspace/firefox-scan-build/dom/svg -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xml -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xslt/xpath -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xul -I /var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/src -I /var/lib/jenkins/workspace/firefox-scan-build/gfx/2d -I /var/lib/jenkins/workspace/firefox-scan-build/image -I /var/lib/jenkins/workspace/firefox-scan-build/js/xpconnect/loader -I /var/lib/jenkins/workspace/firefox-scan-build/js/xpconnect/src -I /var/lib/jenkins/workspace/firefox-scan-build/js/xpconnect/wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/layout/base -I /var/lib/jenkins/workspace/firefox-scan-build/layout/forms -I /var/lib/jenkins/workspace/firefox-scan-build/layout/generic -I /var/lib/jenkins/workspace/firefox-scan-build/layout/style -I /var/lib/jenkins/workspace/firefox-scan-build/layout/xul -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/base -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/url-classifier -I /var/lib/jenkins/workspace/firefox-scan-build/parser/htmlparser -I /var/lib/jenkins/workspace/firefox-scan-build/security/manager/ssl -I /var/lib/jenkins/workspace/firefox-scan-build/third_party/xsimd/include -I /var/lib/jenkins/workspace/firefox-scan-build/widget -I /var/lib/jenkins/workspace/firefox-scan-build/xpcom/build -I /var/lib/jenkins/workspace/firefox-scan-build/xpcom/ds -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/sctp/datachannel -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /var/lib/jenkins/workspace/firefox-scan-build/ipc/chromium/src -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gtk-3.0/unix-print -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-09-22-115206-3586786-1 -x c++ /var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp

/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp

1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7/* A namespace class for static layout utilities. */
8
9#include "nsContentUtils.h"
10
11#include <algorithm>
12#include <cstddef>
13#include <cstdint>
14#include <cstdlib>
15#include <cstring>
16#include <functional>
17#include <new>
18#include <utility>
19#include "BrowserChild.h"
20#include "DecoderTraits.h"
21#include "ErrorList.h"
22#include "HTMLSplitOnSpacesTokenizer.h"
23#include "ImageOps.h"
24#include "InProcessBrowserChildMessageManager.h"
25#include "MainThreadUtils.h"
26#include "PLDHashTable.h"
27#include "ReferrerInfo.h"
28#include "ScopedNSSTypes.h"
29#include "ThirdPartyUtil.h"
30#include "Units.h"
31#include "chrome/common/ipc_message.h"
32#include "gfxDrawable.h"
33#include "harfbuzz/hb.h"
34#include "imgICache.h"
35#include "imgIContainer.h"
36#include "imgILoader.h"
37#include "imgIRequest.h"
38#include "imgLoader.h"
39#include "js/Array.h"
40#include "js/ArrayBuffer.h"
41#include "js/BuildId.h"
42#include "js/GCAPI.h"
43#include "js/Id.h"
44#include "js/JSON.h"
45#include "js/PropertyAndElement.h" // JS_DefineElement, JS_GetProperty
46#include "js/PropertyDescriptor.h"
47#include "js/Realm.h"
48#include "js/RegExp.h"
49#include "js/RegExpFlags.h"
50#include "js/RootingAPI.h"
51#include "js/TypeDecls.h"
52#include "js/Value.h"
53#include "js/Wrapper.h"
54#include "jsapi.h"
55#include "jsfriendapi.h"
56#include "mozAutoDocUpdate.h"
57#include "mozIDOMWindow.h"
58#include "nsIOService.h"
59#include "nsObjectLoadingContent.h"
60#include "mozilla/AlreadyAddRefed.h"
61#include "mozilla/ArrayIterator.h"
62#include "mozilla/ArrayUtils.h"
63#include "mozilla/AsyncEventDispatcher.h"
64#include "mozilla/AtomArray.h"
65#include "mozilla/Atomics.h"
66#include "mozilla/Attributes.h"
67#include "mozilla/AutoRestore.h"
68#include "mozilla/BackgroundHangMonitor.h"
69#include "mozilla/Base64.h"
70#include "mozilla/BasePrincipal.h"
71#include "mozilla/BasicEvents.h"
72#include "mozilla/BloomFilter.h"
73#include "mozilla/CORSMode.h"
74#include "mozilla/CallState.h"
75#include "mozilla/CheckedInt.h"
76#include "mozilla/ClearOnShutdown.h"
77#include "mozilla/Components.h"
78#include "mozilla/ContentBlockingAllowList.h"
79#include "mozilla/CycleCollectedJSContext.h"
80#include "mozilla/DOMEventTargetHelper.h"
81#include "mozilla/DebugOnly.h"
82#include "mozilla/ErrorResult.h"
83#include "mozilla/EventDispatcher.h"
84#include "mozilla/EventListenerManager.h"
85#include "mozilla/EventQueue.h"
86#include "mozilla/EventStateManager.h"
87#include "mozilla/FlushType.h"
88#include "mozilla/FOGIPC.h"
89#include "mozilla/HTMLEditor.h"
90#include "mozilla/HangAnnotations.h"
91#include "mozilla/IMEStateManager.h"
92#include "mozilla/InputEventOptions.h"
93#include "mozilla/InternalMutationEvent.h"
94#include "mozilla/Latin1.h"
95#include "mozilla/Likely.h"
96#include "mozilla/LoadInfo.h"
97#include "mozilla/Logging.h"
98#include "mozilla/MacroForEach.h"
99#include "mozilla/ManualNAC.h"
100#include "mozilla/Maybe.h"
101#include "mozilla/MediaFeatureChange.h"
102#include "mozilla/MouseEvents.h"
103#include "mozilla/NotNull.h"
104#include "mozilla/NullPrincipal.h"
105#include "mozilla/OriginAttributes.h"
106#include "mozilla/Preferences.h"
107#include "mozilla/PresShell.h"
108#include "mozilla/ProfilerRunnable.h"
109#include "mozilla/RangeBoundary.h"
110#include "mozilla/RefPtr.h"
111#include "mozilla/Result.h"
112#include "mozilla/ResultExtensions.h"
113#include "mozilla/ScrollbarPreferences.h"
114#include "mozilla/ScrollContainerFrame.h"
115#include "mozilla/ShutdownPhase.h"
116#include "mozilla/Span.h"
117#include "mozilla/StaticAnalysisFunctions.h"
118#include "mozilla/StaticPrefs_browser.h"
119#include "mozilla/StaticPrefs_dom.h"
120#ifdef FUZZING
121# include "mozilla/StaticPrefs_fuzzing.h"
122#endif
123#include "mozilla/StaticPrefs_nglayout.h"
124#include "mozilla/StaticPrefs_privacy.h"
125#include "mozilla/StaticPrefs_test.h"
126#include "mozilla/StaticPrefs_ui.h"
127#include "mozilla/StaticPtr.h"
128#include "mozilla/TextControlState.h"
129#include "mozilla/TextEditor.h"
130#include "mozilla/TextEvents.h"
131#include "mozilla/UniquePtr.h"
132#include "mozilla/Unused.h"
133#include "mozilla/Variant.h"
134#include "mozilla/ViewportUtils.h"
135#include "mozilla/dom/AncestorIterator.h"
136#include "mozilla/dom/AutoEntryScript.h"
137#include "mozilla/dom/AutocompleteInfoBinding.h"
138#include "mozilla/dom/AutoSuppressEventHandlingAndSuspend.h"
139#include "mozilla/dom/BindingDeclarations.h"
140#include "mozilla/dom/BindingUtils.h"
141#include "mozilla/dom/BlobImpl.h"
142#include "mozilla/dom/BlobURLProtocolHandler.h"
143#include "mozilla/dom/BorrowedAttrInfo.h"
144#include "mozilla/dom/BrowserBridgeParent.h"
145#include "mozilla/dom/BrowserParent.h"
146#include "mozilla/dom/BrowsingContext.h"
147#include "mozilla/dom/BrowsingContextGroup.h"
148#include "mozilla/dom/CacheExpirationTime.h"
149#include "mozilla/dom/CallbackFunction.h"
150#include "mozilla/dom/CallbackObject.h"
151#include "mozilla/dom/ChromeMessageBroadcaster.h"
152#include "mozilla/dom/ContentChild.h"
153#include "mozilla/dom/ContentFrameMessageManager.h"
154#include "mozilla/dom/ContentParent.h"
155#include "mozilla/dom/CustomElementRegistry.h"
156#include "mozilla/dom/CustomElementRegistryBinding.h"
157#include "mozilla/dom/CustomElementTypes.h"
158#include "mozilla/dom/DOMArena.h"
159#include "mozilla/dom/DOMException.h"
160#include "mozilla/dom/DOMExceptionBinding.h"
161#include "mozilla/dom/DOMSecurityMonitor.h"
162#include "mozilla/dom/DOMTypes.h"
163#include "mozilla/dom/DataTransfer.h"
164#include "mozilla/dom/DocGroup.h"
165#include "mozilla/dom/Document.h"
166#include "mozilla/dom/DocumentFragment.h"
167#include "mozilla/dom/DocumentInlines.h"
168#include "mozilla/dom/Element.h"
169#include "mozilla/dom/ElementBinding.h"
170#include "mozilla/dom/ElementInlines.h"
171#include "mozilla/dom/Event.h"
172#include "mozilla/dom/EventTarget.h"
173#include "mozilla/dom/FileBlobImpl.h"
174#include "mozilla/dom/FileSystemSecurity.h"
175#include "mozilla/dom/FilteredNodeIterator.h"
176#include "mozilla/dom/FormData.h"
177#include "mozilla/dom/FragmentOrElement.h"
178#include "mozilla/dom/FromParser.h"
179#include "mozilla/dom/HTMLElement.h"
180#include "mozilla/dom/HTMLFormElement.h"
181#include "mozilla/dom/HTMLImageElement.h"
182#include "mozilla/dom/HTMLInputElement.h"
183#include "mozilla/dom/HTMLTemplateElement.h"
184#include "mozilla/dom/HTMLTextAreaElement.h"
185#include "mozilla/dom/IPCBlob.h"
186#include "mozilla/dom/IPCBlobUtils.h"
187#include "mozilla/dom/MessageBroadcaster.h"
188#include "mozilla/dom/MessageListenerManager.h"
189#include "mozilla/dom/MessagePort.h"
190#include "mozilla/dom/MouseEventBinding.h"
191#include "mozilla/dom/NameSpaceConstants.h"
192#include "mozilla/dom/NodeBinding.h"
193#include "mozilla/dom/NodeInfo.h"
194#include "mozilla/dom/PBrowser.h"
195#include "mozilla/dom/PContentChild.h"
196#include "mozilla/dom/PrototypeList.h"
197#include "mozilla/dom/ReferrerPolicyBinding.h"
198#include "mozilla/dom/ScriptSettings.h"
199#include "mozilla/dom/Selection.h"
200#include "mozilla/dom/ShadowRoot.h"
201#include "mozilla/dom/Text.h"
202#include "mozilla/dom/UserActivation.h"
203#include "mozilla/dom/WindowContext.h"
204#include "mozilla/dom/WorkerCommon.h"
205#include "mozilla/dom/WorkerPrivate.h"
206#include "mozilla/dom/WorkerRunnable.h"
207#include "mozilla/dom/XULCommandEvent.h"
208#include "mozilla/glean/GleanPings.h"
209#include "mozilla/fallible.h"
210#include "mozilla/gfx/2D.h"
211#include "mozilla/gfx/BaseMargin.h"
212#include "mozilla/gfx/BasePoint.h"
213#include "mozilla/gfx/BaseSize.h"
214#include "mozilla/gfx/DataSurfaceHelpers.h"
215#include "mozilla/gfx/Point.h"
216#include "mozilla/gfx/Rect.h"
217#include "mozilla/gfx/Types.h"
218#include "mozilla/ipc/ProtocolUtils.h"
219#include "mozilla/ipc/SharedMemory.h"
220#include "mozilla/net/UrlClassifierCommon.h"
221#include "mozilla/Tokenizer.h"
222#include "mozilla/widget/IMEData.h"
223#include "nsAboutProtocolUtils.h"
224#include "nsAlgorithm.h"
225#include "nsArrayUtils.h"
226#include "nsAtomHashKeys.h"
227#include "nsAttrName.h"
228#include "nsAttrValue.h"
229#include "nsAttrValueInlines.h"
230#include "nsBaseHashtable.h"
231#include "nsCCUncollectableMarker.h"
232#include "nsCOMPtr.h"
233#include "nsCRT.h"
234#include "nsCRTGlue.h"
235#include "nsCanvasFrame.h"
236#include "nsCaseTreatment.h"
237#include "nsCharSeparatedTokenizer.h"
238#include "nsCharTraits.h"
239#include "nsCompatibility.h"
240#include "nsComponentManagerUtils.h"
241#include "nsContainerFrame.h"
242#include "nsContentCreatorFunctions.h"
243#include "nsContentDLF.h"
244#include "nsContentList.h"
245#include "nsContentListDeclarations.h"
246#include "nsContentPolicyUtils.h"
247#include "nsCoord.h"
248#include "nsCycleCollectionNoteChild.h"
249#include "nsDOMMutationObserver.h"
250#include "nsDOMString.h"
251#include "nsTHashMap.h"
252#include "nsDebug.h"
253#include "nsDocShell.h"
254#include "nsDocShellCID.h"
255#include "nsError.h"
256#include "nsFocusManager.h"
257#include "nsFrameList.h"
258#include "nsFrameLoader.h"
259#include "nsFrameLoaderOwner.h"
260#include "nsGenericHTMLElement.h"
261#include "nsGkAtoms.h"
262#include "nsGlobalWindowInner.h"
263#include "nsGlobalWindowOuter.h"
264#include "nsHTMLDocument.h"
265#include "nsHTMLTags.h"
266#include "nsHashKeys.h"
267#include "nsHtml5StringParser.h"
268#include "nsIAboutModule.h"
269#include "nsIAnonymousContentCreator.h"
270#include "nsIAppShell.h"
271#include "nsIArray.h"
272#include "nsIAsyncVerifyRedirectCallback.h"
273#include "nsIBidiKeyboard.h"
274#include "nsIBrowser.h"
275#include "nsICacheInfoChannel.h"
276#include "nsICachingChannel.h"
277#include "nsICategoryManager.h"
278#include "nsIChannel.h"
279#include "nsIChannelEventSink.h"
280#include "nsIClassifiedChannel.h"
281#include "nsIConsoleService.h"
282#include "nsIContent.h"
283#include "nsIContentInlines.h"
284#include "nsIContentPolicy.h"
285#include "nsIContentSecurityPolicy.h"
286#include "nsIContentSink.h"
287#include "nsIDOMWindowUtils.h"
288#include "nsIDocShell.h"
289#include "nsIDocShellTreeItem.h"
290#include "nsIDocumentEncoder.h"
291#include "nsIDocumentLoaderFactory.h"
292#include "nsIDocumentViewer.h"
293#include "nsIDragService.h"
294#include "nsIDragSession.h"
295#include "nsIFile.h"
296#include "nsIFocusManager.h"
297#include "nsIFormControl.h"
298#include "nsIFragmentContentSink.h"
299#include "nsIFrame.h"
300#include "nsIGlobalObject.h"
301#include "nsIHttpChannel.h"
302#include "nsIHttpChannelInternal.h"
303#include "nsIIOService.h"
304#include "nsIImageLoadingContent.h"
305#include "nsIInputStream.h"
306#include "nsIInterfaceRequestor.h"
307#include "nsIInterfaceRequestorUtils.h"
308#include "nsILoadContext.h"
309#include "nsILoadGroup.h"
310#include "nsILoadInfo.h"
311#include "nsIMIMEService.h"
312#include "nsIMemoryReporter.h"
313#include "nsINetUtil.h"
314#include "nsINode.h"
315#include "nsIObjectLoadingContent.h"
316#include "nsIObserver.h"
317#include "nsIObserverService.h"
318#include "nsIParserUtils.h"
319#include "nsIPermissionManager.h"
320#include "nsIPrincipal.h"
321#include "nsIProperties.h"
322#include "nsIProtocolHandler.h"
323#include "nsIRequest.h"
324#include "nsIRunnable.h"
325#include "nsIScreen.h"
326#include "nsIScriptError.h"
327#include "nsIScriptGlobalObject.h"
328#include "nsIScriptObjectPrincipal.h"
329#include "nsIScriptSecurityManager.h"
330#include "nsISerialEventTarget.h"
331#include "nsIStreamConverter.h"
332#include "nsIStreamConverterService.h"
333#include "nsIStringBundle.h"
334#include "nsISupports.h"
335#include "nsISupportsPrimitives.h"
336#include "nsISupportsUtils.h"
337#include "nsITransferable.h"
338#include "nsIURI.h"
339#include "nsIURIMutator.h"
340#if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
341# include "nsIURIWithSpecialOrigin.h"
342#endif
343#include "nsIUserIdleServiceInternal.h"
344#include "nsIWeakReferenceUtils.h"
345#include "nsIWebNavigation.h"
346#include "nsIWebNavigationInfo.h"
347#include "nsIWidget.h"
348#include "nsIWindowMediator.h"
349#include "nsIXPConnect.h"
350#include "nsJSPrincipals.h"
351#include "nsJSUtils.h"
352#include "nsLayoutUtils.h"
353#include "nsLiteralString.h"
354#include "nsMargin.h"
355#include "nsMimeTypes.h"
356#include "nsNameSpaceManager.h"
357#include "nsNetCID.h"
358#include "nsNetUtil.h"
359#include "nsNodeInfoManager.h"
360#include "nsPIDOMWindow.h"
361#include "nsPIDOMWindowInlines.h"
362#include "nsParser.h"
363#include "nsParserConstants.h"
364#include "nsPoint.h"
365#include "nsPointerHashKeys.h"
366#include "nsPresContext.h"
367#include "nsQueryFrame.h"
368#include "nsQueryObject.h"
369#include "nsRange.h"
370#include "nsRefPtrHashtable.h"
371#include "nsSandboxFlags.h"
372#include "nsScriptSecurityManager.h"
373#include "nsServiceManagerUtils.h"
374#include "nsStreamUtils.h"
375#include "nsString.h"
376#include "nsStringBundle.h"
377#include "nsStringFlags.h"
378#include "nsStringFwd.h"
379#include "nsStringIterator.h"
380#include "nsStringStream.h"
381#include "nsTArray.h"
382#include "nsTLiteralString.h"
383#include "nsTPromiseFlatString.h"
384#include "nsTStringRepr.h"
385#include "nsTextFragment.h"
386#include "nsTextNode.h"
387#include "nsThreadManager.h"
388#include "nsThreadUtils.h"
389#include "nsTreeSanitizer.h"
390#include "nsUGenCategory.h"
391#include "nsURLHelper.h"
392#include "nsUnicodeProperties.h"
393#include "nsVariant.h"
394#include "nsWidgetsCID.h"
395#include "nsView.h"
396#include "nsViewManager.h"
397#include "nsXPCOM.h"
398#include "nsXPCOMCID.h"
399#include "nsXULAppAPI.h"
400#include "nsXULElement.h"
401#include "nsXULPopupManager.h"
402#include "nscore.h"
403#include "prinrval.h"
404#include "xpcprivate.h"
405#include "xpcpublic.h"
406
407#if defined(XP_WIN)
408// Undefine LoadImage to prevent naming conflict with Windows.
409# undef LoadImage
410#endif
411
412extern "C" int MOZ_XMLTranslateEntity(const char* ptr, const char* end,
413 const char** next, char16_t* result);
414extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end, int ns_aware,
415 const char** colon);
416
417using namespace mozilla::dom;
418using namespace mozilla::ipc;
419using namespace mozilla::gfx;
420using namespace mozilla::layers;
421using namespace mozilla::widget;
422using namespace mozilla;
423
424const char kLoadAsData[] = "loadAsData";
425
426nsIXPConnect* nsContentUtils::sXPConnect;
427nsIScriptSecurityManager* nsContentUtils::sSecurityManager;
428nsIPrincipal* nsContentUtils::sSystemPrincipal;
429nsIPrincipal* nsContentUtils::sNullSubjectPrincipal;
430nsIPrincipal* nsContentUtils::sFingerprintingProtectionPrincipal;
431nsIConsoleService* nsContentUtils::sConsoleService;
432
433static nsTHashMap<RefPtr<nsAtom>, EventNameMapping>* sAtomEventTable;
434static nsTHashMap<nsStringHashKey, EventNameMapping>* sStringEventTable;
435static nsTArray<RefPtr<nsAtom>>* sUserDefinedEvents;
436nsIStringBundleService* nsContentUtils::sStringBundleService;
437
438static StaticRefPtr<nsIStringBundle>
439 sStringBundles[nsContentUtils::PropertiesFile_COUNT];
440
441nsIContentPolicy* nsContentUtils::sContentPolicyService;
442bool nsContentUtils::sTriedToGetContentPolicy = false;
443StaticRefPtr<nsIBidiKeyboard> nsContentUtils::sBidiKeyboard;
444uint32_t nsContentUtils::sScriptBlockerCount = 0;
445uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0;
446AutoTArray<nsCOMPtr<nsIRunnable>, 8>* nsContentUtils::sBlockedScriptRunners =
447 nullptr;
448uint32_t nsContentUtils::sRunnersCountAtFirstBlocker = 0;
449nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nullptr;
450
451bool nsContentUtils::sIsHandlingKeyBoardEvent = false;
452
453nsString* nsContentUtils::sShiftText = nullptr;
454nsString* nsContentUtils::sControlText = nullptr;
455nsString* nsContentUtils::sCommandOrWinText = nullptr;
456nsString* nsContentUtils::sAltText = nullptr;
457nsString* nsContentUtils::sModifierSeparator = nullptr;
458
459bool nsContentUtils::sInitialized = false;
460#ifndef RELEASE_OR_BETA
461bool nsContentUtils::sBypassCSSOMOriginCheck = false;
462#endif
463
464nsCString* nsContentUtils::sJSScriptBytecodeMimeType = nullptr;
465nsCString* nsContentUtils::sJSModuleBytecodeMimeType = nullptr;
466
467nsContentUtils::UserInteractionObserver*
468 nsContentUtils::sUserInteractionObserver = nullptr;
469
470nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr;
471nsParser* nsContentUtils::sXMLFragmentParser = nullptr;
472nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr;
473bool nsContentUtils::sFragmentParsingActive = false;
474
475bool nsContentUtils::sMayHaveFormCheckboxStateChangeListeners = false;
476bool nsContentUtils::sMayHaveFormRadioStateChangeListeners = false;
477
478mozilla::LazyLogModule nsContentUtils::gResistFingerprintingLog(
479 "nsResistFingerprinting");
480mozilla::LazyLogModule nsContentUtils::sDOMDumpLog("Dump");
481
482int32_t nsContentUtils::sInnerOrOuterWindowCount = 0;
483uint32_t nsContentUtils::sInnerOrOuterWindowSerialCounter = 0;
484
485template Maybe<int32_t> nsContentUtils::ComparePoints(
486 const RangeBoundary& aFirstBoundary, const RangeBoundary& aSecondBoundary);
487template Maybe<int32_t> nsContentUtils::ComparePoints(
488 const RangeBoundary& aFirstBoundary,
489 const RawRangeBoundary& aSecondBoundary);
490template Maybe<int32_t> nsContentUtils::ComparePoints(
491 const RawRangeBoundary& aFirstBoundary,
492 const RangeBoundary& aSecondBoundary);
493template Maybe<int32_t> nsContentUtils::ComparePoints(
494 const RawRangeBoundary& aFirstBoundary,
495 const RawRangeBoundary& aSecondBoundary);
496
497template int32_t nsContentUtils::ComparePoints_Deprecated(
498 const RangeBoundary& aFirstBoundary, const RangeBoundary& aSecondBoundary,
499 bool* aDisconnected);
500template int32_t nsContentUtils::ComparePoints_Deprecated(
501 const RangeBoundary& aFirstBoundary,
502 const RawRangeBoundary& aSecondBoundary, bool* aDisconnected);
503template int32_t nsContentUtils::ComparePoints_Deprecated(
504 const RawRangeBoundary& aFirstBoundary,
505 const RangeBoundary& aSecondBoundary, bool* aDisconnected);
506template int32_t nsContentUtils::ComparePoints_Deprecated(
507 const RawRangeBoundary& aFirstBoundary,
508 const RawRangeBoundary& aSecondBoundary, bool* aDisconnected);
509
510// Subset of
511// http://www.whatwg.org/specs/web-apps/current-work/#autofill-field-name
512enum AutocompleteUnsupportedFieldName : uint8_t {
513#define AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME(name_, value_) \
514 eAutocompleteUnsupportedFieldName_##name_,
515#include "AutocompleteFieldList.h"
516#undef AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME
517};
518
519enum AutocompleteNoPersistFieldName : uint8_t {
520#define AUTOCOMPLETE_NO_PERSIST_FIELD_NAME(name_, value_) \
521 eAutocompleteNoPersistFieldName_##name_,
522#include "AutocompleteFieldList.h"
523#undef AUTOCOMPLETE_NO_PERSIST_FIELD_NAME
524};
525
526enum AutocompleteUnsupportFieldContactHint : uint8_t {
527#define AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT(name_, value_) \
528 eAutocompleteUnsupportedFieldContactHint_##name_,
529#include "AutocompleteFieldList.h"
530#undef AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT
531};
532
533enum AutocompleteFieldName : uint8_t {
534#define AUTOCOMPLETE_FIELD_NAME(name_, value_) eAutocompleteFieldName_##name_,
535#define AUTOCOMPLETE_CONTACT_FIELD_NAME(name_, value_) \
536 AUTOCOMPLETE_FIELD_NAME(name_, value_)
537#include "AutocompleteFieldList.h"
538#undef AUTOCOMPLETE_FIELD_NAME
539#undef AUTOCOMPLETE_CONTACT_FIELD_NAME
540};
541
542enum AutocompleteFieldHint : uint8_t {
543#define AUTOCOMPLETE_FIELD_HINT(name_, value_) eAutocompleteFieldHint_##name_,
544#include "AutocompleteFieldList.h"
545#undef AUTOCOMPLETE_FIELD_HINT
546};
547
548enum AutocompleteFieldContactHint : uint8_t {
549#define AUTOCOMPLETE_FIELD_CONTACT_HINT(name_, value_) \
550 eAutocompleteFieldContactHint_##name_,
551#include "AutocompleteFieldList.h"
552#undef AUTOCOMPLETE_FIELD_CONTACT_HINT
553};
554
555enum AutocompleteCredentialType : uint8_t {
556#define AUTOCOMPLETE_CREDENTIAL_TYPE(name_, value_) \
557 eAutocompleteCredentialType_##name_,
558#include "AutocompleteFieldList.h"
559#undef AUTOCOMPLETE_CREDENTIAL_TYPE
560};
561
562enum AutocompleteCategory {
563#define AUTOCOMPLETE_CATEGORY(name_, value_) eAutocompleteCategory_##name_,
564#include "AutocompleteFieldList.h"
565#undef AUTOCOMPLETE_CATEGORY
566};
567
568static const nsAttrValue::EnumTable kAutocompleteUnsupportedFieldNameTable[] = {
569#define AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME(name_, value_) \
570 {value_, eAutocompleteUnsupportedFieldName_##name_},
571#include "AutocompleteFieldList.h"
572#undef AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME
573 {nullptr, 0}};
574
575static const nsAttrValue::EnumTable kAutocompleteNoPersistFieldNameTable[] = {
576#define AUTOCOMPLETE_NO_PERSIST_FIELD_NAME(name_, value_) \
577 {value_, eAutocompleteNoPersistFieldName_##name_},
578#include "AutocompleteFieldList.h"
579#undef AUTOCOMPLETE_NO_PERSIST_FIELD_NAME
580 {nullptr, 0}};
581
582static const nsAttrValue::EnumTable
583 kAutocompleteUnsupportedContactFieldHintTable[] = {
584#define AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT(name_, value_) \
585 {value_, eAutocompleteUnsupportedFieldContactHint_##name_},
586#include "AutocompleteFieldList.h"
587#undef AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT
588 {nullptr, 0}};
589
590static const nsAttrValue::EnumTable kAutocompleteFieldNameTable[] = {
591#define AUTOCOMPLETE_FIELD_NAME(name_, value_) \
592 {value_, eAutocompleteFieldName_##name_},
593#include "AutocompleteFieldList.h"
594#undef AUTOCOMPLETE_FIELD_NAME
595 {nullptr, 0}};
596
597static const nsAttrValue::EnumTable kAutocompleteContactFieldNameTable[] = {
598#define AUTOCOMPLETE_CONTACT_FIELD_NAME(name_, value_) \
599 {value_, eAutocompleteFieldName_##name_},
600#include "AutocompleteFieldList.h"
601#undef AUTOCOMPLETE_CONTACT_FIELD_NAME
602 {nullptr, 0}};
603
604static const nsAttrValue::EnumTable kAutocompleteFieldHintTable[] = {
605#define AUTOCOMPLETE_FIELD_HINT(name_, value_) \
606 {value_, eAutocompleteFieldHint_##name_},
607#include "AutocompleteFieldList.h"
608#undef AUTOCOMPLETE_FIELD_HINT
609 {nullptr, 0}};
610
611static const nsAttrValue::EnumTable kAutocompleteContactFieldHintTable[] = {
612#define AUTOCOMPLETE_FIELD_CONTACT_HINT(name_, value_) \
613 {value_, eAutocompleteFieldContactHint_##name_},
614#include "AutocompleteFieldList.h"
615#undef AUTOCOMPLETE_FIELD_CONTACT_HINT
616 {nullptr, 0}};
617
618static const nsAttrValue::EnumTable kAutocompleteCredentialTypeTable[] = {
619#define AUTOCOMPLETE_CREDENTIAL_TYPE(name_, value_) \
620 {value_, eAutocompleteCredentialType_##name_},
621#include "AutocompleteFieldList.h"
622#undef AUTOCOMPLETE_CREDENTIAL_TYPE
623 {nullptr, 0}};
624
625namespace {
626
627static PLDHashTable* sEventListenerManagersHash;
628
629// A global hashtable to for keeping the arena alive for cross docGroup node
630// adoption.
631static nsRefPtrHashtable<nsPtrHashKey<const nsINode>, mozilla::dom::DOMArena>*
632 sDOMArenaHashtable;
633
634class DOMEventListenerManagersHashReporter final : public nsIMemoryReporter {
635 MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)static size_t MallocSizeOf(const void* aPtr) { mozilla::dmd::
Report(aPtr); return moz_malloc_size_of(aPtr); }
636
637 ~DOMEventListenerManagersHashReporter() = default;
638
639 public:
640 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
641
642 NS_IMETHODvirtual nsresult CollectReports(nsIHandleReportCallback* aHandleReport,
643 nsISupports* aData, bool aAnonymize) override {
644 // We don't measure the |EventListenerManager| objects pointed to by the
645 // entries because those references are non-owning.
646 int64_t amount =
647 sEventListenerManagersHash
648 ? sEventListenerManagersHash->ShallowSizeOfIncludingThis(
649 MallocSizeOf)
650 : 0;
651
652 MOZ_COLLECT_REPORT((void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/dom/event-listener-managers-hash"
), KIND_HEAP, UNITS_BYTES, amount, nsLiteralCString("Memory used by the event listener manager's hash table."
), aData)
653 "explicit/dom/event-listener-managers-hash", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/dom/event-listener-managers-hash"
), KIND_HEAP, UNITS_BYTES, amount, nsLiteralCString("Memory used by the event listener manager's hash table."
), aData)
654 amount, "Memory used by the event listener manager's hash table.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/dom/event-listener-managers-hash"
), KIND_HEAP, UNITS_BYTES, amount, nsLiteralCString("Memory used by the event listener manager's hash table."
), aData)
;
655
656 return NS_OK;
657 }
658};
659
660NS_IMPL_ISUPPORTS(DOMEventListenerManagersHashReporter, nsIMemoryReporter)MozExternalRefCountType DOMEventListenerManagersHashReporter::
AddRef(void) { static_assert(!std::is_destructible_v<DOMEventListenerManagersHashReporter
>, "Reference-counted class " "DOMEventListenerManagersHashReporter"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 660); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
660; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("DOMEventListenerManagersHashReporter" != nullptr
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("DOMEventListenerManagersHashReporter" != nullptr)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"DOMEventListenerManagersHashReporter\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 660); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"DOMEventListenerManagersHashReporter\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 660; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("DOMEventListenerManagersHashReporter" " not thread-safe"
); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"DOMEventListenerManagersHashReporter"), (uint32_t)(sizeof(*this
))); return count; } MozExternalRefCountType DOMEventListenerManagersHashReporter
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 660); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 660
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("DOMEventListenerManagersHashReporter" != nullptr
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("DOMEventListenerManagersHashReporter" != nullptr)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"DOMEventListenerManagersHashReporter\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 660); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"DOMEventListenerManagersHashReporter\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 660; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("DOMEventListenerManagersHashReporter" " not thread-safe"
); const char* const nametmp = "DOMEventListenerManagersHashReporter"
; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (
nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return
0; } return count; } nsresult DOMEventListenerManagersHashReporter
::QueryInterface(const nsIID& aIID, void** aInstancePtr) {
do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 660); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<DOMEventListenerManagersHashReporter, nsIMemoryReporter
>, int32_t( reinterpret_cast<char*>(static_cast<nsIMemoryReporter
*>((DOMEventListenerManagersHashReporter*)0x1000)) - reinterpret_cast
<char*>((DOMEventListenerManagersHashReporter*)0x1000))
}, {&mozilla::detail::kImplementedIID<DOMEventListenerManagersHashReporter
, nsISupports>, int32_t(reinterpret_cast<char*>(static_cast
<nsISupports*>( static_cast<nsIMemoryReporter*>((
DOMEventListenerManagersHashReporter*)0x1000))) - reinterpret_cast
<char*>((DOMEventListenerManagersHashReporter*)0x1000))
}, { nullptr, 0 } } ; static_assert((sizeof(table) / sizeof(table
[0])) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
661
662class EventListenerManagerMapEntry : public PLDHashEntryHdr {
663 public:
664 explicit EventListenerManagerMapEntry(const void* aKey) : mKey(aKey) {}
665
666 ~EventListenerManagerMapEntry() {
667 NS_ASSERTION(!mListenerManager, "caller must release and disconnect ELM")do { if (!(!mListenerManager)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "caller must release and disconnect ELM", "!mListenerManager"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 667); MOZ_PretendNoReturn(); } } while (0)
;
668 }
669
670 protected: // declared protected to silence clang warnings
671 const void* mKey; // must be first, to look like PLDHashEntryStub
672
673 public:
674 RefPtr<EventListenerManager> mListenerManager;
675};
676
677static void EventListenerManagerHashInitEntry(PLDHashEntryHdr* entry,
678 const void* key) {
679 // Initialize the entry with placement new
680 new (entry) EventListenerManagerMapEntry(key);
681}
682
683static void EventListenerManagerHashClearEntry(PLDHashTable* table,
684 PLDHashEntryHdr* entry) {
685 EventListenerManagerMapEntry* lm =
686 static_cast<EventListenerManagerMapEntry*>(entry);
687
688 // Let the EventListenerManagerMapEntry clean itself up...
689 lm->~EventListenerManagerMapEntry();
690}
691
692class SameOriginCheckerImpl final : public nsIChannelEventSink,
693 public nsIInterfaceRequestor {
694 ~SameOriginCheckerImpl() = default;
695
696 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
697 NS_DECL_NSICHANNELEVENTSINKvirtual nsresult AsyncOnChannelRedirect(nsIChannel *oldChannel
, nsIChannel *newChannel, uint32_t flags, nsIAsyncVerifyRedirectCallback
*callback) override;
698 NS_DECL_NSIINTERFACEREQUESTORvirtual nsresult GetInterface(const nsIID & uuid, void * *
result) override;
699};
700
701} // namespace
702
703void AutoSuppressEventHandling::SuppressDocument(Document* aDoc) {
704 // Note: Document::SuppressEventHandling will also automatically suppress
705 // event handling for any in-process sub-documents. However, since we need
706 // to deal with cases where remote BrowsingContexts may be interleaved
707 // with in-process ones, we still need to walk the entire tree ourselves.
708 // This may be slightly redundant in some cases, but since event handling
709 // suppressions maintain a count of current blockers, it does not cause
710 // any problems.
711 aDoc->SuppressEventHandling();
712}
713
714void AutoSuppressEventHandling::UnsuppressDocument(Document* aDoc) {
715 aDoc->UnsuppressEventHandlingAndFireEvents(true);
716}
717
718AutoSuppressEventHandling::~AutoSuppressEventHandling() {
719 UnsuppressDocuments();
720}
721
722void AutoSuppressEventHandlingAndSuspend::SuppressDocument(Document* aDoc) {
723 AutoSuppressEventHandling::SuppressDocument(aDoc);
724 if (nsCOMPtr<nsPIDOMWindowInner> win = aDoc->GetInnerWindow()) {
725 win->Suspend();
726 mWindows.AppendElement(win);
727 }
728}
729
730AutoSuppressEventHandlingAndSuspend::~AutoSuppressEventHandlingAndSuspend() {
731 for (const auto& win : mWindows) {
732 win->Resume();
733 }
734}
735
736/**
737 * This class is used to determine whether or not the user is currently
738 * interacting with the browser. It listens to observer events to toggle the
739 * value of the sUserActive static.
740 *
741 * This class is an internal implementation detail.
742 * nsContentUtils::GetUserIsInteracting() should be used to access current
743 * user interaction status.
744 */
745class nsContentUtils::UserInteractionObserver final
746 : public nsIObserver,
747 public BackgroundHangAnnotator {
748 public:
749 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
750 NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic
, const char16_t * aData) override;
751
752 void Init();
753 void Shutdown();
754 void AnnotateHang(BackgroundHangAnnotations& aAnnotations) override;
755
756 static Atomic<bool> sUserActive;
757
758 private:
759 ~UserInteractionObserver() = default;
760};
761
762static constexpr nsLiteralCString kRfpPrefs[] = {
763 "privacy.resistFingerprinting"_ns,
764 "privacy.resistFingerprinting.pbmode"_ns,
765 "privacy.fingerprintingProtection"_ns,
766 "privacy.fingerprintingProtection.pbmode"_ns,
767 "privacy.fingerprintingProtection.overrides"_ns,
768};
769
770static void RecomputeResistFingerprintingAllDocs(const char*, void*) {
771 AutoTArray<RefPtr<BrowsingContextGroup>, 5> bcGroups;
772 BrowsingContextGroup::GetAllGroups(bcGroups);
773 for (auto& bcGroup : bcGroups) {
774 AutoTArray<DocGroup*, 5> docGroups;
775 bcGroup->GetDocGroups(docGroups);
776 for (auto* docGroup : docGroups) {
777 for (Document* doc : *docGroup) {
778 if (doc->RecomputeResistFingerprinting()) {
779 if (auto* pc = doc->GetPresContext()) {
780 pc->MediaFeatureValuesChanged(
781 {MediaFeatureChangeReason::PreferenceChange},
782 MediaFeatureChangePropagation::JustThisDocument);
783 }
784 }
785 }
786 }
787 }
788}
789
790// static
791nsresult nsContentUtils::Init() {
792 if (sInitialized) {
793 NS_WARNING("Init() called twice")NS_DebugBreak(NS_DEBUG_WARNING, "Init() called twice", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 793)
;
794
795 return NS_OK;
796 }
797
798 nsHTMLTags::AddRefTable();
799
800 sXPConnect = nsXPConnect::XPConnect();
801 // We hold a strong ref to sXPConnect to ensure that it does not go away until
802 // nsLayoutStatics::Shutdown is happening. Otherwise ~nsXPConnect can be
803 // triggered by xpcModuleDtor late in shutdown and cause crashes due to
804 // various stuff already being torn down by then. Note that this means that
805 // we are effectively making sure that if we leak nsLayoutStatics then we also
806 // leak nsXPConnect.
807 NS_ADDREF(sXPConnect)(sXPConnect)->AddRef();
808
809 sSecurityManager = nsScriptSecurityManager::GetScriptSecurityManager();
810 if (!sSecurityManager) return NS_ERROR_FAILURE;
811 NS_ADDREF(sSecurityManager)(sSecurityManager)->AddRef();
812
813 sSecurityManager->GetSystemPrincipal(&sSystemPrincipal);
814 MOZ_ASSERT(sSystemPrincipal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sSystemPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sSystemPrincipal))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("sSystemPrincipal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 814); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sSystemPrincipal"
")"); do { *((volatile int*)__null) = 814; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
815
816 RefPtr<NullPrincipal> nullPrincipal =
817 NullPrincipal::CreateWithoutOriginAttributes();
818 if (!nullPrincipal) {
819 return NS_ERROR_FAILURE;
820 }
821
822 nullPrincipal.forget(&sNullSubjectPrincipal);
823
824 RefPtr<nsIPrincipal> fingerprintingProtectionPrincipal =
825 BasePrincipal::CreateContentPrincipal(
826 "about:fingerprintingprotection"_ns);
827 if (!fingerprintingProtectionPrincipal) {
828 return NS_ERROR_FAILURE;
829 }
830
831 fingerprintingProtectionPrincipal.forget(&sFingerprintingProtectionPrincipal);
832
833 if (!InitializeEventTable()) return NS_ERROR_FAILURE;
834
835 if (!sEventListenerManagersHash) {
836 static const PLDHashTableOps hash_table_ops = {
837 PLDHashTable::HashVoidPtrKeyStub, PLDHashTable::MatchEntryStub,
838 PLDHashTable::MoveEntryStub, EventListenerManagerHashClearEntry,
839 EventListenerManagerHashInitEntry};
840
841 sEventListenerManagersHash =
842 new PLDHashTable(&hash_table_ops, sizeof(EventListenerManagerMapEntry));
843
844 RegisterStrongMemoryReporter(new DOMEventListenerManagersHashReporter());
845 }
846
847 sBlockedScriptRunners = new AutoTArray<nsCOMPtr<nsIRunnable>, 8>;
848
849#ifndef RELEASE_OR_BETA
850 sBypassCSSOMOriginCheck = getenv("MOZ_BYPASS_CSSOM_ORIGIN_CHECK");
851#endif
852
853 Element::InitCCCallbacks();
854
855 RefPtr<nsRFPService> rfpService = nsRFPService::GetOrCreate();
856 MOZ_ASSERT(rfpService)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(rfpService)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(rfpService))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("rfpService", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 856); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rfpService" ")"
); do { *((volatile int*)__null) = 856; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
857
858 if (XRE_IsParentProcess()) {
859 AsyncPrecreateStringBundles();
860
861#if defined(MOZ_WIDGET_ANDROID)
862 // On Android, at-shutdown ping submission isn't reliable
863 // (( because, on Android, we usually get killed, not shut down )).
864 // To have a chance at submitting the ping, aim for idle after startup.
865 nsresult rv = NS_DispatchToCurrentThreadQueue(
866 NS_NewRunnableFunction(
867 "AndroidUseCounterPingSubmitter",
868 []() { glean_pings::UseCounters.Submit("idle_startup"_ns); }),
869 EventQueuePriority::Idle);
870 // This is mostly best-effort, so if it goes awry, just log.
871 Unused << NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 871)
;
872#endif // defined(MOZ_WIDGET_ANDROID)
873
874 RunOnShutdown(
875 [&] { glean_pings::UseCounters.Submit("app_shutdown_confirmed"_ns); },
876 ShutdownPhase::AppShutdownConfirmed);
877 }
878
879 RefPtr<UserInteractionObserver> uio = new UserInteractionObserver();
880 uio->Init();
881 uio.forget(&sUserInteractionObserver);
882
883 for (const auto& pref : kRfpPrefs) {
884 Preferences::RegisterCallback(RecomputeResistFingerprintingAllDocs, pref);
885 }
886
887 sInitialized = true;
888
889 return NS_OK;
890}
891
892bool nsContentUtils::InitJSBytecodeMimeType() {
893 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 893); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 893; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
894 MOZ_ASSERT(!sJSScriptBytecodeMimeType)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!sJSScriptBytecodeMimeType)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!sJSScriptBytecodeMimeType))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!sJSScriptBytecodeMimeType"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 894); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sJSScriptBytecodeMimeType"
")"); do { *((volatile int*)__null) = 894; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
895 MOZ_ASSERT(!sJSModuleBytecodeMimeType)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!sJSModuleBytecodeMimeType)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!sJSModuleBytecodeMimeType))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!sJSModuleBytecodeMimeType"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 895); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sJSModuleBytecodeMimeType"
")"); do { *((volatile int*)__null) = 895; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
896
897 JS::BuildIdCharVector jsBuildId;
898 if (!JS::GetScriptTranscodingBuildId(&jsBuildId)) {
899 return false;
900 }
901
902 nsDependentCSubstring jsBuildIdStr(jsBuildId.begin(), jsBuildId.length());
903 sJSScriptBytecodeMimeType =
904 new nsCString("javascript/moz-script-bytecode-"_ns + jsBuildIdStr);
905 sJSModuleBytecodeMimeType =
906 new nsCString("javascript/moz-module-bytecode-"_ns + jsBuildIdStr);
907 return true;
908}
909
910void nsContentUtils::GetShiftText(nsAString& text) {
911 if (!sShiftText) InitializeModifierStrings();
912 text.Assign(*sShiftText);
913}
914
915void nsContentUtils::GetControlText(nsAString& text) {
916 if (!sControlText) InitializeModifierStrings();
917 text.Assign(*sControlText);
918}
919
920void nsContentUtils::GetCommandOrWinText(nsAString& text) {
921 if (!sCommandOrWinText) {
922 InitializeModifierStrings();
923 }
924 text.Assign(*sCommandOrWinText);
925}
926
927void nsContentUtils::GetAltText(nsAString& text) {
928 if (!sAltText) InitializeModifierStrings();
929 text.Assign(*sAltText);
930}
931
932void nsContentUtils::GetModifierSeparatorText(nsAString& text) {
933 if (!sModifierSeparator) InitializeModifierStrings();
934 text.Assign(*sModifierSeparator);
935}
936
937void nsContentUtils::InitializeModifierStrings() {
938 // load the display strings for the keyboard accelerators
939 nsCOMPtr<nsIStringBundleService> bundleService =
940 mozilla::components::StringBundle::Service();
941 nsCOMPtr<nsIStringBundle> bundle;
942 DebugOnly<nsresult> rv = NS_OK;
943 if (bundleService) {
944 rv = bundleService->CreateBundle(
945 "chrome://global-platform/locale/platformKeys.properties",
946 getter_AddRefs(bundle));
947 }
948
949 NS_ASSERTION(do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))) && bundle)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "chrome://global/locale/platformKeys.properties could not be loaded"
, "NS_SUCCEEDED(rv) && bundle", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 951); MOZ_PretendNoReturn(); } } while (0)
950 NS_SUCCEEDED(rv) && bundle,do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))) && bundle)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "chrome://global/locale/platformKeys.properties could not be loaded"
, "NS_SUCCEEDED(rv) && bundle", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 951); MOZ_PretendNoReturn(); } } while (0)
951 "chrome://global/locale/platformKeys.properties could not be loaded")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))) && bundle)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "chrome://global/locale/platformKeys.properties could not be loaded"
, "NS_SUCCEEDED(rv) && bundle", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 951); MOZ_PretendNoReturn(); } } while (0)
;
952 nsAutoString shiftModifier;
953 nsAutoString commandOrWinModifier;
954 nsAutoString altModifier;
955 nsAutoString controlModifier;
956 nsAutoString modifierSeparator;
957 if (bundle) {
958 // macs use symbols for each modifier key, so fetch each from the bundle,
959 // which also covers i18n
960 bundle->GetStringFromName("VK_SHIFT", shiftModifier);
961 bundle->GetStringFromName("VK_COMMAND_OR_WIN", commandOrWinModifier);
962 bundle->GetStringFromName("VK_ALT", altModifier);
963 bundle->GetStringFromName("VK_CONTROL", controlModifier);
964 bundle->GetStringFromName("MODIFIER_SEPARATOR", modifierSeparator);
965 }
966 // if any of these don't exist, we get an empty string
967 sShiftText = new nsString(shiftModifier);
968 sCommandOrWinText = new nsString(commandOrWinModifier);
969 sAltText = new nsString(altModifier);
970 sControlText = new nsString(controlModifier);
971 sModifierSeparator = new nsString(modifierSeparator);
972}
973
974mozilla::EventClassID nsContentUtils::GetEventClassIDFromMessage(
975 EventMessage aEventMessage) {
976 switch (aEventMessage) {
977#define MESSAGE_TO_EVENT(name_, message_, type_, struct_) \
978 case message_: \
979 return struct_;
980#include "mozilla/EventNameList.h"
981#undef MESSAGE_TO_EVENT
982 default:
983 MOZ_ASSERT_UNREACHABLE("Invalid event message?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Invalid event message?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 983); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Invalid event message?" ")"); do
{ *((volatile int*)__null) = 983; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
984 return eBasicEventClass;
985 }
986}
987
988bool nsContentUtils::IsExternalProtocol(nsIURI* aURI) {
989 bool doesNotReturnData = false;
990 nsresult rv = NS_URIChainHasFlags(
991 aURI, nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA, &doesNotReturnData);
992 return NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && doesNotReturnData;
993}
994
995/* static */
996nsAtom* nsContentUtils::GetEventTypeFromMessage(EventMessage aEventMessage) {
997 switch (aEventMessage) {
998#define MESSAGE_TO_EVENT(name_, message_, type_, struct_) \
999 case message_: \
1000 return nsGkAtoms::on##name_;
1001#include "mozilla/EventNameList.h"
1002#undef MESSAGE_TO_EVENT
1003 default:
1004 return nullptr;
1005 }
1006}
1007
1008bool nsContentUtils::InitializeEventTable() {
1009 NS_ASSERTION(!sAtomEventTable, "EventTable already initialized!")do { if (!(!sAtomEventTable)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "EventTable already initialized!", "!sAtomEventTable", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 1009); MOZ_PretendNoReturn(); } } while (0)
;
1010 NS_ASSERTION(!sStringEventTable, "EventTable already initialized!")do { if (!(!sStringEventTable)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "EventTable already initialized!", "!sStringEventTable", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 1010); MOZ_PretendNoReturn(); } } while (0)
;
1011
1012 static const EventNameMapping eventArray[] = {
1013#define EVENT(name_, _message, _type, _class) \
1014 {nsGkAtoms::on##name_, _type, _message, _class},
1015#define WINDOW_ONLY_EVENT EVENT
1016#define DOCUMENT_ONLY_EVENTEVENT EVENT
1017#define NON_IDL_EVENT EVENT
1018#include "mozilla/EventNameList.h"
1019#undef WINDOW_ONLY_EVENT
1020#undef NON_IDL_EVENT
1021#undef EVENT
1022 {nullptr}};
1023
1024 sAtomEventTable =
1025 new nsTHashMap<RefPtr<nsAtom>, EventNameMapping>(ArrayLength(eventArray));
1026 sStringEventTable = new nsTHashMap<nsStringHashKey, EventNameMapping>(
1027 ArrayLength(eventArray));
1028 sUserDefinedEvents = new nsTArray<RefPtr<nsAtom>>(64);
1029
1030 // Subtract one from the length because of the trailing null
1031 for (uint32_t i = 0; i < ArrayLength(eventArray) - 1; ++i) {
1032 MOZ_ASSERT(!sAtomEventTable->Contains(eventArray[i].mAtom),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!sAtomEventTable->Contains(eventArray[i].mAtom))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!sAtomEventTable->Contains(eventArray[i].mAtom)))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!sAtomEventTable->Contains(eventArray[i].mAtom)"
" (" "Double-defining event name; fix your EventNameList.h" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 1033); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sAtomEventTable->Contains(eventArray[i].mAtom)"
") (" "Double-defining event name; fix your EventNameList.h"
")"); do { *((volatile int*)__null) = 1033; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1033 "Double-defining event name; fix your EventNameList.h")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!sAtomEventTable->Contains(eventArray[i].mAtom))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!sAtomEventTable->Contains(eventArray[i].mAtom)))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!sAtomEventTable->Contains(eventArray[i].mAtom)"
" (" "Double-defining event name; fix your EventNameList.h" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 1033); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sAtomEventTable->Contains(eventArray[i].mAtom)"
") (" "Double-defining event name; fix your EventNameList.h"
")"); do { *((volatile int*)__null) = 1033; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1034 sAtomEventTable->InsertOrUpdate(eventArray[i].mAtom, eventArray[i]);
1035 sStringEventTable->InsertOrUpdate(
1036 Substring(nsDependentAtomString(eventArray[i].mAtom), 2),
1037 eventArray[i]);
1038 }
1039
1040 return true;
1041}
1042
1043void nsContentUtils::InitializeTouchEventTable() {
1044 static bool sEventTableInitialized = false;
1045 if (!sEventTableInitialized && sAtomEventTable && sStringEventTable) {
1046 sEventTableInitialized = true;
1047 static const EventNameMapping touchEventArray[] = {
1048#define EVENT(name_, _message, _type, _class)
1049#define TOUCH_EVENT(name_, _message, _type, _class) \
1050 {nsGkAtoms::on##name_, _type, _message, _class},
1051#include "mozilla/EventNameList.h"
1052#undef TOUCH_EVENT
1053#undef EVENT
1054 {nullptr}};
1055 // Subtract one from the length because of the trailing null
1056 for (uint32_t i = 0; i < ArrayLength(touchEventArray) - 1; ++i) {
1057 sAtomEventTable->InsertOrUpdate(touchEventArray[i].mAtom,
1058 touchEventArray[i]);
1059 sStringEventTable->InsertOrUpdate(
1060 Substring(nsDependentAtomString(touchEventArray[i].mAtom), 2),
1061 touchEventArray[i]);
1062 }
1063 }
1064}
1065
1066static bool Is8bit(const nsAString& aString) {
1067 static const char16_t EIGHT_BIT = char16_t(~0x00FF);
1068
1069 for (nsAString::const_char_iterator start = aString.BeginReading(),
1070 end = aString.EndReading();
1071 start != end; ++start) {
1072 if (*start & EIGHT_BIT) {
1073 return false;
1074 }
1075 }
1076
1077 return true;
1078}
1079
1080nsresult nsContentUtils::Btoa(const nsAString& aBinaryData,
1081 nsAString& aAsciiBase64String) {
1082 if (!Is8bit(aBinaryData)) {
1083 aAsciiBase64String.Truncate();
1084 return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
1085 }
1086
1087 return Base64Encode(aBinaryData, aAsciiBase64String);
1088}
1089
1090nsresult nsContentUtils::Atob(const nsAString& aAsciiBase64String,
1091 nsAString& aBinaryData) {
1092 if (!Is8bit(aAsciiBase64String)) {
1093 aBinaryData.Truncate();
1094 return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
1095 }
1096
1097 const char16_t* start = aAsciiBase64String.BeginReading();
1098 const char16_t* cur = start;
1099 const char16_t* end = aAsciiBase64String.EndReading();
1100 bool hasWhitespace = false;
1101
1102 while (cur < end) {
1103 if (nsContentUtils::IsHTMLWhitespace(*cur)) {
1104 hasWhitespace = true;
1105 break;
1106 }
1107 cur++;
1108 }
1109
1110 nsresult rv;
1111
1112 if (hasWhitespace) {
1113 nsString trimmedString;
1114
1115 if (!trimmedString.SetCapacity(aAsciiBase64String.Length(), fallible)) {
1116 return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
1117 }
1118
1119 trimmedString.Append(start, cur - start);
1120
1121 while (cur < end) {
1122 if (!nsContentUtils::IsHTMLWhitespace(*cur)) {
1123 trimmedString.Append(*cur);
1124 }
1125 cur++;
1126 }
1127 rv = Base64Decode(trimmedString, aBinaryData);
1128 } else {
1129 rv = Base64Decode(aAsciiBase64String, aBinaryData);
1130 }
1131
1132 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && rv == NS_ERROR_INVALID_ARG) {
1133 return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
1134 }
1135 return rv;
1136}
1137
1138bool nsContentUtils::IsAutocompleteEnabled(
1139 mozilla::dom::HTMLInputElement* aInput) {
1140 MOZ_ASSERT(aInput, "aInput should not be null!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aInput)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aInput))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aInput" " (" "aInput should not be null!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 1140); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aInput" ") ("
"aInput should not be null!" ")"); do { *((volatile int*)__null
) = 1140; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
1141
1142 nsAutoString autocomplete;
1143 aInput->GetAutocomplete(autocomplete);
1144
1145 if (autocomplete.IsEmpty()) {
1146 auto* form = aInput->GetForm();
1147 if (!form) {
1148 return true;
1149 }
1150
1151 form->GetAutocomplete(autocomplete);
1152 }
1153
1154 return !autocomplete.EqualsLiteral("off");
1155}
1156
1157nsContentUtils::AutocompleteAttrState
1158nsContentUtils::SerializeAutocompleteAttribute(
1159 const nsAttrValue* aAttr, nsAString& aResult,
1160 AutocompleteAttrState aCachedState) {
1161 if (!aAttr ||
1162 aCachedState == nsContentUtils::eAutocompleteAttrState_Invalid) {
1163 return aCachedState;
1164 }
1165
1166 if (aCachedState == nsContentUtils::eAutocompleteAttrState_Valid) {
1167 uint32_t atomCount = aAttr->GetAtomCount();
1168 for (uint32_t i = 0; i < atomCount; i++) {
1169 if (i != 0) {
1170 aResult.Append(' ');
1171 }
1172 aResult.Append(nsDependentAtomString(aAttr->AtomAt(i)));
1173 }
1174 nsContentUtils::ASCIIToLower(aResult);
1175 return aCachedState;
1176 }
1177
1178 aResult.Truncate();
1179
1180 mozilla::dom::AutocompleteInfo info;
1181 AutocompleteAttrState state =
1182 InternalSerializeAutocompleteAttribute(aAttr, info);
1183 if (state == eAutocompleteAttrState_Valid) {
1184 // Concatenate the info fields.
1185 aResult = info.mSection;
1186
1187 if (!info.mAddressType.IsEmpty()) {
1188 if (!aResult.IsEmpty()) {
1189 aResult += ' ';
1190 }
1191 aResult += info.mAddressType;
1192 }
1193
1194 if (!info.mContactType.IsEmpty()) {
1195 if (!aResult.IsEmpty()) {
1196 aResult += ' ';
1197 }
1198 aResult += info.mContactType;
1199 }
1200
1201 if (!info.mFieldName.IsEmpty()) {
1202 if (!aResult.IsEmpty()) {
1203 aResult += ' ';
1204 }
1205 aResult += info.mFieldName;
1206 }
1207
1208 // The autocomplete attribute value "webauthn" is interpreted as both a
1209 // field name and a credential type. The corresponding IDL-exposed autofill
1210 // value is "webauthn", not "webauthn webauthn".
1211 if (!info.mCredentialType.IsEmpty() &&
1212 !(info.mCredentialType.Equals(u"webauthn"_ns) &&
1213 info.mCredentialType.Equals(aResult))) {
1214 if (!aResult.IsEmpty()) {
1215 aResult += ' ';
1216 }
1217 aResult += info.mCredentialType;
1218 }
1219 }
1220
1221 return state;
1222}
1223
1224nsContentUtils::AutocompleteAttrState
1225nsContentUtils::SerializeAutocompleteAttribute(
1226 const nsAttrValue* aAttr, mozilla::dom::AutocompleteInfo& aInfo,
1227 AutocompleteAttrState aCachedState, bool aGrantAllValidValue) {
1228 if (!aAttr ||
1229 aCachedState == nsContentUtils::eAutocompleteAttrState_Invalid) {
1230 return aCachedState;
1231 }
1232
1233 return InternalSerializeAutocompleteAttribute(aAttr, aInfo,
1234 aGrantAllValidValue);
1235}
1236
1237/**
1238 * Helper to validate the @autocomplete tokens.
1239 *
1240 * @return {AutocompleteAttrState} The state of the attribute (invalid/valid).
1241 */
1242nsContentUtils::AutocompleteAttrState
1243nsContentUtils::InternalSerializeAutocompleteAttribute(
1244 const nsAttrValue* aAttrVal, mozilla::dom::AutocompleteInfo& aInfo,
1245 bool aGrantAllValidValue) {
1246 // No autocomplete attribute so we are done
1247 if (!aAttrVal) {
1248 return eAutocompleteAttrState_Invalid;
1249 }
1250
1251 uint32_t numTokens = aAttrVal->GetAtomCount();
1252 if (!numTokens || numTokens > INT32_MAX(2147483647)) {
1253 return eAutocompleteAttrState_Invalid;
1254 }
1255
1256 uint32_t index = numTokens - 1;
1257 nsString tokenString = nsDependentAtomString(aAttrVal->AtomAt(index));
1258 AutocompleteCategory category;
1259 nsAttrValue enumValue;
1260 nsAutoString credentialTypeStr;
1261
1262 bool result = enumValue.ParseEnumValue(
1263 tokenString, kAutocompleteCredentialTypeTable, false);
1264 if (result) {
1265 if (!enumValue.Equals(u"webauthn"_ns, eIgnoreCase) || numTokens > 5) {
1266 return eAutocompleteAttrState_Invalid;
1267 }
1268 enumValue.ToString(credentialTypeStr);
1269 ASCIIToLower(credentialTypeStr);
1270 // category is Credential and the indexth token is "webauthn"
1271 if (index == 0) {
1272 aInfo.mFieldName.Assign(credentialTypeStr);
1273 aInfo.mCredentialType.Assign(credentialTypeStr);
1274 return eAutocompleteAttrState_Valid;
1275 }
1276
1277 --index;
1278 tokenString = nsDependentAtomString(aAttrVal->AtomAt(index));
1279
1280 // Only the Normal and Contact categories are allowed with webauthn
1281 // - disallow Credential
1282 if (enumValue.ParseEnumValue(tokenString, kAutocompleteCredentialTypeTable,
1283 false)) {
1284 return eAutocompleteAttrState_Invalid;
1285 }
1286 // - disallow Off and Automatic
1287 if (enumValue.ParseEnumValue(tokenString, kAutocompleteFieldNameTable,
1288 false)) {
1289 if (enumValue.Equals(u"off"_ns, eIgnoreCase) ||
1290 enumValue.Equals(u"on"_ns, eIgnoreCase)) {
1291 return eAutocompleteAttrState_Invalid;
1292 }
1293 }
1294
1295 // Proceed to process the remaining tokens as if "webauthn" was not present.
1296 // We need to decrement numTokens to enforce the correct per-category limits
1297 // on the maximum number of tokens.
1298 --numTokens;
1299 }
1300
1301 bool unsupported = false;
1302 if (!aGrantAllValidValue) {
1303 unsupported = enumValue.ParseEnumValue(
1304 tokenString, kAutocompleteUnsupportedFieldNameTable, false);
1305 if (unsupported) {
1306 return eAutocompleteAttrState_Invalid;
1307 }
1308 }
1309
1310 nsAutoString fieldNameStr;
1311 result =
1312 enumValue.ParseEnumValue(tokenString, kAutocompleteFieldNameTable, false);
1313
1314 if (result) {
1315 // Off/Automatic/Normal categories.
1316 if (enumValue.Equals(u"off"_ns, eIgnoreCase) ||
1317 enumValue.Equals(u"on"_ns, eIgnoreCase)) {
1318 if (numTokens > 1) {
1319 return eAutocompleteAttrState_Invalid;
1320 }
1321 enumValue.ToString(fieldNameStr);
1322 ASCIIToLower(fieldNameStr);
1323 aInfo.mFieldName.Assign(fieldNameStr);
1324 aInfo.mCredentialType.Assign(credentialTypeStr);
1325 aInfo.mCanAutomaticallyPersist =
1326 !enumValue.Equals(u"off"_ns, eIgnoreCase);
1327 return eAutocompleteAttrState_Valid;
1328 }
1329
1330 // Only allow on/off if form autofill @autocomplete values aren't enabled
1331 // and it doesn't grant all valid values.
1332 if (!StaticPrefs::dom_forms_autocomplete_formautofill() &&
1333 !aGrantAllValidValue) {
1334 return eAutocompleteAttrState_Invalid;
1335 }
1336
1337 // Normal category
1338 if (numTokens > 3) {
1339 return eAutocompleteAttrState_Invalid;
1340 }
1341 category = eAutocompleteCategory_NORMAL;
1342 } else { // Check if the last token is of the contact category instead.
1343 // Only allow on/off if form autofill @autocomplete values aren't enabled
1344 // and it doesn't grant all valid values.
1345 if (!StaticPrefs::dom_forms_autocomplete_formautofill() &&
1346 !aGrantAllValidValue) {
1347 return eAutocompleteAttrState_Invalid;
1348 }
1349
1350 result = enumValue.ParseEnumValue(
1351 tokenString, kAutocompleteContactFieldNameTable, false);
1352 if (!result || numTokens > 4) {
1353 return eAutocompleteAttrState_Invalid;
1354 }
1355
1356 category = eAutocompleteCategory_CONTACT;
1357 }
1358
1359 enumValue.ToString(fieldNameStr);
1360 ASCIIToLower(fieldNameStr);
1361
1362 aInfo.mFieldName.Assign(fieldNameStr);
1363 aInfo.mCredentialType.Assign(credentialTypeStr);
1364 aInfo.mCanAutomaticallyPersist = !enumValue.ParseEnumValue(
1365 tokenString, kAutocompleteNoPersistFieldNameTable, false);
1366
1367 // We are done if this was the only token.
1368 if (numTokens == 1) {
1369 return eAutocompleteAttrState_Valid;
1370 }
1371
1372 --index;
1373 tokenString = nsDependentAtomString(aAttrVal->AtomAt(index));
1374
1375 if (category == eAutocompleteCategory_CONTACT) {
1376 if (!aGrantAllValidValue) {
1377 unsupported = enumValue.ParseEnumValue(
1378 tokenString, kAutocompleteUnsupportedContactFieldHintTable, false);
1379 if (unsupported) {
1380 return eAutocompleteAttrState_Invalid;
1381 }
1382 }
1383
1384 nsAttrValue contactFieldHint;
1385 result = contactFieldHint.ParseEnumValue(
1386 tokenString, kAutocompleteContactFieldHintTable, false);
1387 if (result) {
1388 nsAutoString contactFieldHintString;
1389 contactFieldHint.ToString(contactFieldHintString);
1390 ASCIIToLower(contactFieldHintString);
1391 aInfo.mContactType.Assign(contactFieldHintString);
1392 if (index == 0) {
1393 return eAutocompleteAttrState_Valid;
1394 }
1395 --index;
1396 tokenString = nsDependentAtomString(aAttrVal->AtomAt(index));
1397 }
1398 }
1399
1400 // Check for billing/shipping tokens
1401 nsAttrValue fieldHint;
1402 if (fieldHint.ParseEnumValue(tokenString, kAutocompleteFieldHintTable,
1403 false)) {
1404 nsString fieldHintString;
1405 fieldHint.ToString(fieldHintString);
1406 ASCIIToLower(fieldHintString);
1407 aInfo.mAddressType.Assign(fieldHintString);
1408 if (index == 0) {
1409 return eAutocompleteAttrState_Valid;
1410 }
1411 --index;
1412 tokenString = nsDependentAtomString(aAttrVal->AtomAt(index));
1413 }
1414
1415 // Check for section-* token
1416 const nsDependentSubstring& section = Substring(tokenString, 0, 8);
1417 if (section.LowerCaseEqualsASCII("section-")) {
1418 ASCIIToLower(tokenString);
1419 aInfo.mSection.Assign(tokenString);
1420 if (index == 0) {
1421 return eAutocompleteAttrState_Valid;
1422 }
1423 }
1424
1425 // Clear the fields as the autocomplete attribute is invalid.
1426 aInfo.mSection.Truncate();
1427 aInfo.mAddressType.Truncate();
1428 aInfo.mContactType.Truncate();
1429 aInfo.mFieldName.Truncate();
1430 aInfo.mCredentialType.Truncate();
1431
1432 return eAutocompleteAttrState_Invalid;
1433}
1434
1435// Parse an integer according to HTML spec
1436template <class CharT>
1437int32_t nsContentUtils::ParseHTMLIntegerImpl(
1438 const CharT* aStart, const CharT* aEnd,
1439 ParseHTMLIntegerResultFlags* aResult) {
1440 int result = eParseHTMLInteger_NoFlags;
1441
1442 const CharT* iter = aStart;
1443
1444 while (iter != aEnd && nsContentUtils::IsHTMLWhitespace(*iter)) {
1445 result |= eParseHTMLInteger_NonStandard;
1446 ++iter;
1447 }
1448
1449 if (iter == aEnd) {
1450 result |= eParseHTMLInteger_Error | eParseHTMLInteger_ErrorNoValue;
1451 *aResult = (ParseHTMLIntegerResultFlags)result;
1452 return 0;
1453 }
1454
1455 int sign = 1;
1456 if (*iter == CharT('-')) {
1457 sign = -1;
1458 result |= eParseHTMLInteger_Negative;
1459 ++iter;
1460 } else if (*iter == CharT('+')) {
1461 result |= eParseHTMLInteger_NonStandard;
1462 ++iter;
1463 }
1464
1465 bool foundValue = false;
1466 CheckedInt32 value = 0;
1467
1468 // Check for leading zeros first.
1469 uint64_t leadingZeros = 0;
1470 while (iter != aEnd) {
1471 if (*iter != CharT('0')) {
1472 break;
1473 }
1474
1475 ++leadingZeros;
1476 foundValue = true;
1477 ++iter;
1478 }
1479
1480 while (iter != aEnd) {
1481 if (*iter >= CharT('0') && *iter <= CharT('9')) {
1482 value = (value * 10) + (*iter - CharT('0')) * sign;
1483 ++iter;
1484 if (!value.isValid()) {
1485 result |= eParseHTMLInteger_Error | eParseHTMLInteger_ErrorOverflow;
1486 break;
1487 }
1488 foundValue = true;
1489 } else {
1490 break;
1491 }
1492 }
1493
1494 if (!foundValue) {
1495 result |= eParseHTMLInteger_Error | eParseHTMLInteger_ErrorNoValue;
1496 }
1497
1498 if (value.isValid() &&
1499 ((leadingZeros > 1 || (leadingZeros == 1 && !(value == 0))) ||
1500 (sign == -1 && value == 0))) {
1501 result |= eParseHTMLInteger_NonStandard;
1502 }
1503
1504 if (iter != aEnd) {
1505 result |= eParseHTMLInteger_DidNotConsumeAllInput;
1506 }
1507
1508 *aResult = (ParseHTMLIntegerResultFlags)result;
1509 return value.isValid() ? value.value() : 0;
1510}
1511
1512// Parse an integer according to HTML spec
1513int32_t nsContentUtils::ParseHTMLInteger(const char16_t* aStart,
1514 const char16_t* aEnd,
1515 ParseHTMLIntegerResultFlags* aResult) {
1516 return ParseHTMLIntegerImpl(aStart, aEnd, aResult);
1517}
1518
1519int32_t nsContentUtils::ParseHTMLInteger(const char* aStart, const char* aEnd,
1520 ParseHTMLIntegerResultFlags* aResult) {
1521 return ParseHTMLIntegerImpl(aStart, aEnd, aResult);
1522}
1523
1524#define SKIP_WHITESPACE(iter, end_iter, end_res)while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*(
iter))) { ++(iter); } if ((iter) == (end_iter)) { return (end_res
); }
\
1525 while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*(iter))) { \
1526 ++(iter); \
1527 } \
1528 if ((iter) == (end_iter)) { \
1529 return (end_res); \
1530 }
1531
1532#define SKIP_ATTR_NAME(iter, end_iter)while ((iter) != (end_iter) && !nsCRT::IsAsciiSpace(*
(iter)) && *(iter) != '=') { ++(iter); }
\
1533 while ((iter) != (end_iter) && !nsCRT::IsAsciiSpace(*(iter)) && \
1534 *(iter) != '=') { \
1535 ++(iter); \
1536 }
1537
1538bool nsContentUtils::GetPseudoAttributeValue(const nsString& aSource,
1539 nsAtom* aName, nsAString& aValue) {
1540 aValue.Truncate();
1541
1542 const char16_t* start = aSource.get();
1543 const char16_t* end = start + aSource.Length();
1544 const char16_t* iter;
1545
1546 while (start != end) {
1547 SKIP_WHITESPACE(start, end, false)while ((start) != (end) && nsCRT::IsAsciiSpace(*(start
))) { ++(start); } if ((start) == (end)) { return (false); }
1548 iter = start;
1549 SKIP_ATTR_NAME(iter, end)while ((iter) != (end) && !nsCRT::IsAsciiSpace(*(iter
)) && *(iter) != '=') { ++(iter); }
1550
1551 if (start == iter) {
1552 return false;
1553 }
1554
1555 // Remember the attr name.
1556 const nsDependentSubstring& attrName = Substring(start, iter);
1557
1558 // Now check whether this is a valid name="value" pair.
1559 start = iter;
1560 SKIP_WHITESPACE(start, end, false)while ((start) != (end) && nsCRT::IsAsciiSpace(*(start
))) { ++(start); } if ((start) == (end)) { return (false); }
1561 if (*start != '=') {
1562 // No '=', so this is not a name="value" pair. We don't know
1563 // what it is, and we have no way to handle it.
1564 return false;
1565 }
1566
1567 // Have to skip the value.
1568 ++start;
1569 SKIP_WHITESPACE(start, end, false)while ((start) != (end) && nsCRT::IsAsciiSpace(*(start
))) { ++(start); } if ((start) == (end)) { return (false); }
1570 char16_t q = *start;
1571 if (q != kQuote && q != kApostrophe) {
1572 // Not a valid quoted value, so bail.
1573 return false;
1574 }
1575
1576 ++start; // Point to the first char of the value.
1577 iter = start;
1578
1579 while (iter != end && *iter != q) {
1580 ++iter;
1581 }
1582
1583 if (iter == end) {
1584 // Oops, unterminated quoted string.
1585 return false;
1586 }
1587
1588 // At this point attrName holds the name of the "attribute" and
1589 // the value is between start and iter.
1590
1591 if (aName->Equals(attrName)) {
1592 // We'll accumulate as many characters as possible (until we hit either
1593 // the end of the string or the beginning of an entity). Chunks will be
1594 // delimited by start and chunkEnd.
1595 const char16_t* chunkEnd = start;
1596 while (chunkEnd != iter) {
1597 if (*chunkEnd == kLessThan) {
1598 aValue.Truncate();
1599
1600 return false;
1601 }
1602
1603 if (*chunkEnd == kAmpersand) {
1604 aValue.Append(start, chunkEnd - start);
1605
1606 const char16_t* afterEntity = nullptr;
1607 char16_t result[2];
1608 uint32_t count = MOZ_XMLTranslateEntity(
1609 reinterpret_cast<const char*>(chunkEnd),
1610 reinterpret_cast<const char*>(iter),
1611 reinterpret_cast<const char**>(&afterEntity), result);
1612 if (count == 0) {
1613 aValue.Truncate();
1614
1615 return false;
1616 }
1617
1618 aValue.Append(result, count);
1619
1620 // Advance to after the entity and begin a new chunk.
1621 start = chunkEnd = afterEntity;
1622 } else {
1623 ++chunkEnd;
1624 }
1625 }
1626
1627 // Append remainder.
1628 aValue.Append(start, iter - start);
1629
1630 return true;
1631 }
1632
1633 // Resume scanning after the end of the attribute value (past the quote
1634 // char).
1635 start = iter + 1;
1636 }
1637
1638 return false;
1639}
1640
1641bool nsContentUtils::IsJavaScriptLanguage(const nsString& aName) {
1642 // Create MIME type as "text/" + given input
1643 nsAutoString mimeType(u"text/");
1644 mimeType.Append(aName);
1645
1646 return IsJavascriptMIMEType(mimeType);
1647}
1648
1649void nsContentUtils::SplitMimeType(const nsAString& aValue, nsString& aType,
1650 nsString& aParams) {
1651 aType.Truncate();
1652 aParams.Truncate();
1653 int32_t semiIndex = aValue.FindChar(char16_t(';'));
1654 if (-1 != semiIndex) {
1655 aType = Substring(aValue, 0, semiIndex);
1656 aParams =
1657 Substring(aValue, semiIndex + 1, aValue.Length() - (semiIndex + 1));
1658 aParams.StripWhitespace();
1659 } else {
1660 aType = aValue;
1661 }
1662 aType.StripWhitespace();
1663}
1664
1665/**
1666 * A helper function that parses a sandbox attribute (of an <iframe> or a CSP
1667 * directive) and converts it to the set of flags used internally.
1668 *
1669 * @param aSandboxAttr the sandbox attribute
1670 * @return the set of flags (SANDBOXED_NONE if aSandboxAttr is
1671 * null)
1672 */
1673uint32_t nsContentUtils::ParseSandboxAttributeToFlags(
1674 const nsAttrValue* aSandboxAttr) {
1675 if (!aSandboxAttr) {
1676 return SANDBOXED_NONE;
1677 }
1678
1679 uint32_t out = SANDBOX_ALL_FLAGS;
1680
1681#define SANDBOX_KEYWORD(string, atom, flags) \
1682 if (aSandboxAttr->Contains(nsGkAtoms::atom, eIgnoreCase)) { \
1683 out &= ~(flags); \
1684 }
1685#include "IframeSandboxKeywordList.h"
1686#undef SANDBOX_KEYWORD
1687
1688 return out;
1689}
1690
1691/**
1692 * A helper function that checks if a string matches a valid sandbox flag.
1693 *
1694 * @param aFlag the potential sandbox flag.
1695 * @return true if the flag is a sandbox flag.
1696 */
1697bool nsContentUtils::IsValidSandboxFlag(const nsAString& aFlag) {
1698#define SANDBOX_KEYWORD(string, atom, flags) \
1699 if (EqualsIgnoreASCIICase(nsDependentAtomString(nsGkAtoms::atom), aFlag)) { \
1700 return true; \
1701 }
1702#include "IframeSandboxKeywordList.h"
1703#undef SANDBOX_KEYWORD
1704 return false;
1705}
1706
1707/**
1708 * A helper function that returns a string attribute corresponding to the
1709 * sandbox flags.
1710 *
1711 * @param aFlags the sandbox flags
1712 * @param aString the attribute corresponding to the flags (null if aFlags
1713 * is zero)
1714 */
1715void nsContentUtils::SandboxFlagsToString(uint32_t aFlags, nsAString& aString) {
1716 if (!aFlags) {
1717 SetDOMStringToNull(aString);
1718 return;
1719 }
1720
1721 aString.Truncate();
1722
1723#define SANDBOX_KEYWORD(string, atom, flags) \
1724 if (!(aFlags & (flags))) { \
1725 if (!aString.IsEmpty()) { \
1726 aString.AppendLiteral(u" "); \
1727 } \
1728 aString.Append(nsDependentAtomString(nsGkAtoms::atom)); \
1729 }
1730#include "IframeSandboxKeywordList.h"
1731#undef SANDBOX_KEYWORD
1732}
1733
1734nsIBidiKeyboard* nsContentUtils::GetBidiKeyboard() {
1735 if (!sBidiKeyboard) {
1736 sBidiKeyboard = nsIWidget::CreateBidiKeyboard();
1737 }
1738 return sBidiKeyboard;
1739}
1740
1741/**
1742 * This is used to determine whether a character is in one of the classes
1743 * which CSS says should be part of the first-letter. Currently, that is
1744 * all punctuation classes (P*). Note that this is a change from CSS2
1745 * which excluded Pc and Pd.
1746 *
1747 * https://www.w3.org/TR/css-pseudo-4/#first-letter-pseudo
1748 * "Punctuation (i.e, characters that belong to the Punctuation (P*) Unicode
1749 * general category [UAX44]) [...]"
1750 */
1751
1752// static
1753bool nsContentUtils::IsFirstLetterPunctuation(uint32_t aChar) {
1754 switch (mozilla::unicode::GetGeneralCategory(aChar)) {
1755 case HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION: /* Pc */
1756 case HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION: /* Pd */
1757 case HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION: /* Pe */
1758 case HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION: /* Pf */
1759 case HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION: /* Pi */
1760 case HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION: /* Po */
1761 case HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION: /* Ps */
1762 return true;
1763 default:
1764 return false;
1765 }
1766}
1767
1768// static
1769bool nsContentUtils::IsAlphanumeric(uint32_t aChar) {
1770 nsUGenCategory cat = mozilla::unicode::GetGenCategory(aChar);
1771
1772 return (cat == nsUGenCategory::kLetter || cat == nsUGenCategory::kNumber);
1773}
1774
1775// static
1776bool nsContentUtils::IsAlphanumericOrSymbol(uint32_t aChar) {
1777 nsUGenCategory cat = mozilla::unicode::GetGenCategory(aChar);
1778
1779 return cat == nsUGenCategory::kLetter || cat == nsUGenCategory::kNumber ||
1780 cat == nsUGenCategory::kSymbol;
1781}
1782
1783// static
1784bool nsContentUtils::IsHyphen(uint32_t aChar) {
1785 // Characters treated as hyphens for the purpose of "emergency" breaking
1786 // when the content would otherwise overflow.
1787 return aChar == uint32_t('-') || // HYPHEN-MINUS
1788 aChar == 0x2010 || // HYPHEN
1789 aChar == 0x2012 || // FIGURE DASH
1790 aChar == 0x2013 || // EN DASH
1791 aChar == 0x058A; // ARMENIAN HYPHEN
1792}
1793
1794/* static */
1795bool nsContentUtils::IsHTMLWhitespace(char16_t aChar) {
1796 return aChar == char16_t(0x0009) || aChar == char16_t(0x000A) ||
1797 aChar == char16_t(0x000C) || aChar == char16_t(0x000D) ||
1798 aChar == char16_t(0x0020);
1799}
1800
1801/* static */
1802bool nsContentUtils::IsHTMLWhitespaceOrNBSP(char16_t aChar) {
1803 return IsHTMLWhitespace(aChar) || aChar == char16_t(0xA0);
1804}
1805
1806/* static */
1807bool nsContentUtils::IsHTMLBlockLevelElement(nsIContent* aContent) {
1808 return aContent->IsAnyOfHTMLElements(
1809 nsGkAtoms::address, nsGkAtoms::article, nsGkAtoms::aside,
1810 nsGkAtoms::blockquote, nsGkAtoms::center, nsGkAtoms::dir, nsGkAtoms::div,
1811 nsGkAtoms::dl, // XXX why not dt and dd?
1812 nsGkAtoms::fieldset,
1813 nsGkAtoms::figure, // XXX shouldn't figcaption be on this list
1814 nsGkAtoms::footer, nsGkAtoms::form, nsGkAtoms::h1, nsGkAtoms::h2,
1815 nsGkAtoms::h3, nsGkAtoms::h4, nsGkAtoms::h5, nsGkAtoms::h6,
1816 nsGkAtoms::header, nsGkAtoms::hgroup, nsGkAtoms::hr, nsGkAtoms::li,
1817 nsGkAtoms::listing, nsGkAtoms::menu, nsGkAtoms::nav, nsGkAtoms::ol,
1818 nsGkAtoms::p, nsGkAtoms::pre, nsGkAtoms::section, nsGkAtoms::table,
1819 nsGkAtoms::ul, nsGkAtoms::xmp);
1820}
1821
1822/* static */
1823bool nsContentUtils::ParseIntMarginValue(const nsAString& aString,
1824 nsIntMargin& result) {
1825 nsAutoString marginStr(aString);
1826 marginStr.CompressWhitespace(true, true);
1827 if (marginStr.IsEmpty()) {
1828 return false;
1829 }
1830
1831 int32_t start = 0, end = 0;
1832 for (int count = 0; count < 4; count++) {
1833 if ((uint32_t)end >= marginStr.Length()) return false;
1834
1835 // top, right, bottom, left
1836 if (count < 3)
1837 end = Substring(marginStr, start).FindChar(',');
1838 else
1839 end = Substring(marginStr, start).Length();
1840
1841 if (end <= 0) return false;
1842
1843 nsresult ec;
1844 int32_t val = nsString(Substring(marginStr, start, end)).ToInteger(&ec);
1845 if (NS_FAILED(ec)((bool)(__builtin_expect(!!(NS_FAILED_impl(ec)), 0)))) return false;
1846
1847 switch (count) {
1848 case 0:
1849 result.top = val;
1850 break;
1851 case 1:
1852 result.right = val;
1853 break;
1854 case 2:
1855 result.bottom = val;
1856 break;
1857 case 3:
1858 result.left = val;
1859 break;
1860 }
1861 start += end + 1;
1862 }
1863 return true;
1864}
1865
1866// static
1867int32_t nsContentUtils::ParseLegacyFontSize(const nsAString& aValue) {
1868 nsAString::const_iterator iter, end;
1869 aValue.BeginReading(iter);
1870 aValue.EndReading(end);
1871
1872 while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
1873 ++iter;
1874 }
1875
1876 if (iter == end) {
1877 return 0;
1878 }
1879
1880 bool relative = false;
1881 bool negate = false;
1882 if (*iter == char16_t('-')) {
1883 relative = true;
1884 negate = true;
1885 ++iter;
1886 } else if (*iter == char16_t('+')) {
1887 relative = true;
1888 ++iter;
1889 }
1890
1891 if (iter == end || *iter < char16_t('0') || *iter > char16_t('9')) {
1892 return 0;
1893 }
1894
1895 // We don't have to worry about overflow, since we can bail out as soon as
1896 // we're bigger than 7.
1897 int32_t value = 0;
1898 while (iter != end && *iter >= char16_t('0') && *iter <= char16_t('9')) {
1899 value = 10 * value + (*iter - char16_t('0'));
1900 if (value >= 7) {
1901 break;
1902 }
1903 ++iter;
1904 }
1905
1906 if (relative) {
1907 if (negate) {
1908 value = 3 - value;
1909 } else {
1910 value = 3 + value;
1911 }
1912 }
1913
1914 return clamped(value, 1, 7);
1915}
1916
1917/* static */
1918void nsContentUtils::GetOfflineAppManifest(Document* aDocument, nsIURI** aURI) {
1919 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 1919); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 1919; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1920 MOZ_ASSERT(aDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDocument))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 1920); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocument" ")"
); do { *((volatile int*)__null) = 1920; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1921 *aURI = nullptr;
1922
1923 if (aDocument->GetController().isSome()) {
1924 return;
1925 }
1926
1927 Element* docElement = aDocument->GetRootElement();
1928 if (!docElement) {
1929 return;
1930 }
1931
1932 nsAutoString manifestSpec;
1933 docElement->GetAttr(nsGkAtoms::manifest, manifestSpec);
1934
1935 // Manifest URIs can't have fragment identifiers.
1936 if (manifestSpec.IsEmpty() || manifestSpec.Contains('#')) {
1937 return;
1938 }
1939
1940 nsContentUtils::NewURIWithDocumentCharset(aURI, manifestSpec, aDocument,
1941 aDocument->GetDocBaseURI());
1942}
1943
1944/* static */
1945bool nsContentUtils::OfflineAppAllowed(nsIURI* aURI) { return false; }
1946
1947/* static */
1948bool nsContentUtils::OfflineAppAllowed(nsIPrincipal* aPrincipal) {
1949 return false;
1950}
1951// Static
1952bool nsContentUtils::IsErrorPage(nsIURI* aURI) {
1953 if (!aURI) {
1954 return false;
1955 }
1956
1957 if (!aURI->SchemeIs("about")) {
1958 return false;
1959 }
1960
1961 nsAutoCString name;
1962 nsresult rv = NS_GetAboutModuleName(aURI, name);
1963 NS_ENSURE_SUCCESS(rv, false)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "false", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 1963); return false; } } while (false)
;
1964
1965 return name.EqualsLiteral("certerror") || name.EqualsLiteral("neterror") ||
1966 name.EqualsLiteral("blocked");
1967}
1968
1969// static
1970void nsContentUtils::Shutdown() {
1971 sInitialized = false;
1972
1973 nsHTMLTags::ReleaseTable();
1974
1975 NS_IF_RELEASE(sContentPolicyService)do { if (sContentPolicyService) { (sContentPolicyService)->
Release(); (sContentPolicyService) = 0; } } while (0)
;
1976 sTriedToGetContentPolicy = false;
1977 for (StaticRefPtr<nsIStringBundle>& bundle : sStringBundles) {
1978 bundle = nullptr;
1979 }
1980
1981 NS_IF_RELEASE(sStringBundleService)do { if (sStringBundleService) { (sStringBundleService)->Release
(); (sStringBundleService) = 0; } } while (0)
;
1982 NS_IF_RELEASE(sConsoleService)do { if (sConsoleService) { (sConsoleService)->Release(); (
sConsoleService) = 0; } } while (0)
;
1983 NS_IF_RELEASE(sXPConnect)do { if (sXPConnect) { (sXPConnect)->Release(); (sXPConnect
) = 0; } } while (0)
;
1984 NS_IF_RELEASE(sSecurityManager)do { if (sSecurityManager) { (sSecurityManager)->Release()
; (sSecurityManager) = 0; } } while (0)
;
1985 NS_IF_RELEASE(sSystemPrincipal)do { if (sSystemPrincipal) { (sSystemPrincipal)->Release()
; (sSystemPrincipal) = 0; } } while (0)
;
1986 NS_IF_RELEASE(sNullSubjectPrincipal)do { if (sNullSubjectPrincipal) { (sNullSubjectPrincipal)->
Release(); (sNullSubjectPrincipal) = 0; } } while (0)
;
1987 NS_IF_RELEASE(sFingerprintingProtectionPrincipal)do { if (sFingerprintingProtectionPrincipal) { (sFingerprintingProtectionPrincipal
)->Release(); (sFingerprintingProtectionPrincipal) = 0; } }
while (0)
;
1988
1989 sBidiKeyboard = nullptr;
1990
1991 delete sAtomEventTable;
1992 sAtomEventTable = nullptr;
1993 delete sStringEventTable;
1994 sStringEventTable = nullptr;
1995 delete sUserDefinedEvents;
1996 sUserDefinedEvents = nullptr;
1997
1998 if (sEventListenerManagersHash) {
1999 NS_ASSERTION(sEventListenerManagersHash->EntryCount() == 0,do { if (!(sEventListenerManagersHash->EntryCount() == 0))
{ NS_DebugBreak(NS_DEBUG_ASSERTION, "Event listener manager hash not empty at shutdown!"
, "sEventListenerManagersHash->EntryCount() == 0", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2000); MOZ_PretendNoReturn(); } } while (0)
2000 "Event listener manager hash not empty at shutdown!")do { if (!(sEventListenerManagersHash->EntryCount() == 0))
{ NS_DebugBreak(NS_DEBUG_ASSERTION, "Event listener manager hash not empty at shutdown!"
, "sEventListenerManagersHash->EntryCount() == 0", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2000); MOZ_PretendNoReturn(); } } while (0)
;
2001
2002 // See comment above.
2003
2004 // However, we have to handle this table differently. If it still
2005 // has entries, we want to leak it too, so that we can keep it alive
2006 // in case any elements are destroyed. Because if they are, we need
2007 // their event listener managers to be destroyed too, or otherwise
2008 // it could leave dangling references in DOMClassInfo's preserved
2009 // wrapper table.
2010
2011 if (sEventListenerManagersHash->EntryCount() == 0) {
2012 delete sEventListenerManagersHash;
2013 sEventListenerManagersHash = nullptr;
2014 }
2015 }
2016
2017 if (sDOMArenaHashtable) {
2018 MOZ_ASSERT(sDOMArenaHashtable->Count() == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sDOMArenaHashtable->Count() == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sDOMArenaHashtable->Count
() == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("sDOMArenaHashtable->Count() == 0", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2018); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sDOMArenaHashtable->Count() == 0"
")"); do { *((volatile int*)__null) = 2018; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2019 MOZ_ASSERT(StaticPrefs::dom_arena_allocator_enabled_AtStartup())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(StaticPrefs::dom_arena_allocator_enabled_AtStartup()
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(StaticPrefs::dom_arena_allocator_enabled_AtStartup()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"StaticPrefs::dom_arena_allocator_enabled_AtStartup()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2019); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::dom_arena_allocator_enabled_AtStartup()"
")"); do { *((volatile int*)__null) = 2019; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2020 delete sDOMArenaHashtable;
2021 sDOMArenaHashtable = nullptr;
2022 }
2023
2024 NS_ASSERTION(!sBlockedScriptRunners || sBlockedScriptRunners->Length() == 0,do { if (!(!sBlockedScriptRunners || sBlockedScriptRunners->
Length() == 0)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "How'd this happen?"
, "!sBlockedScriptRunners || sBlockedScriptRunners->Length() == 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2025); MOZ_PretendNoReturn(); } } while (0)
2025 "How'd this happen?")do { if (!(!sBlockedScriptRunners || sBlockedScriptRunners->
Length() == 0)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "How'd this happen?"
, "!sBlockedScriptRunners || sBlockedScriptRunners->Length() == 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2025); MOZ_PretendNoReturn(); } } while (0)
;
2026 delete sBlockedScriptRunners;
2027 sBlockedScriptRunners = nullptr;
2028
2029 delete sShiftText;
2030 sShiftText = nullptr;
2031 delete sControlText;
2032 sControlText = nullptr;
2033 delete sCommandOrWinText;
2034 sCommandOrWinText = nullptr;
2035 delete sAltText;
2036 sAltText = nullptr;
2037 delete sModifierSeparator;
2038 sModifierSeparator = nullptr;
2039
2040 delete sJSScriptBytecodeMimeType;
2041 sJSScriptBytecodeMimeType = nullptr;
2042
2043 delete sJSModuleBytecodeMimeType;
2044 sJSModuleBytecodeMimeType = nullptr;
2045
2046 NS_IF_RELEASE(sSameOriginChecker)do { if (sSameOriginChecker) { (sSameOriginChecker)->Release
(); (sSameOriginChecker) = 0; } } while (0)
;
2047
2048 if (sUserInteractionObserver) {
2049 sUserInteractionObserver->Shutdown();
2050 NS_RELEASE(sUserInteractionObserver)do { (sUserInteractionObserver)->Release(); (sUserInteractionObserver
) = 0; } while (0)
;
2051 }
2052
2053 for (const auto& pref : kRfpPrefs) {
2054 Preferences::UnregisterCallback(RecomputeResistFingerprintingAllDocs, pref);
2055 }
2056
2057 TextControlState::Shutdown();
2058}
2059
2060/**
2061 * Checks whether two nodes come from the same origin. aTrustedNode is
2062 * considered 'safe' in that a user can operate on it.
2063 */
2064// static
2065nsresult nsContentUtils::CheckSameOrigin(const nsINode* aTrustedNode,
2066 const nsINode* unTrustedNode) {
2067 MOZ_ASSERT(aTrustedNode)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTrustedNode)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTrustedNode))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aTrustedNode", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2067); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTrustedNode"
")"); do { *((volatile int*)__null) = 2067; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2068 MOZ_ASSERT(unTrustedNode)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(unTrustedNode)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(unTrustedNode))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("unTrustedNode",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2068); AnnotateMozCrashReason("MOZ_ASSERT" "(" "unTrustedNode"
")"); do { *((volatile int*)__null) = 2068; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2069
2070 /*
2071 * Get hold of each node's principal
2072 */
2073
2074 nsIPrincipal* trustedPrincipal = aTrustedNode->NodePrincipal();
2075 nsIPrincipal* unTrustedPrincipal = unTrustedNode->NodePrincipal();
2076
2077 if (trustedPrincipal == unTrustedPrincipal) {
2078 return NS_OK;
2079 }
2080
2081 bool equal;
2082 // XXXbz should we actually have a Subsumes() check here instead? Or perhaps
2083 // a separate method for that, with callers using one or the other?
2084 if (NS_FAILED(trustedPrincipal->Equals(unTrustedPrincipal, &equal))((bool)(__builtin_expect(!!(NS_FAILED_impl(trustedPrincipal->
Equals(unTrustedPrincipal, &equal))), 0)))
||
2085 !equal) {
2086 return NS_ERROR_DOM_PROP_ACCESS_DENIED;
2087 }
2088
2089 return NS_OK;
2090}
2091
2092// static
2093bool nsContentUtils::CanCallerAccess(nsIPrincipal* aSubjectPrincipal,
2094 nsIPrincipal* aPrincipal) {
2095 bool subsumes;
2096 nsresult rv = aSubjectPrincipal->Subsumes(aPrincipal, &subsumes);
2097 NS_ENSURE_SUCCESS(rv, false)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "false", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2097); return false; } } while (false)
;
2098
2099 if (subsumes) {
2100 return true;
2101 }
2102
2103 // The subject doesn't subsume aPrincipal. Allow access only if the subject
2104 // is chrome.
2105 return IsCallerChrome();
2106}
2107
2108// static
2109bool nsContentUtils::CanCallerAccess(const nsINode* aNode) {
2110 nsIPrincipal* subject = SubjectPrincipal();
2111 if (subject->IsSystemPrincipal()) {
2112 return true;
2113 }
2114
2115 if (aNode->ChromeOnlyAccess()) {
2116 return false;
2117 }
2118
2119 return CanCallerAccess(subject, aNode->NodePrincipal());
2120}
2121
2122// static
2123bool nsContentUtils::CanCallerAccess(nsPIDOMWindowInner* aWindow) {
2124 nsCOMPtr<nsIScriptObjectPrincipal> scriptObject = do_QueryInterface(aWindow);
2125 NS_ENSURE_TRUE(scriptObject, false)do { if ((__builtin_expect(!!(!(scriptObject)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "scriptObject" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2125); return false; } } while (false)
;
2126
2127 return CanCallerAccess(SubjectPrincipal(), scriptObject->GetPrincipal());
2128}
2129
2130// static
2131bool nsContentUtils::PrincipalHasPermission(nsIPrincipal& aPrincipal,
2132 const nsAtom* aPerm) {
2133 // Chrome gets access by default.
2134 if (aPrincipal.IsSystemPrincipal()) {
2135 return true;
2136 }
2137
2138 // Otherwise, only allow if caller is an addon with the permission.
2139 return BasePrincipal::Cast(aPrincipal).AddonHasPermission(aPerm);
2140}
2141
2142// static
2143bool nsContentUtils::CallerHasPermission(JSContext* aCx, const nsAtom* aPerm) {
2144 return PrincipalHasPermission(*SubjectPrincipal(aCx), aPerm);
2145}
2146
2147// static
2148nsIPrincipal* nsContentUtils::GetAttrTriggeringPrincipal(
2149 nsIContent* aContent, const nsAString& aAttrValue,
2150 nsIPrincipal* aSubjectPrincipal) {
2151 nsIPrincipal* contentPrin = aContent ? aContent->NodePrincipal() : nullptr;
2152
2153 // If the subject principal is the same as the content principal, or no
2154 // explicit subject principal was provided, we don't need to do any further
2155 // checks. Just return the content principal.
2156 if (contentPrin == aSubjectPrincipal || !aSubjectPrincipal) {
2157 return contentPrin;
2158 }
2159
2160 // Only use the subject principal if the URL string we are going to end up
2161 // fetching is under the control of that principal, which is never the case
2162 // for relative URLs.
2163 if (aAttrValue.IsEmpty() ||
2164 !IsAbsoluteURL(NS_ConvertUTF16toUTF8(aAttrValue))) {
2165 return contentPrin;
2166 }
2167
2168 // Only use the subject principal as the attr triggering principal if it
2169 // should override the CSP of the node's principal.
2170 if (BasePrincipal::Cast(aSubjectPrincipal)->OverridesCSP(contentPrin)) {
2171 return aSubjectPrincipal;
2172 }
2173
2174 return contentPrin;
2175}
2176
2177// static
2178bool nsContentUtils::IsAbsoluteURL(const nsACString& aURL) {
2179 nsAutoCString scheme;
2180 if (NS_FAILED(net_ExtractURLScheme(aURL, scheme))((bool)(__builtin_expect(!!(NS_FAILED_impl(net_ExtractURLScheme
(aURL, scheme))), 0)))
) {
2181 // If we can't extract a scheme, it's not an absolute URL.
2182 return false;
2183 }
2184
2185 // If it parses as an absolute StandardURL, it's definitely an absolute URL,
2186 // so no need to check with the IO service.
2187 if (net_IsAbsoluteURL(aURL)) {
2188 return true;
2189 }
2190
2191 nsresult rv = NS_OK;
2192 nsCOMPtr<nsIIOService> io = mozilla::components::IO::Service(&rv);
2193 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2193); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 2193; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2194 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2195 return false;
2196 }
2197
2198 uint32_t flags;
2199 if (NS_SUCCEEDED(io->GetProtocolFlags(scheme.get(), &flags))((bool)(__builtin_expect(!!(!NS_FAILED_impl(io->GetProtocolFlags
(scheme.get(), &flags))), 1)))
) {
2200 return flags & nsIProtocolHandler::URI_NORELATIVE;
2201 }
2202
2203 return false;
2204}
2205
2206// static
2207bool nsContentUtils::InProlog(nsINode* aNode) {
2208 MOZ_ASSERT(aNode, "missing node to nsContentUtils::InProlog")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNode)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aNode))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aNode" " (" "missing node to nsContentUtils::InProlog"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2208); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNode" ") ("
"missing node to nsContentUtils::InProlog" ")"); do { *((volatile
int*)__null) = 2208; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2209
2210 nsINode* parent = aNode->GetParentNode();
2211 if (!parent || !parent->IsDocument()) {
2212 return false;
2213 }
2214
2215 const Document* doc = parent->AsDocument();
2216 const nsIContent* root = doc->GetRootElement();
2217 if (!root) {
2218 return true;
2219 }
2220 const Maybe<uint32_t> indexOfNode = doc->ComputeIndexOf(aNode);
2221 const Maybe<uint32_t> indexOfRoot = doc->ComputeIndexOf(root);
2222 if (MOZ_LIKELY(indexOfNode.isSome() && indexOfRoot.isSome())(__builtin_expect(!!(indexOfNode.isSome() && indexOfRoot
.isSome()), 1))
) {
2223 return *indexOfNode < *indexOfRoot;
2224 }
2225 // XXX Keep the odd traditional behavior for now.
2226 return indexOfNode.isNothing() && indexOfRoot.isSome();
2227}
2228
2229bool nsContentUtils::IsCallerChrome() {
2230 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2230); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 2230; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2231 return SubjectPrincipal() == sSystemPrincipal;
2232}
2233
2234#ifdef FUZZING
2235bool nsContentUtils::IsFuzzingEnabled() {
2236 return StaticPrefs::fuzzing_enabled();
2237}
2238#endif
2239
2240/* static */
2241bool nsContentUtils::IsCallerChromeOrElementTransformGettersEnabled(
2242 JSContext* aCx, JSObject*) {
2243 return ThreadsafeIsSystemCaller(aCx) ||
2244 StaticPrefs::dom_element_transform_getters_enabled();
2245}
2246
2247// Older Should RFP Functions ----------------------------------
2248
2249/* static */
2250bool nsContentUtils::ShouldResistFingerprinting(bool aIsPrivateMode,
2251 RFPTarget aTarget) {
2252 return nsRFPService::IsRFPEnabledFor(aIsPrivateMode, aTarget, Nothing());
2253}
2254
2255/* static */
2256bool nsContentUtils::ShouldResistFingerprinting(nsIGlobalObject* aGlobalObject,
2257 RFPTarget aTarget) {
2258 if (!aGlobalObject) {
2259 return ShouldResistFingerprinting("Null Object", aTarget);
2260 }
2261 return aGlobalObject->ShouldResistFingerprinting(aTarget);
2262}
2263
2264// Newer Should RFP Functions ----------------------------------
2265// Utilities ---------------------------------------------------
2266
2267inline void LogDomainAndPrefList(const char* urlType,
2268 const char* exemptedDomainsPrefName,
2269 nsAutoCString& url, bool isExemptDomain) {
2270 nsAutoCString list;
2271 Preferences::GetCString(exemptedDomainsPrefName, list);
2272 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"%s \"%s\" is %s the exempt list \"%s\"", urlType, TPromiseFlatString
<char>(url).get(), isExemptDomain ? "in" : "NOT in", TPromiseFlatString
<char>(list).get()); } } while (0)
2273 ("%s \"%s\" is %s the exempt list \"%s\"", urlType,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"%s \"%s\" is %s the exempt list \"%s\"", urlType, TPromiseFlatString
<char>(url).get(), isExemptDomain ? "in" : "NOT in", TPromiseFlatString
<char>(list).get()); } } while (0)
2274 PromiseFlatCString(url).get(), isExemptDomain ? "in" : "NOT in",do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"%s \"%s\" is %s the exempt list \"%s\"", urlType, TPromiseFlatString
<char>(url).get(), isExemptDomain ? "in" : "NOT in", TPromiseFlatString
<char>(list).get()); } } while (0)
2275 PromiseFlatCString(list).get()))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"%s \"%s\" is %s the exempt list \"%s\"", urlType, TPromiseFlatString
<char>(url).get(), isExemptDomain ? "in" : "NOT in", TPromiseFlatString
<char>(list).get()); } } while (0)
;
2276}
2277
2278inline already_AddRefed<nsICookieJarSettings> GetCookieJarSettings(
2279 nsILoadInfo* aLoadInfo) {
2280 nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
2281 nsresult rv =
2282 aLoadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings));
2283 if (rv == NS_ERROR_NOT_IMPLEMENTED) {
2284 // The TRRLoadInfo in particular does not implement this method
2285 // In that instance. We will return false and let other code decide if
2286 // we shouldRFP for this connection
2287 return nullptr;
2288 }
2289 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2289)
) {
2290 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Called CookieJarSettingsSaysShouldResistFingerprinting but the "
"loadinfo's CookieJarSettings couldn't be retrieved"); } } while
(0)
2291 ("Called CookieJarSettingsSaysShouldResistFingerprinting but the "do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Called CookieJarSettingsSaysShouldResistFingerprinting but the "
"loadinfo's CookieJarSettings couldn't be retrieved"); } } while
(0)
2292 "loadinfo's CookieJarSettings couldn't be retrieved"))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Called CookieJarSettingsSaysShouldResistFingerprinting but the "
"loadinfo's CookieJarSettings couldn't be retrieved"); } } while
(0)
;
2293 return nullptr;
2294 }
2295
2296 MOZ_ASSERT(cookieJarSettings)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cookieJarSettings)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(cookieJarSettings))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("cookieJarSettings"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cookieJarSettings"
")"); do { *((volatile int*)__null) = 2296; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2297 return cookieJarSettings.forget();
2298}
2299
2300bool ETPSaysShouldNotResistFingerprinting(nsIChannel* aChannel,
2301 nsILoadInfo* aLoadInfo) {
2302 // A positive return from this function should always be obeyed.
2303 // A negative return means we should keep checking things.
2304
2305 bool isPBM = NS_UsePrivateBrowsing(aChannel);
2306 // We do not want this check to apply to RFP, only to FPP
2307 // There is one problematic combination of prefs; however:
2308 // If RFP is enabled in PBMode only and FPP is enabled globally
2309 // (so, in non-PBM mode) - we need to know if we're in PBMode or not.
2310 // But that's kind of expensive and we'd like to avoid it if we
2311 // don't have to, so special-case that scenario
2312 if (StaticPrefs::privacy_fingerprintingProtection_DoNotUseDirectly() &&
2313 !StaticPrefs::privacy_resistFingerprinting_DoNotUseDirectly() &&
2314 StaticPrefs::privacy_resistFingerprinting_pbmode_DoNotUseDirectly()) {
2315 if (isPBM) {
2316 // In PBM (where RFP is enabled) do not exempt based on the ETP toggle
2317 return false;
2318 }
2319 } else if (StaticPrefs::privacy_resistFingerprinting_DoNotUseDirectly() ||
2320 (isPBM &&
2321 StaticPrefs::
2322 privacy_resistFingerprinting_pbmode_DoNotUseDirectly())) {
2323 // In RFP, never use the ETP toggle to exempt.
2324 // We can safely return false here even if we are not in PBM mode
2325 // and RFP_pbmode is enabled because we will later see that and
2326 // return false from the ShouldRFP function entirely.
2327 return false;
2328 }
2329
2330 nsCOMPtr<nsICookieJarSettings> cookieJarSettings =
2331 GetCookieJarSettings(aLoadInfo);
2332 if (!cookieJarSettings) {
2333 return false;
2334 }
2335
2336 return ContentBlockingAllowList::Check(cookieJarSettings);
2337}
2338
2339inline bool CookieJarSettingsSaysShouldResistFingerprinting(
2340 nsILoadInfo* aLoadInfo) {
2341 // A positive return from this function should always be obeyed.
2342 // A negative return means we should keep checking things.
2343
2344 nsCOMPtr<nsICookieJarSettings> cookieJarSettings =
2345 GetCookieJarSettings(aLoadInfo);
2346 if (!cookieJarSettings) {
2347 return false;
2348 }
2349 return cookieJarSettings->GetShouldResistFingerprinting();
2350}
2351
2352inline bool SchemeSaysShouldNotResistFingerprinting(nsIURI* aURI) {
2353 return aURI->SchemeIs("chrome") || aURI->SchemeIs("resource") ||
2354 aURI->SchemeIs("view-source") || aURI->SchemeIs("moz-extension") ||
2355 (aURI->SchemeIs("about") && !NS_IsContentAccessibleAboutURI(aURI));
2356}
2357
2358inline bool SchemeSaysShouldNotResistFingerprinting(nsIPrincipal* aPrincipal) {
2359 if (aPrincipal->SchemeIs("chrome") || aPrincipal->SchemeIs("resource") ||
2360 aPrincipal->SchemeIs("view-source") ||
2361 aPrincipal->SchemeIs("moz-extension")) {
2362 return true;
2363 }
2364
2365 if (!aPrincipal->SchemeIs("about")) {
2366 return false;
2367 }
2368
2369 bool isContentAccessibleAboutURI;
2370 Unused << aPrincipal->IsContentAccessibleAboutURI(
2371 &isContentAccessibleAboutURI);
2372 return !isContentAccessibleAboutURI;
2373}
2374
2375const char* kExemptedDomainsPrefName =
2376 "privacy.resistFingerprinting.exemptedDomains";
2377
2378inline bool PartionKeyIsAlsoExempted(
2379 const mozilla::OriginAttributes& aOriginAttributes) {
2380 // If we've gotten here we have (probably) passed the CookieJarSettings
2381 // check that would tell us that if we _are_ a subdocument, then we are on
2382 // an exempted top-level domain and we should see if we ourselves are
2383 // exempted. But we may have gotten here because we directly called the
2384 // _dangerous function and we haven't done that check, but we _were_
2385 // instatiated from a state where we could have been partitioned.
2386 // So perform this last-ditch check for that scenario.
2387 // We arbitrarily use https as the scheme, but it doesn't matter.
2388 nsresult rv = NS_ERROR_NOT_INITIALIZED;
2389 nsCOMPtr<nsIURI> uri;
2390 if (StaticPrefs::privacy_firstparty_isolate() &&
2391 !aOriginAttributes.mFirstPartyDomain.IsEmpty()) {
2392 rv = NS_NewURI(getter_AddRefs(uri),
2393 u"https://"_ns + aOriginAttributes.mFirstPartyDomain);
2394 } else if (!aOriginAttributes.mPartitionKey.IsEmpty()) {
2395 rv = NS_NewURI(getter_AddRefs(uri),
2396 u"https://"_ns + aOriginAttributes.mPartitionKey);
2397 }
2398
2399 if (!NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2400 bool isExemptPartitionKey =
2401 nsContentUtils::IsURIInPrefList(uri, kExemptedDomainsPrefName);
2402 if (MOZ_LOG_TEST(nsContentUtils::ResistFingerprintingLog(),(__builtin_expect(!!(mozilla::detail::log_test(nsContentUtils
::ResistFingerprintingLog(), mozilla::LogLevel::Debug)), 0))
2403 mozilla::LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(nsContentUtils
::ResistFingerprintingLog(), mozilla::LogLevel::Debug)), 0))
) {
2404 nsAutoCString url;
2405 uri->GetHost(url);
2406 LogDomainAndPrefList("Partition Key", kExemptedDomainsPrefName, url,
2407 isExemptPartitionKey);
2408 }
2409 return isExemptPartitionKey;
2410 }
2411 return true;
2412}
2413
2414// Functions ---------------------------------------------------
2415
2416/* static */
2417bool nsContentUtils::ShouldResistFingerprinting(const char* aJustification,
2418 RFPTarget aTarget) {
2419 // See comment in header file for information about usage
2420 // We hardcode PBM to true to be the more restrictive option.
2421 return nsContentUtils::ShouldResistFingerprinting(true, aTarget);
2422}
2423
2424namespace {
2425
2426// This function is only called within this file for Positive Return Checks
2427bool ShouldResistFingerprinting_(const char* aJustification,
2428 bool aIsPrivateMode, RFPTarget aTarget) {
2429 // See comment in header file for information about usage
2430 return nsContentUtils::ShouldResistFingerprinting(aIsPrivateMode, aTarget);
2431}
2432
2433} // namespace
2434
2435/* static */
2436bool nsContentUtils::ShouldResistFingerprinting(CallerType aCallerType,
2437 nsIGlobalObject* aGlobalObject,
2438 RFPTarget aTarget) {
2439 if (aCallerType == CallerType::System) {
2440 return false;
2441 }
2442 return ShouldResistFingerprinting(aGlobalObject, aTarget);
2443}
2444
2445bool nsContentUtils::ShouldResistFingerprinting(nsIDocShell* aDocShell,
2446 RFPTarget aTarget) {
2447 if (!aDocShell) {
2448 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Called nsContentUtils::ShouldResistFingerprinting(nsIDocShell*) "
"with NULL docshell"); } } while (0)
2449 ("Called nsContentUtils::ShouldResistFingerprinting(nsIDocShell*) "do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Called nsContentUtils::ShouldResistFingerprinting(nsIDocShell*) "
"with NULL docshell"); } } while (0)
2450 "with NULL docshell"))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Called nsContentUtils::ShouldResistFingerprinting(nsIDocShell*) "
"with NULL docshell"); } } while (0)
;
2451 return ShouldResistFingerprinting("Null Object", aTarget);
2452 }
2453 Document* doc = aDocShell->GetDocument();
2454 if (!doc) {
2455 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Called nsContentUtils::ShouldResistFingerprinting(nsIDocShell*) "
"with NULL doc"); } } while (0)
2456 ("Called nsContentUtils::ShouldResistFingerprinting(nsIDocShell*) "do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Called nsContentUtils::ShouldResistFingerprinting(nsIDocShell*) "
"with NULL doc"); } } while (0)
2457 "with NULL doc"))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Called nsContentUtils::ShouldResistFingerprinting(nsIDocShell*) "
"with NULL doc"); } } while (0)
;
2458 return ShouldResistFingerprinting("Null Object", aTarget);
2459 }
2460 return doc->ShouldResistFingerprinting(aTarget);
2461}
2462
2463/* static */
2464bool nsContentUtils::ShouldResistFingerprinting(nsIChannel* aChannel,
2465 RFPTarget aTarget) {
2466 if (!aChannel) {
2467 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Called nsContentUtils::ShouldResistFingerprinting(nsIChannel* "
"aChannel) with NULL channel"); } } while (0)
2468 ("Called nsContentUtils::ShouldResistFingerprinting(nsIChannel* "do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Called nsContentUtils::ShouldResistFingerprinting(nsIChannel* "
"aChannel) with NULL channel"); } } while (0)
2469 "aChannel) with NULL channel"))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Called nsContentUtils::ShouldResistFingerprinting(nsIChannel* "
"aChannel) with NULL channel"); } } while (0)
;
2470 return ShouldResistFingerprinting("Null Object", aTarget);
2471 }
2472
2473 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
2474 if (!loadInfo) {
2475 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Called nsContentUtils::ShouldResistFingerprinting(nsIChannel* "
"aChannel) but the channel's loadinfo was NULL"); } } while (
0)
2476 ("Called nsContentUtils::ShouldResistFingerprinting(nsIChannel* "do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Called nsContentUtils::ShouldResistFingerprinting(nsIChannel* "
"aChannel) but the channel's loadinfo was NULL"); } } while (
0)
2477 "aChannel) but the channel's loadinfo was NULL"))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Called nsContentUtils::ShouldResistFingerprinting(nsIChannel* "
"aChannel) but the channel's loadinfo was NULL"); } } while (
0)
;
2478 return ShouldResistFingerprinting("Null Object", aTarget);
2479 }
2480
2481 // With this check, we can ensure that the prefs and target say yes, so only
2482 // an exemption would cause us to return false.
2483 bool isPBM = NS_UsePrivateBrowsing(aChannel);
2484 if (!ShouldResistFingerprinting_("Positive return check", isPBM, aTarget)) {
2485 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIChannel*)" " Positive return check said false (PBM: %s)"
, isPBM ? "Yes" : "No"); } } while (0)
2486 ("Inside ShouldResistFingerprinting(nsIChannel*)"do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIChannel*)" " Positive return check said false (PBM: %s)"
, isPBM ? "Yes" : "No"); } } while (0)
2487 " Positive return check said false (PBM: %s)",do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIChannel*)" " Positive return check said false (PBM: %s)"
, isPBM ? "Yes" : "No"); } } while (0)
2488 isPBM ? "Yes" : "No"))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIChannel*)" " Positive return check said false (PBM: %s)"
, isPBM ? "Yes" : "No"); } } while (0)
;
2489 return false;
2490 }
2491
2492 if (ETPSaysShouldNotResistFingerprinting(aChannel, loadInfo)) {
2493 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIChannel*)" " ETPSaysShouldNotResistFingerprinting said false"
); } } while (0)
2494 ("Inside ShouldResistFingerprinting(nsIChannel*)"do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIChannel*)" " ETPSaysShouldNotResistFingerprinting said false"
); } } while (0)
2495 " ETPSaysShouldNotResistFingerprinting said false"))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIChannel*)" " ETPSaysShouldNotResistFingerprinting said false"
); } } while (0)
;
2496 return false;
2497 }
2498
2499 if (CookieJarSettingsSaysShouldResistFingerprinting(loadInfo)) {
2500 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIChannel*)" " CookieJarSettingsSaysShouldResistFingerprinting said true"
); } } while (0)
2501 ("Inside ShouldResistFingerprinting(nsIChannel*)"do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIChannel*)" " CookieJarSettingsSaysShouldResistFingerprinting said true"
); } } while (0)
2502 " CookieJarSettingsSaysShouldResistFingerprinting said true"))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIChannel*)" " CookieJarSettingsSaysShouldResistFingerprinting said true"
); } } while (0)
;
2503 return true;
2504 }
2505
2506 // Document types have no loading principal. Subdocument types do have a
2507 // loading principal, but it is the loading principal of the parent
2508 // document; not the subdocument.
2509 auto contentType = loadInfo->GetExternalContentPolicyType();
2510 // Case 1: Document or Subdocument load
2511 if (contentType == ExtContentPolicy::TYPE_DOCUMENT ||
2512 contentType == ExtContentPolicy::TYPE_SUBDOCUMENT) {
2513 nsCOMPtr<nsIURI> channelURI;
2514 nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
2515 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" " ("
"Failed to get URI in " "nsContentUtils::ShouldResistFingerprinting(nsIChannel* aChannel)"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2518); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
") (" "Failed to get URI in " "nsContentUtils::ShouldResistFingerprinting(nsIChannel* aChannel)"
")"); do { *((volatile int*)__null) = 2518; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2516 NS_SUCCEEDED(rv),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" " ("
"Failed to get URI in " "nsContentUtils::ShouldResistFingerprinting(nsIChannel* aChannel)"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2518); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
") (" "Failed to get URI in " "nsContentUtils::ShouldResistFingerprinting(nsIChannel* aChannel)"
")"); do { *((volatile int*)__null) = 2518; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2517 "Failed to get URI in "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" " ("
"Failed to get URI in " "nsContentUtils::ShouldResistFingerprinting(nsIChannel* aChannel)"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2518); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
") (" "Failed to get URI in " "nsContentUtils::ShouldResistFingerprinting(nsIChannel* aChannel)"
")"); do { *((volatile int*)__null) = 2518; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2518 "nsContentUtils::ShouldResistFingerprinting(nsIChannel* aChannel)")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" " ("
"Failed to get URI in " "nsContentUtils::ShouldResistFingerprinting(nsIChannel* aChannel)"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2518); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
") (" "Failed to get URI in " "nsContentUtils::ShouldResistFingerprinting(nsIChannel* aChannel)"
")"); do { *((volatile int*)__null) = 2518; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2519 // this check is to ensure that we do not crash in non-debug builds.
2520 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2521 return true;
2522 }
2523
2524#if 0
2525 if (loadInfo->GetExternalContentPolicyType() == ExtContentPolicy::TYPE_SUBDOCUMENT) {
2526 nsCOMPtr<nsIURI> channelURI;
2527 nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
2528 nsAutoCString channelSpec;
2529 channelURI->GetSpec(channelSpec);
2530
2531 if (!loadInfo->GetLoadingPrincipal()) {
2532 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Sub Document Type. FinalChannelURI is %s, Loading Principal is NULL\n"
, channelSpec.get()); } } while (0)
2533 ("Sub Document Type. FinalChannelURI is %s, Loading Principal is NULL\n",do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Sub Document Type. FinalChannelURI is %s, Loading Principal is NULL\n"
, channelSpec.get()); } } while (0)
2534 channelSpec.get()))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Sub Document Type. FinalChannelURI is %s, Loading Principal is NULL\n"
, channelSpec.get()); } } while (0)
;
2535
2536 } else {
2537 nsAutoCString loadingPrincipalSpec;
2538 loadInfo->GetLoadingPrincipal()->GetOrigin(loadingPrincipalSpec);
2539
2540 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Sub Document Type. FinalChannelURI is %s, Loading Principal Origin is %s\n"
, channelSpec.get(), loadingPrincipalSpec.get()); } } while (
0)
2541 ("Sub Document Type. FinalChannelURI is %s, Loading Principal Origin is %s\n",do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Sub Document Type. FinalChannelURI is %s, Loading Principal Origin is %s\n"
, channelSpec.get(), loadingPrincipalSpec.get()); } } while (
0)
2542 channelSpec.get(), loadingPrincipalSpec.get()))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Sub Document Type. FinalChannelURI is %s, Loading Principal Origin is %s\n"
, channelSpec.get(), loadingPrincipalSpec.get()); } } while (
0)
;
2543 }
2544 }
2545
2546#endif
2547
2548 return ShouldResistFingerprinting_dangerous(
2549 channelURI, loadInfo->GetOriginAttributes(), "Internal Call", aTarget);
2550 }
2551
2552 // Case 2: Subresource Load
2553 // Because this code is only used for subresource loads, this
2554 // will check the parent's principal
2555 nsIPrincipal* principal = loadInfo->GetLoadingPrincipal();
2556
2557 MOZ_ASSERT_IF(principal && !principal->IsSystemPrincipal() &&do { if (principal && !principal->IsSystemPrincipal
() && !principal->GetIsAddonOrExpandedAddonPrincipal
()) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(BasePrincipal::Cast(principal)->OriginAttributesRef
() == loadInfo->GetOriginAttributes())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(BasePrincipal::Cast(principal
)->OriginAttributesRef() == loadInfo->GetOriginAttributes
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("BasePrincipal::Cast(principal)->OriginAttributesRef() == loadInfo->GetOriginAttributes()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2560); AnnotateMozCrashReason("MOZ_ASSERT" "(" "BasePrincipal::Cast(principal)->OriginAttributesRef() == loadInfo->GetOriginAttributes()"
")"); do { *((volatile int*)__null) = 2560; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
2558 !principal->GetIsAddonOrExpandedAddonPrincipal(),do { if (principal && !principal->IsSystemPrincipal
() && !principal->GetIsAddonOrExpandedAddonPrincipal
()) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(BasePrincipal::Cast(principal)->OriginAttributesRef
() == loadInfo->GetOriginAttributes())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(BasePrincipal::Cast(principal
)->OriginAttributesRef() == loadInfo->GetOriginAttributes
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("BasePrincipal::Cast(principal)->OriginAttributesRef() == loadInfo->GetOriginAttributes()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2560); AnnotateMozCrashReason("MOZ_ASSERT" "(" "BasePrincipal::Cast(principal)->OriginAttributesRef() == loadInfo->GetOriginAttributes()"
")"); do { *((volatile int*)__null) = 2560; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
2559 BasePrincipal::Cast(principal)->OriginAttributesRef() ==do { if (principal && !principal->IsSystemPrincipal
() && !principal->GetIsAddonOrExpandedAddonPrincipal
()) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(BasePrincipal::Cast(principal)->OriginAttributesRef
() == loadInfo->GetOriginAttributes())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(BasePrincipal::Cast(principal
)->OriginAttributesRef() == loadInfo->GetOriginAttributes
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("BasePrincipal::Cast(principal)->OriginAttributesRef() == loadInfo->GetOriginAttributes()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2560); AnnotateMozCrashReason("MOZ_ASSERT" "(" "BasePrincipal::Cast(principal)->OriginAttributesRef() == loadInfo->GetOriginAttributes()"
")"); do { *((volatile int*)__null) = 2560; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
2560 loadInfo->GetOriginAttributes())do { if (principal && !principal->IsSystemPrincipal
() && !principal->GetIsAddonOrExpandedAddonPrincipal
()) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(BasePrincipal::Cast(principal)->OriginAttributesRef
() == loadInfo->GetOriginAttributes())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(BasePrincipal::Cast(principal
)->OriginAttributesRef() == loadInfo->GetOriginAttributes
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("BasePrincipal::Cast(principal)->OriginAttributesRef() == loadInfo->GetOriginAttributes()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2560); AnnotateMozCrashReason("MOZ_ASSERT" "(" "BasePrincipal::Cast(principal)->OriginAttributesRef() == loadInfo->GetOriginAttributes()"
")"); do { *((volatile int*)__null) = 2560; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2561 return ShouldResistFingerprinting_dangerous(principal, "Internal Call",
2562 aTarget);
2563}
2564
2565/* static */
2566bool nsContentUtils::ShouldResistFingerprinting_dangerous(
2567 nsIURI* aURI, const mozilla::OriginAttributes& aOriginAttributes,
2568 const char* aJustification, RFPTarget aTarget) {
2569 // With this check, we can ensure that the prefs and target say yes, so only
2570 // an exemption would cause us to return false.
2571 bool isPBM = aOriginAttributes.IsPrivateBrowsing();
2572 if (!ShouldResistFingerprinting_("Positive return check", isPBM, aTarget)) {
2573 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting_dangerous(nsIURI*," " OriginAttributes) Positive return check said false (PBM: %s)"
, isPBM ? "Yes" : "No"); } } while (0)
2574 ("Inside ShouldResistFingerprinting_dangerous(nsIURI*,"do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting_dangerous(nsIURI*," " OriginAttributes) Positive return check said false (PBM: %s)"
, isPBM ? "Yes" : "No"); } } while (0)
2575 " OriginAttributes) Positive return check said false (PBM: %s)",do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting_dangerous(nsIURI*," " OriginAttributes) Positive return check said false (PBM: %s)"
, isPBM ? "Yes" : "No"); } } while (0)
2576 isPBM ? "Yes" : "No"))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting_dangerous(nsIURI*," " OriginAttributes) Positive return check said false (PBM: %s)"
, isPBM ? "Yes" : "No"); } } while (0)
;
2577 return false;
2578 }
2579
2580 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting_dangerous(nsIURI*," " OriginAttributes) and the URI is %s"
, aURI->GetSpecOrDefault().get()); } } while (0)
2581 ("Inside ShouldResistFingerprinting_dangerous(nsIURI*,"do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting_dangerous(nsIURI*," " OriginAttributes) and the URI is %s"
, aURI->GetSpecOrDefault().get()); } } while (0)
2582 " OriginAttributes) and the URI is %s",do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting_dangerous(nsIURI*," " OriginAttributes) and the URI is %s"
, aURI->GetSpecOrDefault().get()); } } while (0)
2583 aURI->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting_dangerous(nsIURI*," " OriginAttributes) and the URI is %s"
, aURI->GetSpecOrDefault().get()); } } while (0)
;
2584
2585 if (!StaticPrefs::privacy_resistFingerprinting_DoNotUseDirectly() &&
2586 !StaticPrefs::privacy_fingerprintingProtection_DoNotUseDirectly()) {
2587 // If neither of the 'regular' RFP prefs are set, then one (or both)
2588 // of the PBM-Only prefs are set (or we would have failed the
2589 // Positive return check.) Therefore, if we are not in PBM, return false
2590 if (!aOriginAttributes.IsPrivateBrowsing()) {
2591 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting_dangerous(nsIURI*," " OriginAttributes) OA PBM Check said false"
); } } while (0)
2592 ("Inside ShouldResistFingerprinting_dangerous(nsIURI*,"do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting_dangerous(nsIURI*," " OriginAttributes) OA PBM Check said false"
); } } while (0)
2593 " OriginAttributes) OA PBM Check said false"))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting_dangerous(nsIURI*," " OriginAttributes) OA PBM Check said false"
); } } while (0)
;
2594 return false;
2595 }
2596 }
2597
2598 // Exclude internal schemes and web extensions
2599 if (SchemeSaysShouldNotResistFingerprinting(aURI)) {
2600 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIURI*)" " SchemeSaysShouldNotResistFingerprinting said false"
); } } while (0)
2601 ("Inside ShouldResistFingerprinting(nsIURI*)"do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIURI*)" " SchemeSaysShouldNotResistFingerprinting said false"
); } } while (0)
2602 " SchemeSaysShouldNotResistFingerprinting said false"))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIURI*)" " SchemeSaysShouldNotResistFingerprinting said false"
); } } while (0)
;
2603 return false;
2604 }
2605
2606 bool isExemptDomain = false;
2607 nsAutoCString list;
2608 Preferences::GetCString(kExemptedDomainsPrefName, list);
2609 ToLowerCase(list);
2610 isExemptDomain = IsURIInList(aURI, list);
2611
2612 if (MOZ_LOG_TEST(nsContentUtils::ResistFingerprintingLog(),(__builtin_expect(!!(mozilla::detail::log_test(nsContentUtils
::ResistFingerprintingLog(), mozilla::LogLevel::Debug)), 0))
2613 mozilla::LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(nsContentUtils
::ResistFingerprintingLog(), mozilla::LogLevel::Debug)), 0))
) {
2614 nsAutoCString url;
2615 aURI->GetHost(url);
2616 LogDomainAndPrefList("URI", kExemptedDomainsPrefName, url, isExemptDomain);
2617 }
2618
2619 if (isExemptDomain) {
2620 isExemptDomain &= PartionKeyIsAlsoExempted(aOriginAttributes);
2621 }
2622
2623 return !isExemptDomain;
2624}
2625
2626/* static */
2627bool nsContentUtils::ShouldResistFingerprinting_dangerous(
2628 nsIPrincipal* aPrincipal, const char* aJustification, RFPTarget aTarget) {
2629 if (!aPrincipal) {
2630 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Called nsContentUtils::ShouldResistFingerprinting(nsILoadInfo* "
"aChannel) but the loadinfo's loadingprincipal was NULL"); }
} while (0)
2631 ("Called nsContentUtils::ShouldResistFingerprinting(nsILoadInfo* "do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Called nsContentUtils::ShouldResistFingerprinting(nsILoadInfo* "
"aChannel) but the loadinfo's loadingprincipal was NULL"); }
} while (0)
2632 "aChannel) but the loadinfo's loadingprincipal was NULL"))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Info)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Info, "Called nsContentUtils::ShouldResistFingerprinting(nsILoadInfo* "
"aChannel) but the loadinfo's loadingprincipal was NULL"); }
} while (0)
;
2633 return ShouldResistFingerprinting("Null object", aTarget);
2634 }
2635
2636 auto originAttributes =
2637 BasePrincipal::Cast(aPrincipal)->OriginAttributesRef();
2638 // With this check, we can ensure that the prefs and target say yes, so only
2639 // an exemption would cause us to return false.
2640 bool isPBM = originAttributes.IsPrivateBrowsing();
2641 if (!ShouldResistFingerprinting_("Positive return check", isPBM, aTarget)) {
2642 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIPrincipal*) Positive return "
"check said false (PBM: %s)", isPBM ? "Yes" : "No"); } } while
(0)
2643 ("Inside ShouldResistFingerprinting(nsIPrincipal*) Positive return "do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIPrincipal*) Positive return "
"check said false (PBM: %s)", isPBM ? "Yes" : "No"); } } while
(0)
2644 "check said false (PBM: %s)",do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIPrincipal*) Positive return "
"check said false (PBM: %s)", isPBM ? "Yes" : "No"); } } while
(0)
2645 isPBM ? "Yes" : "No"))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIPrincipal*) Positive return "
"check said false (PBM: %s)", isPBM ? "Yes" : "No"); } } while
(0)
;
2646 return false;
2647 }
2648
2649 if (aPrincipal->IsSystemPrincipal()) {
2650 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIPrincipal*) System " "Principal said false"
); } } while (0)
2651 ("Inside ShouldResistFingerprinting(nsIPrincipal*) System "do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIPrincipal*) System " "Principal said false"
); } } while (0)
2652 "Principal said false"))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIPrincipal*) System " "Principal said false"
); } } while (0)
;
2653 return false;
2654 }
2655
2656 // Exclude internal schemes and web extensions
2657 if (SchemeSaysShouldNotResistFingerprinting(aPrincipal)) {
2658 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIPrincipal*)" " SchemeSaysShouldNotResistFingerprinting said false"
); } } while (0)
2659 ("Inside ShouldResistFingerprinting(nsIPrincipal*)"do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIPrincipal*)" " SchemeSaysShouldNotResistFingerprinting said false"
); } } while (0)
2660 " SchemeSaysShouldNotResistFingerprinting said false"))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIPrincipal*)" " SchemeSaysShouldNotResistFingerprinting said false"
); } } while (0)
;
2661 return false;
2662 }
2663
2664 // Web extension principals are also excluded
2665 if (BasePrincipal::Cast(aPrincipal)->AddonPolicy()) {
2666 MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIPrincipal*)" " and AddonPolicy said false"
); } } while (0)
2667 ("Inside ShouldResistFingerprinting(nsIPrincipal*)"do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIPrincipal*)" " and AddonPolicy said false"
); } } while (0)
2668 " and AddonPolicy said false"))do { const ::mozilla::LogModule* moz_real_module = nsContentUtils
::ResistFingerprintingLog(); if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, LogLevel::Debug)), 0))) {
mozilla::detail::log_print(moz_real_module, LogLevel::Debug,
"Inside ShouldResistFingerprinting(nsIPrincipal*)" " and AddonPolicy said false"
); } } while (0)
;
2669 return false;
2670 }
2671
2672 bool isExemptDomain = false;
2673 aPrincipal->IsURIInPrefList(kExemptedDomainsPrefName, &isExemptDomain);
2674
2675 if (MOZ_LOG_TEST(nsContentUtils::ResistFingerprintingLog(),(__builtin_expect(!!(mozilla::detail::log_test(nsContentUtils
::ResistFingerprintingLog(), mozilla::LogLevel::Debug)), 0))
2676 mozilla::LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(nsContentUtils
::ResistFingerprintingLog(), mozilla::LogLevel::Debug)), 0))
) {
2677 nsAutoCString origin;
2678 aPrincipal->GetOrigin(origin);
2679 LogDomainAndPrefList("URI", kExemptedDomainsPrefName, origin,
2680 isExemptDomain);
2681 }
2682
2683 if (isExemptDomain) {
2684 isExemptDomain &= PartionKeyIsAlsoExempted(originAttributes);
2685 }
2686
2687 return !isExemptDomain;
2688}
2689
2690// --------------------------------------------------------------------
2691
2692/* static */
2693void nsContentUtils::CalcRoundedWindowSizeForResistingFingerprinting(
2694 int32_t aChromeWidth, int32_t aChromeHeight, int32_t aScreenWidth,
2695 int32_t aScreenHeight, int32_t aInputWidth, int32_t aInputHeight,
2696 bool aSetOuterWidth, bool aSetOuterHeight, int32_t* aOutputWidth,
2697 int32_t* aOutputHeight) {
2698 MOZ_ASSERT(aOutputWidth)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOutputWidth)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aOutputWidth))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aOutputWidth", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2698); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOutputWidth"
")"); do { *((volatile int*)__null) = 2698; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2699 MOZ_ASSERT(aOutputHeight)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOutputHeight)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aOutputHeight))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aOutputHeight",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2699); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOutputHeight"
")"); do { *((volatile int*)__null) = 2699; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2700
2701 int32_t availContentWidth = 0;
2702 int32_t availContentHeight = 0;
2703
2704 availContentWidth = std::min(StaticPrefs::privacy_window_maxInnerWidth(),
2705 aScreenWidth - aChromeWidth);
2706#ifdef MOZ_WIDGET_GTK1
2707 // In the GTK window, it will not report outside system decorations
2708 // when we get available window size, see Bug 581863. So, we leave a
2709 // 40 pixels space for them when calculating the available content
2710 // height. It is not necessary for the width since the content width
2711 // is usually pretty much the same as the chrome width.
2712 availContentHeight = std::min(StaticPrefs::privacy_window_maxInnerHeight(),
2713 (-40 + aScreenHeight) - aChromeHeight);
2714#else
2715 availContentHeight = std::min(StaticPrefs::privacy_window_maxInnerHeight(),
2716 aScreenHeight - aChromeHeight);
2717#endif
2718
2719 // Ideally, we'd like to round window size to 1000x1000, but the
2720 // screen space could be too small to accommodate this size in some
2721 // cases. If it happens, we would round the window size to the nearest
2722 // 200x100.
2723 availContentWidth = availContentWidth - (availContentWidth % 200);
2724 availContentHeight = availContentHeight - (availContentHeight % 100);
2725
2726 // If aIsOuter is true, we are setting the outer window. So we
2727 // have to consider the chrome UI.
2728 int32_t chromeOffsetWidth = aSetOuterWidth ? aChromeWidth : 0;
2729 int32_t chromeOffsetHeight = aSetOuterHeight ? aChromeHeight : 0;
2730 int32_t resultWidth = 0, resultHeight = 0;
2731
2732 // if the original size is greater than the maximum available size, we set
2733 // it to the maximum size. And if the original value is less than the
2734 // minimum rounded size, we set it to the minimum 200x100.
2735 if (aInputWidth > (availContentWidth + chromeOffsetWidth)) {
2736 resultWidth = availContentWidth + chromeOffsetWidth;
2737 } else if (aInputWidth < (200 + chromeOffsetWidth)) {
2738 resultWidth = 200 + chromeOffsetWidth;
2739 } else {
2740 // Otherwise, we round the window to the nearest upper rounded 200x100.
2741 resultWidth = NSToIntCeil((aInputWidth - chromeOffsetWidth) / 200.0) * 200 +
2742 chromeOffsetWidth;
2743 }
2744
2745 if (aInputHeight > (availContentHeight + chromeOffsetHeight)) {
2746 resultHeight = availContentHeight + chromeOffsetHeight;
2747 } else if (aInputHeight < (100 + chromeOffsetHeight)) {
2748 resultHeight = 100 + chromeOffsetHeight;
2749 } else {
2750 resultHeight =
2751 NSToIntCeil((aInputHeight - chromeOffsetHeight) / 100.0) * 100 +
2752 chromeOffsetHeight;
2753 }
2754
2755 *aOutputWidth = resultWidth;
2756 *aOutputHeight = resultHeight;
2757}
2758
2759bool nsContentUtils::ThreadsafeIsCallerChrome() {
2760 return NS_IsMainThread() ? IsCallerChrome()
2761 : IsCurrentThreadRunningChromeWorker();
2762}
2763
2764bool nsContentUtils::IsCallerUAWidget() {
2765 JSContext* cx = GetCurrentJSContext();
2766 if (!cx) {
2767 return false;
2768 }
2769
2770 JS::Realm* realm = JS::GetCurrentRealmOrNull(cx);
2771 if (!realm) {
2772 return false;
2773 }
2774
2775 return xpc::IsUAWidgetScope(realm);
2776}
2777
2778bool nsContentUtils::IsSystemCaller(JSContext* aCx) {
2779 // Note that SubjectPrincipal() assumes we are in a compartment here.
2780 return SubjectPrincipal(aCx) == sSystemPrincipal;
2781}
2782
2783bool nsContentUtils::ThreadsafeIsSystemCaller(JSContext* aCx) {
2784 CycleCollectedJSContext* ccjscx = CycleCollectedJSContext::Get();
2785 MOZ_ASSERT(ccjscx->Context() == aCx)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ccjscx->Context() == aCx)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ccjscx->Context() == aCx)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("ccjscx->Context() == aCx"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2785); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ccjscx->Context() == aCx"
")"); do { *((volatile int*)__null) = 2785; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2786
2787 return ccjscx->IsSystemCaller();
2788}
2789
2790// static
2791bool nsContentUtils::LookupBindingMember(
2792 JSContext* aCx, nsIContent* aContent, JS::Handle<jsid> aId,
2793 JS::MutableHandle<JS::PropertyDescriptor> aDesc) {
2794 return true;
2795}
2796
2797nsINode* nsContentUtils::GetNearestInProcessCrossDocParentNode(
2798 nsINode* aChild) {
2799 if (aChild->IsDocument()) {
2800 for (BrowsingContext* bc = aChild->AsDocument()->GetBrowsingContext(); bc;
2801 bc = bc->GetParent()) {
2802 if (bc->GetEmbedderElement()) {
2803 return bc->GetEmbedderElement();
2804 }
2805 }
2806 return nullptr;
2807 }
2808
2809 nsINode* parent = aChild->GetParentNode();
2810 if (parent && parent->IsContent() && aChild->IsContent()) {
2811 parent = aChild->AsContent()->GetFlattenedTreeParent();
2812 }
2813
2814 return parent;
2815}
2816
2817bool nsContentUtils::ContentIsHostIncludingDescendantOf(
2818 const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor) {
2819 MOZ_ASSERT(aPossibleDescendant, "The possible descendant is null!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPossibleDescendant)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPossibleDescendant))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("aPossibleDescendant"
" (" "The possible descendant is null!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2819); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPossibleDescendant"
") (" "The possible descendant is null!" ")"); do { *((volatile
int*)__null) = 2819; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2820 MOZ_ASSERT(aPossibleAncestor, "The possible ancestor is null!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPossibleAncestor)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPossibleAncestor))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aPossibleAncestor"
" (" "The possible ancestor is null!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2820); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPossibleAncestor"
") (" "The possible ancestor is null!" ")"); do { *((volatile
int*)__null) = 2820; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2821
2822 do {
2823 if (aPossibleDescendant == aPossibleAncestor) return true;
2824 if (aPossibleDescendant->IsDocumentFragment()) {
2825 aPossibleDescendant =
2826 aPossibleDescendant->AsDocumentFragment()->GetHost();
2827 } else {
2828 aPossibleDescendant = aPossibleDescendant->GetParentNode();
2829 }
2830 } while (aPossibleDescendant);
2831
2832 return false;
2833}
2834
2835// static
2836bool nsContentUtils::ContentIsCrossDocDescendantOf(nsINode* aPossibleDescendant,
2837 nsINode* aPossibleAncestor) {
2838 MOZ_ASSERT(aPossibleDescendant, "The possible descendant is null!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPossibleDescendant)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPossibleDescendant))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("aPossibleDescendant"
" (" "The possible descendant is null!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2838); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPossibleDescendant"
") (" "The possible descendant is null!" ")"); do { *((volatile
int*)__null) = 2838; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2839 MOZ_ASSERT(aPossibleAncestor, "The possible ancestor is null!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPossibleAncestor)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPossibleAncestor))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aPossibleAncestor"
" (" "The possible ancestor is null!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2839); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPossibleAncestor"
") (" "The possible ancestor is null!" ")"); do { *((volatile
int*)__null) = 2839; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2840
2841 do {
2842 if (aPossibleDescendant == aPossibleAncestor) {
2843 return true;
2844 }
2845
2846 aPossibleDescendant =
2847 GetNearestInProcessCrossDocParentNode(aPossibleDescendant);
2848 } while (aPossibleDescendant);
2849
2850 return false;
2851}
2852
2853// static
2854bool nsContentUtils::ContentIsFlattenedTreeDescendantOf(
2855 const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor) {
2856 MOZ_ASSERT(aPossibleDescendant, "The possible descendant is null!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPossibleDescendant)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPossibleDescendant))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("aPossibleDescendant"
" (" "The possible descendant is null!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2856); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPossibleDescendant"
") (" "The possible descendant is null!" ")"); do { *((volatile
int*)__null) = 2856; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2857 MOZ_ASSERT(aPossibleAncestor, "The possible ancestor is null!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPossibleAncestor)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPossibleAncestor))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aPossibleAncestor"
" (" "The possible ancestor is null!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2857); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPossibleAncestor"
") (" "The possible ancestor is null!" ")"); do { *((volatile
int*)__null) = 2857; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2858
2859 do {
2860 if (aPossibleDescendant == aPossibleAncestor) {
2861 return true;
2862 }
2863 aPossibleDescendant = aPossibleDescendant->GetFlattenedTreeParentNode();
2864 } while (aPossibleDescendant);
2865
2866 return false;
2867}
2868
2869// static
2870bool nsContentUtils::ContentIsFlattenedTreeDescendantOfForStyle(
2871 const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor) {
2872 MOZ_ASSERT(aPossibleDescendant, "The possible descendant is null!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPossibleDescendant)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPossibleDescendant))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("aPossibleDescendant"
" (" "The possible descendant is null!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2872); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPossibleDescendant"
") (" "The possible descendant is null!" ")"); do { *((volatile
int*)__null) = 2872; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2873 MOZ_ASSERT(aPossibleAncestor, "The possible ancestor is null!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPossibleAncestor)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPossibleAncestor))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aPossibleAncestor"
" (" "The possible ancestor is null!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2873); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPossibleAncestor"
") (" "The possible ancestor is null!" ")"); do { *((volatile
int*)__null) = 2873; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2874
2875 do {
2876 if (aPossibleDescendant == aPossibleAncestor) {
2877 return true;
2878 }
2879 aPossibleDescendant =
2880 aPossibleDescendant->GetFlattenedTreeParentNodeForStyle();
2881 } while (aPossibleDescendant);
2882
2883 return false;
2884}
2885
2886// static
2887nsINode* nsContentUtils::Retarget(nsINode* aTargetA, nsINode* aTargetB) {
2888 while (true && aTargetA) {
2889 // If A's root is not a shadow root...
2890 nsINode* root = aTargetA->SubtreeRoot();
2891 if (!root->IsShadowRoot()) {
2892 // ...then return A.
2893 return aTargetA;
2894 }
2895
2896 // or A's root is a shadow-including inclusive ancestor of B...
2897 if (aTargetB->IsShadowIncludingInclusiveDescendantOf(root)) {
2898 // ...then return A.
2899 return aTargetA;
2900 }
2901
2902 aTargetA = ShadowRoot::FromNode(root)->GetHost();
2903 }
2904
2905 return nullptr;
2906}
2907
2908// static
2909Element* nsContentUtils::GetAnElementForTiming(Element* aTarget,
2910 const Document* aDocument,
2911 nsIGlobalObject* aGlobal) {
2912 if (!aTarget->IsInComposedDoc()) {
2913 return nullptr;
2914 }
2915
2916 if (!aDocument) {
2917 nsCOMPtr<nsPIDOMWindowInner> inner = do_QueryInterface(aGlobal);
2918 if (!inner) {
2919 return nullptr;
2920 }
2921 aDocument = inner->GetExtantDoc();
2922 }
2923
2924 MOZ_ASSERT(aDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDocument))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2924); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocument" ")"
); do { *((volatile int*)__null) = 2924; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2925
2926 if (aTarget->GetUncomposedDocOrConnectedShadowRoot() != aDocument ||
2927 !aDocument->IsCurrentActiveDocument()) {
2928 return nullptr;
2929 }
2930
2931 return aTarget;
2932}
2933
2934// static
2935nsresult nsContentUtils::GetInclusiveAncestors(nsINode* aNode,
2936 nsTArray<nsINode*>& aArray) {
2937 while (aNode) {
2938 aArray.AppendElement(aNode);
2939 aNode = aNode->GetParentNode();
2940 }
2941 return NS_OK;
2942}
2943
2944// static
2945template <typename GetParentFunc>
2946nsresult static GetInclusiveAncestorsAndOffsetsHelper(
2947 nsINode* aNode, uint32_t aOffset, nsTArray<nsIContent*>& aAncestorNodes,
2948 nsTArray<Maybe<uint32_t>>& aAncestorOffsets, GetParentFunc aGetParentFunc) {
2949 NS_ENSURE_ARG_POINTER(aNode)do { if ((__builtin_expect(!!(!(aNode)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aNode" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2949); return NS_ERROR_INVALID_POINTER; } } while (false)
;
2950
2951 if (!aNode->IsContent()) {
2952 return NS_ERROR_FAILURE;
2953 }
2954 nsIContent* content = aNode->AsContent();
2955
2956 if (!aAncestorNodes.IsEmpty()) {
2957 NS_WARNING("aAncestorNodes is not empty")NS_DebugBreak(NS_DEBUG_WARNING, "aAncestorNodes is not empty"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2957)
;
2958 aAncestorNodes.Clear();
2959 }
2960
2961 if (!aAncestorOffsets.IsEmpty()) {
2962 NS_WARNING("aAncestorOffsets is not empty")NS_DebugBreak(NS_DEBUG_WARNING, "aAncestorOffsets is not empty"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 2962)
;
2963 aAncestorOffsets.Clear();
2964 }
2965
2966 // insert the node itself
2967 aAncestorNodes.AppendElement(content);
2968 aAncestorOffsets.AppendElement(Some(aOffset));
2969
2970 // insert all the ancestors
2971 nsIContent* child = content;
2972 nsIContent* parent = aGetParentFunc(child);
2973 while (parent) {
2974 aAncestorNodes.AppendElement(parent->AsContent());
2975 aAncestorOffsets.AppendElement(parent->ComputeIndexOf(child));
2976 child = parent;
2977 parent = aGetParentFunc(child);
2978 }
2979
2980 return NS_OK;
2981}
2982
2983nsresult nsContentUtils::GetInclusiveAncestorsAndOffsets(
2984 nsINode* aNode, uint32_t aOffset, nsTArray<nsIContent*>& aAncestorNodes,
2985 nsTArray<Maybe<uint32_t>>& aAncestorOffsets) {
2986 return GetInclusiveAncestorsAndOffsetsHelper(
2987 aNode, aOffset, aAncestorNodes, aAncestorOffsets,
2988 [](nsIContent* aContent) { return aContent->GetParent(); });
2989}
2990
2991nsresult nsContentUtils::GetShadowIncludingAncestorsAndOffsets(
2992 nsINode* aNode, uint32_t aOffset, nsTArray<nsIContent*>& aAncestorNodes,
2993 nsTArray<Maybe<uint32_t>>& aAncestorOffsets) {
2994 return GetInclusiveAncestorsAndOffsetsHelper(
2995 aNode, aOffset, aAncestorNodes, aAncestorOffsets,
2996 [](nsIContent* aContent) -> nsIContent* {
2997 return nsIContent::FromNodeOrNull(
2998 aContent->GetParentOrShadowHostNode());
2999 });
3000}
3001
3002template <typename Node, typename GetParentFunc>
3003static Node* GetCommonAncestorInternal(Node* aNode1, Node* aNode2,
3004 GetParentFunc aGetParentFunc) {
3005 MOZ_ASSERT(aNode1 != aNode2)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNode1 != aNode2)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNode1 != aNode2))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aNode1 != aNode2"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3005); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNode1 != aNode2"
")"); do { *((volatile int*)__null) = 3005; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3006
3007 // Build the chain of parents
3008 AutoTArray<Node*, 30> parents1, parents2;
3009 do {
3010 parents1.AppendElement(aNode1);
3011 aNode1 = aGetParentFunc(aNode1);
3012 } while (aNode1);
3013 do {
3014 parents2.AppendElement(aNode2);
3015 aNode2 = aGetParentFunc(aNode2);
3016 } while (aNode2);
3017
3018 // Find where the parent chain differs
3019 uint32_t pos1 = parents1.Length();
3020 uint32_t pos2 = parents2.Length();
3021 Node** data1 = parents1.Elements();
3022 Node** data2 = parents2.Elements();
3023 Node* parent = nullptr;
3024 uint32_t len;
3025 for (len = std::min(pos1, pos2); len > 0; --len) {
3026 Node* child1 = data1[--pos1];
3027 Node* child2 = data2[--pos2];
3028 if (child1 != child2) {
3029 break;
3030 }
3031 parent = child1;
3032 }
3033
3034 return parent;
3035}
3036
3037/* static */
3038nsINode* nsContentUtils::GetCommonAncestorHelper(nsINode* aNode1,
3039 nsINode* aNode2) {
3040 return GetCommonAncestorInternal(
3041 aNode1, aNode2, [](nsINode* aNode) { return aNode->GetParentNode(); });
3042}
3043
3044/* static */
3045nsINode* nsContentUtils::GetClosestCommonShadowIncludingInclusiveAncestor(
3046 nsINode* aNode1, nsINode* aNode2) {
3047 if (aNode1 == aNode2) {
3048 return aNode1;
3049 }
3050
3051 return GetCommonAncestorInternal(aNode1, aNode2, [](nsINode* aNode) {
3052 return aNode->GetParentOrShadowHostNode();
3053 });
3054}
3055
3056/* static */
3057nsIContent* nsContentUtils::GetCommonFlattenedTreeAncestorHelper(
3058 nsIContent* aContent1, nsIContent* aContent2) {
3059 return GetCommonAncestorInternal(
3060 aContent1, aContent2,
3061 [](nsIContent* aContent) { return aContent->GetFlattenedTreeParent(); });
3062}
3063
3064/* static */
3065nsIContent* nsContentUtils::GetCommonFlattenedTreeAncestorForSelection(
3066 nsIContent* aContent1, nsIContent* aContent2) {
3067 if (aContent1 == aContent2) {
3068 return aContent1;
3069 }
3070
3071 return GetCommonAncestorInternal(
3072 aContent1, aContent2, [](nsIContent* aContent) {
3073 return aContent->GetFlattenedTreeParentNodeForSelection();
3074 });
3075}
3076
3077/* static */
3078Element* nsContentUtils::GetCommonFlattenedTreeAncestorForStyle(
3079 Element* aElement1, Element* aElement2) {
3080 return GetCommonAncestorInternal(aElement1, aElement2, [](Element* aElement) {
3081 return aElement->GetFlattenedTreeParentElementForStyle();
3082 });
3083}
3084
3085/* static */
3086bool nsContentUtils::PositionIsBefore(nsINode* aNode1, nsINode* aNode2,
3087 Maybe<uint32_t>* aNode1Index,
3088 Maybe<uint32_t>* aNode2Index) {
3089 // Note, CompareDocumentPosition takes the latter params in different order.
3090 return (aNode2->CompareDocumentPosition(*aNode1, aNode2Index, aNode1Index) &
3091 (Node_Binding::DOCUMENT_POSITION_PRECEDING |
3092 Node_Binding::DOCUMENT_POSITION_DISCONNECTED)) ==
3093 Node_Binding::DOCUMENT_POSITION_PRECEDING;
3094}
3095
3096/* static */
3097Maybe<int32_t> nsContentUtils::ComparePoints(const nsINode* aParent1,
3098 uint32_t aOffset1,
3099 const nsINode* aParent2,
3100 uint32_t aOffset2,
3101 NodeIndexCache* aIndexCache) {
3102 bool disconnected{false};
3103
3104 const int32_t order = ComparePoints_Deprecated(
3105 aParent1, aOffset1, aParent2, aOffset2, &disconnected, aIndexCache);
3106 if (disconnected) {
3107 return Nothing();
3108 }
3109
3110 return Some(order);
3111}
3112
3113/* static */
3114int32_t nsContentUtils::ComparePoints_Deprecated(
3115 const nsINode* aParent1, uint32_t aOffset1, const nsINode* aParent2,
3116 uint32_t aOffset2, bool* aDisconnected, NodeIndexCache* aIndexCache) {
3117 if (aParent1 == aParent2) {
3118 return aOffset1 < aOffset2 ? -1 : aOffset1 > aOffset2 ? 1 : 0;
3119 }
3120
3121 AutoTArray<const nsINode*, 32> parents1, parents2;
3122 const nsINode* node1 = aParent1;
3123 const nsINode* node2 = aParent2;
3124 do {
3125 parents1.AppendElement(node1);
3126 node1 = node1->GetParentOrShadowHostNode();
3127 } while (node1);
3128 do {
3129 parents2.AppendElement(node2);
3130 node2 = node2->GetParentOrShadowHostNode();
3131 } while (node2);
3132
3133 uint32_t pos1 = parents1.Length() - 1;
3134 uint32_t pos2 = parents2.Length() - 1;
3135
3136 bool disconnected = parents1.ElementAt(pos1) != parents2.ElementAt(pos2);
3137 if (aDisconnected) {
3138 *aDisconnected = disconnected;
3139 }
3140 if (disconnected) {
3141 NS_ASSERTION(aDisconnected, "unexpected disconnected nodes")do { if (!(aDisconnected)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "unexpected disconnected nodes", "aDisconnected", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3141); MOZ_PretendNoReturn(); } } while (0)
;
3142 return 1;
3143 }
3144
3145 // Find where the parent chains differ
3146 const nsINode* parent = parents1.ElementAt(pos1);
3147 uint32_t len;
3148 for (len = std::min(pos1, pos2); len > 0; --len) {
3149 const nsINode* child1 = parents1.ElementAt(--pos1);
3150 const nsINode* child2 = parents2.ElementAt(--pos2);
3151 if (child1 != child2) {
3152 if (MOZ_UNLIKELY(child1->IsShadowRoot())(__builtin_expect(!!(child1->IsShadowRoot()), 0))) {
3153 // Shadow roots come before light DOM per
3154 // https://dom.spec.whatwg.org/#concept-shadow-including-tree-order
3155 MOZ_ASSERT(!child2->IsShadowRoot(), "Two shadow roots?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!child2->IsShadowRoot())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!child2->IsShadowRoot()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!child2->IsShadowRoot()"
" (" "Two shadow roots?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3155); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!child2->IsShadowRoot()"
") (" "Two shadow roots?" ")"); do { *((volatile int*)__null
) = 3155; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
3156 return -1;
3157 }
3158 if (MOZ_UNLIKELY(child2->IsShadowRoot())(__builtin_expect(!!(child2->IsShadowRoot()), 0))) {
3159 return 1;
3160 }
3161 Maybe<uint32_t> child1Index;
3162 Maybe<uint32_t> child2Index;
3163 if (aIndexCache) {
3164 aIndexCache->ComputeIndicesOf(parent, child1, child2, child1Index,
3165 child2Index);
3166 } else {
3167 child1Index = parent->ComputeIndexOf(child1);
3168 child2Index = parent->ComputeIndexOf(child2);
3169 }
3170 if (MOZ_LIKELY(child1Index.isSome() && child2Index.isSome())(__builtin_expect(!!(child1Index.isSome() && child2Index
.isSome()), 1))
) {
3171 return *child1Index < *child2Index ? -1 : 1;
3172 }
3173 // XXX Keep the odd traditional behavior for now.
3174 return child1Index.isNothing() && child2Index.isSome() ? -1 : 1;
3175 }
3176 parent = child1;
3177 }
3178
3179 // The parent chains never differed, so one of the nodes is an ancestor of
3180 // the other
3181
3182 NS_ASSERTION(!pos1 || !pos2,do { if (!(!pos1 || !pos2)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "should have run out of parent chain for one of the nodes",
"!pos1 || !pos2", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3183); MOZ_PretendNoReturn(); } } while (0)
3183 "should have run out of parent chain for one of the nodes")do { if (!(!pos1 || !pos2)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "should have run out of parent chain for one of the nodes",
"!pos1 || !pos2", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3183); MOZ_PretendNoReturn(); } } while (0)
;
3184
3185 if (!pos1) {
3186 const nsINode* child2 = parents2.ElementAt(--pos2);
3187 const Maybe<uint32_t> child2Index =
3188 aIndexCache ? aIndexCache->ComputeIndexOf(parent, child2)
3189 : parent->ComputeIndexOf(child2);
3190 if (MOZ_UNLIKELY(NS_WARN_IF(child2Index.isNothing()))(__builtin_expect(!!(NS_warn_if_impl(child2Index.isNothing(),
"child2Index.isNothing()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3190)), 0))
) {
3191 return 1;
3192 }
3193 return aOffset1 <= *child2Index ? -1 : 1;
3194 }
3195
3196 const nsINode* child1 = parents1.ElementAt(--pos1);
3197 const Maybe<uint32_t> child1Index =
3198 aIndexCache ? aIndexCache->ComputeIndexOf(parent, child1)
3199 : parent->ComputeIndexOf(child1);
3200 if (MOZ_UNLIKELY(NS_WARN_IF(child1Index.isNothing()))(__builtin_expect(!!(NS_warn_if_impl(child1Index.isNothing(),
"child1Index.isNothing()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3200)), 0))
) {
3201 return -1;
3202 }
3203 return *child1Index < aOffset2 ? -1 : 1;
3204}
3205
3206/* static */
3207BrowserParent* nsContentUtils::GetCommonBrowserParentAncestor(
3208 BrowserParent* aBrowserParent1, BrowserParent* aBrowserParent2) {
3209 return GetCommonAncestorInternal(
3210 aBrowserParent1, aBrowserParent2, [](BrowserParent* aBrowserParent) {
3211 return aBrowserParent->GetBrowserBridgeParent()
3212 ? aBrowserParent->GetBrowserBridgeParent()->Manager()
3213 : nullptr;
3214 });
3215}
3216
3217/* static */
3218Element* nsContentUtils::GetTargetElement(Document* aDocument,
3219 const nsAString& aAnchorName) {
3220 MOZ_ASSERT(aDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDocument))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocument" ")"
); do { *((volatile int*)__null) = 3220; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3221
3222 if (aAnchorName.IsEmpty()) {
3223 return nullptr;
3224 }
3225 // 1. If there is an element in the document tree that has an ID equal to
3226 // fragment, then return the first such element in tree order.
3227 if (Element* el = aDocument->GetElementById(aAnchorName)) {
3228 return el;
3229 }
3230
3231 // 2. If there is an a element in the document tree that has a name
3232 // attribute whose value is equal to fragment, then return the first such
3233 // element in tree order.
3234 //
3235 // FIXME(emilio): Why the different code-paths for HTML and non-HTML docs?
3236 if (aDocument->IsHTMLDocument()) {
3237 nsCOMPtr<nsINodeList> list = aDocument->GetElementsByName(aAnchorName);
3238 // Loop through the named nodes looking for the first anchor
3239 uint32_t length = list->Length();
3240 for (uint32_t i = 0; i < length; i++) {
3241 nsIContent* node = list->Item(i);
3242 if (node->IsHTMLElement(nsGkAtoms::a)) {
3243 return node->AsElement();
3244 }
3245 }
3246 } else {
3247 constexpr auto nameSpace = u"http://www.w3.org/1999/xhtml"_ns;
3248 // Get the list of anchor elements
3249 nsCOMPtr<nsINodeList> list =
3250 aDocument->GetElementsByTagNameNS(nameSpace, u"a"_ns);
3251 // Loop through the anchors looking for the first one with the given name.
3252 for (uint32_t i = 0; true; i++) {
3253 nsIContent* node = list->Item(i);
3254 if (!node) { // End of list
3255 break;
3256 }
3257
3258 // Compare the name attribute
3259 if (node->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
3260 aAnchorName, eCaseMatters)) {
3261 return node->AsElement();
3262 }
3263 }
3264 }
3265
3266 // 3. Return null.
3267 return nullptr;
3268}
3269
3270/* static */
3271template <typename FPT, typename FRT, typename SPT, typename SRT>
3272Maybe<int32_t> nsContentUtils::ComparePoints(
3273 const RangeBoundaryBase<FPT, FRT>& aFirstBoundary,
3274 const RangeBoundaryBase<SPT, SRT>& aSecondBoundary) {
3275 if (!aFirstBoundary.IsSet() || !aSecondBoundary.IsSet()) {
3276 return Nothing{};
3277 }
3278
3279 bool disconnected{false};
3280 const int32_t order =
3281 ComparePoints_Deprecated(aFirstBoundary, aSecondBoundary, &disconnected);
3282
3283 if (disconnected) {
3284 return Nothing{};
3285 }
3286
3287 return Some(order);
3288}
3289
3290/* static */
3291template <typename FPT, typename FRT, typename SPT, typename SRT>
3292int32_t nsContentUtils::ComparePoints_Deprecated(
3293 const RangeBoundaryBase<FPT, FRT>& aFirstBoundary,
3294 const RangeBoundaryBase<SPT, SRT>& aSecondBoundary, bool* aDisconnected) {
3295 if (NS_WARN_IF(!aFirstBoundary.IsSet())NS_warn_if_impl(!aFirstBoundary.IsSet(), "!aFirstBoundary.IsSet()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3295)
||
3296 NS_WARN_IF(!aSecondBoundary.IsSet())NS_warn_if_impl(!aSecondBoundary.IsSet(), "!aSecondBoundary.IsSet()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3296)
) {
3297 return -1;
3298 }
3299 // XXX Re-implement this without calling `Offset()` as far as possible,
3300 // and the other overload should be an alias of this.
3301 return ComparePoints_Deprecated(
3302 aFirstBoundary.Container(),
3303 *aFirstBoundary.Offset(
3304 RangeBoundaryBase<FPT, FRT>::OffsetFilter::kValidOrInvalidOffsets),
3305 aSecondBoundary.Container(),
3306 *aSecondBoundary.Offset(
3307 RangeBoundaryBase<SPT, SRT>::OffsetFilter::kValidOrInvalidOffsets),
3308 aDisconnected);
3309}
3310
3311inline bool IsCharInSet(const char* aSet, const char16_t aChar) {
3312 char16_t ch;
3313 while ((ch = *aSet)) {
3314 if (aChar == char16_t(ch)) {
3315 return true;
3316 }
3317 ++aSet;
3318 }
3319 return false;
3320}
3321
3322/**
3323 * This method strips leading/trailing chars, in given set, from string.
3324 */
3325
3326// static
3327const nsDependentSubstring nsContentUtils::TrimCharsInSet(
3328 const char* aSet, const nsAString& aValue) {
3329 nsAString::const_iterator valueCurrent, valueEnd;
3330
3331 aValue.BeginReading(valueCurrent);
3332 aValue.EndReading(valueEnd);
3333
3334 // Skip characters in the beginning
3335 while (valueCurrent != valueEnd) {
3336 if (!IsCharInSet(aSet, *valueCurrent)) {
3337 break;
3338 }
3339 ++valueCurrent;
3340 }
3341
3342 if (valueCurrent != valueEnd) {
3343 for (;;) {
3344 --valueEnd;
3345 if (!IsCharInSet(aSet, *valueEnd)) {
3346 break;
3347 }
3348 }
3349 ++valueEnd; // Step beyond the last character we want in the value.
3350 }
3351
3352 // valueEnd should point to the char after the last to copy
3353 return Substring(valueCurrent, valueEnd);
3354}
3355
3356/**
3357 * This method strips leading and trailing whitespace from a string.
3358 */
3359
3360// static
3361template <bool IsWhitespace(char16_t)>
3362const nsDependentSubstring nsContentUtils::TrimWhitespace(const nsAString& aStr,
3363 bool aTrimTrailing) {
3364 nsAString::const_iterator start, end;
3365
3366 aStr.BeginReading(start);
3367 aStr.EndReading(end);
3368
3369 // Skip whitespace characters in the beginning
3370 while (start != end && IsWhitespace(*start)) {
3371 ++start;
3372 }
3373
3374 if (aTrimTrailing) {
3375 // Skip whitespace characters in the end.
3376 while (end != start) {
3377 --end;
3378
3379 if (!IsWhitespace(*end)) {
3380 // Step back to the last non-whitespace character.
3381 ++end;
3382
3383 break;
3384 }
3385 }
3386 }
3387
3388 // Return a substring for the string w/o leading and/or trailing
3389 // whitespace
3390
3391 return Substring(start, end);
3392}
3393
3394// Declaring the templates we are going to use avoid linking issues without
3395// inlining the method. Considering there is not so much spaces checking
3396// methods we can consider this to be better than inlining.
3397template const nsDependentSubstring
3398nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(const nsAString&, bool);
3399template const nsDependentSubstring nsContentUtils::TrimWhitespace<
3400 nsContentUtils::IsHTMLWhitespace>(const nsAString&, bool);
3401template const nsDependentSubstring nsContentUtils::TrimWhitespace<
3402 nsContentUtils::IsHTMLWhitespaceOrNBSP>(const nsAString&, bool);
3403
3404static inline void KeyAppendSep(nsACString& aKey) {
3405 if (!aKey.IsEmpty()) {
3406 aKey.Append('>');
3407 }
3408}
3409
3410static inline void KeyAppendString(const nsAString& aString, nsACString& aKey) {
3411 KeyAppendSep(aKey);
3412
3413 // Could escape separator here if collisions happen. > is not a legal char
3414 // for a name or type attribute, so we should be safe avoiding that extra
3415 // work.
3416
3417 AppendUTF16toUTF8(aString, aKey);
3418}
3419
3420static inline void KeyAppendString(const nsACString& aString,
3421 nsACString& aKey) {
3422 KeyAppendSep(aKey);
3423
3424 // Could escape separator here if collisions happen. > is not a legal char
3425 // for a name or type attribute, so we should be safe avoiding that extra
3426 // work.
3427
3428 aKey.Append(aString);
3429}
3430
3431static inline void KeyAppendInt(int32_t aInt, nsACString& aKey) {
3432 KeyAppendSep(aKey);
3433
3434 aKey.AppendInt(aInt);
3435}
3436
3437static inline bool IsAutocompleteOff(const nsIContent* aContent) {
3438 return aContent->IsElement() &&
3439 aContent->AsElement()->AttrValueIs(kNameSpaceID_None,
3440 nsGkAtoms::autocomplete, u"off"_ns,
3441 eIgnoreCase);
3442}
3443
3444/*static*/
3445void nsContentUtils::GenerateStateKey(nsIContent* aContent, Document* aDocument,
3446 nsACString& aKey) {
3447 MOZ_ASSERT(aContent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aContent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3447); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent" ")"
); do { *((volatile int*)__null) = 3447; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3448
3449 aKey.Truncate();
3450
3451 uint32_t partID = aDocument ? aDocument->GetPartID() : 0;
3452
3453 // Don't capture state for anonymous content
3454 if (aContent->IsInNativeAnonymousSubtree()) {
3455 return;
3456 }
3457
3458 if (IsAutocompleteOff(aContent)) {
3459 return;
3460 }
3461
3462 RefPtr<Document> doc = aContent->GetUncomposedDoc();
3463
3464 KeyAppendInt(partID, aKey); // first append a partID
3465 bool generatedUniqueKey = false;
3466
3467 if (doc && doc->IsHTMLOrXHTML()) {
3468 nsHTMLDocument* htmlDoc = doc->AsHTMLDocument();
3469
3470 // If we have a form control and can calculate form information, use that
3471 // as the key - it is more reliable than just recording position in the
3472 // DOM.
3473 // XXXbz Is it, really? We have bugs on this, I think...
3474 // Important to have a unique key, and tag/type/name may not be.
3475 //
3476 // The format of the key depends on whether the control has a form,
3477 // and whether the element was parser inserted:
3478 //
3479 // [Has Form, Parser Inserted]:
3480 // fp>type>FormNum>IndOfControlInForm>FormName>name
3481 //
3482 // [No Form, Parser Inserted]:
3483 // dp>type>ControlNum>name
3484 //
3485 // [Has Form, Not Parser Inserted]:
3486 // fn>type>IndOfFormInDoc>IndOfControlInForm>FormName>name
3487 //
3488 // [No Form, Not Parser Inserted]:
3489 // dn>type>IndOfControlInDoc>name
3490 //
3491 // XXX We don't need to use index if name is there
3492 // XXXbz We don't? Why not? I don't follow.
3493 //
3494 if (const auto* control = nsIFormControl::FromNode(aContent)) {
3495 // Get the control number if this was a parser inserted element from the
3496 // network.
3497 int32_t controlNumber =
3498 control->GetParserInsertedControlNumberForStateKey();
3499 bool parserInserted = controlNumber != -1;
3500
3501 RefPtr<nsContentList> htmlForms;
3502 RefPtr<nsContentList> htmlFormControls;
3503 if (!parserInserted) {
3504 // Getting these lists is expensive, as we need to keep them up to date
3505 // as the document loads, so we avoid it if we don't need them.
3506 htmlDoc->GetFormsAndFormControls(getter_AddRefs(htmlForms),
3507 getter_AddRefs(htmlFormControls));
3508 }
3509
3510 // Append the control type
3511 KeyAppendInt(int32_t(control->ControlType()), aKey);
3512
3513 // If in a form, add form name / index of form / index in form
3514 HTMLFormElement* formElement = control->GetForm();
3515 if (formElement) {
3516 if (IsAutocompleteOff(formElement)) {
3517 aKey.Truncate();
3518 return;
3519 }
3520
3521 // Append the form number, if this is a parser inserted control, or
3522 // the index of the form in the document otherwise.
3523 bool appendedForm = false;
3524 if (parserInserted) {
3525 MOZ_ASSERT(formElement->GetFormNumberForStateKey() != -1,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(formElement->GetFormNumberForStateKey() != -1)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(formElement->GetFormNumberForStateKey() != -1))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("formElement->GetFormNumberForStateKey() != -1"
" (" "when generating a state key for a parser inserted form "
"control we should have a parser inserted <form> element"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3527); AnnotateMozCrashReason("MOZ_ASSERT" "(" "formElement->GetFormNumberForStateKey() != -1"
") (" "when generating a state key for a parser inserted form "
"control we should have a parser inserted <form> element"
")"); do { *((volatile int*)__null) = 3527; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3526 "when generating a state key for a parser inserted form "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(formElement->GetFormNumberForStateKey() != -1)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(formElement->GetFormNumberForStateKey() != -1))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("formElement->GetFormNumberForStateKey() != -1"
" (" "when generating a state key for a parser inserted form "
"control we should have a parser inserted <form> element"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3527); AnnotateMozCrashReason("MOZ_ASSERT" "(" "formElement->GetFormNumberForStateKey() != -1"
") (" "when generating a state key for a parser inserted form "
"control we should have a parser inserted <form> element"
")"); do { *((volatile int*)__null) = 3527; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3527 "control we should have a parser inserted <form> element")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(formElement->GetFormNumberForStateKey() != -1)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(formElement->GetFormNumberForStateKey() != -1))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("formElement->GetFormNumberForStateKey() != -1"
" (" "when generating a state key for a parser inserted form "
"control we should have a parser inserted <form> element"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3527); AnnotateMozCrashReason("MOZ_ASSERT" "(" "formElement->GetFormNumberForStateKey() != -1"
") (" "when generating a state key for a parser inserted form "
"control we should have a parser inserted <form> element"
")"); do { *((volatile int*)__null) = 3527; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3528 KeyAppendString("fp"_ns, aKey);
3529 KeyAppendInt(formElement->GetFormNumberForStateKey(), aKey);
3530 appendedForm = true;
3531 } else {
3532 KeyAppendString("fn"_ns, aKey);
3533 int32_t index = htmlForms->IndexOf(formElement, false);
3534 if (index <= -1) {
3535 //
3536 // XXX HACK this uses some state that was dumped into the document
3537 // specifically to fix bug 138892. What we are trying to do is
3538 // *guess* which form this control's state is found in, with the
3539 // highly likely guess that the highest form parsed so far is the
3540 // one. This code should not be on trunk, only branch.
3541 //
3542 index = htmlDoc->GetNumFormsSynchronous() - 1;
3543 }
3544 if (index > -1) {
3545 KeyAppendInt(index, aKey);
3546 appendedForm = true;
3547 }
3548 }
3549
3550 if (appendedForm) {
3551 // Append the index of the control in the form
3552 int32_t index = formElement->IndexOfContent(aContent);
3553
3554 if (index > -1) {
3555 KeyAppendInt(index, aKey);
3556 generatedUniqueKey = true;
3557 }
3558 }
3559
3560 // Append the form name
3561 nsAutoString formName;
3562 formElement->GetAttr(nsGkAtoms::name, formName);
3563 KeyAppendString(formName, aKey);
3564 } else {
3565 // Not in a form. Append the control number, if this is a parser
3566 // inserted control, or the index of the control in the document
3567 // otherwise.
3568 if (parserInserted) {
3569 KeyAppendString("dp"_ns, aKey);
3570 KeyAppendInt(control->GetParserInsertedControlNumberForStateKey(),
3571 aKey);
3572 generatedUniqueKey = true;
3573 } else {
3574 KeyAppendString("dn"_ns, aKey);
3575 int32_t index = htmlFormControls->IndexOf(aContent, true);
3576 if (index > -1) {
3577 KeyAppendInt(index, aKey);
3578 generatedUniqueKey = true;
3579 }
3580 }
3581
3582 // Append the control name
3583 nsAutoString name;
3584 aContent->AsElement()->GetAttr(nsGkAtoms::name, name);
3585 KeyAppendString(name, aKey);
3586 }
3587 }
3588 }
3589
3590 if (!generatedUniqueKey) {
3591 // Either we didn't have a form control or we aren't in an HTML document so
3592 // we can't figure out form info. Append the tag name if it's an element
3593 // to avoid restoring state for one type of element on another type.
3594 if (aContent->IsElement()) {
3595 KeyAppendString(nsDependentAtomString(aContent->NodeInfo()->NameAtom()),
3596 aKey);
3597 } else {
3598 // Append a character that is not "d" or "f" to disambiguate from
3599 // the case when we were a form control in an HTML document.
3600 KeyAppendString("o"_ns, aKey);
3601 }
3602
3603 // Now start at aContent and append the indices of it and all its ancestors
3604 // in their containers. That should at least pin down its position in the
3605 // DOM...
3606 nsINode* parent = aContent->GetParentNode();
3607 nsINode* content = aContent;
3608 while (parent) {
3609 KeyAppendInt(parent->ComputeIndexOf_Deprecated(content), aKey);
3610 content = parent;
3611 parent = content->GetParentNode();
3612 }
3613 }
3614}
3615
3616// static
3617nsIPrincipal* nsContentUtils::SubjectPrincipal(JSContext* aCx) {
3618 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3618); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 3618; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3619
3620 // As opposed to SubjectPrincipal(), we do in fact assume that
3621 // we're in a realm here; anyone who calls this function in
3622 // situations where that's not the case is doing it wrong.
3623 JS::Realm* realm = js::GetContextRealm(aCx);
3624 MOZ_ASSERT(realm)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(realm)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(realm))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("realm", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3624); AnnotateMozCrashReason("MOZ_ASSERT" "(" "realm" ")")
; do { *((volatile int*)__null) = 3624; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3625
3626 JSPrincipals* principals = JS::GetRealmPrincipals(realm);
3627 return nsJSPrincipals::get(principals);
3628}
3629
3630// static
3631nsIPrincipal* nsContentUtils::SubjectPrincipal() {
3632 MOZ_ASSERT(IsInitialized())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsInitialized())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsInitialized()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("IsInitialized()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3632); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsInitialized()"
")"); do { *((volatile int*)__null) = 3632; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3633 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3633); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 3633; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3634 JSContext* cx = GetCurrentJSContext();
3635 if (!cx) {
3636 MOZ_CRASH(do { do { } while (false); MOZ_ReportCrash("" "Accessing the Subject Principal without an AutoJSAPI on the stack is "
"forbidden", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3638); AnnotateMozCrashReason("MOZ_CRASH(" "Accessing the Subject Principal without an AutoJSAPI on the stack is "
"forbidden" ")"); do { *((volatile int*)__null) = 3638; __attribute__
((nomerge)) ::abort(); } while (false); } while (false)
3637 "Accessing the Subject Principal without an AutoJSAPI on the stack is "do { do { } while (false); MOZ_ReportCrash("" "Accessing the Subject Principal without an AutoJSAPI on the stack is "
"forbidden", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3638); AnnotateMozCrashReason("MOZ_CRASH(" "Accessing the Subject Principal without an AutoJSAPI on the stack is "
"forbidden" ")"); do { *((volatile int*)__null) = 3638; __attribute__
((nomerge)) ::abort(); } while (false); } while (false)
3638 "forbidden")do { do { } while (false); MOZ_ReportCrash("" "Accessing the Subject Principal without an AutoJSAPI on the stack is "
"forbidden", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3638); AnnotateMozCrashReason("MOZ_CRASH(" "Accessing the Subject Principal without an AutoJSAPI on the stack is "
"forbidden" ")"); do { *((volatile int*)__null) = 3638; __attribute__
((nomerge)) ::abort(); } while (false); } while (false)
;
3639 }
3640
3641 JS::Realm* realm = js::GetContextRealm(cx);
3642
3643 // When an AutoJSAPI is instantiated, we are in a null realm until the
3644 // first JSAutoRealm, which is kind of a purgatory as far as permissions
3645 // go. It would be nice to just hard-abort if somebody does a security check
3646 // in this purgatory zone, but that would be too fragile, since it could be
3647 // triggered by random IsCallerChrome() checks 20-levels deep.
3648 //
3649 // So we want to return _something_ here - and definitely not the System
3650 // Principal, since that would make an AutoJSAPI a very dangerous thing to
3651 // instantiate.
3652 //
3653 // The natural thing to return is a null principal. Ideally, we'd return a
3654 // different null principal each time, to avoid any unexpected interactions
3655 // when the principal accidentally gets inherited somewhere. But
3656 // SubjectPrincipal doesn't return strong references, so there's no way to
3657 // sanely manage the lifetime of multiple null principals.
3658 //
3659 // So we use a singleton null principal. To avoid it being accidentally
3660 // inherited and becoming a "real" subject or object principal, we do a
3661 // release-mode assert during realm creation against using this principal on
3662 // an actual global.
3663 if (!realm) {
3664 return sNullSubjectPrincipal;
3665 }
3666
3667 return SubjectPrincipal(cx);
3668}
3669
3670// static
3671nsIPrincipal* nsContentUtils::ObjectPrincipal(JSObject* aObj) {
3672#ifdef DEBUG1
3673 JS::AssertObjectBelongsToCurrentThread(aObj);
3674#endif
3675
3676 MOZ_DIAGNOSTIC_ASSERT(!js::IsCrossCompartmentWrapper(aObj))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!js::IsCrossCompartmentWrapper(aObj))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!js::IsCrossCompartmentWrapper
(aObj)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!js::IsCrossCompartmentWrapper(aObj)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3676); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!js::IsCrossCompartmentWrapper(aObj)"
")"); do { *((volatile int*)__null) = 3676; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3677
3678 JS::Realm* realm = js::GetNonCCWObjectRealm(aObj);
3679 JSPrincipals* principals = JS::GetRealmPrincipals(realm);
3680 return nsJSPrincipals::get(principals);
3681}
3682
3683// static
3684nsresult nsContentUtils::NewURIWithDocumentCharset(nsIURI** aResult,
3685 const nsAString& aSpec,
3686 Document* aDocument,
3687 nsIURI* aBaseURI) {
3688 if (aDocument) {
3689 return NS_NewURI(aResult, aSpec, aDocument->GetDocumentCharacterSet(),
3690 aBaseURI);
3691 }
3692 return NS_NewURI(aResult, aSpec, nullptr, aBaseURI);
3693}
3694
3695// static
3696bool nsContentUtils::ContainsChar(nsAtom* aAtom, char aChar) {
3697 const uint32_t len = aAtom->GetLength();
3698 if (!len) {
3699 return false;
3700 }
3701 const char16_t* name = aAtom->GetUTF16String();
3702 uint32_t i = 0;
3703 while (i < len) {
3704 if (name[i] == aChar) {
3705 return true;
3706 }
3707 i++;
3708 }
3709 return false;
3710}
3711
3712// static
3713bool nsContentUtils::IsNameWithDash(nsAtom* aName) {
3714 // A valid custom element name is a sequence of characters name which
3715 // must match the PotentialCustomElementName production:
3716 // PotentialCustomElementName ::= [a-z] (PCENChar)* '-' (PCENChar)*
3717 const char16_t* name = aName->GetUTF16String();
3718 uint32_t len = aName->GetLength();
3719 bool hasDash = false;
3720
3721 if (!len || name[0] < 'a' || name[0] > 'z') {
3722 return false;
3723 }
3724
3725 uint32_t i = 1;
3726 while (i < len) {
3727 if (i + 1 < len && NS_IS_SURROGATE_PAIR(name[i], name[i + 1])(((uint32_t(name[i]) & 0xFFFFFC00) == 0xD800) && (
(uint32_t(name[i + 1]) & 0xFFFFFC00) == 0xDC00))
) {
3728 // Merged two 16-bit surrogate pairs into code point.
3729 char32_t code = SURROGATE_TO_UCS4(name[i], name[i + 1])(((uint32_t(name[i]) & 0x03FF) << 10) + (uint32_t(name
[i + 1]) & 0x03FF) + uint32_t(0x00010000))
;
3730
3731 if (code < 0x10000 || code > 0xEFFFF) {
3732 return false;
3733 }
3734
3735 i += 2;
3736 } else {
3737 if (name[i] == '-') {
3738 hasDash = true;
3739 }
3740
3741 if (name[i] != '-' && name[i] != '.' && name[i] != '_' &&
3742 name[i] != 0xB7 && (name[i] < '0' || name[i] > '9') &&
3743 (name[i] < 'a' || name[i] > 'z') &&
3744 (name[i] < 0xC0 || name[i] > 0xD6) &&
3745 (name[i] < 0xF8 || name[i] > 0x37D) &&
3746 (name[i] < 0x37F || name[i] > 0x1FFF) &&
3747 (name[i] < 0x200C || name[i] > 0x200D) &&
3748 (name[i] < 0x203F || name[i] > 0x2040) &&
3749 (name[i] < 0x2070 || name[i] > 0x218F) &&
3750 (name[i] < 0x2C00 || name[i] > 0x2FEF) &&
3751 (name[i] < 0x3001 || name[i] > 0xD7FF) &&
3752 (name[i] < 0xF900 || name[i] > 0xFDCF) &&
3753 (name[i] < 0xFDF0 || name[i] > 0xFFFD)) {
3754 return false;
3755 }
3756
3757 i++;
3758 }
3759 }
3760
3761 return hasDash;
3762}
3763
3764// static
3765bool nsContentUtils::IsCustomElementName(nsAtom* aName, uint32_t aNameSpaceID) {
3766 // Allow non-dashed names in XUL for XBL to Custom Element migrations.
3767 if (aNameSpaceID == kNameSpaceID_XUL8) {
3768 return true;
3769 }
3770
3771 bool hasDash = IsNameWithDash(aName);
3772 if (!hasDash) {
3773 return false;
3774 }
3775
3776 // The custom element name must not be one of the following values:
3777 // annotation-xml
3778 // color-profile
3779 // font-face
3780 // font-face-src
3781 // font-face-uri
3782 // font-face-format
3783 // font-face-name
3784 // missing-glyph
3785 return aName != nsGkAtoms::annotation_xml_ &&
3786 aName != nsGkAtoms::colorProfile && aName != nsGkAtoms::font_face &&
3787 aName != nsGkAtoms::font_face_src &&
3788 aName != nsGkAtoms::font_face_uri &&
3789 aName != nsGkAtoms::font_face_format &&
3790 aName != nsGkAtoms::font_face_name && aName != nsGkAtoms::missingGlyph;
3791}
3792
3793// static
3794nsresult nsContentUtils::CheckQName(const nsAString& aQualifiedName,
3795 bool aNamespaceAware,
3796 const char16_t** aColon) {
3797 const char* colon = nullptr;
3798 const char16_t* begin = aQualifiedName.BeginReading();
3799 const char16_t* end = aQualifiedName.EndReading();
3800
3801 int result = MOZ_XMLCheckQName(reinterpret_cast<const char*>(begin),
3802 reinterpret_cast<const char*>(end),
3803 aNamespaceAware, &colon);
3804
3805 if (!result) {
3806 if (aColon) {
3807 *aColon = reinterpret_cast<const char16_t*>(colon);
3808 }
3809
3810 return NS_OK;
3811 }
3812
3813 return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
3814}
3815
3816// static
3817nsresult nsContentUtils::SplitQName(const nsIContent* aNamespaceResolver,
3818 const nsString& aQName, int32_t* aNamespace,
3819 nsAtom** aLocalName) {
3820 const char16_t* colon;
3821 nsresult rv = nsContentUtils::CheckQName(aQName, true, &colon);
3822 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3822); return rv; } } while (false)
;
3823
3824 if (colon) {
3825 const char16_t* end;
3826 aQName.EndReading(end);
3827 nsAutoString nameSpace;
3828 rv = aNamespaceResolver->LookupNamespaceURIInternal(
3829 Substring(aQName.get(), colon), nameSpace);
3830 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3830); return rv; } } while (false)
;
3831
3832 *aNamespace = nsNameSpaceManager::GetInstance()->GetNameSpaceID(
3833 nameSpace, nsContentUtils::IsChromeDoc(aNamespaceResolver->OwnerDoc()));
3834 if (*aNamespace == kNameSpaceID_Unknown-1) return NS_ERROR_FAILURE;
3835
3836 *aLocalName = NS_AtomizeMainThread(Substring(colon + 1, end)).take();
3837 } else {
3838 *aNamespace = kNameSpaceID_None;
3839 *aLocalName = NS_AtomizeMainThread(aQName).take();
3840 }
3841 NS_ENSURE_TRUE(aLocalName, NS_ERROR_OUT_OF_MEMORY)do { if ((__builtin_expect(!!(!(aLocalName)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aLocalName" ") failed",
nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3841); return NS_ERROR_OUT_OF_MEMORY; } } while (false)
;
3842 return NS_OK;
3843}
3844
3845// static
3846nsresult nsContentUtils::GetNodeInfoFromQName(
3847 const nsAString& aNamespaceURI, const nsAString& aQualifiedName,
3848 nsNodeInfoManager* aNodeInfoManager, uint16_t aNodeType,
3849 mozilla::dom::NodeInfo** aNodeInfo) {
3850 const nsString& qName = PromiseFlatStringTPromiseFlatString<char16_t>(aQualifiedName);
3851 const char16_t* colon;
3852 nsresult rv = nsContentUtils::CheckQName(qName, true, &colon);
3853 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3853); return rv; } } while (false)
;
3854
3855 int32_t nsID;
3856 nsNameSpaceManager::GetInstance()->RegisterNameSpace(aNamespaceURI, nsID);
3857 if (colon) {
3858 const char16_t* end;
3859 qName.EndReading(end);
3860
3861 RefPtr<nsAtom> prefix = NS_AtomizeMainThread(Substring(qName.get(), colon));
3862
3863 rv = aNodeInfoManager->GetNodeInfo(Substring(colon + 1, end), prefix, nsID,
3864 aNodeType, aNodeInfo);
3865 } else {
3866 rv = aNodeInfoManager->GetNodeInfo(aQualifiedName, nullptr, nsID, aNodeType,
3867 aNodeInfo);
3868 }
3869 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 3869); return rv; } } while (false)
;
3870
3871 return nsContentUtils::IsValidNodeName((*aNodeInfo)->NameAtom(),
3872 (*aNodeInfo)->GetPrefixAtom(),
3873 (*aNodeInfo)->NamespaceID())
3874 ? NS_OK
3875 : NS_ERROR_DOM_NAMESPACE_ERR;
3876}
3877
3878// static
3879void nsContentUtils::SplitExpatName(const char16_t* aExpatName,
3880 nsAtom** aPrefix, nsAtom** aLocalName,
3881 int32_t* aNameSpaceID) {
3882 /**
3883 * Expat can send the following:
3884 * localName
3885 * namespaceURI<separator>localName
3886 * namespaceURI<separator>localName<separator>prefix
3887 *
3888 * and we use 0xFFFF for the <separator>.
3889 *
3890 */
3891
3892 const char16_t* uriEnd = nullptr;
3893 const char16_t* nameEnd = nullptr;
3894 const char16_t* pos;
3895 for (pos = aExpatName; *pos; ++pos) {
3896 if (*pos == 0xFFFF) {
3897 if (uriEnd) {
3898 nameEnd = pos;
3899 } else {
3900 uriEnd = pos;
3901 }
3902 }
3903 }
3904
3905 const char16_t* nameStart;
3906 if (uriEnd) {
3907 nsNameSpaceManager::GetInstance()->RegisterNameSpace(
3908 nsDependentSubstring(aExpatName, uriEnd), *aNameSpaceID);
3909
3910 nameStart = (uriEnd + 1);
3911 if (nameEnd) {
3912 const char16_t* prefixStart = nameEnd + 1;
3913 *aPrefix = NS_AtomizeMainThread(Substring(prefixStart, pos)).take();
3914 } else {
3915 nameEnd = pos;
3916 *aPrefix = nullptr;
3917 }
3918 } else {
3919 *aNameSpaceID = kNameSpaceID_None;
3920 nameStart = aExpatName;
3921 nameEnd = pos;
3922 *aPrefix = nullptr;
3923 }
3924 *aLocalName = NS_AtomizeMainThread(Substring(nameStart, nameEnd)).take();
3925}
3926
3927// static
3928PresShell* nsContentUtils::GetPresShellForContent(const nsIContent* aContent) {
3929 Document* doc = aContent->GetComposedDoc();
3930 if (!doc) {
3931 return nullptr;
3932 }
3933 return doc->GetPresShell();
3934}
3935
3936// static
3937nsPresContext* nsContentUtils::GetContextForContent(
3938 const nsIContent* aContent) {
3939 PresShell* presShell = GetPresShellForContent(aContent);
3940 if (!presShell) {
3941 return nullptr;
3942 }
3943 return presShell->GetPresContext();
3944}
3945
3946// static
3947bool nsContentUtils::IsInPrivateBrowsing(const Document* aDoc) {
3948 if (!aDoc) {
3949 return false;
3950 }
3951
3952 nsCOMPtr<nsILoadGroup> loadGroup = aDoc->GetDocumentLoadGroup();
3953 // See duplicated code below in IsInPrivateBrowsing(nsILoadGroup*)
3954 // and Document::Reset/ResetToURI
3955 if (loadGroup) {
3956 nsCOMPtr<nsIInterfaceRequestor> callbacks;
3957 loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
3958 if (callbacks) {
3959 nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
3960 if (loadContext) {
3961 return loadContext->UsePrivateBrowsing();
3962 }
3963 }
3964 }
3965
3966 nsCOMPtr<nsIChannel> channel = aDoc->GetChannel();
3967 return channel && NS_UsePrivateBrowsing(channel);
3968}
3969
3970// static
3971bool nsContentUtils::IsInPrivateBrowsing(nsILoadGroup* aLoadGroup) {
3972 if (!aLoadGroup) {
3973 return false;
3974 }
3975 bool isPrivate = false;
3976 nsCOMPtr<nsIInterfaceRequestor> callbacks;
3977 aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
3978 if (callbacks) {
3979 nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
3980 isPrivate = loadContext && loadContext->UsePrivateBrowsing();
3981 }
3982 return isPrivate;
3983}
3984
3985// FIXME(emilio): This is (effectively) almost but not quite the same as
3986// Document::ShouldLoadImages(), which one is right?
3987bool nsContentUtils::DocumentInactiveForImageLoads(Document* aDocument) {
3988 if (!aDocument) {
3989 return false;
3990 }
3991 if (IsChromeDoc(aDocument) || aDocument->IsResourceDoc() ||
3992 aDocument->IsStaticDocument()) {
3993 return false;
3994 }
3995 nsCOMPtr<nsPIDOMWindowInner> win =
3996 do_QueryInterface(aDocument->GetScopeObject());
3997 return !win || !win->GetDocShell();
3998}
3999
4000imgLoader* nsContentUtils::GetImgLoaderForDocument(Document* aDoc) {
4001 NS_ENSURE_TRUE(!DocumentInactiveForImageLoads(aDoc), nullptr)do { if ((__builtin_expect(!!(!(!DocumentInactiveForImageLoads
(aDoc))), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE("
"!DocumentInactiveForImageLoads(aDoc)" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4001); return nullptr; } } while (false)
;
4002
4003 if (!aDoc) {
4004 return imgLoader::NormalLoader();
4005 }
4006 bool isPrivate = IsInPrivateBrowsing(aDoc);
4007 return isPrivate ? imgLoader::PrivateBrowsingLoader()
4008 : imgLoader::NormalLoader();
4009}
4010
4011// static
4012imgLoader* nsContentUtils::GetImgLoaderForChannel(nsIChannel* aChannel,
4013 Document* aContext) {
4014 NS_ENSURE_TRUE(!DocumentInactiveForImageLoads(aContext), nullptr)do { if ((__builtin_expect(!!(!(!DocumentInactiveForImageLoads
(aContext))), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE("
"!DocumentInactiveForImageLoads(aContext)" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4014); return nullptr; } } while (false)
;
4015
4016 if (!aChannel) {
4017 return imgLoader::NormalLoader();
4018 }
4019 return NS_UsePrivateBrowsing(aChannel) ? imgLoader::PrivateBrowsingLoader()
4020 : imgLoader::NormalLoader();
4021}
4022
4023// static
4024int32_t nsContentUtils::CORSModeToLoadImageFlags(mozilla::CORSMode aMode) {
4025 switch (aMode) {
4026 case CORS_ANONYMOUS:
4027 return imgILoader::LOAD_CORS_ANONYMOUS;
4028 case CORS_USE_CREDENTIALS:
4029 return imgILoader::LOAD_CORS_USE_CREDENTIALS;
4030 default:
4031 return 0;
4032 }
4033}
4034
4035// static
4036nsresult nsContentUtils::LoadImage(
4037 nsIURI* aURI, nsINode* aContext, Document* aLoadingDocument,
4038 nsIPrincipal* aLoadingPrincipal, uint64_t aRequestContextID,
4039 nsIReferrerInfo* aReferrerInfo, imgINotificationObserver* aObserver,
4040 int32_t aLoadFlags, const nsAString& initiatorType,
4041 imgRequestProxy** aRequest, nsContentPolicyType aContentPolicyType,
4042 bool aUseUrgentStartForChannel, bool aLinkPreload,
4043 uint64_t aEarlyHintPreloaderId,
4044 mozilla::dom::FetchPriority aFetchPriority) {
4045 MOZ_ASSERT(aURI, "Must have a URI")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aURI)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aURI))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aURI" " (" "Must have a URI" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4045); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aURI" ") ("
"Must have a URI" ")"); do { *((volatile int*)__null) = 4045
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
4046 MOZ_ASSERT(aContext, "Must have a context")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContext))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aContext" " (" "Must have a context"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4046); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContext" ") ("
"Must have a context" ")"); do { *((volatile int*)__null) = 4046
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
4047 MOZ_ASSERT(aLoadingDocument, "Must have a document")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadingDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadingDocument))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aLoadingDocument"
" (" "Must have a document" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4047); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadingDocument"
") (" "Must have a document" ")"); do { *((volatile int*)__null
) = 4047; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
4048 MOZ_ASSERT(aLoadingPrincipal, "Must have a principal")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadingPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadingPrincipal))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aLoadingPrincipal"
" (" "Must have a principal" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4048); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadingPrincipal"
") (" "Must have a principal" ")"); do { *((volatile int*)__null
) = 4048; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
4049 MOZ_ASSERT(aRequest, "Null out param")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRequest)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRequest))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aRequest" " (" "Null out param"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4049); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRequest" ") ("
"Null out param" ")"); do { *((volatile int*)__null) = 4049;
__attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
4050
4051 imgLoader* imgLoader = GetImgLoaderForDocument(aLoadingDocument);
4052 if (!imgLoader) {
4053 // nothing we can do here
4054 return NS_ERROR_FAILURE;
4055 }
4056
4057 nsCOMPtr<nsILoadGroup> loadGroup = aLoadingDocument->GetDocumentLoadGroup();
4058
4059 nsIURI* documentURI = aLoadingDocument->GetDocumentURI();
4060
4061 NS_ASSERTION(loadGroup || aLoadingDocument->IsSVGGlyphsDocument(),do { if (!(loadGroup || aLoadingDocument->IsSVGGlyphsDocument
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Could not get loadgroup; onload may fire too early"
, "loadGroup || aLoadingDocument->IsSVGGlyphsDocument()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4062); MOZ_PretendNoReturn(); } } while (0)
4062 "Could not get loadgroup; onload may fire too early")do { if (!(loadGroup || aLoadingDocument->IsSVGGlyphsDocument
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Could not get loadgroup; onload may fire too early"
, "loadGroup || aLoadingDocument->IsSVGGlyphsDocument()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4062); MOZ_PretendNoReturn(); } } while (0)
;
4063
4064 // XXXbz using "documentURI" for the initialDocumentURI is not quite
4065 // right, but the best we can do here...
4066 return imgLoader->LoadImage(aURI, /* uri to load */
4067 documentURI, /* initialDocumentURI */
4068 aReferrerInfo, /* referrerInfo */
4069 aLoadingPrincipal, /* loading principal */
4070 aRequestContextID, /* request context ID */
4071 loadGroup, /* loadgroup */
4072 aObserver, /* imgINotificationObserver */
4073 aContext, /* loading context */
4074 aLoadingDocument, /* uniquification key */
4075 aLoadFlags, /* load flags */
4076 nullptr, /* cache key */
4077 aContentPolicyType, /* content policy type */
4078 initiatorType, /* the load initiator */
4079 aUseUrgentStartForChannel, /* urgent-start flag */
4080 aLinkPreload, /* <link preload> initiator */
4081 aEarlyHintPreloaderId, aFetchPriority, aRequest);
4082}
4083
4084// static
4085already_AddRefed<imgIContainer> nsContentUtils::GetImageFromContent(
4086 nsIImageLoadingContent* aContent, imgIRequest** aRequest) {
4087 if (aRequest) {
4088 *aRequest = nullptr;
4089 }
4090
4091 NS_ENSURE_TRUE(aContent, nullptr)do { if ((__builtin_expect(!!(!(aContent)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aContent" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4091); return nullptr; } } while (false)
;
4092
4093 nsCOMPtr<imgIRequest> imgRequest;
4094 aContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
4095 getter_AddRefs(imgRequest));
4096 if (!imgRequest) {
4097 return nullptr;
4098 }
4099
4100 nsCOMPtr<imgIContainer> imgContainer;
4101 imgRequest->GetImage(getter_AddRefs(imgContainer));
4102
4103 if (!imgContainer) {
4104 return nullptr;
4105 }
4106
4107 if (aRequest) {
4108 // If the consumer wants the request, verify it has actually loaded
4109 // successfully.
4110 uint32_t imgStatus;
4111 imgRequest->GetImageStatus(&imgStatus);
4112 if (imgStatus & imgIRequest::STATUS_FRAME_COMPLETE &&
4113 !(imgStatus & imgIRequest::STATUS_ERROR)) {
4114 imgRequest.swap(*aRequest);
4115 }
4116 }
4117
4118 return imgContainer.forget();
4119}
4120
4121static bool IsLinkWithURI(const nsIContent& aContent) {
4122 const auto* element = Element::FromNode(aContent);
4123 if (!element || !element->IsLink()) {
4124 return false;
4125 }
4126 nsCOMPtr<nsIURI> absURI = element->GetHrefURI();
4127 return !!absURI;
4128}
4129
4130static bool HasImageRequest(nsIContent& aContent) {
4131 nsCOMPtr<nsIImageLoadingContent> imageContent(do_QueryInterface(&aContent));
4132 if (!imageContent) {
4133 return false;
4134 }
4135
4136 nsCOMPtr<imgIRequest> imgRequest;
4137 imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
4138 getter_AddRefs(imgRequest));
4139
4140 // XXXbz It may be draggable even if the request resulted in an error. Why?
4141 // Not sure; that's what the old nsContentAreaDragDrop/nsFrame code did.
4142 return !!imgRequest;
4143}
4144
4145static Maybe<bool> DraggableOverride(const nsIContent& aContent) {
4146 if (auto* el = nsGenericHTMLElement::FromNode(aContent)) {
4147 if (el->Draggable()) {
4148 return Some(true);
4149 }
4150
4151 if (el->AttrValueIs(kNameSpaceID_None, nsGkAtoms::draggable,
4152 nsGkAtoms::_false, eIgnoreCase)) {
4153 return Some(false);
4154 }
4155 }
4156 if (aContent.IsSVGElement()) {
4157 return Some(false);
4158 }
4159 return Nothing();
4160}
4161
4162// static
4163bool nsContentUtils::ContentIsDraggable(nsIContent* aContent) {
4164 MOZ_ASSERT(aContent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aContent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4164); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent" ")"
); do { *((volatile int*)__null) = 4164; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4165
4166 if (auto draggable = DraggableOverride(*aContent)) {
4167 return *draggable;
4168 }
4169
4170 // special handling for content area image and link dragging
4171 return HasImageRequest(*aContent) || IsLinkWithURI(*aContent);
4172}
4173
4174// static
4175bool nsContentUtils::IsDraggableImage(nsIContent* aContent) {
4176 MOZ_ASSERT(aContent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aContent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4176); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent" ")"
); do { *((volatile int*)__null) = 4176; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4177 return HasImageRequest(*aContent) &&
4178 DraggableOverride(*aContent).valueOr(true);
4179}
4180
4181// static
4182bool nsContentUtils::IsDraggableLink(const nsIContent* aContent) {
4183 MOZ_ASSERT(aContent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aContent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4183); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent" ")"
); do { *((volatile int*)__null) = 4183; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4184 return IsLinkWithURI(*aContent) && DraggableOverride(*aContent).valueOr(true);
4185}
4186
4187// static
4188nsresult nsContentUtils::QNameChanged(mozilla::dom::NodeInfo* aNodeInfo,
4189 nsAtom* aName,
4190 mozilla::dom::NodeInfo** aResult) {
4191 nsNodeInfoManager* niMgr = aNodeInfo->NodeInfoManager();
4192
4193 *aResult = niMgr
4194 ->GetNodeInfo(aName, nullptr, aNodeInfo->NamespaceID(),
4195 aNodeInfo->NodeType(), aNodeInfo->GetExtraName())
4196 .take();
4197 return NS_OK;
4198}
4199
4200static bool TestSitePerm(nsIPrincipal* aPrincipal, const nsACString& aType,
4201 uint32_t aPerm, bool aExactHostMatch) {
4202 if (!aPrincipal) {
4203 // We always deny (i.e. don't allow) the permission if we don't have a
4204 // principal.
4205 return aPerm != nsIPermissionManager::ALLOW_ACTION;
4206 }
4207
4208 nsCOMPtr<nsIPermissionManager> permMgr =
4209 components::PermissionManager::Service();
4210 NS_ENSURE_TRUE(permMgr, false)do { if ((__builtin_expect(!!(!(permMgr)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "permMgr" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4210); return false; } } while (false)
;
4211
4212 uint32_t perm;
4213 nsresult rv;
4214 if (aExactHostMatch) {
4215 rv = permMgr->TestExactPermissionFromPrincipal(aPrincipal, aType, &perm);
4216 } else {
4217 rv = permMgr->TestPermissionFromPrincipal(aPrincipal, aType, &perm);
4218 }
4219 NS_ENSURE_SUCCESS(rv, false)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "false", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4219); return false; } } while (false)
;
4220
4221 return perm == aPerm;
4222}
4223
4224bool nsContentUtils::IsSitePermAllow(nsIPrincipal* aPrincipal,
4225 const nsACString& aType) {
4226 return TestSitePerm(aPrincipal, aType, nsIPermissionManager::ALLOW_ACTION,
4227 false);
4228}
4229
4230bool nsContentUtils::IsSitePermDeny(nsIPrincipal* aPrincipal,
4231 const nsACString& aType) {
4232 return TestSitePerm(aPrincipal, aType, nsIPermissionManager::DENY_ACTION,
4233 false);
4234}
4235
4236bool nsContentUtils::IsExactSitePermAllow(nsIPrincipal* aPrincipal,
4237 const nsACString& aType) {
4238 return TestSitePerm(aPrincipal, aType, nsIPermissionManager::ALLOW_ACTION,
4239 true);
4240}
4241
4242bool nsContentUtils::IsExactSitePermDeny(nsIPrincipal* aPrincipal,
4243 const nsACString& aType) {
4244 return TestSitePerm(aPrincipal, aType, nsIPermissionManager::DENY_ACTION,
4245 true);
4246}
4247
4248bool nsContentUtils::HasSitePerm(nsIPrincipal* aPrincipal,
4249 const nsACString& aType) {
4250 if (!aPrincipal) {
4251 return false;
4252 }
4253
4254 nsCOMPtr<nsIPermissionManager> permMgr =
4255 components::PermissionManager::Service();
4256 NS_ENSURE_TRUE(permMgr, false)do { if ((__builtin_expect(!!(!(permMgr)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "permMgr" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4256); return false; } } while (false)
;
4257
4258 uint32_t perm;
4259 nsresult rv = permMgr->TestPermissionFromPrincipal(aPrincipal, aType, &perm);
4260 NS_ENSURE_SUCCESS(rv, false)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "false", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4260); return false; } } while (false)
;
4261
4262 return perm != nsIPermissionManager::UNKNOWN_ACTION;
4263}
4264
4265static const char* gEventNames[] = {"event"};
4266static const char* gSVGEventNames[] = {"evt"};
4267// for b/w compat, the first name to onerror is still 'event', even though it
4268// is actually the error message
4269static const char* gOnErrorNames[] = {"event", "source", "lineno", "colno",
4270 "error"};
4271
4272// static
4273void nsContentUtils::GetEventArgNames(int32_t aNameSpaceID, nsAtom* aEventName,
4274 bool aIsForWindow, uint32_t* aArgCount,
4275 const char*** aArgArray) {
4276#define SET_EVENT_ARG_NAMES(names)*aArgCount = sizeof(names) / sizeof(names[0]); *aArgArray = names
;
\
4277 *aArgCount = sizeof(names) / sizeof(names[0]); \
4278 *aArgArray = names;
4279
4280 // JSEventHandler is what does the arg magic for onerror, and it does
4281 // not seem to take the namespace into account. So we let onerror in all
4282 // namespaces get the 3 arg names.
4283 if (aEventName == nsGkAtoms::onerror && aIsForWindow) {
4284 SET_EVENT_ARG_NAMES(gOnErrorNames)*aArgCount = sizeof(gOnErrorNames) / sizeof(gOnErrorNames[0])
; *aArgArray = gOnErrorNames;
;
4285 } else if (aNameSpaceID == kNameSpaceID_SVG9) {
4286 SET_EVENT_ARG_NAMES(gSVGEventNames)*aArgCount = sizeof(gSVGEventNames) / sizeof(gSVGEventNames[0
]); *aArgArray = gSVGEventNames;
;
4287 } else {
4288 SET_EVENT_ARG_NAMES(gEventNames)*aArgCount = sizeof(gEventNames) / sizeof(gEventNames[0]); *aArgArray
= gEventNames;
;
4289 }
4290}
4291
4292// Note: The list of content bundles in nsStringBundle.cpp should be updated
4293// whenever entries are added or removed from this list.
4294static const char* gPropertiesFiles[nsContentUtils::PropertiesFile_COUNT] = {
4295 // Must line up with the enum values in |PropertiesFile| enum.
4296 "chrome://global/locale/css.properties",
4297 "chrome://global/locale/xul.properties",
4298 "chrome://global/locale/layout_errors.properties",
4299 "chrome://global/locale/layout/HtmlForm.properties",
4300 "chrome://global/locale/printing.properties",
4301 "chrome://global/locale/dom/dom.properties",
4302 "chrome://global/locale/layout/htmlparser.properties",
4303 "chrome://global/locale/svg/svg.properties",
4304 "chrome://branding/locale/brand.properties",
4305 "chrome://global/locale/commonDialogs.properties",
4306 "chrome://global/locale/mathml/mathml.properties",
4307 "chrome://global/locale/security/security.properties",
4308 "chrome://necko/locale/necko.properties",
4309 "resource://gre/res/locale/layout/HtmlForm.properties",
4310 "resource://gre/res/locale/dom/dom.properties"};
4311
4312/* static */
4313nsresult nsContentUtils::EnsureStringBundle(PropertiesFile aFile) {
4314 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "Should not create bundles off main thread." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4315); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "NS_IsMainThread()"
") (" "Should not create bundles off main thread." ")"); do {
*((volatile int*)__null) = 4315; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
4315 "Should not create bundles off main thread.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "Should not create bundles off main thread." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4315); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "NS_IsMainThread()"
") (" "Should not create bundles off main thread." ")"); do {
*((volatile int*)__null) = 4315; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4316 if (!sStringBundles[aFile]) {
4317 if (!sStringBundleService) {
4318 nsresult rv =
4319 CallGetService(NS_STRINGBUNDLE_CONTRACTID"@mozilla.org/intl/stringbundle;1", &sStringBundleService);
4320 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4320); return rv; } } while (false)
;
4321 }
4322 RefPtr<nsIStringBundle> bundle;
4323 MOZ_TRY(sStringBundleService->CreateBundle(gPropertiesFiles[aFile],do { auto mozTryTempResult_ = ::mozilla::ToResult(sStringBundleService
->CreateBundle(gPropertiesFiles[aFile], getter_AddRefs(bundle
))); if ((__builtin_expect(!!(mozTryTempResult_.isErr()), 0))
) { return mozTryTempResult_.propagateErr(); } } while (0)
4324 getter_AddRefs(bundle)))do { auto mozTryTempResult_ = ::mozilla::ToResult(sStringBundleService
->CreateBundle(gPropertiesFiles[aFile], getter_AddRefs(bundle
))); if ((__builtin_expect(!!(mozTryTempResult_.isErr()), 0))
) { return mozTryTempResult_.propagateErr(); } } while (0)
;
4325 sStringBundles[aFile] = bundle.forget();
4326 }
4327 return NS_OK;
4328}
4329
4330/* static */
4331void nsContentUtils::AsyncPrecreateStringBundles() {
4332 // We only ever want to pre-create bundles in the parent process.
4333 //
4334 // All nsContentUtils bundles are shared between the parent and child
4335 // precesses, and the shared memory regions that back them *must* be created
4336 // in the parent, and then sent to all children.
4337 //
4338 // If we attempt to create a bundle in the child before its memory region is
4339 // available, we need to create a temporary non-shared bundle, and later
4340 // replace that with the shared memory copy. So attempting to pre-load in the
4341 // child is wasteful and unnecessary.
4342 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4342); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 4342; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4343
4344 for (uint32_t bundleIndex = 0; bundleIndex < PropertiesFile_COUNT;
4345 ++bundleIndex) {
4346 nsresult rv = NS_DispatchToCurrentThreadQueue(
4347 NS_NewRunnableFunction("AsyncPrecreateStringBundles",
4348 [bundleIndex]() {
4349 PropertiesFile file =
4350 static_cast<PropertiesFile>(bundleIndex);
4351 EnsureStringBundle(file);
4352 nsIStringBundle* bundle = sStringBundles[file];
4353 bundle->AsyncPreload();
4354 }),
4355 EventQueuePriority::Idle);
4356 Unused << NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4356)
;
4357 }
4358}
4359
4360/* static */
4361bool nsContentUtils::SpoofLocaleEnglish() {
4362 // 0 - will prompt
4363 // 1 - don't spoof
4364 // 2 - spoof
4365 return StaticPrefs::privacy_spoof_english() == 2;
4366}
4367
4368static nsContentUtils::PropertiesFile GetMaybeSpoofedPropertiesFile(
4369 nsContentUtils::PropertiesFile aFile, const char* aKey,
4370 Document* aDocument) {
4371 // When we spoof English, use en-US properties in strings that are accessible
4372 // by content.
4373 bool spoofLocale = nsContentUtils::SpoofLocaleEnglish() &&
4374 (!aDocument || !aDocument->AllowsL10n());
4375 if (spoofLocale) {
4376 switch (aFile) {
4377 case nsContentUtils::eFORMS_PROPERTIES:
4378 return nsContentUtils::eFORMS_PROPERTIES_en_US;
4379 case nsContentUtils::eDOM_PROPERTIES:
4380 return nsContentUtils::eDOM_PROPERTIES_en_US;
4381 default:
4382 break;
4383 }
4384 }
4385 return aFile;
4386}
4387
4388/* static */
4389nsresult nsContentUtils::GetMaybeLocalizedString(PropertiesFile aFile,
4390 const char* aKey,
4391 Document* aDocument,
4392 nsAString& aResult) {
4393 return GetLocalizedString(
4394 GetMaybeSpoofedPropertiesFile(aFile, aKey, aDocument), aKey, aResult);
4395}
4396
4397/* static */
4398nsresult nsContentUtils::GetLocalizedString(PropertiesFile aFile,
4399 const char* aKey,
4400 nsAString& aResult) {
4401 return FormatLocalizedString(aFile, aKey, {}, aResult);
4402}
4403
4404/* static */
4405nsresult nsContentUtils::FormatMaybeLocalizedString(
4406 PropertiesFile aFile, const char* aKey, Document* aDocument,
4407 const nsTArray<nsString>& aParams, nsAString& aResult) {
4408 return FormatLocalizedString(
4409 GetMaybeSpoofedPropertiesFile(aFile, aKey, aDocument), aKey, aParams,
4410 aResult);
4411}
4412
4413class FormatLocalizedStringRunnable final : public WorkerMainThreadRunnable {
4414 public:
4415 FormatLocalizedStringRunnable(WorkerPrivate* aWorkerPrivate,
4416 nsContentUtils::PropertiesFile aFile,
4417 const char* aKey,
4418 const nsTArray<nsString>& aParams,
4419 nsAString& aLocalizedString)
4420 : WorkerMainThreadRunnable(aWorkerPrivate,
4421 "FormatLocalizedStringRunnable"_ns),
4422 mFile(aFile),
4423 mKey(aKey),
4424 mParams(aParams),
4425 mLocalizedString(aLocalizedString) {
4426 MOZ_ASSERT(aWorkerPrivate)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWorkerPrivate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWorkerPrivate))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aWorkerPrivate"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4426); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWorkerPrivate"
")"); do { *((volatile int*)__null) = 4426; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4427 aWorkerPrivate->AssertIsOnWorkerThread();
4428 }
4429
4430 bool MainThreadRun() override {
4431 AssertIsOnMainThread();
4432
4433 mResult = nsContentUtils::FormatLocalizedString(mFile, mKey, mParams,
4434 mLocalizedString);
4435 Unused << NS_WARN_IF(NS_FAILED(mResult))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(mResult
)), 0))), "NS_FAILED(mResult)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4435)
;
4436 return true;
4437 }
4438
4439 nsresult GetResult() const { return mResult; }
4440
4441 private:
4442 const nsContentUtils::PropertiesFile mFile;
4443 const char* mKey;
4444 const nsTArray<nsString>& mParams;
4445 nsresult mResult = NS_ERROR_FAILURE;
4446 nsAString& mLocalizedString;
4447};
4448
4449/* static */
4450nsresult nsContentUtils::FormatLocalizedString(
4451 PropertiesFile aFile, const char* aKey, const nsTArray<nsString>& aParams,
4452 nsAString& aResult) {
4453 if (!NS_IsMainThread()) {
4454 // nsIStringBundle is thread-safe but its creation is not, and in particular
4455 // we don't create and store nsIStringBundle objects in a thread-safe way.
4456 //
4457 // TODO(emilio): Maybe if we already have the right bundle created we could
4458 // just call into it, but we should make sure that Shutdown() doesn't get
4459 // called on the main thread when that happens which is a bit tricky to
4460 // prove?
4461 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
4462 if (NS_WARN_IF(!workerPrivate)NS_warn_if_impl(!workerPrivate, "!workerPrivate", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4462)
) {
4463 return NS_ERROR_UNEXPECTED;
4464 }
4465
4466 auto runnable = MakeRefPtr<FormatLocalizedStringRunnable>(
4467 workerPrivate, aFile, aKey, aParams, aResult);
4468
4469 runnable->Dispatch(workerPrivate, Canceling, IgnoreErrors());
4470 return runnable->GetResult();
4471 }
4472
4473 MOZ_TRY(EnsureStringBundle(aFile))do { auto mozTryTempResult_ = ::mozilla::ToResult(EnsureStringBundle
(aFile)); if ((__builtin_expect(!!(mozTryTempResult_.isErr())
, 0))) { return mozTryTempResult_.propagateErr(); } } while (
0)
;
4474 nsIStringBundle* bundle = sStringBundles[aFile];
4475 if (aParams.IsEmpty()) {
4476 return bundle->GetStringFromName(aKey, aResult);
4477 }
4478 return bundle->FormatStringFromName(aKey, aParams, aResult);
4479}
4480
4481/* static */
4482void nsContentUtils::LogSimpleConsoleError(const nsAString& aErrorText,
4483 const nsACString& aCategory,
4484 bool aFromPrivateWindow,
4485 bool aFromChromeContext,
4486 uint32_t aErrorFlags) {
4487 nsCOMPtr<nsIScriptError> scriptError =
4488 do_CreateInstance(NS_SCRIPTERROR_CONTRACTID"@mozilla.org/scripterror;1");
4489 if (scriptError) {
4490 nsCOMPtr<nsIConsoleService> console =
4491 do_GetService(NS_CONSOLESERVICE_CONTRACTID"@mozilla.org/consoleservice;1");
4492 if (console && NS_SUCCEEDED(scriptError->Init(((bool)(__builtin_expect(!!(!NS_FAILED_impl(scriptError->Init
( aErrorText, ""_ns, 0, 0, aErrorFlags, aCategory, aFromPrivateWindow
, aFromChromeContext))), 1)))
4493 aErrorText, ""_ns, 0, 0, aErrorFlags, aCategory,((bool)(__builtin_expect(!!(!NS_FAILED_impl(scriptError->Init
( aErrorText, ""_ns, 0, 0, aErrorFlags, aCategory, aFromPrivateWindow
, aFromChromeContext))), 1)))
4494 aFromPrivateWindow, aFromChromeContext))((bool)(__builtin_expect(!!(!NS_FAILED_impl(scriptError->Init
( aErrorText, ""_ns, 0, 0, aErrorFlags, aCategory, aFromPrivateWindow
, aFromChromeContext))), 1)))
) {
4495 console->LogMessage(scriptError);
4496 }
4497 }
4498}
4499
4500/* static */
4501nsresult nsContentUtils::ReportToConsole(
4502 uint32_t aErrorFlags, const nsACString& aCategory,
4503 const Document* aDocument, PropertiesFile aFile, const char* aMessageName,
4504 const nsTArray<nsString>& aParams, const SourceLocation& aLoc) {
4505 nsresult rv;
4506 nsAutoString errorText;
4507 if (!aParams.IsEmpty()) {
4508 rv = FormatLocalizedString(aFile, aMessageName, aParams, errorText);
4509 } else {
4510 rv = GetLocalizedString(aFile, aMessageName, errorText);
4511 }
4512 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4512); return rv; } } while (false)
;
4513 return ReportToConsoleNonLocalized(errorText, aErrorFlags, aCategory,
4514 aDocument, aLoc);
4515}
4516
4517/* static */
4518void nsContentUtils::ReportEmptyGetElementByIdArg(const Document* aDoc) {
4519 ReportToConsole(nsIScriptError::warningFlag, "DOM"_ns, aDoc,
4520 nsContentUtils::eDOM_PROPERTIES, "EmptyGetElementByIdParam");
4521}
4522
4523/* static */
4524nsresult nsContentUtils::ReportToConsoleNonLocalized(
4525 const nsAString& aErrorText, uint32_t aErrorFlags,
4526 const nsACString& aCategory, const Document* aDocument,
4527 const SourceLocation& aLoc) {
4528 uint64_t innerWindowID = aDocument ? aDocument->InnerWindowID() : 0;
4529 if (aLoc || !aDocument || !aDocument->GetDocumentURI()) {
4530 return ReportToConsoleByWindowID(aErrorText, aErrorFlags, aCategory,
4531 innerWindowID, aLoc);
4532 }
4533 return ReportToConsoleByWindowID(aErrorText, aErrorFlags, aCategory,
4534 innerWindowID,
4535 SourceLocation(aDocument->GetDocumentURI()));
4536}
4537
4538/* static */
4539nsresult nsContentUtils::ReportToConsoleByWindowID(
4540 const nsAString& aErrorText, uint32_t aErrorFlags,
4541 const nsACString& aCategory, uint64_t aInnerWindowID,
4542 const SourceLocation& aLocation) {
4543 nsresult rv;
4544 if (!sConsoleService) { // only need to bother null-checking here
4545 rv = CallGetService(NS_CONSOLESERVICE_CONTRACTID"@mozilla.org/consoleservice;1", &sConsoleService);
4546 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4546); return rv; } } while (false)
;
4547 }
4548
4549 nsCOMPtr<nsIScriptError> errorObject =
4550 do_CreateInstance(NS_SCRIPTERROR_CONTRACTID"@mozilla.org/scripterror;1", &rv);
4551 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4551); return rv; } } while (false)
;
4552
4553 if (aLocation.mResource.is<nsCOMPtr<nsIURI>>()) {
4554 nsIURI* uri = aLocation.mResource.as<nsCOMPtr<nsIURI>>();
4555 rv = errorObject->InitWithSourceURI(aErrorText, uri, aLocation.mLine,
4556 aLocation.mColumn, aErrorFlags,
4557 aCategory, aInnerWindowID);
4558 } else {
4559 rv = errorObject->InitWithWindowID(
4560 aErrorText, aLocation.mResource.as<nsCString>(), aLocation.mLine,
4561 aLocation.mColumn, aErrorFlags, aCategory, aInnerWindowID);
4562 }
4563 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4563); return rv; } } while (false)
;
4564
4565 return sConsoleService->LogMessage(errorObject);
4566}
4567
4568void nsContentUtils::LogMessageToConsole(const char* aMsg) {
4569 if (!sConsoleService) { // only need to bother null-checking here
4570 CallGetService(NS_CONSOLESERVICE_CONTRACTID"@mozilla.org/consoleservice;1", &sConsoleService);
4571 if (!sConsoleService) {
4572 return;
4573 }
4574 }
4575 sConsoleService->LogStringMessage(NS_ConvertUTF8toUTF16(aMsg).get());
4576}
4577
4578bool nsContentUtils::IsChromeDoc(const Document* aDocument) {
4579 return aDocument && aDocument->NodePrincipal() == sSystemPrincipal;
4580}
4581
4582bool nsContentUtils::IsAddonDoc(const Document* aDocument) {
4583 return aDocument &&
4584 aDocument->NodePrincipal()->GetIsAddonOrExpandedAddonPrincipal();
4585}
4586
4587bool nsContentUtils::IsChildOfSameType(Document* aDoc) {
4588 if (BrowsingContext* bc = aDoc->GetBrowsingContext()) {
4589 return bc->GetParent();
4590 }
4591 return false;
4592}
4593
4594static bool IsJSONType(const nsACString& aContentType) {
4595 return aContentType.EqualsLiteral(TEXT_JSON"text/json") ||
4596 aContentType.EqualsLiteral(APPLICATION_JSON"application/json");
4597}
4598
4599static bool IsNonPlainTextType(const nsACString& aContentType) {
4600 // MIME type suffixes which should not be plain text.
4601 static constexpr std::string_view kNonPlainTextTypes[] = {
4602 "html",
4603 "xml",
4604 "xsl",
4605 "calendar",
4606 "x-calendar",
4607 "x-vcalendar",
4608 "vcalendar",
4609 "vcard",
4610 "x-vcard",
4611 "directory",
4612 "ldif",
4613 "qif",
4614 "x-qif",
4615 "x-csv",
4616 "x-vcf",
4617 "rtf",
4618 "comma-separated-values",
4619 "csv",
4620 "tab-separated-values",
4621 "tsv",
4622 "ofx",
4623 "vnd.sun.j2me.app-descriptor",
4624 "x-ms-iqy",
4625 "x-ms-odc",
4626 "x-ms-rqy",
4627 "x-ms-contact"};
4628
4629 // Trim off the "text/" prefix for comparison.
4630 MOZ_ASSERT(StringBeginsWith(aContentType, "text/"_ns))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(StringBeginsWith(aContentType, "text/"_ns))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(StringBeginsWith(aContentType, "text/"_ns)))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("StringBeginsWith(aContentType, \"text/\"_ns)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4630); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StringBeginsWith(aContentType, \"text/\"_ns)"
")"); do { *((volatile int*)__null) = 4630; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4631 std::string_view suffix = aContentType;
4632 suffix.remove_prefix(5);
4633
4634 for (std::string_view type : kNonPlainTextTypes) {
4635 if (type == suffix) {
4636 return true;
4637 }
4638 }
4639 return false;
4640}
4641
4642bool nsContentUtils::IsPlainTextType(const nsACString& aContentType) {
4643 // All `text/*`, any JSON type and any JavaScript type are considered "plain
4644 // text" types for the purposes of how to render them as a document.
4645 return (StringBeginsWith(aContentType, "text/"_ns) &&
4646 !IsNonPlainTextType(aContentType)) ||
4647 IsJSONType(aContentType) || IsJavascriptMIMEType(aContentType);
4648}
4649
4650bool nsContentUtils::IsUtf8OnlyPlainTextType(const nsACString& aContentType) {
4651 // NOTE: This must be a subset of the list in IsPlainTextType().
4652 return IsJSONType(aContentType) ||
4653 aContentType.EqualsLiteral(TEXT_CACHE_MANIFEST"text/cache-manifest") ||
4654 aContentType.EqualsLiteral(TEXT_VTT"text/vtt");
4655}
4656
4657bool nsContentUtils::IsInChromeDocshell(const Document* aDocument) {
4658 return aDocument && aDocument->IsInChromeDocShell();
4659}
4660
4661// static
4662nsIContentPolicy* nsContentUtils::GetContentPolicy() {
4663 if (!sTriedToGetContentPolicy) {
4664 CallGetService(NS_CONTENTPOLICY_CONTRACTID"@mozilla.org/layout/content-policy;1", &sContentPolicyService);
4665 // It's OK to not have a content policy service
4666 sTriedToGetContentPolicy = true;
4667 }
4668
4669 return sContentPolicyService;
4670}
4671
4672// static
4673bool nsContentUtils::IsEventAttributeName(nsAtom* aName, int32_t aType) {
4674 const char16_t* name = aName->GetUTF16String();
4675 if (name[0] != 'o' || name[1] != 'n') {
4676 return false;
4677 }
4678
4679 EventNameMapping mapping;
4680 return (sAtomEventTable->Get(aName, &mapping) && mapping.mType & aType);
4681}
4682
4683// static
4684EventMessage nsContentUtils::GetEventMessage(nsAtom* aName) {
4685 MOZ_ASSERT(NS_IsMainThread(), "sAtomEventTable is not threadsafe")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "sAtomEventTable is not threadsafe" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4685); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "sAtomEventTable is not threadsafe" ")"); do { *((volatile
int*)__null) = 4685; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4686 if (aName) {
4687 EventNameMapping mapping;
4688 if (sAtomEventTable->Get(aName, &mapping)) {
4689 return mapping.mMessage;
4690 }
4691 }
4692
4693 return eUnidentifiedEvent;
4694}
4695
4696// static
4697mozilla::EventClassID nsContentUtils::GetEventClassID(const nsAString& aName) {
4698 EventNameMapping mapping;
4699 if (sStringEventTable->Get(aName, &mapping)) return mapping.mEventClassID;
4700
4701 return eBasicEventClass;
4702}
4703
4704nsAtom* nsContentUtils::GetEventMessageAndAtom(
4705 const nsAString& aName, mozilla::EventClassID aEventClassID,
4706 EventMessage* aEventMessage) {
4707 MOZ_ASSERT(NS_IsMainThread(), "Our hashtables are not threadsafe")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "Our hashtables are not threadsafe" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4707); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "Our hashtables are not threadsafe" ")"); do { *((volatile
int*)__null) = 4707; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4708 EventNameMapping mapping;
4709 if (sStringEventTable->Get(aName, &mapping)) {
4710 *aEventMessage = mapping.mEventClassID == aEventClassID
4711 ? mapping.mMessage
4712 : eUnidentifiedEvent;
4713 return mapping.mAtom;
4714 }
4715
4716 // If we have cached lots of user defined event names, clear some of them.
4717 if (sUserDefinedEvents->Length() > 127) {
4718 while (sUserDefinedEvents->Length() > 64) {
4719 nsAtom* first = sUserDefinedEvents->ElementAt(0);
4720 sStringEventTable->Remove(Substring(nsDependentAtomString(first), 2));
4721 sUserDefinedEvents->RemoveElementAt(0);
4722 }
4723 }
4724
4725 *aEventMessage = eUnidentifiedEvent;
4726 RefPtr<nsAtom> atom = NS_AtomizeMainThread(u"on"_ns + aName);
4727 sUserDefinedEvents->AppendElement(atom);
4728 mapping.mAtom = atom;
4729 mapping.mMessage = eUnidentifiedEvent;
4730 mapping.mType = EventNameType_None;
4731 mapping.mEventClassID = eBasicEventClass;
4732 sStringEventTable->InsertOrUpdate(aName, mapping);
4733 return mapping.mAtom;
4734}
4735
4736// static
4737EventMessage nsContentUtils::GetEventMessageAndAtomForListener(
4738 const nsAString& aName, nsAtom** aOnName) {
4739 MOZ_ASSERT(NS_IsMainThread(), "Our hashtables are not threadsafe")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "Our hashtables are not threadsafe" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4739); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "Our hashtables are not threadsafe" ")"); do { *((volatile
int*)__null) = 4739; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4740
4741 // Check sStringEventTable for a matching entry. This will only fail for
4742 // user-defined event types.
4743 EventNameMapping mapping;
4744 if (sStringEventTable->Get(aName, &mapping)) {
4745 RefPtr<nsAtom> atom = mapping.mAtom;
4746 atom.forget(aOnName);
4747 return mapping.mMessage;
4748 }
4749
4750 // sStringEventTable did not contain an entry for this event type string.
4751 // Call GetEventMessageAndAtom, which will create an event type atom and
4752 // cache it in sStringEventTable for future calls.
4753 EventMessage msg = eUnidentifiedEvent;
4754 RefPtr<nsAtom> atom = GetEventMessageAndAtom(aName, eBasicEventClass, &msg);
4755 atom.forget(aOnName);
4756 return msg;
4757}
4758
4759static already_AddRefed<Event> GetEventWithTarget(
4760 Document* aDoc, EventTarget* aTarget, const nsAString& aEventName,
4761 CanBubble aCanBubble, Cancelable aCancelable, Composed aComposed,
4762 Trusted aTrusted, ErrorResult& aErrorResult) {
4763 RefPtr<Event> event =
4764 aDoc->CreateEvent(u"Events"_ns, CallerType::System, aErrorResult);
4765 if (aErrorResult.Failed()) {
4766 return nullptr;
4767 }
4768
4769 event->InitEvent(aEventName, aCanBubble, aCancelable, aComposed);
4770 event->SetTrusted(aTrusted == Trusted::eYes);
4771
4772 event->SetTarget(aTarget);
4773
4774 return event.forget();
4775}
4776
4777// static
4778nsresult nsContentUtils::DispatchTrustedEvent(
4779 Document* aDoc, EventTarget* aTarget, const nsAString& aEventName,
4780 CanBubble aCanBubble, Cancelable aCancelable, Composed aComposed,
4781 bool* aDefaultAction) {
4782 MOZ_ASSERT(!aEventName.EqualsLiteral("input") &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEventName.EqualsLiteral("input") && !aEventName
.EqualsLiteral("beforeinput"))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aEventName.EqualsLiteral("input"
) && !aEventName.EqualsLiteral("beforeinput")))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("!aEventName.EqualsLiteral(\"input\") && !aEventName.EqualsLiteral(\"beforeinput\")"
" (" "Use DispatchInputEvent() instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4784); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEventName.EqualsLiteral(\"input\") && !aEventName.EqualsLiteral(\"beforeinput\")"
") (" "Use DispatchInputEvent() instead" ")"); do { *((volatile
int*)__null) = 4784; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
4783 !aEventName.EqualsLiteral("beforeinput"),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEventName.EqualsLiteral("input") && !aEventName
.EqualsLiteral("beforeinput"))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aEventName.EqualsLiteral("input"
) && !aEventName.EqualsLiteral("beforeinput")))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("!aEventName.EqualsLiteral(\"input\") && !aEventName.EqualsLiteral(\"beforeinput\")"
" (" "Use DispatchInputEvent() instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4784); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEventName.EqualsLiteral(\"input\") && !aEventName.EqualsLiteral(\"beforeinput\")"
") (" "Use DispatchInputEvent() instead" ")"); do { *((volatile
int*)__null) = 4784; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
4784 "Use DispatchInputEvent() instead")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEventName.EqualsLiteral("input") && !aEventName
.EqualsLiteral("beforeinput"))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aEventName.EqualsLiteral("input"
) && !aEventName.EqualsLiteral("beforeinput")))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("!aEventName.EqualsLiteral(\"input\") && !aEventName.EqualsLiteral(\"beforeinput\")"
" (" "Use DispatchInputEvent() instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4784); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEventName.EqualsLiteral(\"input\") && !aEventName.EqualsLiteral(\"beforeinput\")"
") (" "Use DispatchInputEvent() instead" ")"); do { *((volatile
int*)__null) = 4784; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4785 return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable,
4786 aComposed, Trusted::eYes, aDefaultAction);
4787}
4788
4789// static
4790nsresult nsContentUtils::DispatchUntrustedEvent(
4791 Document* aDoc, EventTarget* aTarget, const nsAString& aEventName,
4792 CanBubble aCanBubble, Cancelable aCancelable, bool* aDefaultAction) {
4793 return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable,
4794 Composed::eDefault, Trusted::eNo, aDefaultAction);
4795}
4796
4797// static
4798nsresult nsContentUtils::DispatchEvent(Document* aDoc, EventTarget* aTarget,
4799 const nsAString& aEventName,
4800 CanBubble aCanBubble,
4801 Cancelable aCancelable,
4802 Composed aComposed, Trusted aTrusted,
4803 bool* aDefaultAction,
4804 ChromeOnlyDispatch aOnlyChromeDispatch) {
4805 if (!aDoc || !aTarget) {
4806 return NS_ERROR_INVALID_ARG;
4807 }
4808
4809 ErrorResult err;
4810 RefPtr<Event> event =
4811 GetEventWithTarget(aDoc, aTarget, aEventName, aCanBubble, aCancelable,
4812 aComposed, aTrusted, err);
4813 if (err.Failed()) {
4814 return err.StealNSResult();
4815 }
4816 event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch =
4817 aOnlyChromeDispatch == ChromeOnlyDispatch::eYes;
4818
4819 bool doDefault = aTarget->DispatchEvent(*event, CallerType::System, err);
4820 if (aDefaultAction) {
4821 *aDefaultAction = doDefault;
4822 }
4823 return err.StealNSResult();
4824}
4825
4826// static
4827nsresult nsContentUtils::DispatchEvent(Document* aDoc, EventTarget* aTarget,
4828 WidgetEvent& aEvent,
4829 EventMessage aEventMessage,
4830 CanBubble aCanBubble,
4831 Cancelable aCancelable, Trusted aTrusted,
4832 bool* aDefaultAction,
4833 ChromeOnlyDispatch aOnlyChromeDispatch) {
4834 MOZ_ASSERT_IF(aOnlyChromeDispatch == ChromeOnlyDispatch::eYes,do { if (aOnlyChromeDispatch == ChromeOnlyDispatch::eYes) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(aTrusted == Trusted::eYes)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTrusted == Trusted::eYes)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("aTrusted == Trusted::eYes"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4835); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTrusted == Trusted::eYes"
")"); do { *((volatile int*)__null) = 4835; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4835 aTrusted == Trusted::eYes)do { if (aOnlyChromeDispatch == ChromeOnlyDispatch::eYes) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(aTrusted == Trusted::eYes)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTrusted == Trusted::eYes)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("aTrusted == Trusted::eYes"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4835); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTrusted == Trusted::eYes"
")"); do { *((volatile int*)__null) = 4835; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4836
4837 aEvent.mSpecifiedEventType = GetEventTypeFromMessage(aEventMessage);
4838 aEvent.SetDefaultComposed();
4839 aEvent.SetDefaultComposedInNativeAnonymousContent();
4840
4841 aEvent.mFlags.mBubbles = aCanBubble == CanBubble::eYes;
4842 aEvent.mFlags.mCancelable = aCancelable == Cancelable::eYes;
4843 aEvent.mFlags.mOnlyChromeDispatch =
4844 aOnlyChromeDispatch == ChromeOnlyDispatch::eYes;
4845
4846 aEvent.mTarget = aTarget;
4847
4848 nsEventStatus status = nsEventStatus_eIgnore;
4849 nsresult rv = EventDispatcher::DispatchDOMEvent(aTarget, &aEvent, nullptr,
4850 nullptr, &status);
4851 if (aDefaultAction) {
4852 *aDefaultAction = (status != nsEventStatus_eConsumeNoDefault);
4853 }
4854 return rv;
4855}
4856
4857// static
4858nsresult nsContentUtils::DispatchInputEvent(Element* aEventTarget) {
4859 return DispatchInputEvent(aEventTarget, mozilla::eEditorInput,
4860 mozilla::EditorInputType::eUnknown, nullptr,
4861 InputEventOptions());
4862}
4863
4864// static
4865nsresult nsContentUtils::DispatchInputEvent(
4866 Element* aEventTargetElement, EventMessage aEventMessage,
4867 EditorInputType aEditorInputType, EditorBase* aEditorBase,
4868 InputEventOptions&& aOptions, nsEventStatus* aEventStatus /* = nullptr */) {
4869 MOZ_ASSERT(aEventMessage == eEditorInput ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEventMessage == eEditorInput || aEventMessage == eEditorBeforeInput
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aEventMessage == eEditorInput || aEventMessage == eEditorBeforeInput
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aEventMessage == eEditorInput || aEventMessage == eEditorBeforeInput"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4870); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEventMessage == eEditorInput || aEventMessage == eEditorBeforeInput"
")"); do { *((volatile int*)__null) = 4870; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4870 aEventMessage == eEditorBeforeInput)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEventMessage == eEditorInput || aEventMessage == eEditorBeforeInput
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aEventMessage == eEditorInput || aEventMessage == eEditorBeforeInput
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aEventMessage == eEditorInput || aEventMessage == eEditorBeforeInput"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4870); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEventMessage == eEditorInput || aEventMessage == eEditorBeforeInput"
")"); do { *((volatile int*)__null) = 4870; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4871
4872 if (NS_WARN_IF(!aEventTargetElement)NS_warn_if_impl(!aEventTargetElement, "!aEventTargetElement",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4872)
) {
4873 return NS_ERROR_INVALID_ARG;
4874 }
4875
4876 // If this is called from editor, the instance should be set to aEditorBase.
4877 // Otherwise, we need to look for an editor for aEventTargetElement.
4878 // However, we don't need to do it for HTMLEditor since nobody shouldn't
4879 // dispatch "beforeinput" nor "input" event for HTMLEditor except HTMLEditor
4880 // itself.
4881 bool useInputEvent = false;
4882 if (aEditorBase) {
4883 useInputEvent = true;
4884 } else if (HTMLTextAreaElement* textAreaElement =
4885 HTMLTextAreaElement::FromNode(aEventTargetElement)) {
4886 aEditorBase = textAreaElement->GetTextEditorWithoutCreation();
4887 useInputEvent = true;
4888 } else if (HTMLInputElement* inputElement =
4889 HTMLInputElement::FromNode(aEventTargetElement)) {
4890 if (inputElement->IsInputEventTarget()) {
4891 aEditorBase = inputElement->GetTextEditorWithoutCreation();
4892 useInputEvent = true;
4893 }
4894 }
4895#ifdef DEBUG1
4896 else {
4897 MOZ_ASSERT(!aEventTargetElement->IsTextControlElement(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEventTargetElement->IsTextControlElement())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aEventTargetElement->IsTextControlElement()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!aEventTargetElement->IsTextControlElement()"
" (" "The event target may have editor, but we've not known it yet."
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4898); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEventTargetElement->IsTextControlElement()"
") (" "The event target may have editor, but we've not known it yet."
")"); do { *((volatile int*)__null) = 4898; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4898 "The event target may have editor, but we've not known it yet.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEventTargetElement->IsTextControlElement())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aEventTargetElement->IsTextControlElement()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!aEventTargetElement->IsTextControlElement()"
" (" "The event target may have editor, but we've not known it yet."
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4898); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEventTargetElement->IsTextControlElement()"
") (" "The event target may have editor, but we've not known it yet."
")"); do { *((volatile int*)__null) = 4898; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4899 }
4900#endif // #ifdef DEBUG
4901
4902 if (!useInputEvent) {
4903 MOZ_ASSERT(aEventMessage == eEditorInput)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEventMessage == eEditorInput)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEventMessage == eEditorInput
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aEventMessage == eEditorInput", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4903); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEventMessage == eEditorInput"
")"); do { *((volatile int*)__null) = 4903; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4904 MOZ_ASSERT(aEditorInputType == EditorInputType::eUnknown)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEditorInputType == EditorInputType::eUnknown)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aEditorInputType == EditorInputType::eUnknown))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aEditorInputType == EditorInputType::eUnknown"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4904); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEditorInputType == EditorInputType::eUnknown"
")"); do { *((volatile int*)__null) = 4904; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4905 MOZ_ASSERT(!aOptions.mNeverCancelable)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aOptions.mNeverCancelable)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aOptions.mNeverCancelable))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aOptions.mNeverCancelable"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4905); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aOptions.mNeverCancelable"
")"); do { *((volatile int*)__null) = 4905; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4906 // Dispatch "input" event with Event instance.
4907 WidgetEvent widgetEvent(true, eUnidentifiedEvent);
4908 widgetEvent.mSpecifiedEventType = nsGkAtoms::oninput;
4909 widgetEvent.mFlags.mCancelable = false;
4910 widgetEvent.mFlags.mComposed = true;
4911 return AsyncEventDispatcher::RunDOMEventWhenSafe(*aEventTargetElement,
4912 widgetEvent, aEventStatus);
4913 }
4914
4915 MOZ_ASSERT_IF(aEventMessage != eEditorBeforeInput,do { if (aEventMessage != eEditorBeforeInput) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(!aOptions
.mNeverCancelable)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aOptions.mNeverCancelable))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aOptions.mNeverCancelable"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4916); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aOptions.mNeverCancelable"
")"); do { *((volatile int*)__null) = 4916; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4916 !aOptions.mNeverCancelable)do { if (aEventMessage != eEditorBeforeInput) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(!aOptions
.mNeverCancelable)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aOptions.mNeverCancelable))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aOptions.mNeverCancelable"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4916); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aOptions.mNeverCancelable"
")"); do { *((volatile int*)__null) = 4916; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4917 MOZ_ASSERT_IF(do { if (aEventMessage == eEditorBeforeInput && aOptions
.mNeverCancelable) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(aEditorInputType == EditorInputType::eInsertReplacementText
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aEditorInputType == EditorInputType::eInsertReplacementText
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aEditorInputType == EditorInputType::eInsertReplacementText"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4919); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEditorInputType == EditorInputType::eInsertReplacementText"
")"); do { *((volatile int*)__null) = 4919; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4918 aEventMessage == eEditorBeforeInput && aOptions.mNeverCancelable,do { if (aEventMessage == eEditorBeforeInput && aOptions
.mNeverCancelable) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(aEditorInputType == EditorInputType::eInsertReplacementText
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aEditorInputType == EditorInputType::eInsertReplacementText
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aEditorInputType == EditorInputType::eInsertReplacementText"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4919); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEditorInputType == EditorInputType::eInsertReplacementText"
")"); do { *((volatile int*)__null) = 4919; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4919 aEditorInputType == EditorInputType::eInsertReplacementText)do { if (aEventMessage == eEditorBeforeInput && aOptions
.mNeverCancelable) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(aEditorInputType == EditorInputType::eInsertReplacementText
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aEditorInputType == EditorInputType::eInsertReplacementText
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aEditorInputType == EditorInputType::eInsertReplacementText"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4919); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEditorInputType == EditorInputType::eInsertReplacementText"
")"); do { *((volatile int*)__null) = 4919; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4920
4921 nsCOMPtr<nsIWidget> widget;
4922 if (aEditorBase) {
4923 widget = aEditorBase->GetWidget();
4924 if (NS_WARN_IF(!widget)NS_warn_if_impl(!widget, "!widget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4924)
) {
4925 return NS_ERROR_FAILURE;
4926 }
4927 } else {
4928 Document* document = aEventTargetElement->OwnerDoc();
4929 if (NS_WARN_IF(!document)NS_warn_if_impl(!document, "!document", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4929)
) {
4930 return NS_ERROR_FAILURE;
4931 }
4932 // If we're running xpcshell tests, we fail to get presShell here.
4933 // Even in such case, we need to dispatch "input" event without widget.
4934 PresShell* presShell = document->GetPresShell();
4935 if (presShell) {
4936 nsPresContext* presContext = presShell->GetPresContext();
4937 if (NS_WARN_IF(!presContext)NS_warn_if_impl(!presContext, "!presContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4937)
) {
4938 return NS_ERROR_FAILURE;
4939 }
4940 widget = presContext->GetRootWidget();
4941 if (NS_WARN_IF(!widget)NS_warn_if_impl(!widget, "!widget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4941)
) {
4942 return NS_ERROR_FAILURE;
4943 }
4944 }
4945 }
4946
4947 // Dispatch "input" event with InputEvent instance.
4948 InternalEditorInputEvent inputEvent(true, aEventMessage, widget);
4949
4950 inputEvent.mFlags.mCancelable =
4951 !aOptions.mNeverCancelable && aEventMessage == eEditorBeforeInput &&
4952 IsCancelableBeforeInputEvent(aEditorInputType);
4953 MOZ_ASSERT(!inputEvent.mFlags.mCancelable || aEventStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!inputEvent.mFlags.mCancelable || aEventStatus)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!inputEvent.mFlags.mCancelable || aEventStatus))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!inputEvent.mFlags.mCancelable || aEventStatus"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4953); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inputEvent.mFlags.mCancelable || aEventStatus"
")"); do { *((volatile int*)__null) = 4953; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4954
4955 // If there is an editor, set isComposing to true when it has composition.
4956 // Note that EditorBase::IsIMEComposing() may return false even when we
4957 // need to set it to true.
4958 // Otherwise, i.e., editor hasn't been created for the element yet,
4959 // we should set isComposing to false since the element can never has
4960 // composition without editor.
4961 inputEvent.mIsComposing = aEditorBase && aEditorBase->GetComposition();
4962
4963 if (!aEditorBase || aEditorBase->IsTextEditor()) {
4964 if (IsDataAvailableOnTextEditor(aEditorInputType)) {
4965 inputEvent.mData = std::move(aOptions.mData);
4966 MOZ_ASSERT(!inputEvent.mData.IsVoid(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!inputEvent.mData.IsVoid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!inputEvent.mData.IsVoid()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!inputEvent.mData.IsVoid()"
" (" "inputEvent.mData shouldn't be void" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4967); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inputEvent.mData.IsVoid()"
") (" "inputEvent.mData shouldn't be void" ")"); do { *((volatile
int*)__null) = 4967; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
4967 "inputEvent.mData shouldn't be void")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!inputEvent.mData.IsVoid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!inputEvent.mData.IsVoid()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!inputEvent.mData.IsVoid()"
" (" "inputEvent.mData shouldn't be void" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4967); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inputEvent.mData.IsVoid()"
") (" "inputEvent.mData shouldn't be void" ")"); do { *((volatile
int*)__null) = 4967; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4968 }
4969#ifdef DEBUG1
4970 else {
4971 MOZ_ASSERT(inputEvent.mData.IsVoid(), "inputEvent.mData should be void")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(inputEvent.mData.IsVoid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(inputEvent.mData.IsVoid())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("inputEvent.mData.IsVoid()"
" (" "inputEvent.mData should be void" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4971); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inputEvent.mData.IsVoid()"
") (" "inputEvent.mData should be void" ")"); do { *((volatile
int*)__null) = 4971; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4972 }
4973#endif // #ifdef DEBUG
4974 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOptions.mTargetRanges.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aOptions.mTargetRanges.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aOptions.mTargetRanges.IsEmpty()" " (" "Target ranges for <input> and <textarea> should always be empty"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4976); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOptions.mTargetRanges.IsEmpty()"
") (" "Target ranges for <input> and <textarea> should always be empty"
")"); do { *((volatile int*)__null) = 4976; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4975 aOptions.mTargetRanges.IsEmpty(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOptions.mTargetRanges.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aOptions.mTargetRanges.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aOptions.mTargetRanges.IsEmpty()" " (" "Target ranges for <input> and <textarea> should always be empty"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4976); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOptions.mTargetRanges.IsEmpty()"
") (" "Target ranges for <input> and <textarea> should always be empty"
")"); do { *((volatile int*)__null) = 4976; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4976 "Target ranges for <input> and <textarea> should always be empty")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOptions.mTargetRanges.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aOptions.mTargetRanges.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aOptions.mTargetRanges.IsEmpty()" " (" "Target ranges for <input> and <textarea> should always be empty"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4976); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOptions.mTargetRanges.IsEmpty()"
") (" "Target ranges for <input> and <textarea> should always be empty"
")"); do { *((volatile int*)__null) = 4976; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4977 } else {
4978 MOZ_ASSERT(aEditorBase->IsHTMLEditor())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEditorBase->IsHTMLEditor())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEditorBase->IsHTMLEditor
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aEditorBase->IsHTMLEditor()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4978); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEditorBase->IsHTMLEditor()"
")"); do { *((volatile int*)__null) = 4978; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4979 if (IsDataAvailableOnHTMLEditor(aEditorInputType)) {
4980 inputEvent.mData = std::move(aOptions.mData);
4981 MOZ_ASSERT(!inputEvent.mData.IsVoid(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!inputEvent.mData.IsVoid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!inputEvent.mData.IsVoid()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!inputEvent.mData.IsVoid()"
" (" "inputEvent.mData shouldn't be void" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4982); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inputEvent.mData.IsVoid()"
") (" "inputEvent.mData shouldn't be void" ")"); do { *((volatile
int*)__null) = 4982; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
4982 "inputEvent.mData shouldn't be void")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!inputEvent.mData.IsVoid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!inputEvent.mData.IsVoid()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!inputEvent.mData.IsVoid()"
" (" "inputEvent.mData shouldn't be void" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4982); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inputEvent.mData.IsVoid()"
") (" "inputEvent.mData shouldn't be void" ")"); do { *((volatile
int*)__null) = 4982; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4983 } else {
4984 MOZ_ASSERT(inputEvent.mData.IsVoid(), "inputEvent.mData should be void")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(inputEvent.mData.IsVoid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(inputEvent.mData.IsVoid())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("inputEvent.mData.IsVoid()"
" (" "inputEvent.mData should be void" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4984); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inputEvent.mData.IsVoid()"
") (" "inputEvent.mData should be void" ")"); do { *((volatile
int*)__null) = 4984; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4985 if (IsDataTransferAvailableOnHTMLEditor(aEditorInputType)) {
4986 inputEvent.mDataTransfer = std::move(aOptions.mDataTransfer);
4987 MOZ_ASSERT(inputEvent.mDataTransfer,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(inputEvent.mDataTransfer)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(inputEvent.mDataTransfer))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("inputEvent.mDataTransfer"
" (" "inputEvent.mDataTransfer shouldn't be nullptr" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4988); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inputEvent.mDataTransfer"
") (" "inputEvent.mDataTransfer shouldn't be nullptr" ")"); do
{ *((volatile int*)__null) = 4988; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
4988 "inputEvent.mDataTransfer shouldn't be nullptr")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(inputEvent.mDataTransfer)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(inputEvent.mDataTransfer))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("inputEvent.mDataTransfer"
" (" "inputEvent.mDataTransfer shouldn't be nullptr" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4988); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inputEvent.mDataTransfer"
") (" "inputEvent.mDataTransfer shouldn't be nullptr" ")"); do
{ *((volatile int*)__null) = 4988; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4989 MOZ_ASSERT(inputEvent.mDataTransfer->IsReadOnly(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(inputEvent.mDataTransfer->IsReadOnly())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(inputEvent.mDataTransfer->IsReadOnly()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("inputEvent.mDataTransfer->IsReadOnly()"
" (" "inputEvent.mDataTransfer should be read only" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4990); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inputEvent.mDataTransfer->IsReadOnly()"
") (" "inputEvent.mDataTransfer should be read only" ")"); do
{ *((volatile int*)__null) = 4990; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
4990 "inputEvent.mDataTransfer should be read only")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(inputEvent.mDataTransfer->IsReadOnly())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(inputEvent.mDataTransfer->IsReadOnly()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("inputEvent.mDataTransfer->IsReadOnly()"
" (" "inputEvent.mDataTransfer should be read only" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4990); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inputEvent.mDataTransfer->IsReadOnly()"
") (" "inputEvent.mDataTransfer should be read only" ")"); do
{ *((volatile int*)__null) = 4990; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4991 }
4992#ifdef DEBUG1
4993 else {
4994 MOZ_ASSERT(!inputEvent.mDataTransfer,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!inputEvent.mDataTransfer)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!inputEvent.mDataTransfer)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("!inputEvent.mDataTransfer"
" (" "inputEvent.mDataTransfer should be nullptr" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4995); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inputEvent.mDataTransfer"
") (" "inputEvent.mDataTransfer should be nullptr" ")"); do {
*((volatile int*)__null) = 4995; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
4995 "inputEvent.mDataTransfer should be nullptr")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!inputEvent.mDataTransfer)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!inputEvent.mDataTransfer)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("!inputEvent.mDataTransfer"
" (" "inputEvent.mDataTransfer should be nullptr" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 4995); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inputEvent.mDataTransfer"
") (" "inputEvent.mDataTransfer should be nullptr" ")"); do {
*((volatile int*)__null) = 4995; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4996 }
4997#endif // #ifdef DEBUG
4998 }
4999 if (aEventMessage == eEditorBeforeInput &&
5000 MayHaveTargetRangesOnHTMLEditor(aEditorInputType)) {
5001 inputEvent.mTargetRanges = std::move(aOptions.mTargetRanges);
5002 }
5003#ifdef DEBUG1
5004 else {
5005 MOZ_ASSERT(aOptions.mTargetRanges.IsEmpty(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOptions.mTargetRanges.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aOptions.mTargetRanges.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aOptions.mTargetRanges.IsEmpty()" " (" "Target ranges shouldn't be set for the dispatching event"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5006); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOptions.mTargetRanges.IsEmpty()"
") (" "Target ranges shouldn't be set for the dispatching event"
")"); do { *((volatile int*)__null) = 5006; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5006 "Target ranges shouldn't be set for the dispatching event")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOptions.mTargetRanges.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aOptions.mTargetRanges.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aOptions.mTargetRanges.IsEmpty()" " (" "Target ranges shouldn't be set for the dispatching event"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5006); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOptions.mTargetRanges.IsEmpty()"
") (" "Target ranges shouldn't be set for the dispatching event"
")"); do { *((volatile int*)__null) = 5006; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5007 }
5008#endif // #ifdef DEBUG
5009 }
5010
5011 inputEvent.mInputType = aEditorInputType;
5012
5013 // If we cannot dispatch an event right now, we cannot make it cancelable.
5014 if (!nsContentUtils::IsSafeToRunScript()) {
5015 NS_ASSERTION(do { if (!(!inputEvent.mFlags.mCancelable)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Cancelable beforeinput event dispatcher should run when it's safe"
, "!inputEvent.mFlags.mCancelable", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5017); MOZ_PretendNoReturn(); } } while (0)
5016 !inputEvent.mFlags.mCancelable,do { if (!(!inputEvent.mFlags.mCancelable)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Cancelable beforeinput event dispatcher should run when it's safe"
, "!inputEvent.mFlags.mCancelable", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5017); MOZ_PretendNoReturn(); } } while (0)
5017 "Cancelable beforeinput event dispatcher should run when it's safe")do { if (!(!inputEvent.mFlags.mCancelable)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Cancelable beforeinput event dispatcher should run when it's safe"
, "!inputEvent.mFlags.mCancelable", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5017); MOZ_PretendNoReturn(); } } while (0)
;
5018 inputEvent.mFlags.mCancelable = false;
5019 }
5020 return AsyncEventDispatcher::RunDOMEventWhenSafe(*aEventTargetElement,
5021 inputEvent, aEventStatus);
5022}
5023
5024nsresult nsContentUtils::DispatchChromeEvent(
5025 Document* aDoc, EventTarget* aTarget, const nsAString& aEventName,
5026 CanBubble aCanBubble, Cancelable aCancelable, bool* aDefaultAction) {
5027 if (!aDoc || !aTarget) {
5028 return NS_ERROR_INVALID_ARG;
5029 }
5030
5031 if (!aDoc->GetWindow()) {
5032 return NS_ERROR_INVALID_ARG;
5033 }
5034
5035 EventTarget* piTarget = aDoc->GetWindow()->GetParentTarget();
5036 if (!piTarget) {
5037 return NS_ERROR_INVALID_ARG;
5038 }
5039
5040 ErrorResult err;
5041 RefPtr<Event> event =
5042 GetEventWithTarget(aDoc, aTarget, aEventName, aCanBubble, aCancelable,
5043 Composed::eDefault, Trusted::eYes, err);
5044 if (err.Failed()) {
5045 return err.StealNSResult();
5046 }
5047
5048 bool defaultActionEnabled =
5049 piTarget->DispatchEvent(*event, CallerType::System, err);
5050 if (aDefaultAction) {
5051 *aDefaultAction = defaultActionEnabled;
5052 }
5053 return err.StealNSResult();
5054}
5055
5056void nsContentUtils::RequestFrameFocus(Element& aFrameElement, bool aCanRaise,
5057 CallerType aCallerType) {
5058 RefPtr<Element> target = &aFrameElement;
5059 bool defaultAction = true;
5060 if (aCanRaise) {
5061 DispatchEventOnlyToChrome(target->OwnerDoc(), target,
5062 u"framefocusrequested"_ns, CanBubble::eYes,
5063 Cancelable::eYes, &defaultAction);
5064 }
5065 if (!defaultAction) {
5066 return;
5067 }
5068
5069 RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager();
5070 if (!fm) {
5071 return;
5072 }
5073
5074 uint32_t flags = nsIFocusManager::FLAG_NOSCROLL;
5075 if (aCanRaise) {
5076 flags |= nsIFocusManager::FLAG_RAISE;
5077 }
5078
5079 if (aCallerType == CallerType::NonSystem) {
5080 flags |= nsIFocusManager::FLAG_NONSYSTEMCALLER;
5081 }
5082
5083 fm->SetFocus(target, flags);
5084}
5085
5086nsresult nsContentUtils::DispatchEventOnlyToChrome(
5087 Document* aDoc, EventTarget* aTarget, const nsAString& aEventName,
5088 CanBubble aCanBubble, Cancelable aCancelable, Composed aComposed,
5089 bool* aDefaultAction) {
5090 return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable,
5091 aComposed, Trusted::eYes, aDefaultAction,
5092 ChromeOnlyDispatch::eYes);
5093}
5094
5095/* static */
5096Element* nsContentUtils::MatchElementId(nsIContent* aContent,
5097 const nsAtom* aId) {
5098 for (nsIContent* cur = aContent; cur; cur = cur->GetNextNode(aContent)) {
5099 if (aId == cur->GetID()) {
5100 return cur->AsElement();
5101 }
5102 }
5103
5104 return nullptr;
5105}
5106
5107/* static */
5108Element* nsContentUtils::MatchElementId(nsIContent* aContent,
5109 const nsAString& aId) {
5110 MOZ_ASSERT(!aId.IsEmpty(), "Will match random elements")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aId.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aId.IsEmpty()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!aId.IsEmpty()"
" (" "Will match random elements" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5110); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aId.IsEmpty()"
") (" "Will match random elements" ")"); do { *((volatile int
*)__null) = 5110; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
5111
5112 // ID attrs are generally stored as atoms, so just atomize this up front
5113 RefPtr<nsAtom> id(NS_Atomize(aId));
5114 if (!id) {
5115 // OOM, so just bail
5116 return nullptr;
5117 }
5118
5119 return MatchElementId(aContent, id);
5120}
5121
5122/* static */
5123void nsContentUtils::RegisterShutdownObserver(nsIObserver* aObserver) {
5124 nsCOMPtr<nsIObserverService> observerService =
5125 mozilla::services::GetObserverService();
5126 if (observerService) {
5127 observerService->AddObserver(aObserver, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown",
5128 false);
5129 }
5130}
5131
5132/* static */
5133void nsContentUtils::UnregisterShutdownObserver(nsIObserver* aObserver) {
5134 nsCOMPtr<nsIObserverService> observerService =
5135 mozilla::services::GetObserverService();
5136 if (observerService) {
5137 observerService->RemoveObserver(aObserver, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown");
5138 }
5139}
5140
5141/* static */
5142bool nsContentUtils::HasNonEmptyAttr(const nsIContent* aContent,
5143 int32_t aNameSpaceID, nsAtom* aName) {
5144 static AttrArray::AttrValuesArray strings[] = {nsGkAtoms::_empty, nullptr};
5145 return aContent->IsElement() &&
5146 aContent->AsElement()->FindAttrValueIn(aNameSpaceID, aName, strings,
5147 eCaseMatters) ==
5148 AttrArray::ATTR_VALUE_NO_MATCH;
5149}
5150
5151/* static */
5152bool nsContentUtils::WantMutationEvents(nsINode* aNode, uint32_t aType,
5153 nsINode* aTargetForSubtreeModified) {
5154 Document* doc = aNode->OwnerDoc();
5155 if (!doc->MutationEventsEnabled()) {
5156 return false;
5157 }
5158
5159 if (!doc->FireMutationEvents()) {
5160 return false;
5161 }
5162
5163 // global object will be null for documents that don't have windows.
5164 nsPIDOMWindowInner* window = doc->GetInnerWindow();
5165 // This relies on EventListenerManager::AddEventListener, which sets
5166 // all mutation bits when there is a listener for DOMSubtreeModified event.
5167 if (window && !window->HasMutationListeners(aType)) {
5168 return false;
5169 }
5170
5171 if (aNode->ChromeOnlyAccess() || aNode->IsInShadowTree()) {
5172 return false;
5173 }
5174
5175 doc->MayDispatchMutationEvent(aTargetForSubtreeModified);
5176
5177 // If we have a window, we can check it for mutation listeners now.
5178 if (aNode->IsInUncomposedDoc()) {
5179 nsCOMPtr<EventTarget> piTarget(do_QueryInterface(window));
5180 if (piTarget) {
5181 EventListenerManager* manager = piTarget->GetExistingListenerManager();
5182 if (manager && manager->HasMutationListeners()) {
5183 return true;
5184 }
5185 }
5186 }
5187
5188 // If we have a window, we know a mutation listener is registered, but it
5189 // might not be in our chain. If we don't have a window, we might have a
5190 // mutation listener. Check quickly to see.
5191 while (aNode) {
5192 EventListenerManager* manager = aNode->GetExistingListenerManager();
5193 if (manager && manager->HasMutationListeners()) {
5194 return true;
5195 }
5196
5197 aNode = aNode->GetParentNode();
5198 }
5199
5200 return false;
5201}
5202
5203/* static */
5204bool nsContentUtils::HasMutationListeners(Document* aDocument, uint32_t aType) {
5205 nsPIDOMWindowInner* window =
5206 aDocument ? aDocument->GetInnerWindow() : nullptr;
5207
5208 // This relies on EventListenerManager::AddEventListener, which sets
5209 // all mutation bits when there is a listener for DOMSubtreeModified event.
5210 return !window || window->HasMutationListeners(aType);
5211}
5212
5213void nsContentUtils::MaybeFireNodeRemoved(nsINode* aChild, nsINode* aParent) {
5214 MOZ_ASSERT(aChild, "Missing child")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aChild))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aChild" " (" "Missing child"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5214); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild" ") ("
"Missing child" ")"); do { *((volatile int*)__null) = 5214; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
5215 MOZ_ASSERT(aChild->GetParentNode() == aParent, "Wrong parent")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild->GetParentNode() == aParent)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(aChild->GetParentNode() == aParent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aChild->GetParentNode() == aParent"
" (" "Wrong parent" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5215); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->GetParentNode() == aParent"
") (" "Wrong parent" ")"); do { *((volatile int*)__null) = 5215
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
5216 MOZ_ASSERT(aChild->OwnerDoc() == aParent->OwnerDoc(), "Wrong owner-doc")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild->OwnerDoc() == aParent->OwnerDoc())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aChild->OwnerDoc() == aParent->OwnerDoc()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aChild->OwnerDoc() == aParent->OwnerDoc()"
" (" "Wrong owner-doc" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5216); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->OwnerDoc() == aParent->OwnerDoc()"
") (" "Wrong owner-doc" ")"); do { *((volatile int*)__null) =
5216; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
5217
5218 // Having an explicit check here since it's an easy mistake to fall into,
5219 // and there might be existing code with problems. We'd rather be safe
5220 // than fire DOMNodeRemoved in all corner cases. We also rely on it for
5221 // nsAutoScriptBlockerSuppressNodeRemoved.
5222 if (!IsSafeToRunScript()) {
5223 // This checks that IsSafeToRunScript is true since we don't want to fire
5224 // events when that is false. We can't rely on EventDispatcher to assert
5225 // this in this situation since most of the time there are no mutation
5226 // event listeners, in which case we won't even attempt to dispatch events.
5227 // However this also allows for two exceptions. First off, we don't assert
5228 // if the mutation happens to native anonymous content since we never fire
5229 // mutation events on such content anyway.
5230 // Second, we don't assert if sDOMNodeRemovedSuppressCount is true since
5231 // that is a know case when we'd normally fire a mutation event, but can't
5232 // make that safe and so we suppress it at this time. Ideally this should
5233 // go away eventually.
5234 if (!aChild->IsInNativeAnonymousSubtree() &&
5235 !sDOMNodeRemovedSuppressCount) {
5236 NS_ERROR("Want to fire DOMNodeRemoved event, but it's not safe")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Want to fire DOMNodeRemoved event, but it's not safe"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5236); MOZ_PretendNoReturn(); } while (0)
;
5237 WarnScriptWasIgnored(aChild->OwnerDoc());
5238 }
5239 return;
5240 }
5241
5242 {
5243 Document* doc = aParent->OwnerDoc();
5244 if (MOZ_UNLIKELY(doc->DevToolsWatchingDOMMutations())(__builtin_expect(!!(doc->DevToolsWatchingDOMMutations()),
0))
&&
5245 aChild->IsInComposedDoc() && !aChild->ChromeOnlyAccess()) {
5246 DispatchChromeEvent(doc, aChild, u"devtoolschildremoved"_ns,
5247 CanBubble::eNo, Cancelable::eNo);
5248 }
5249 }
5250
5251 if (WantMutationEvents(aChild, NS_EVENT_BITS_MUTATION_NODEREMOVED0x04, aParent)) {
5252 InternalMutationEvent mutation(true, eLegacyNodeRemoved);
5253 mutation.mRelatedNode = aParent;
5254
5255 mozAutoSubtreeModified subtree(aParent->OwnerDoc(), aParent);
5256 EventDispatcher::Dispatch(aChild, nullptr, &mutation);
5257 }
5258}
5259
5260void nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments() {
5261 if (!sEventListenerManagersHash) {
5262 return;
5263 }
5264
5265 for (auto i = sEventListenerManagersHash->Iter(); !i.Done(); i.Next()) {
5266 auto entry = static_cast<EventListenerManagerMapEntry*>(i.Get());
5267 nsINode* n = static_cast<nsINode*>(entry->mListenerManager->GetTarget());
5268 if (n && n->IsInComposedDoc() &&
5269 nsCCUncollectableMarker::InGeneration(
5270 n->OwnerDoc()->GetMarkedCCGeneration())) {
5271 entry->mListenerManager->MarkForCC();
5272 }
5273 }
5274}
5275
5276/* static */
5277void nsContentUtils::TraverseListenerManager(
5278 nsINode* aNode, nsCycleCollectionTraversalCallback& cb) {
5279 if (!sEventListenerManagersHash) {
5280 // We're already shut down, just return.
5281 return;
5282 }
5283
5284 auto entry = static_cast<EventListenerManagerMapEntry*>(
5285 sEventListenerManagersHash->Search(aNode));
5286 if (entry) {
5287 CycleCollectionNoteChild(cb, entry->mListenerManager.get(),
5288 "[via hash] mListenerManager");
5289 }
5290}
5291
5292EventListenerManager* nsContentUtils::GetListenerManagerForNode(
5293 nsINode* aNode) {
5294 if (!sEventListenerManagersHash) {
5295 // We're already shut down, don't bother creating an event listener
5296 // manager.
5297
5298 return nullptr;
5299 }
5300
5301 auto entry = static_cast<EventListenerManagerMapEntry*>(
5302 sEventListenerManagersHash->Add(aNode, fallible));
5303
5304 if (!entry) {
5305 return nullptr;
5306 }
5307
5308 if (!entry->mListenerManager) {
5309 entry->mListenerManager = new EventListenerManager(aNode);
5310
5311 aNode->SetFlags(NODE_HAS_LISTENERMANAGER);
5312 }
5313
5314 return entry->mListenerManager;
5315}
5316
5317EventListenerManager* nsContentUtils::GetExistingListenerManagerForNode(
5318 const nsINode* aNode) {
5319 if (!aNode->HasFlag(NODE_HAS_LISTENERMANAGER)) {
5320 return nullptr;
5321 }
5322
5323 if (!sEventListenerManagersHash) {
5324 // We're already shut down, don't bother creating an event listener
5325 // manager.
5326
5327 return nullptr;
5328 }
5329
5330 auto entry = static_cast<EventListenerManagerMapEntry*>(
5331 sEventListenerManagersHash->Search(aNode));
5332 if (entry) {
5333 return entry->mListenerManager;
5334 }
5335
5336 return nullptr;
5337}
5338
5339void nsContentUtils::AddEntryToDOMArenaTable(nsINode* aNode,
5340 DOMArena* aDOMArena) {
5341 MOZ_ASSERT(StaticPrefs::dom_arena_allocator_enabled_AtStartup())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(StaticPrefs::dom_arena_allocator_enabled_AtStartup()
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(StaticPrefs::dom_arena_allocator_enabled_AtStartup()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"StaticPrefs::dom_arena_allocator_enabled_AtStartup()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5341); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::dom_arena_allocator_enabled_AtStartup()"
")"); do { *((volatile int*)__null) = 5341; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5342 MOZ_ASSERT_IF(sDOMArenaHashtable, !sDOMArenaHashtable->Contains(aNode))do { if (sDOMArenaHashtable) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(!sDOMArenaHashtable->
Contains(aNode))>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(!sDOMArenaHashtable->Contains
(aNode)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!sDOMArenaHashtable->Contains(aNode)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5342); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sDOMArenaHashtable->Contains(aNode)"
")"); do { *((volatile int*)__null) = 5342; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
5343 MOZ_ASSERT(!aNode->HasFlag(NODE_KEEPS_DOMARENA))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aNode->HasFlag(NODE_KEEPS_DOMARENA))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aNode->HasFlag(NODE_KEEPS_DOMARENA)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!aNode->HasFlag(NODE_KEEPS_DOMARENA)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5343); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aNode->HasFlag(NODE_KEEPS_DOMARENA)"
")"); do { *((volatile int*)__null) = 5343; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5344 if (!sDOMArenaHashtable) {
5345 sDOMArenaHashtable =
5346 new nsRefPtrHashtable<nsPtrHashKey<const nsINode>, dom::DOMArena>();
5347 }
5348 aNode->SetFlags(NODE_KEEPS_DOMARENA);
5349 sDOMArenaHashtable->InsertOrUpdate(aNode, RefPtr<DOMArena>(aDOMArena));
5350}
5351
5352already_AddRefed<DOMArena> nsContentUtils::TakeEntryFromDOMArenaTable(
5353 const nsINode* aNode) {
5354 MOZ_ASSERT(sDOMArenaHashtable->Contains(aNode))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sDOMArenaHashtable->Contains(aNode))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(sDOMArenaHashtable->Contains(aNode)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("sDOMArenaHashtable->Contains(aNode)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5354); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sDOMArenaHashtable->Contains(aNode)"
")"); do { *((volatile int*)__null) = 5354; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5355 MOZ_ASSERT(StaticPrefs::dom_arena_allocator_enabled_AtStartup())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(StaticPrefs::dom_arena_allocator_enabled_AtStartup()
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(StaticPrefs::dom_arena_allocator_enabled_AtStartup()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"StaticPrefs::dom_arena_allocator_enabled_AtStartup()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5355); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::dom_arena_allocator_enabled_AtStartup()"
")"); do { *((volatile int*)__null) = 5355; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5356 RefPtr<DOMArena> arena;
5357 sDOMArenaHashtable->Remove(aNode, getter_AddRefs(arena));
5358 return arena.forget();
5359}
5360
5361/* static */
5362void nsContentUtils::RemoveListenerManager(nsINode* aNode) {
5363 if (sEventListenerManagersHash) {
5364 auto entry = static_cast<EventListenerManagerMapEntry*>(
5365 sEventListenerManagersHash->Search(aNode));
5366 if (entry) {
5367 RefPtr<EventListenerManager> listenerManager;
5368 listenerManager.swap(entry->mListenerManager);
5369 // Remove the entry and *then* do operations that could cause further
5370 // modification of sEventListenerManagersHash. See bug 334177.
5371 sEventListenerManagersHash->RawRemove(entry);
5372 if (listenerManager) {
5373 listenerManager->Disconnect();
5374 }
5375 }
5376 }
5377}
5378
5379/* static */
5380bool nsContentUtils::IsValidNodeName(nsAtom* aLocalName, nsAtom* aPrefix,
5381 int32_t aNamespaceID) {
5382 if (aNamespaceID == kNameSpaceID_Unknown-1) {
5383 return false;
5384 }
5385
5386 if (!aPrefix) {
5387 // If the prefix is null, then either the QName must be xmlns or the
5388 // namespace must not be XMLNS.
5389 return (aLocalName == nsGkAtoms::xmlns) ==
5390 (aNamespaceID == kNameSpaceID_XMLNS1);
5391 }
5392
5393 // If the prefix is non-null then the namespace must not be null.
5394 if (aNamespaceID == kNameSpaceID_None) {
5395 return false;
5396 }
5397
5398 // If the namespace is the XMLNS namespace then the prefix must be xmlns,
5399 // but the localname must not be xmlns.
5400 if (aNamespaceID == kNameSpaceID_XMLNS1) {
5401 return aPrefix == nsGkAtoms::xmlns && aLocalName != nsGkAtoms::xmlns;
5402 }
5403
5404 // If the namespace is not the XMLNS namespace then the prefix must not be
5405 // xmlns.
5406 // If the namespace is the XML namespace then the prefix can be anything.
5407 // If the namespace is not the XML namespace then the prefix must not be xml.
5408 return aPrefix != nsGkAtoms::xmlns &&
5409 (aNamespaceID == kNameSpaceID_XML2 || aPrefix != nsGkAtoms::xml);
5410}
5411
5412already_AddRefed<DocumentFragment> nsContentUtils::CreateContextualFragment(
5413 nsINode* aContextNode, const nsAString& aFragment,
5414 bool aPreventScriptExecution, ErrorResult& aRv) {
5415 if (!aContextNode) {
5416 aRv.Throw(NS_ERROR_INVALID_ARG);
5417 return nullptr;
5418 }
5419
5420 // If we don't have a document here, we can't get the right security context
5421 // for compiling event handlers... so just bail out.
5422 RefPtr<Document> document = aContextNode->OwnerDoc();
5423 bool isHTML = document->IsHTMLDocument();
5424
5425 if (isHTML) {
5426 RefPtr<DocumentFragment> frag = new (document->NodeInfoManager())
5427 DocumentFragment(document->NodeInfoManager());
5428
5429 Element* element = aContextNode->GetAsElementOrParentElement();
5430 if (element && !element->IsHTMLElement(nsGkAtoms::html)) {
5431 aRv = ParseFragmentHTML(
5432 aFragment, frag, element->NodeInfo()->NameAtom(),
5433 element->GetNameSpaceID(),
5434 (document->GetCompatibilityMode() == eCompatibility_NavQuirks),
5435 aPreventScriptExecution);
5436 } else {
5437 aRv = ParseFragmentHTML(
5438 aFragment, frag, nsGkAtoms::body, kNameSpaceID_XHTML3,
5439 (document->GetCompatibilityMode() == eCompatibility_NavQuirks),
5440 aPreventScriptExecution);
5441 }
5442
5443 return frag.forget();
5444 }
5445
5446 AutoTArray<nsString, 32> tagStack;
5447 nsAutoString uriStr, nameStr;
5448 for (Element* element : aContextNode->InclusiveAncestorsOfType<Element>()) {
5449 nsString& tagName = *tagStack.AppendElement();
5450 // It mostly doesn't actually matter what tag name we use here: XML doesn't
5451 // have parsing that depends on the open tag stack, apart from namespace
5452 // declarations. So this whole tagStack bit is just there to get the right
5453 // namespace declarations to the XML parser. That said, the parser _is_
5454 // going to create elements with the tag names we provide here, so we need
5455 // to make sure they are not names that can trigger custom element
5456 // constructors. Just make up a name that is never going to be a valid
5457 // custom element name.
5458 //
5459 // The principled way to do this would probably be to add a new FromParser
5460 // value and make sure we use it when creating the context elements, then
5461 // make sure we teach all FromParser consumers (and in particular the custom
5462 // element code) about it as needed. But right now the XML parser never
5463 // actually uses FromParser values other than NOT_FROM_PARSER, and changing
5464 // that is pretty complicated.
5465 tagName.AssignLiteral("notacustomelement");
5466
5467 // see if we need to add xmlns declarations
5468 uint32_t count = element->GetAttrCount();
5469 bool setDefaultNamespace = false;
5470 if (count > 0) {
5471 uint32_t index;
5472
5473 for (index = 0; index < count; index++) {
5474 const BorrowedAttrInfo info = element->GetAttrInfoAt(index);
5475 const nsAttrName* name = info.mName;
5476 if (name->NamespaceEquals(kNameSpaceID_XMLNS1)) {
5477 info.mValue->ToString(uriStr);
5478
5479 // really want something like nsXMLContentSerializer::SerializeAttr
5480 tagName.AppendLiteral(" xmlns"); // space important
5481 if (name->GetPrefix()) {
5482 tagName.Append(char16_t(':'));
5483 name->LocalName()->ToString(nameStr);
5484 tagName.Append(nameStr);
5485 } else {
5486 setDefaultNamespace = true;
5487 }
5488 tagName.AppendLiteral(R"(=")");
5489 tagName.Append(uriStr);
5490 tagName.Append('"');
5491 }
5492 }
5493 }
5494
5495 if (!setDefaultNamespace) {
5496 mozilla::dom::NodeInfo* info = element->NodeInfo();
5497 if (!info->GetPrefixAtom() && info->NamespaceID() != kNameSpaceID_None) {
5498 // We have no namespace prefix, but have a namespace ID. Push
5499 // default namespace attr in, so that our kids will be in our
5500 // namespace.
5501 info->GetNamespaceURI(uriStr);
5502 tagName.AppendLiteral(R"( xmlns=")");
5503 tagName.Append(uriStr);
5504 tagName.Append('"');
5505 }
5506 }
5507 }
5508
5509 RefPtr<DocumentFragment> frag;
5510 aRv = ParseFragmentXML(aFragment, document, tagStack, aPreventScriptExecution,
5511 -1, getter_AddRefs(frag));
5512 return frag.forget();
5513}
5514
5515/* static */
5516void nsContentUtils::DropFragmentParsers() {
5517 NS_IF_RELEASE(sHTMLFragmentParser)do { if (sHTMLFragmentParser) { (sHTMLFragmentParser)->Release
(); (sHTMLFragmentParser) = 0; } } while (0)
;
5518 NS_IF_RELEASE(sXMLFragmentParser)do { if (sXMLFragmentParser) { (sXMLFragmentParser)->Release
(); (sXMLFragmentParser) = 0; } } while (0)
;
5519 NS_IF_RELEASE(sXMLFragmentSink)do { if (sXMLFragmentSink) { (sXMLFragmentSink)->Release()
; (sXMLFragmentSink) = 0; } } while (0)
;
5520}
5521
5522/* static */
5523void nsContentUtils::XPCOMShutdown() { nsContentUtils::DropFragmentParsers(); }
5524
5525/* Helper function to compuate Sanitization Flags for ParseFramentHTML/XML */
5526uint32_t computeSanitizationFlags(nsIPrincipal* aPrincipal, int32_t aFlags) {
5527 uint32_t sanitizationFlags = 0;
5528 if (aPrincipal->IsSystemPrincipal()) {
5529 if (aFlags < 0) {
5530 // if this is a chrome-privileged document and no explicit flags
5531 // were passed, then use this sanitization flags.
5532 sanitizationFlags = nsIParserUtils::SanitizerAllowStyle |
5533 nsIParserUtils::SanitizerAllowComments |
5534 nsIParserUtils::SanitizerDropForms |
5535 nsIParserUtils::SanitizerLogRemovals;
5536 } else {
5537 // if the caller explicitly passes flags, then we use those
5538 // flags but additionally drop forms.
5539 sanitizationFlags = aFlags | nsIParserUtils::SanitizerDropForms;
5540 }
5541 } else if (aFlags >= 0) {
5542 // aFlags by default is -1 and is only ever non equal to -1 if the
5543 // caller of ParseFragmentHTML/ParseFragmentXML is
5544 // ParserUtils::ParseFragment(). Only in that case we should use
5545 // the sanitization flags passed within aFlags.
5546 sanitizationFlags = aFlags;
5547 }
5548 return sanitizationFlags;
5549}
5550
5551/* static */
5552void nsContentUtils::SetHTMLUnsafe(FragmentOrElement* aTarget,
5553 Element* aContext,
5554 const nsAString& aSource) {
5555 RefPtr<DocumentFragment> fragment;
5556 {
5557 MOZ_ASSERT(!sFragmentParsingActive,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!sFragmentParsingActive)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!sFragmentParsingActive))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!sFragmentParsingActive"
" (" "Re-entrant fragment parsing attempted." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5558); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sFragmentParsingActive"
") (" "Re-entrant fragment parsing attempted." ")"); do { *(
(volatile int*)__null) = 5558; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
5558 "Re-entrant fragment parsing attempted.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!sFragmentParsingActive)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!sFragmentParsingActive))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!sFragmentParsingActive"
" (" "Re-entrant fragment parsing attempted." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5558); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sFragmentParsingActive"
") (" "Re-entrant fragment parsing attempted." ")"); do { *(
(volatile int*)__null) = 5558; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
5559 mozilla::AutoRestore<bool> guard(sFragmentParsingActive);
5560 sFragmentParsingActive = true;
5561 if (!sHTMLFragmentParser) {
5562 NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser())(sHTMLFragmentParser = new nsHtml5StringParser())->AddRef(
)
;
5563 // Now sHTMLFragmentParser owns the object
5564 }
5565
5566 nsAtom* contextLocalName = aContext->NodeInfo()->NameAtom();
5567 int32_t contextNameSpaceID = aContext->GetNameSpaceID();
5568
5569 RefPtr<Document> doc = aTarget->OwnerDoc();
5570 fragment = doc->CreateDocumentFragment();
5571 nsresult rv = sHTMLFragmentParser->ParseFragment(
5572 aSource, fragment, contextLocalName, contextNameSpaceID,
5573 fragment->OwnerDoc()->GetCompatibilityMode() ==
5574 eCompatibility_NavQuirks,
5575 true, true);
5576 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5577 NS_WARNING("Failed to parse fragment for SetHTMLUnsafe")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to parse fragment for SetHTMLUnsafe"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5577)
;
5578 }
5579 }
5580
5581 aTarget->ReplaceChildren(fragment, IgnoreErrors());
5582}
5583
5584/* static */
5585nsresult nsContentUtils::ParseFragmentHTML(
5586 const nsAString& aSourceBuffer, nsIContent* aTargetNode,
5587 nsAtom* aContextLocalName, int32_t aContextNamespace, bool aQuirks,
5588 bool aPreventScriptExecution, int32_t aFlags) {
5589 if (nsContentUtils::sFragmentParsingActive) {
5590 MOZ_ASSERT_UNREACHABLE("Re-entrant fragment parsing attempted.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Re-entrant fragment parsing attempted." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5590); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Re-entrant fragment parsing attempted."
")"); do { *((volatile int*)__null) = 5590; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5591 return NS_ERROR_DOM_INVALID_STATE_ERR;
5592 }
5593 mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
5594 nsContentUtils::sFragmentParsingActive = true;
5595 if (!sHTMLFragmentParser) {
5596 NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser())(sHTMLFragmentParser = new nsHtml5StringParser())->AddRef(
)
;
5597 // Now sHTMLFragmentParser owns the object
5598 }
5599
5600 nsCOMPtr<nsIPrincipal> nodePrincipal = aTargetNode->NodePrincipal();
5601
5602#ifdef DEBUG1
5603 // aFlags should always be -1 unless the caller of ParseFragmentHTML
5604 // is ParserUtils::ParseFragment() which is the only caller that intends
5605 // sanitization. For all other callers we need to ensure to call
5606 // AuditParsingOfHTMLXMLFragments.
5607 if (aFlags < 0) {
5608 DOMSecurityMonitor::AuditParsingOfHTMLXMLFragments(nodePrincipal,
5609 aSourceBuffer);
5610 }
5611#endif
5612
5613 nsIContent* target = aTargetNode;
5614
5615 RefPtr<Document> doc = aTargetNode->OwnerDoc();
5616 RefPtr<DocumentFragment> fragment;
5617 // We sanitize if the fragment occurs in a system privileged
5618 // context, an about: page, or if there are explicit sanitization flags.
5619 // Please note that about:blank and about:srcdoc inherit the security
5620 // context from the embedding context and hence are not loaded using
5621 // an about: scheme principal.
5622 bool shouldSanitize = nodePrincipal->IsSystemPrincipal() ||
5623 nodePrincipal->SchemeIs("about") || aFlags >= 0;
5624 if (shouldSanitize) {
5625 if (!doc->IsLoadedAsData()) {
5626 doc = nsContentUtils::CreateInertHTMLDocument(doc);
5627 if (!doc) {
5628 return NS_ERROR_FAILURE;
5629 }
5630 }
5631 fragment =
5632 new (doc->NodeInfoManager()) DocumentFragment(doc->NodeInfoManager());
5633 target = fragment;
5634 }
5635
5636 nsresult rv = sHTMLFragmentParser->ParseFragment(
5637 aSourceBuffer, target, aContextLocalName, aContextNamespace, aQuirks,
5638 aPreventScriptExecution, false);
5639 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5639); return rv; } } while (false)
;
5640
5641 if (fragment) {
5642 uint32_t sanitizationFlags =
5643 computeSanitizationFlags(nodePrincipal, aFlags);
5644 // Don't fire mutation events for nodes removed by the sanitizer.
5645 nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
5646 nsTreeSanitizer sanitizer(sanitizationFlags);
5647 sanitizer.Sanitize(fragment);
5648
5649 ErrorResult error;
5650 aTargetNode->AppendChild(*fragment, error);
5651 rv = error.StealNSResult();
5652 }
5653
5654 return rv;
5655}
5656
5657/* static */
5658nsresult nsContentUtils::ParseDocumentHTML(
5659 const nsAString& aSourceBuffer, Document* aTargetDocument,
5660 bool aScriptingEnabledForNoscriptParsing) {
5661 if (nsContentUtils::sFragmentParsingActive) {
5662 MOZ_ASSERT_UNREACHABLE("Re-entrant fragment parsing attempted.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Re-entrant fragment parsing attempted." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5662); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Re-entrant fragment parsing attempted."
")"); do { *((volatile int*)__null) = 5662; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5663 return NS_ERROR_DOM_INVALID_STATE_ERR;
5664 }
5665 mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
5666 nsContentUtils::sFragmentParsingActive = true;
5667 if (!sHTMLFragmentParser) {
5668 NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser())(sHTMLFragmentParser = new nsHtml5StringParser())->AddRef(
)
;
5669 // Now sHTMLFragmentParser owns the object
5670 }
5671 nsresult rv = sHTMLFragmentParser->ParseDocument(
5672 aSourceBuffer, aTargetDocument, aScriptingEnabledForNoscriptParsing);
5673 return rv;
5674}
5675
5676/* static */
5677nsresult nsContentUtils::ParseFragmentXML(const nsAString& aSourceBuffer,
5678 Document* aDocument,
5679 nsTArray<nsString>& aTagStack,
5680 bool aPreventScriptExecution,
5681 int32_t aFlags,
5682 DocumentFragment** aReturn) {
5683 if (nsContentUtils::sFragmentParsingActive) {
5684 MOZ_ASSERT_UNREACHABLE("Re-entrant fragment parsing attempted.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Re-entrant fragment parsing attempted." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5684); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Re-entrant fragment parsing attempted."
")"); do { *((volatile int*)__null) = 5684; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5685 return NS_ERROR_DOM_INVALID_STATE_ERR;
5686 }
5687 mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
5688 nsContentUtils::sFragmentParsingActive = true;
5689 if (!sXMLFragmentParser) {
5690 RefPtr<nsParser> parser = new nsParser();
5691 parser.forget(&sXMLFragmentParser);
5692 // sXMLFragmentParser now owns the parser
5693 }
5694 if (!sXMLFragmentSink) {
5695 NS_NewXMLFragmentContentSink(&sXMLFragmentSink);
5696 // sXMLFragmentSink now owns the sink
5697 }
5698 nsCOMPtr<nsIContentSink> contentsink = do_QueryInterface(sXMLFragmentSink);
5699 MOZ_ASSERT(contentsink, "Sink doesn't QI to nsIContentSink!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentsink)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(contentsink))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("contentsink" " ("
"Sink doesn't QI to nsIContentSink!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5699); AnnotateMozCrashReason("MOZ_ASSERT" "(" "contentsink"
") (" "Sink doesn't QI to nsIContentSink!" ")"); do { *((volatile
int*)__null) = 5699; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
5700 sXMLFragmentParser->SetContentSink(contentsink);
5701
5702 RefPtr<Document> doc;
5703 nsCOMPtr<nsIPrincipal> nodePrincipal = aDocument->NodePrincipal();
5704
5705#ifdef DEBUG1
5706 // aFlags should always be -1 unless the caller of ParseFragmentXML
5707 // is ParserUtils::ParseFragment() which is the only caller that intends
5708 // sanitization. For all other callers we need to ensure to call
5709 // AuditParsingOfHTMLXMLFragments.
5710 if (aFlags < 0) {
5711 DOMSecurityMonitor::AuditParsingOfHTMLXMLFragments(nodePrincipal,
5712 aSourceBuffer);
5713 }
5714#endif
5715
5716 // We sanitize if the fragment occurs in a system privileged
5717 // context, an about: page, or if there are explicit sanitization flags.
5718 // Please note that about:blank and about:srcdoc inherit the security
5719 // context from the embedding context and hence are not loaded using
5720 // an about: scheme principal.
5721 bool shouldSanitize = nodePrincipal->IsSystemPrincipal() ||
5722 nodePrincipal->SchemeIs("about") || aFlags >= 0;
5723 if (shouldSanitize && !aDocument->IsLoadedAsData()) {
5724 doc = nsContentUtils::CreateInertXMLDocument(aDocument);
5725 } else {
5726 doc = aDocument;
5727 }
5728
5729 sXMLFragmentSink->SetTargetDocument(doc);
5730 sXMLFragmentSink->SetPreventScriptExecution(aPreventScriptExecution);
5731
5732 nsresult rv = sXMLFragmentParser->ParseFragment(aSourceBuffer, aTagStack);
5733 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5734 // Drop the fragment parser and sink that might be in an inconsistent state
5735 NS_IF_RELEASE(sXMLFragmentParser)do { if (sXMLFragmentParser) { (sXMLFragmentParser)->Release
(); (sXMLFragmentParser) = 0; } } while (0)
;
5736 NS_IF_RELEASE(sXMLFragmentSink)do { if (sXMLFragmentSink) { (sXMLFragmentSink)->Release()
; (sXMLFragmentSink) = 0; } } while (0)
;
5737 return rv;
5738 }
5739
5740 rv = sXMLFragmentSink->FinishFragmentParsing(aReturn);
5741
5742 sXMLFragmentParser->Reset();
5743 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5743); return rv; } } while (false)
;
5744
5745 if (shouldSanitize) {
5746 uint32_t sanitizationFlags =
5747 computeSanitizationFlags(nodePrincipal, aFlags);
5748 // Don't fire mutation events for nodes removed by the sanitizer.
5749 nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
5750 nsTreeSanitizer sanitizer(sanitizationFlags);
5751 sanitizer.Sanitize(*aReturn);
5752 }
5753
5754 return rv;
5755}
5756
5757/* static */
5758nsresult nsContentUtils::ConvertToPlainText(const nsAString& aSourceBuffer,
5759 nsAString& aResultBuffer,
5760 uint32_t aFlags,
5761 uint32_t aWrapCol) {
5762 RefPtr<Document> document = nsContentUtils::CreateInertHTMLDocument(nullptr);
5763 if (!document) {
5764 return NS_ERROR_FAILURE;
5765 }
5766
5767 nsresult rv = nsContentUtils::ParseDocumentHTML(
5768 aSourceBuffer, document,
5769 !(aFlags & nsIDocumentEncoder::OutputNoScriptContent));
5770 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5770); return rv; } } while (false)
;
5771
5772 nsCOMPtr<nsIDocumentEncoder> encoder = do_createDocumentEncoder("text/plain");
5773
5774 rv = encoder->Init(document, u"text/plain"_ns, aFlags);
5775 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5775); return rv; } } while (false)
;
5776
5777 encoder->SetWrapColumn(aWrapCol);
5778
5779 return encoder->EncodeToString(aResultBuffer);
5780}
5781
5782static already_AddRefed<Document> CreateInertDocument(const Document* aTemplate,
5783 DocumentFlavor aFlavor) {
5784 if (aTemplate) {
5785 bool hasHad = true;
5786 nsIScriptGlobalObject* sgo = aTemplate->GetScriptHandlingObject(hasHad);
5787 NS_ENSURE_TRUE(sgo || !hasHad, nullptr)do { if ((__builtin_expect(!!(!(sgo || !hasHad)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "sgo || !hasHad" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5787); return nullptr; } } while (false)
;
5788
5789 nsCOMPtr<Document> doc;
5790 nsresult rv = NS_NewDOMDocument(
5791 getter_AddRefs(doc), u""_ns, u""_ns, nullptr,
5792 aTemplate->GetDocumentURI(), aTemplate->GetDocBaseURI(),
5793 aTemplate->NodePrincipal(), true, sgo, aFlavor);
5794 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5795 return nullptr;
5796 }
5797 return doc.forget();
5798 }
5799 nsCOMPtr<nsIURI> uri;
5800 NS_NewURI(getter_AddRefs(uri), "about:blank"_ns);
5801 if (!uri) {
5802 return nullptr;
5803 }
5804
5805 RefPtr<NullPrincipal> nullPrincipal =
5806 NullPrincipal::CreateWithoutOriginAttributes();
5807 if (!nullPrincipal) {
5808 return nullptr;
5809 }
5810
5811 nsCOMPtr<Document> doc;
5812 nsresult rv =
5813 NS_NewDOMDocument(getter_AddRefs(doc), u""_ns, u""_ns, nullptr, uri, uri,
5814 nullPrincipal, true, nullptr, aFlavor);
5815 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5816 return nullptr;
5817 }
5818 return doc.forget();
5819}
5820
5821/* static */
5822already_AddRefed<Document> nsContentUtils::CreateInertXMLDocument(
5823 const Document* aTemplate) {
5824 return CreateInertDocument(aTemplate, DocumentFlavorXML);
5825}
5826
5827/* static */
5828already_AddRefed<Document> nsContentUtils::CreateInertHTMLDocument(
5829 const Document* aTemplate) {
5830 return CreateInertDocument(aTemplate, DocumentFlavorHTML);
5831}
5832
5833/* static */
5834nsresult nsContentUtils::SetNodeTextContent(nsIContent* aContent,
5835 const nsAString& aValue,
5836 bool aTryReuse) {
5837 // Fire DOMNodeRemoved mutation events before we do anything else.
5838 nsCOMPtr<nsIContent> owningContent;
5839
5840 // Batch possible DOMSubtreeModified events.
5841 mozAutoSubtreeModified subtree(nullptr, nullptr);
5842
5843 // Scope firing mutation events so that we don't carry any state that
5844 // might be stale
5845 {
5846 // We're relying on mozAutoSubtreeModified to keep a strong reference if
5847 // needed.
5848 Document* doc = aContent->OwnerDoc();
5849
5850 // Optimize the common case of there being no observers
5851 if (HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEREMOVED0x04)) {
5852 subtree.UpdateTarget(doc, nullptr);
5853 owningContent = aContent;
5854 nsCOMPtr<nsINode> child;
5855 bool skipFirst = aTryReuse;
5856 for (child = aContent->GetFirstChild();
5857 child && child->GetParentNode() == aContent;
5858 child = child->GetNextSibling()) {
5859 if (skipFirst && child->IsText()) {
5860 skipFirst = false;
5861 continue;
5862 }
5863 nsContentUtils::MaybeFireNodeRemoved(child, aContent);
5864 }
5865 }
5866 }
5867
5868 // Might as well stick a batch around this since we're performing several
5869 // mutations.
5870 mozAutoDocUpdate updateBatch(aContent->GetComposedDoc(), true);
5871 nsAutoMutationBatch mb;
5872
5873 if (aTryReuse && !aValue.IsEmpty()) {
5874 // Let's remove nodes until we find a eTEXT.
5875 while (aContent->HasChildren()) {
5876 nsIContent* child = aContent->GetFirstChild();
5877 if (child->IsText()) {
5878 break;
5879 }
5880 aContent->RemoveChildNode(child, true);
5881 }
5882
5883 // If we have a node, it must be a eTEXT and we reuse it.
5884 if (aContent->HasChildren()) {
5885 nsIContent* child = aContent->GetFirstChild();
5886 nsresult rv = child->AsText()->SetText(aValue, true);
5887 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5887); return rv; } } while (false)
;
5888
5889 // All the following nodes, if they exist, must be deleted.
5890 while (nsIContent* nextChild = child->GetNextSibling()) {
5891 aContent->RemoveChildNode(nextChild, true);
5892 }
5893 }
5894
5895 if (aContent->HasChildren()) {
5896 return NS_OK;
5897 }
5898 } else {
5899 mb.Init(aContent, true, false);
5900 while (aContent->HasChildren()) {
5901 aContent->RemoveChildNode(aContent->GetFirstChild(), true);
5902 }
5903 }
5904 mb.RemovalDone();
5905
5906 if (aValue.IsEmpty()) {
5907 return NS_OK;
5908 }
5909
5910 RefPtr<nsTextNode> textContent = new (aContent->NodeInfo()->NodeInfoManager())
5911 nsTextNode(aContent->NodeInfo()->NodeInfoManager());
5912
5913 textContent->SetText(aValue, true);
5914
5915 ErrorResult rv;
5916 aContent->AppendChildTo(textContent, true, rv);
5917 mb.NodesAdded();
5918 return rv.StealNSResult();
5919}
5920
5921static bool AppendNodeTextContentsRecurse(const nsINode* aNode,
5922 nsAString& aResult,
5923 const fallible_t& aFallible) {
5924 for (nsIContent* child = aNode->GetFirstChild(); child;
5925 child = child->GetNextSibling()) {
5926 if (child->IsElement()) {
5927 bool ok = AppendNodeTextContentsRecurse(child, aResult, aFallible);
5928 if (!ok) {
5929 return false;
5930 }
5931 } else if (Text* text = child->GetAsText()) {
5932 bool ok = text->AppendTextTo(aResult, aFallible);
5933 if (!ok) {
5934 return false;
5935 }
5936 }
5937 }
5938
5939 return true;
5940}
5941
5942/* static */
5943bool nsContentUtils::AppendNodeTextContent(const nsINode* aNode, bool aDeep,
5944 nsAString& aResult,
5945 const fallible_t& aFallible) {
5946 if (const Text* text = aNode->GetAsText()) {
5947 return text->AppendTextTo(aResult, aFallible);
5948 }
5949 if (aDeep) {
5950 return AppendNodeTextContentsRecurse(aNode, aResult, aFallible);
5951 }
5952
5953 for (nsIContent* child = aNode->GetFirstChild(); child;
5954 child = child->GetNextSibling()) {
5955 if (Text* text = child->GetAsText()) {
5956 bool ok = text->AppendTextTo(aResult, fallible);
5957 if (!ok) {
5958 return false;
5959 }
5960 }
5961 }
5962 return true;
5963}
5964
5965bool nsContentUtils::HasNonEmptyTextContent(
5966 nsINode* aNode, TextContentDiscoverMode aDiscoverMode) {
5967 for (nsIContent* child = aNode->GetFirstChild(); child;
5968 child = child->GetNextSibling()) {
5969 if (child->IsText() && child->TextLength() > 0) {
5970 return true;
5971 }
5972
5973 if (aDiscoverMode == eRecurseIntoChildren &&
5974 HasNonEmptyTextContent(child, aDiscoverMode)) {
5975 return true;
5976 }
5977 }
5978
5979 return false;
5980}
5981
5982/* static */
5983bool nsContentUtils::IsInSameAnonymousTree(const nsINode* aNode,
5984 const nsINode* aOtherNode) {
5985 MOZ_ASSERT(aNode, "Must have a node to work with")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNode)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aNode))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aNode" " (" "Must have a node to work with"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5985); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNode" ") ("
"Must have a node to work with" ")"); do { *((volatile int*)
__null) = 5985; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5986 MOZ_ASSERT(aOtherNode, "Must have a content to work with")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOtherNode)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aOtherNode))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aOtherNode" " (" "Must have a content to work with"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 5986); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOtherNode"
") (" "Must have a content to work with" ")"); do { *((volatile
int*)__null) = 5986; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
5987
5988 const bool anon = aNode->IsInNativeAnonymousSubtree();
5989 if (anon != aOtherNode->IsInNativeAnonymousSubtree()) {
5990 return false;
5991 }
5992
5993 if (anon) {
5994 return aOtherNode->GetClosestNativeAnonymousSubtreeRoot() ==
5995 aNode->GetClosestNativeAnonymousSubtreeRoot();
5996 }
5997
5998 // FIXME: This doesn't deal with disconnected nodes whatsoever, but it didn't
5999 // use to either. Maybe that's fine.
6000 return aNode->GetContainingShadow() == aOtherNode->GetContainingShadow();
6001}
6002
6003/* static */
6004bool nsContentUtils::IsInInteractiveHTMLContent(const Element* aElement,
6005 const Element* aStop) {
6006 const Element* element = aElement;
6007 while (element && element != aStop) {
6008 if (element->IsInteractiveHTMLContent()) {
6009 return true;
6010 }
6011 element = element->GetFlattenedTreeParentElement();
6012 }
6013 return false;
6014}
6015
6016/* static */
6017void nsContentUtils::NotifyInstalledMenuKeyboardListener(bool aInstalling) {
6018 IMEStateManager::OnInstalledMenuKeyboardListener(aInstalling);
6019}
6020
6021/* static */
6022bool nsContentUtils::SchemeIs(nsIURI* aURI, const char* aScheme) {
6023 nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI);
6024 NS_ENSURE_TRUE(baseURI, false)do { if ((__builtin_expect(!!(!(baseURI)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "baseURI" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6024); return false; } } while (false)
;
6025 return baseURI->SchemeIs(aScheme);
6026}
6027
6028bool nsContentUtils::IsExpandedPrincipal(nsIPrincipal* aPrincipal) {
6029 return aPrincipal && aPrincipal->GetIsExpandedPrincipal();
6030}
6031
6032bool nsContentUtils::IsSystemOrExpandedPrincipal(nsIPrincipal* aPrincipal) {
6033 return (aPrincipal && aPrincipal->IsSystemPrincipal()) ||
6034 IsExpandedPrincipal(aPrincipal);
6035}
6036
6037nsIPrincipal* nsContentUtils::GetSystemPrincipal() {
6038 MOZ_ASSERT(IsInitialized())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsInitialized())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsInitialized()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("IsInitialized()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6038); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsInitialized()"
")"); do { *((volatile int*)__null) = 6038; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6039 return sSystemPrincipal;
6040}
6041
6042bool nsContentUtils::CombineResourcePrincipals(
6043 nsCOMPtr<nsIPrincipal>* aResourcePrincipal, nsIPrincipal* aExtraPrincipal) {
6044 if (!aExtraPrincipal) {
6045 return false;
6046 }
6047 if (!*aResourcePrincipal) {
6048 *aResourcePrincipal = aExtraPrincipal;
6049 return true;
6050 }
6051 if (*aResourcePrincipal == aExtraPrincipal) {
6052 return false;
6053 }
6054 bool subsumes;
6055 if (NS_SUCCEEDED(((bool)(__builtin_expect(!!(!NS_FAILED_impl((*aResourcePrincipal
)->Subsumes(aExtraPrincipal, &subsumes))), 1)))
6056 (*aResourcePrincipal)->Subsumes(aExtraPrincipal, &subsumes))((bool)(__builtin_expect(!!(!NS_FAILED_impl((*aResourcePrincipal
)->Subsumes(aExtraPrincipal, &subsumes))), 1)))
&&
6057 subsumes) {
6058 return false;
6059 }
6060 *aResourcePrincipal = sSystemPrincipal;
6061 return true;
6062}
6063
6064/* static */
6065void nsContentUtils::TriggerLink(nsIContent* aContent, nsIURI* aLinkURI,
6066 const nsString& aTargetSpec, bool aClick,
6067 bool aIsTrusted) {
6068 MOZ_ASSERT(aLinkURI, "No link URI")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLinkURI)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLinkURI))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aLinkURI" " (" "No link URI"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6068); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLinkURI" ") ("
"No link URI" ")"); do { *((volatile int*)__null) = 6068; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
6069
6070 if (aContent->IsEditable() || !aContent->OwnerDoc()->LinkHandlingEnabled()) {
6071 return;
6072 }
6073
6074 nsCOMPtr<nsIDocShell> docShell = aContent->OwnerDoc()->GetDocShell();
6075 if (!docShell) {
6076 return;
6077 }
6078
6079 if (!aClick) {
6080 nsDocShell::Cast(docShell)->OnOverLink(aContent, aLinkURI, aTargetSpec);
6081 return;
6082 }
6083
6084 // Check that this page is allowed to load this URI.
6085 nsresult proceed = NS_OK;
6086
6087 if (sSecurityManager) {
6088 uint32_t flag = static_cast<uint32_t>(nsIScriptSecurityManager::STANDARD);
6089 proceed = sSecurityManager->CheckLoadURIWithPrincipal(
6090 aContent->NodePrincipal(), aLinkURI, flag,
6091 aContent->OwnerDoc()->InnerWindowID());
6092 }
6093
6094 // Only pass off the click event if the script security manager says it's ok.
6095 // We need to rest aTargetSpec for forced downloads.
6096 if (NS_SUCCEEDED(proceed)((bool)(__builtin_expect(!!(!NS_FAILED_impl(proceed)), 1)))) {
6097 // A link/area element with a download attribute is allowed to set
6098 // a pseudo Content-Disposition header.
6099 // For security reasons we only allow websites to declare same-origin
6100 // resources as downloadable. If this check fails we will just do the normal
6101 // thing (i.e. navigate to the resource).
6102 nsAutoString fileName;
6103 if ((!aContent->IsHTMLElement(nsGkAtoms::a) &&
6104 !aContent->IsHTMLElement(nsGkAtoms::area) &&
6105 !aContent->IsSVGElement(nsGkAtoms::a)) ||
6106 !aContent->AsElement()->GetAttr(nsGkAtoms::download, fileName) ||
6107 NS_FAILED(aContent->NodePrincipal()->CheckMayLoad(aLinkURI, true))((bool)(__builtin_expect(!!(NS_FAILED_impl(aContent->NodePrincipal
()->CheckMayLoad(aLinkURI, true))), 0)))
) {
6108 fileName.SetIsVoid(true); // No actionable download attribute was found.
6109 }
6110
6111 nsCOMPtr<nsIPrincipal> triggeringPrincipal = aContent->NodePrincipal();
6112 nsCOMPtr<nsIContentSecurityPolicy> csp = aContent->GetCsp();
6113
6114 // Sanitize fileNames containing null characters by replacing them with
6115 // underscores.
6116 if (!fileName.IsVoid()) {
6117 fileName.ReplaceChar(char16_t(0), '_');
6118 }
6119 nsDocShell::Cast(docShell)->OnLinkClick(
6120 aContent, aLinkURI, fileName.IsVoid() ? aTargetSpec : u""_ns, fileName,
6121 nullptr, nullptr, UserActivation::IsHandlingUserInput(), aIsTrusted,
6122 triggeringPrincipal, csp);
6123 }
6124}
6125
6126/* static */
6127void nsContentUtils::GetLinkLocation(Element* aElement,
6128 nsString& aLocationString) {
6129 nsCOMPtr<nsIURI> hrefURI = aElement->GetHrefURI();
6130 if (hrefURI) {
6131 nsAutoCString specUTF8;
6132 nsresult rv = hrefURI->GetSpec(specUTF8);
6133 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) CopyUTF8toUTF16(specUTF8, aLocationString);
6134 }
6135}
6136
6137/* static */
6138nsIWidget* nsContentUtils::GetTopLevelWidget(nsIWidget* aWidget) {
6139 if (!aWidget) return nullptr;
6140
6141 return aWidget->GetTopLevelWidget();
6142}
6143
6144/* static */
6145const nsDependentString nsContentUtils::GetLocalizedEllipsis() {
6146 static char16_t sBuf[4] = {0, 0, 0, 0};
6147 if (!sBuf[0]) {
6148 if (!SpoofLocaleEnglish()) {
6149 nsAutoString tmp;
6150 Preferences::GetLocalizedString("intl.ellipsis", tmp);
6151 uint32_t len =
6152 std::min(uint32_t(tmp.Length()), uint32_t(ArrayLength(sBuf) - 1));
6153 CopyUnicodeTo(tmp, 0, sBuf, len);
6154 }
6155 if (!sBuf[0]) sBuf[0] = char16_t(0x2026);
6156 }
6157 return nsDependentString(sBuf);
6158}
6159
6160/* static */
6161void nsContentUtils::AddScriptBlocker() {
6162 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6162); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 6162; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6163 if (!sScriptBlockerCount) {
6164 MOZ_ASSERT(sRunnersCountAtFirstBlocker == 0,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sRunnersCountAtFirstBlocker == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sRunnersCountAtFirstBlocker ==
0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("sRunnersCountAtFirstBlocker == 0" " (" "Should not already have a count"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6165); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sRunnersCountAtFirstBlocker == 0"
") (" "Should not already have a count" ")"); do { *((volatile
int*)__null) = 6165; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
6165 "Should not already have a count")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sRunnersCountAtFirstBlocker == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sRunnersCountAtFirstBlocker ==
0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("sRunnersCountAtFirstBlocker == 0" " (" "Should not already have a count"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6165); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sRunnersCountAtFirstBlocker == 0"
") (" "Should not already have a count" ")"); do { *((volatile
int*)__null) = 6165; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
6166 sRunnersCountAtFirstBlocker =
6167 sBlockedScriptRunners ? sBlockedScriptRunners->Length() : 0;
6168 }
6169 ++sScriptBlockerCount;
6170}
6171
6172#ifdef DEBUG1
6173static bool sRemovingScriptBlockers = false;
6174#endif
6175
6176/* static */
6177void nsContentUtils::RemoveScriptBlocker() {
6178 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6178); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 6178; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6179 MOZ_ASSERT(!sRemovingScriptBlockers)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!sRemovingScriptBlockers)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!sRemovingScriptBlockers))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!sRemovingScriptBlockers"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6179); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sRemovingScriptBlockers"
")"); do { *((volatile int*)__null) = 6179; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6180 NS_ASSERTION(sScriptBlockerCount != 0, "Negative script blockers")do { if (!(sScriptBlockerCount != 0)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Negative script blockers", "sScriptBlockerCount != 0", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6180); MOZ_PretendNoReturn(); } } while (0)
;
6181 --sScriptBlockerCount;
6182 if (sScriptBlockerCount) {
6183 return;
6184 }
6185
6186 if (!sBlockedScriptRunners) {
6187 return;
6188 }
6189
6190 uint32_t firstBlocker = sRunnersCountAtFirstBlocker;
6191 uint32_t lastBlocker = sBlockedScriptRunners->Length();
6192 uint32_t originalFirstBlocker = firstBlocker;
6193 uint32_t blockersCount = lastBlocker - firstBlocker;
6194 sRunnersCountAtFirstBlocker = 0;
6195 NS_ASSERTION(firstBlocker <= lastBlocker, "bad sRunnersCountAtFirstBlocker")do { if (!(firstBlocker <= lastBlocker)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "bad sRunnersCountAtFirstBlocker", "firstBlocker <= lastBlocker"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6195); MOZ_PretendNoReturn(); } } while (0)
;
6196
6197 while (firstBlocker < lastBlocker) {
6198 nsCOMPtr<nsIRunnable> runnable;
6199 runnable.swap((*sBlockedScriptRunners)[firstBlocker]);
6200 ++firstBlocker;
6201
6202 // Calling the runnable can reenter us
6203 {
6204 AUTO_PROFILE_FOLLOWING_RUNNABLE(runnable)mozilla::Maybe<mozilla::AutoProfileRunnable> raiiRunnableMarker
; if (profiler_thread_is_being_profiled_for_markers()) { raiiRunnableMarker
.emplace(runnable); }
;
6205 runnable->Run();
6206 }
6207 // So can dropping the reference to the runnable
6208 runnable = nullptr;
6209
6210 NS_ASSERTION(sRunnersCountAtFirstBlocker == 0, "Bad count")do { if (!(sRunnersCountAtFirstBlocker == 0)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Bad count", "sRunnersCountAtFirstBlocker == 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6210); MOZ_PretendNoReturn(); } } while (0)
;
6211 NS_ASSERTION(!sScriptBlockerCount, "This is really bad")do { if (!(!sScriptBlockerCount)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "This is really bad", "!sScriptBlockerCount", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6211); MOZ_PretendNoReturn(); } } while (0)
;
6212 }
6213#ifdef DEBUG1
6214 AutoRestore<bool> removingScriptBlockers(sRemovingScriptBlockers);
6215 sRemovingScriptBlockers = true;
6216#endif
6217 sBlockedScriptRunners->RemoveElementsAt(originalFirstBlocker, blockersCount);
6218}
6219
6220/* static */
6221already_AddRefed<nsPIDOMWindowOuter>
6222nsContentUtils::GetMostRecentNonPBWindow() {
6223 nsCOMPtr<nsIWindowMediator> wm = do_GetService(NS_WINDOWMEDIATOR_CONTRACTID"@mozilla.org/appshell/window-mediator;1");
6224
6225 nsCOMPtr<mozIDOMWindowProxy> window;
6226 wm->GetMostRecentNonPBWindow(u"navigator:browser", getter_AddRefs(window));
6227 nsCOMPtr<nsPIDOMWindowOuter> pwindow;
6228 pwindow = do_QueryInterface(window);
6229
6230 return pwindow.forget();
6231}
6232
6233/* static */
6234void nsContentUtils::WarnScriptWasIgnored(Document* aDocument) {
6235 nsAutoString msg;
6236 bool privateBrowsing = false;
6237 bool chromeContext = false;
6238
6239 if (aDocument) {
6240 nsCOMPtr<nsIURI> uri = aDocument->GetDocumentURI();
6241 if (uri) {
6242 msg.Append(NS_ConvertUTF8toUTF16(uri->GetSpecOrDefault()));
6243 msg.AppendLiteral(" : ");
6244 }
6245 privateBrowsing =
6246 aDocument->NodePrincipal()->OriginAttributesRef().IsPrivateBrowsing();
6247 chromeContext = aDocument->NodePrincipal()->IsSystemPrincipal();
6248 }
6249
6250 msg.AppendLiteral(
6251 "Unable to run script because scripts are blocked internally.");
6252 LogSimpleConsoleError(msg, "DOM"_ns, privateBrowsing, chromeContext);
6253}
6254
6255/* static */
6256void nsContentUtils::AddScriptRunner(already_AddRefed<nsIRunnable> aRunnable) {
6257 nsCOMPtr<nsIRunnable> runnable = aRunnable;
6258 if (!runnable) {
2
Taking false branch
6259 return;
6260 }
6261
6262 if (sScriptBlockerCount) {
3
Assuming 'sScriptBlockerCount' is 0
4
Taking false branch
6263 sBlockedScriptRunners->AppendElement(runnable.forget());
6264 return;
6265 }
6266
6267 AUTO_PROFILE_FOLLOWING_RUNNABLE(runnable)mozilla::Maybe<mozilla::AutoProfileRunnable> raiiRunnableMarker
; if (profiler_thread_is_being_profiled_for_markers()) { raiiRunnableMarker
.emplace(runnable); }
;
5
Calling defaulted default constructor for 'Maybe<mozilla::AutoProfileRunnable>'
16
Returning from default constructor for 'Maybe<mozilla::AutoProfileRunnable>'
17
Assuming the condition is false
18
Taking false branch
6268 runnable->Run();
6269}
19
Calling implicit destructor for 'Maybe<mozilla::AutoProfileRunnable>'
20
Calling '~MaybeStorage'
6270
6271/* static */
6272void nsContentUtils::AddScriptRunner(nsIRunnable* aRunnable) {
6273 nsCOMPtr<nsIRunnable> runnable = aRunnable;
6274 AddScriptRunner(runnable.forget());
1
Calling 'nsContentUtils::AddScriptRunner'
6275}
6276
6277/* static */ bool nsContentUtils::IsSafeToRunScript() {
6278 MOZ_ASSERT(NS_IsMainThread(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "This static variable only makes sense on the main thread!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6279); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "This static variable only makes sense on the main thread!"
")"); do { *((volatile int*)__null) = 6279; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6279 "This static variable only makes sense on the main thread!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "This static variable only makes sense on the main thread!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6279); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "This static variable only makes sense on the main thread!"
")"); do { *((volatile int*)__null) = 6279; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6280 return sScriptBlockerCount == 0;
6281}
6282
6283/* static */
6284void nsContentUtils::RunInStableState(already_AddRefed<nsIRunnable> aRunnable) {
6285 MOZ_ASSERT(CycleCollectedJSContext::Get(), "Must be on a script thread!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(CycleCollectedJSContext::Get())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(CycleCollectedJSContext::Get
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("CycleCollectedJSContext::Get()" " (" "Must be on a script thread!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6285); AnnotateMozCrashReason("MOZ_ASSERT" "(" "CycleCollectedJSContext::Get()"
") (" "Must be on a script thread!" ")"); do { *((volatile int
*)__null) = 6285; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
6286 CycleCollectedJSContext::Get()->RunInStableState(std::move(aRunnable));
6287}
6288
6289/* static */
6290void nsContentUtils::AddPendingIDBTransaction(
6291 already_AddRefed<nsIRunnable> aTransaction) {
6292 MOZ_ASSERT(CycleCollectedJSContext::Get(), "Must be on a script thread!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(CycleCollectedJSContext::Get())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(CycleCollectedJSContext::Get
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("CycleCollectedJSContext::Get()" " (" "Must be on a script thread!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6292); AnnotateMozCrashReason("MOZ_ASSERT" "(" "CycleCollectedJSContext::Get()"
") (" "Must be on a script thread!" ")"); do { *((volatile int
*)__null) = 6292; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
6293 CycleCollectedJSContext::Get()->AddPendingIDBTransaction(
6294 std::move(aTransaction));
6295}
6296
6297/* static */
6298bool nsContentUtils::IsInStableOrMetaStableState() {
6299 MOZ_ASSERT(CycleCollectedJSContext::Get(), "Must be on a script thread!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(CycleCollectedJSContext::Get())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(CycleCollectedJSContext::Get
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("CycleCollectedJSContext::Get()" " (" "Must be on a script thread!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6299); AnnotateMozCrashReason("MOZ_ASSERT" "(" "CycleCollectedJSContext::Get()"
") (" "Must be on a script thread!" ")"); do { *((volatile int
*)__null) = 6299; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
6300 return CycleCollectedJSContext::Get()->IsInStableOrMetaStableState();
6301}
6302
6303/* static */
6304void nsContentUtils::HidePopupsInDocument(Document* aDocument) {
6305 RefPtr<nsXULPopupManager> pm = nsXULPopupManager::GetInstance();
6306 if (!pm || !aDocument) {
6307 return;
6308 }
6309 nsCOMPtr<nsIDocShellTreeItem> docShellToHide = aDocument->GetDocShell();
6310 if (docShellToHide) {
6311 pm->HidePopupsInDocShell(docShellToHide);
6312 }
6313}
6314
6315/* static */
6316already_AddRefed<nsIDragSession> nsContentUtils::GetDragSession(
6317 nsIWidget* aWidget) {
6318 nsCOMPtr<nsIDragSession> dragSession;
6319 nsCOMPtr<nsIDragService> dragService =
6320 do_GetService("@mozilla.org/widget/dragservice;1");
6321 if (dragService) {
6322 dragSession = dragService->GetCurrentSession(aWidget);
6323 }
6324 return dragSession.forget();
6325}
6326
6327/* static */
6328already_AddRefed<nsIDragSession> nsContentUtils::GetDragSession(
6329 nsPresContext* aPC) {
6330 NS_ENSURE_TRUE(aPC, nullptr)do { if ((__builtin_expect(!!(!(aPC)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "aPC" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6330); return nullptr; } } while (false)
;
6331 auto* widget = aPC->GetRootWidget();
6332 if (!widget) {
6333 return nullptr;
6334 }
6335 return GetDragSession(widget);
6336}
6337
6338/* static */
6339nsresult nsContentUtils::SetDataTransferInEvent(WidgetDragEvent* aDragEvent) {
6340 if (aDragEvent->mDataTransfer || !aDragEvent->IsTrusted()) {
6341 return NS_OK;
6342 }
6343
6344 // For dragstart events, the data transfer object is
6345 // created before the event fires, so it should already be set. For other
6346 // drag events, get the object from the drag session.
6347 NS_ASSERTION(aDragEvent->mMessage != eDragStart,do { if (!(aDragEvent->mMessage != eDragStart)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "draggesture event created without a dataTransfer"
, "aDragEvent->mMessage != eDragStart", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6348); MOZ_PretendNoReturn(); } } while (0)
6348 "draggesture event created without a dataTransfer")do { if (!(aDragEvent->mMessage != eDragStart)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "draggesture event created without a dataTransfer"
, "aDragEvent->mMessage != eDragStart", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6348); MOZ_PretendNoReturn(); } } while (0)
;
6349
6350 nsCOMPtr<nsIDragSession> dragSession = GetDragSession(aDragEvent->mWidget);
6351 NS_ENSURE_TRUE(dragSession, NS_OK)do { if ((__builtin_expect(!!(!(dragSession)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "dragSession" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6351); return NS_OK; } } while (false)
; // no drag in progress
6352
6353 RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
6354 if (!initialDataTransfer) {
6355 // A dataTransfer won't exist when a drag was started by some other
6356 // means, for instance calling the drag service directly, or a drag
6357 // from another application. In either case, a new dataTransfer should
6358 // be created that reflects the data.
6359 initialDataTransfer = new DataTransfer(
6360 aDragEvent->mTarget, aDragEvent->mMessage, true, Nothing());
6361
6362 // now set it in the drag session so we don't need to create it again
6363 dragSession->SetDataTransfer(initialDataTransfer);
6364 }
6365
6366 bool isCrossDomainSubFrameDrop = false;
6367 if (aDragEvent->mMessage == eDrop) {
6368 isCrossDomainSubFrameDrop = CheckForSubFrameDrop(dragSession, aDragEvent);
6369 }
6370
6371 // each event should use a clone of the original dataTransfer.
6372 initialDataTransfer->Clone(
6373 aDragEvent->mTarget, aDragEvent->mMessage, aDragEvent->mUserCancelled,
6374 isCrossDomainSubFrameDrop, getter_AddRefs(aDragEvent->mDataTransfer));
6375 if (NS_WARN_IF(!aDragEvent->mDataTransfer)NS_warn_if_impl(!aDragEvent->mDataTransfer, "!aDragEvent->mDataTransfer"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6375)
) {
6376 return NS_ERROR_OUT_OF_MEMORY;
6377 }
6378
6379 // for the dragenter and dragover events, initialize the drop effect
6380 // from the drop action, which platform specific widget code sets before
6381 // the event is fired based on the keyboard state.
6382 if (aDragEvent->mMessage == eDragEnter || aDragEvent->mMessage == eDragOver) {
6383 uint32_t action;
6384 dragSession->GetDragAction(&action);
6385 uint32_t effectAllowed = aDragEvent->mDataTransfer->EffectAllowedInt();
6386 aDragEvent->mDataTransfer->SetDropEffectInt(
6387 FilterDropEffect(action, effectAllowed));
6388 } else if (aDragEvent->mMessage == eDrop ||
6389 aDragEvent->mMessage == eDragEnd) {
6390 // For the drop and dragend events, set the drop effect based on the
6391 // last value that the dropEffect had. This will have been set in
6392 // EventStateManager::PostHandleEvent for the last dragenter or
6393 // dragover event.
6394 aDragEvent->mDataTransfer->SetDropEffectInt(
6395 initialDataTransfer->DropEffectInt());
6396 }
6397
6398 return NS_OK;
6399}
6400
6401/* static */
6402uint32_t nsContentUtils::FilterDropEffect(uint32_t aAction,
6403 uint32_t aEffectAllowed) {
6404 // It is possible for the drag action to include more than one action, but
6405 // the widget code which sets the action from the keyboard state should only
6406 // be including one. If multiple actions were set, we just consider them in
6407 // the following order:
6408 // copy, link, move
6409 if (aAction & nsIDragService::DRAGDROP_ACTION_COPY)
6410 aAction = nsIDragService::DRAGDROP_ACTION_COPY;
6411 else if (aAction & nsIDragService::DRAGDROP_ACTION_LINK)
6412 aAction = nsIDragService::DRAGDROP_ACTION_LINK;
6413 else if (aAction & nsIDragService::DRAGDROP_ACTION_MOVE)
6414 aAction = nsIDragService::DRAGDROP_ACTION_MOVE;
6415
6416 // Filter the action based on the effectAllowed. If the effectAllowed
6417 // doesn't include the action, then that action cannot be done, so adjust
6418 // the action to something that is allowed. For a copy, adjust to move or
6419 // link. For a move, adjust to copy or link. For a link, adjust to move or
6420 // link. Otherwise, use none.
6421 if (aAction & aEffectAllowed ||
6422 aEffectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED)
6423 return aAction;
6424 if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_MOVE)
6425 return nsIDragService::DRAGDROP_ACTION_MOVE;
6426 if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_COPY)
6427 return nsIDragService::DRAGDROP_ACTION_COPY;
6428 if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_LINK)
6429 return nsIDragService::DRAGDROP_ACTION_LINK;
6430 return nsIDragService::DRAGDROP_ACTION_NONE;
6431}
6432
6433/* static */
6434bool nsContentUtils::CheckForSubFrameDrop(nsIDragSession* aDragSession,
6435 WidgetDragEvent* aDropEvent) {
6436 nsCOMPtr<nsIContent> target =
6437 nsIContent::FromEventTargetOrNull(aDropEvent->mOriginalTarget);
6438 if (!target) {
6439 return true;
6440 }
6441
6442 // Always allow dropping onto chrome shells.
6443 BrowsingContext* targetBC = target->OwnerDoc()->GetBrowsingContext();
6444 if (targetBC->IsChrome()) {
6445 return false;
6446 }
6447
6448 WindowContext* targetWC = target->OwnerDoc()->GetWindowContext();
6449
6450 // If there is no source browsing context, then this is a drag from another
6451 // application, which should be allowed.
6452 RefPtr<WindowContext> sourceWC;
6453 aDragSession->GetSourceWindowContext(getter_AddRefs(sourceWC));
6454 if (sourceWC) {
6455 // Get each successive parent of the source document and compare it to
6456 // the drop document. If they match, then this is a drag from a child frame.
6457 for (sourceWC = sourceWC->GetParentWindowContext(); sourceWC;
6458 sourceWC = sourceWC->GetParentWindowContext()) {
6459 // If the source and the target match, then the drag started in a
6460 // descendant frame. If the source is discarded, err on the side of
6461 // caution and treat it as a subframe drag.
6462 if (sourceWC == targetWC || sourceWC->IsDiscarded()) {
6463 return true;
6464 }
6465 }
6466 }
6467
6468 return false;
6469}
6470
6471/* static */
6472bool nsContentUtils::URIIsLocalFile(nsIURI* aURI) {
6473 bool isFile;
6474 nsCOMPtr<nsINetUtil> util = mozilla::components::IO::Service();
6475
6476 // Important: we do NOT test the entire URI chain here!
6477 return util &&
6478 NS_SUCCEEDED(util->ProtocolHasFlags(((bool)(__builtin_expect(!!(!NS_FAILED_impl(util->ProtocolHasFlags
( aURI, nsIProtocolHandler::URI_IS_LOCAL_FILE, &isFile)))
, 1)))
6479 aURI, nsIProtocolHandler::URI_IS_LOCAL_FILE, &isFile))((bool)(__builtin_expect(!!(!NS_FAILED_impl(util->ProtocolHasFlags
( aURI, nsIProtocolHandler::URI_IS_LOCAL_FILE, &isFile)))
, 1)))
&&
6480 isFile;
6481}
6482
6483/* static */
6484JSContext* nsContentUtils::GetCurrentJSContext() {
6485 MOZ_ASSERT(IsInitialized())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsInitialized())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsInitialized()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("IsInitialized()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6485); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsInitialized()"
")"); do { *((volatile int*)__null) = 6485; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6486 if (!IsJSAPIActive()) {
6487 return nullptr;
6488 }
6489 return danger::GetJSContext();
6490}
6491
6492template <typename StringType, typename CharType>
6493void _ASCIIToLowerInSitu(StringType& aStr) {
6494 CharType* iter = aStr.BeginWriting();
6495 CharType* end = aStr.EndWriting();
6496 MOZ_ASSERT(iter && end)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(iter && end)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(iter && end))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("iter && end"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6496); AnnotateMozCrashReason("MOZ_ASSERT" "(" "iter && end"
")"); do { *((volatile int*)__null) = 6496; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6497
6498 while (iter != end) {
6499 CharType c = *iter;
6500 if (c >= 'A' && c <= 'Z') {
6501 *iter = c + ('a' - 'A');
6502 }
6503 ++iter;
6504 }
6505}
6506
6507/* static */
6508void nsContentUtils::ASCIIToLower(nsAString& aStr) {
6509 return _ASCIIToLowerInSitu<nsAString, char16_t>(aStr);
6510}
6511
6512/* static */
6513void nsContentUtils::ASCIIToLower(nsACString& aStr) {
6514 return _ASCIIToLowerInSitu<nsACString, char>(aStr);
6515}
6516
6517template <typename StringType, typename CharType>
6518void _ASCIIToLowerCopy(const StringType& aSource, StringType& aDest) {
6519 uint32_t len = aSource.Length();
6520 aDest.SetLength(len);
6521 MOZ_ASSERT(aDest.Length() == len)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDest.Length() == len)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDest.Length() == len))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aDest.Length() == len"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6521); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDest.Length() == len"
")"); do { *((volatile int*)__null) = 6521; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6522
6523 CharType* dest = aDest.BeginWriting();
6524 MOZ_ASSERT(dest)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dest)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(dest))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("dest", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6524); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dest" ")");
do { *((volatile int*)__null) = 6524; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6525
6526 const CharType* iter = aSource.BeginReading();
6527 const CharType* end = aSource.EndReading();
6528 while (iter != end) {
6529 CharType c = *iter;
6530 *dest = (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c;
6531 ++iter;
6532 ++dest;
6533 }
6534}
6535
6536/* static */
6537void nsContentUtils::ASCIIToLower(const nsAString& aSource, nsAString& aDest) {
6538 return _ASCIIToLowerCopy<nsAString, char16_t>(aSource, aDest);
6539}
6540
6541/* static */
6542void nsContentUtils::ASCIIToLower(const nsACString& aSource,
6543 nsACString& aDest) {
6544 return _ASCIIToLowerCopy<nsACString, char>(aSource, aDest);
6545}
6546
6547template <typename StringType, typename CharType>
6548void _ASCIIToUpperInSitu(StringType& aStr) {
6549 CharType* iter = aStr.BeginWriting();
6550 CharType* end = aStr.EndWriting();
6551 MOZ_ASSERT(iter && end)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(iter && end)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(iter && end))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("iter && end"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6551); AnnotateMozCrashReason("MOZ_ASSERT" "(" "iter && end"
")"); do { *((volatile int*)__null) = 6551; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6552
6553 while (iter != end) {
6554 CharType c = *iter;
6555 if (c >= 'a' && c <= 'z') {
6556 *iter = c + ('A' - 'a');
6557 }
6558 ++iter;
6559 }
6560}
6561
6562/* static */
6563void nsContentUtils::ASCIIToUpper(nsAString& aStr) {
6564 return _ASCIIToUpperInSitu<nsAString, char16_t>(aStr);
6565}
6566
6567/* static */
6568void nsContentUtils::ASCIIToUpper(nsACString& aStr) {
6569 return _ASCIIToUpperInSitu<nsACString, char>(aStr);
6570}
6571
6572template <typename StringType, typename CharType>
6573void _ASCIIToUpperCopy(const StringType& aSource, StringType& aDest) {
6574 uint32_t len = aSource.Length();
6575 aDest.SetLength(len);
6576 MOZ_ASSERT(aDest.Length() == len)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDest.Length() == len)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDest.Length() == len))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aDest.Length() == len"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6576); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDest.Length() == len"
")"); do { *((volatile int*)__null) = 6576; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6577
6578 CharType* dest = aDest.BeginWriting();
6579 MOZ_ASSERT(dest)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dest)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(dest))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("dest", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6579); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dest" ")");
do { *((volatile int*)__null) = 6579; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6580
6581 const CharType* iter = aSource.BeginReading();
6582 const CharType* end = aSource.EndReading();
6583 while (iter != end) {
6584 CharType c = *iter;
6585 *dest = (c >= 'a' && c <= 'z') ? c + ('A' - 'a') : c;
6586 ++iter;
6587 ++dest;
6588 }
6589}
6590
6591/* static */
6592void nsContentUtils::ASCIIToUpper(const nsAString& aSource, nsAString& aDest) {
6593 return _ASCIIToUpperCopy<nsAString, char16_t>(aSource, aDest);
6594}
6595
6596/* static */
6597void nsContentUtils::ASCIIToUpper(const nsACString& aSource,
6598 nsACString& aDest) {
6599 return _ASCIIToUpperCopy<nsACString, char>(aSource, aDest);
6600}
6601
6602/* static */
6603bool nsContentUtils::EqualsIgnoreASCIICase(nsAtom* aAtom1, nsAtom* aAtom2) {
6604 if (aAtom1 == aAtom2) {
6605 return true;
6606 }
6607
6608 // If both are ascii lowercase already, we know that the slow comparison
6609 // below is going to return false.
6610 if (aAtom1->IsAsciiLowercase() && aAtom2->IsAsciiLowercase()) {
6611 return false;
6612 }
6613
6614 return EqualsIgnoreASCIICase(nsDependentAtomString(aAtom1),
6615 nsDependentAtomString(aAtom2));
6616}
6617
6618/* static */
6619bool nsContentUtils::EqualsIgnoreASCIICase(const nsAString& aStr1,
6620 const nsAString& aStr2) {
6621 uint32_t len = aStr1.Length();
6622 if (len != aStr2.Length()) {
6623 return false;
6624 }
6625
6626 const char16_t* str1 = aStr1.BeginReading();
6627 const char16_t* str2 = aStr2.BeginReading();
6628 const char16_t* end = str1 + len;
6629
6630 while (str1 < end) {
6631 char16_t c1 = *str1++;
6632 char16_t c2 = *str2++;
6633
6634 // First check if any bits other than the 0x0020 differs
6635 if ((c1 ^ c2) & 0xffdf) {
6636 return false;
6637 }
6638
6639 // We know they can only differ in the 0x0020 bit.
6640 // Likely the two chars are the same, so check that first
6641 if (c1 != c2) {
6642 // They do differ, but since it's only in the 0x0020 bit, check if it's
6643 // the same ascii char, but just differing in case
6644 char16_t c1Upper = c1 & 0xffdf;
6645 if (!('A' <= c1Upper && c1Upper <= 'Z')) {
6646 return false;
6647 }
6648 }
6649 }
6650
6651 return true;
6652}
6653
6654/* static */
6655bool nsContentUtils::StringContainsASCIIUpper(const nsAString& aStr) {
6656 const char16_t* iter = aStr.BeginReading();
6657 const char16_t* end = aStr.EndReading();
6658 while (iter != end) {
6659 char16_t c = *iter;
6660 if (c >= 'A' && c <= 'Z') {
6661 return true;
6662 }
6663 ++iter;
6664 }
6665
6666 return false;
6667}
6668
6669/* static */
6670nsIInterfaceRequestor* nsContentUtils::SameOriginChecker() {
6671 if (!sSameOriginChecker) {
6672 sSameOriginChecker = new SameOriginCheckerImpl();
6673 NS_ADDREF(sSameOriginChecker)(sSameOriginChecker)->AddRef();
6674 }
6675 return sSameOriginChecker;
6676}
6677
6678/* static */
6679nsresult nsContentUtils::CheckSameOrigin(nsIChannel* aOldChannel,
6680 nsIChannel* aNewChannel) {
6681 if (!nsContentUtils::GetSecurityManager()) return NS_ERROR_NOT_AVAILABLE;
6682
6683 nsCOMPtr<nsIPrincipal> oldPrincipal;
6684 nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
6685 aOldChannel, getter_AddRefs(oldPrincipal));
6686
6687 nsCOMPtr<nsIURI> newURI;
6688 aNewChannel->GetURI(getter_AddRefs(newURI));
6689 nsCOMPtr<nsIURI> newOriginalURI;
6690 aNewChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
6691
6692 NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI)do { if ((__builtin_expect(!!(!(oldPrincipal && newURI
&& newOriginalURI)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "oldPrincipal && newURI && newOriginalURI"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6692); return NS_ERROR_UNEXPECTED; } } while (false)
;
6693
6694 nsresult rv = oldPrincipal->CheckMayLoad(newURI, false);
6695 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && newOriginalURI != newURI) {
6696 rv = oldPrincipal->CheckMayLoad(newOriginalURI, false);
6697 }
6698
6699 return rv;
6700}
6701
6702NS_IMPL_ISUPPORTS(SameOriginCheckerImpl, nsIChannelEventSink,MozExternalRefCountType SameOriginCheckerImpl::AddRef(void) {
static_assert(!std::is_destructible_v<SameOriginCheckerImpl
>, "Reference-counted class " "SameOriginCheckerImpl" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6703); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
6703; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("SameOriginCheckerImpl" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("SameOriginCheckerImpl" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"SameOriginCheckerImpl\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6703); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"SameOriginCheckerImpl\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 6703; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("SameOriginCheckerImpl" " not thread-safe");
nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("SameOriginCheckerImpl"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
SameOriginCheckerImpl::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6703); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 6703
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("SameOriginCheckerImpl" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("SameOriginCheckerImpl" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"SameOriginCheckerImpl\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6703); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"SameOriginCheckerImpl\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 6703; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("SameOriginCheckerImpl" " not thread-safe");
const char* const nametmp = "SameOriginCheckerImpl"; nsrefcnt
count = --mRefCnt; NS_LogRelease((this), (count), (nametmp))
; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return
count; } nsresult SameOriginCheckerImpl::QueryInterface(const
nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6703); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<SameOriginCheckerImpl, nsIChannelEventSink
>, int32_t( reinterpret_cast<char*>(static_cast<nsIChannelEventSink
*>((SameOriginCheckerImpl*)0x1000)) - reinterpret_cast<
char*>((SameOriginCheckerImpl*)0x1000))}, {&mozilla::detail
::kImplementedIID<SameOriginCheckerImpl, nsIInterfaceRequestor
>, int32_t( reinterpret_cast<char*>(static_cast<nsIInterfaceRequestor
*>((SameOriginCheckerImpl*)0x1000)) - reinterpret_cast<
char*>((SameOriginCheckerImpl*)0x1000))}, {&mozilla::detail
::kImplementedIID<SameOriginCheckerImpl, nsISupports>, int32_t
(reinterpret_cast<char*>(static_cast<nsISupports*>
( static_cast<nsIChannelEventSink*>((SameOriginCheckerImpl
*)0x1000))) - reinterpret_cast<char*>((SameOriginCheckerImpl
*)0x1000))}, { nullptr, 0 } } ; static_assert((sizeof(table) /
sizeof(table[0])) > 1, "need at least 1 interface"); rv =
NS_TableDrivenQI(static_cast<void*>(this), aIID, aInstancePtr
, table); return rv; }
6703 nsIInterfaceRequestor)MozExternalRefCountType SameOriginCheckerImpl::AddRef(void) {
static_assert(!std::is_destructible_v<SameOriginCheckerImpl
>, "Reference-counted class " "SameOriginCheckerImpl" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6703); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
6703; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("SameOriginCheckerImpl" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("SameOriginCheckerImpl" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"SameOriginCheckerImpl\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6703); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"SameOriginCheckerImpl\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 6703; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("SameOriginCheckerImpl" " not thread-safe");
nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("SameOriginCheckerImpl"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
SameOriginCheckerImpl::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6703); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 6703
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("SameOriginCheckerImpl" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("SameOriginCheckerImpl" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"SameOriginCheckerImpl\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6703); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"SameOriginCheckerImpl\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 6703; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("SameOriginCheckerImpl" " not thread-safe");
const char* const nametmp = "SameOriginCheckerImpl"; nsrefcnt
count = --mRefCnt; NS_LogRelease((this), (count), (nametmp))
; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return
count; } nsresult SameOriginCheckerImpl::QueryInterface(const
nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6703); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<SameOriginCheckerImpl, nsIChannelEventSink
>, int32_t( reinterpret_cast<char*>(static_cast<nsIChannelEventSink
*>((SameOriginCheckerImpl*)0x1000)) - reinterpret_cast<
char*>((SameOriginCheckerImpl*)0x1000))}, {&mozilla::detail
::kImplementedIID<SameOriginCheckerImpl, nsIInterfaceRequestor
>, int32_t( reinterpret_cast<char*>(static_cast<nsIInterfaceRequestor
*>((SameOriginCheckerImpl*)0x1000)) - reinterpret_cast<
char*>((SameOriginCheckerImpl*)0x1000))}, {&mozilla::detail
::kImplementedIID<SameOriginCheckerImpl, nsISupports>, int32_t
(reinterpret_cast<char*>(static_cast<nsISupports*>
( static_cast<nsIChannelEventSink*>((SameOriginCheckerImpl
*)0x1000))) - reinterpret_cast<char*>((SameOriginCheckerImpl
*)0x1000))}, { nullptr, 0 } } ; static_assert((sizeof(table) /
sizeof(table[0])) > 1, "need at least 1 interface"); rv =
NS_TableDrivenQI(static_cast<void*>(this), aIID, aInstancePtr
, table); return rv; }
6704
6705NS_IMETHODIMPnsresult
6706SameOriginCheckerImpl::AsyncOnChannelRedirect(
6707 nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aFlags,
6708 nsIAsyncVerifyRedirectCallback* cb) {
6709 MOZ_ASSERT(aNewChannel, "Redirecting to null channel?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewChannel)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewChannel))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aNewChannel" " ("
"Redirecting to null channel?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6709); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewChannel"
") (" "Redirecting to null channel?" ")"); do { *((volatile int
*)__null) = 6709; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
6710
6711 nsresult rv = nsContentUtils::CheckSameOrigin(aOldChannel, aNewChannel);
6712 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
6713 cb->OnRedirectVerifyCallback(NS_OK);
6714 }
6715
6716 return rv;
6717}
6718
6719NS_IMETHODIMPnsresult
6720SameOriginCheckerImpl::GetInterface(const nsIID& aIID, void** aResult) {
6721 return QueryInterface(aIID, aResult);
6722}
6723
6724/* static */
6725nsresult nsContentUtils::GetWebExposedOriginSerialization(nsIURI* aURI,
6726 nsACString& aOrigin) {
6727 nsresult rv;
6728 MOZ_ASSERT(aURI, "missing uri")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aURI)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aURI))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aURI" " (" "missing uri" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6728); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aURI" ") ("
"missing uri" ")"); do { *((volatile int*)__null) = 6728; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
6729
6730 // For Blob URI, the path is the URL of the owning page.
6731 if (aURI->SchemeIs(BLOBURI_SCHEME"blob")) {
6732 nsAutoCString path;
6733 rv = aURI->GetPathQueryRef(path);
6734 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6734); return rv; } } while (false)
;
6735
6736 nsCOMPtr<nsIURI> uri;
6737 rv = NS_NewURI(getter_AddRefs(uri), path);
6738 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
6739 aOrigin.AssignLiteral("null");
6740 return NS_OK;
6741 }
6742
6743 if (
6744 // Schemes in spec. https://url.spec.whatwg.org/#origin
6745 !uri->SchemeIs("http") && !uri->SchemeIs("https") &&
6746 !uri->SchemeIs("file") && !uri->SchemeIs("resource") &&
6747 // Our own schemes.
6748 !uri->SchemeIs("moz-extension")) {
6749 aOrigin.AssignLiteral("null");
6750 return NS_OK;
6751 }
6752
6753 return GetWebExposedOriginSerialization(uri, aOrigin);
6754 }
6755
6756 nsAutoCString scheme;
6757 aURI->GetScheme(scheme);
6758
6759 // If the protocol doesn't have URI_HAS_WEB_EXPOSED_ORIGIN, then
6760 // return "null" as the origin serialization.
6761 // We make an exception for "ftp" since we don't have a protocol handler
6762 // for this scheme
6763 uint32_t flags = 0;
6764 nsCOMPtr<nsIIOService> io = mozilla::components::IO::Service(&rv);
6765 if (!scheme.Equals("ftp") && NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) &&
6766 NS_SUCCEEDED(io->GetProtocolFlags(scheme.get(), &flags))((bool)(__builtin_expect(!!(!NS_FAILED_impl(io->GetProtocolFlags
(scheme.get(), &flags))), 1)))
) {
6767 if (!(flags & nsIProtocolHandler::URI_HAS_WEB_EXPOSED_ORIGIN)) {
6768 aOrigin.AssignLiteral("null");
6769 return NS_OK;
6770 }
6771 }
6772
6773 aOrigin.Truncate();
6774
6775 nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI);
6776 NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED)do { if ((__builtin_expect(!!(!(uri)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "uri" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6776); return NS_ERROR_UNEXPECTED; } } while (false)
;
6777
6778 nsAutoCString host;
6779 rv = uri->GetAsciiHost(host);
6780
6781 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !host.IsEmpty()) {
6782 nsAutoCString userPass;
6783 uri->GetUserPass(userPass);
6784
6785 nsAutoCString prePath;
6786 if (!userPass.IsEmpty()) {
6787 rv = NS_MutateURI(uri).SetUserPass(""_ns).Finalize(uri);
6788 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6788); return rv; } } while (false)
;
6789 }
6790
6791 rv = uri->GetPrePath(prePath);
6792 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6792); return rv; } } while (false)
;
6793
6794 aOrigin = prePath;
6795 } else {
6796 aOrigin.AssignLiteral("null");
6797 }
6798
6799 return NS_OK;
6800}
6801
6802/* static */
6803nsresult nsContentUtils::GetWebExposedOriginSerialization(
6804 nsIPrincipal* aPrincipal, nsAString& aOrigin) {
6805 MOZ_ASSERT(aPrincipal, "missing principal")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPrincipal))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aPrincipal" " (" "missing principal"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6805); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrincipal"
") (" "missing principal" ")"); do { *((volatile int*)__null
) = 6805; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
6806
6807 aOrigin.Truncate();
6808 nsAutoCString webExposedOriginSerialization;
6809
6810 nsresult rv = aPrincipal->GetWebExposedOriginSerialization(
6811 webExposedOriginSerialization);
6812 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
6813 webExposedOriginSerialization.AssignLiteral("null");
6814 }
6815
6816 CopyUTF8toUTF16(webExposedOriginSerialization, aOrigin);
6817 return NS_OK;
6818}
6819
6820/* static */
6821nsresult nsContentUtils::GetWebExposedOriginSerialization(nsIURI* aURI,
6822 nsAString& aOrigin) {
6823 MOZ_ASSERT(aURI, "missing uri")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aURI)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aURI))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aURI" " (" "missing uri" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6823); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aURI" ") ("
"missing uri" ")"); do { *((volatile int*)__null) = 6823; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
6824 nsresult rv;
6825
6826#if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
6827 // Check if either URI has a special origin.
6828 nsCOMPtr<nsIURIWithSpecialOrigin> uriWithSpecialOrigin =
6829 do_QueryInterface(aURI);
6830 if (uriWithSpecialOrigin) {
6831 nsCOMPtr<nsIURI> origin;
6832 rv = uriWithSpecialOrigin->GetOrigin(getter_AddRefs(origin));
6833 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6833); return rv; } } while (false)
;
6834
6835 return GetWebExposedOriginSerialization(origin, aOrigin);
6836 }
6837#endif
6838
6839 nsAutoCString webExposedOriginSerialization;
6840 rv = GetWebExposedOriginSerialization(aURI, webExposedOriginSerialization);
6841 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6841); return rv; } } while (false)
;
6842
6843 CopyUTF8toUTF16(webExposedOriginSerialization, aOrigin);
6844 return NS_OK;
6845}
6846
6847/* static */
6848bool nsContentUtils::CheckMayLoad(nsIPrincipal* aPrincipal,
6849 nsIChannel* aChannel,
6850 bool aAllowIfInheritsPrincipal) {
6851 nsCOMPtr<nsIURI> channelURI;
6852 nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
6853 NS_ENSURE_SUCCESS(rv, false)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "false", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6853); return false; } } while (false)
;
6854
6855 return NS_SUCCEEDED(((bool)(__builtin_expect(!!(!NS_FAILED_impl(aPrincipal->CheckMayLoad
(channelURI, aAllowIfInheritsPrincipal))), 1)))
6856 aPrincipal->CheckMayLoad(channelURI, aAllowIfInheritsPrincipal))((bool)(__builtin_expect(!!(!NS_FAILED_impl(aPrincipal->CheckMayLoad
(channelURI, aAllowIfInheritsPrincipal))), 1)))
;
6857}
6858
6859/* static */
6860bool nsContentUtils::CanAccessNativeAnon() {
6861 return LegacyIsCallerChromeOrNativeCode();
6862}
6863
6864/* static */
6865nsresult nsContentUtils::DispatchXULCommand(nsIContent* aTarget, bool aTrusted,
6866 Event* aSourceEvent,
6867 PresShell* aPresShell, bool aCtrl,
6868 bool aAlt, bool aShift, bool aMeta,
6869 uint16_t aInputSource,
6870 int16_t aButton) {
6871 NS_ENSURE_STATE(aTarget)do { if ((__builtin_expect(!!(!(aTarget)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aTarget" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6871); return NS_ERROR_UNEXPECTED; } } while (false)
;
6872 Document* doc = aTarget->OwnerDoc();
6873 nsPresContext* presContext = doc->GetPresContext();
6874
6875 RefPtr<XULCommandEvent> xulCommand =
6876 new XULCommandEvent(doc, presContext, nullptr);
6877 xulCommand->InitCommandEvent(u"command"_ns, true, true,
6878 nsGlobalWindowInner::Cast(doc->GetInnerWindow()),
6879 0, aCtrl, aAlt, aShift, aMeta, aButton,
6880 aSourceEvent, aInputSource, IgnoreErrors());
6881
6882 if (aPresShell) {
6883 nsEventStatus status = nsEventStatus_eIgnore;
6884 return aPresShell->HandleDOMEventWithTarget(aTarget, xulCommand, &status);
6885 }
6886
6887 ErrorResult rv;
6888 aTarget->DispatchEvent(*xulCommand, rv);
6889 return rv.StealNSResult();
6890}
6891
6892// static
6893nsresult nsContentUtils::WrapNative(JSContext* cx, nsISupports* native,
6894 nsWrapperCache* cache, const nsIID* aIID,
6895 JS::MutableHandle<JS::Value> vp,
6896 bool aAllowWrapping) {
6897 MOZ_ASSERT(cx == GetCurrentJSContext())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cx == GetCurrentJSContext())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(cx == GetCurrentJSContext())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("cx == GetCurrentJSContext()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6897); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cx == GetCurrentJSContext()"
")"); do { *((volatile int*)__null) = 6897; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6898
6899 if (!native) {
6900 vp.setNull();
6901
6902 return NS_OK;
6903 }
6904
6905 JSObject* wrapper = xpc_FastGetCachedWrapper(cx, cache, vp);
6906 if (wrapper) {
6907 return NS_OK;
6908 }
6909
6910 NS_ENSURE_TRUE(sXPConnect, NS_ERROR_UNEXPECTED)do { if ((__builtin_expect(!!(!(sXPConnect)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "sXPConnect" ") failed",
nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6910); return NS_ERROR_UNEXPECTED; } } while (false)
;
6911
6912 if (!NS_IsMainThread()) {
6913 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 6913); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 6913; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
6914 }
6915
6916 JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
6917 nsresult rv = sXPConnect->WrapNativeToJSVal(cx, scope, native, cache, aIID,
6918 aAllowWrapping, vp);
6919 return rv;
6920}
6921
6922void nsContentUtils::StripNullChars(const nsAString& aInStr,
6923 nsAString& aOutStr) {
6924 // In common cases where we don't have nulls in the
6925 // string we can simple simply bypass the checking code.
6926 int32_t firstNullPos = aInStr.FindChar('\0');
6927 if (firstNullPos == kNotFound) {
6928 aOutStr.Assign(aInStr);
6929 return;
6930 }
6931
6932 aOutStr.SetCapacity(aInStr.Length() - 1);
6933 nsAString::const_iterator start, end;
6934 aInStr.BeginReading(start);
6935 aInStr.EndReading(end);
6936 while (start != end) {
6937 if (*start != '\0') aOutStr.Append(*start);
6938 ++start;
6939 }
6940}
6941
6942struct ClassMatchingInfo {
6943 AtomArray mClasses;
6944 nsCaseTreatment mCaseTreatment;
6945};
6946
6947// static
6948bool nsContentUtils::MatchClassNames(Element* aElement, int32_t aNamespaceID,
6949 nsAtom* aAtom, void* aData) {
6950 // We can't match if there are no class names
6951 const nsAttrValue* classAttr = aElement->GetClasses();
6952 if (!classAttr) {
6953 return false;
6954 }
6955
6956 // need to match *all* of the classes
6957 ClassMatchingInfo* info = static_cast<ClassMatchingInfo*>(aData);
6958 uint32_t length = info->mClasses.Length();
6959 if (!length) {
6960 // If we actually had no classes, don't match.
6961 return false;
6962 }
6963 uint32_t i;
6964 for (i = 0; i < length; ++i) {
6965 if (!classAttr->Contains(info->mClasses[i], info->mCaseTreatment)) {
6966 return false;
6967 }
6968 }
6969
6970 return true;
6971}
6972
6973// static
6974void nsContentUtils::DestroyClassNameArray(void* aData) {
6975 ClassMatchingInfo* info = static_cast<ClassMatchingInfo*>(aData);
6976 delete info;
6977}
6978
6979// static
6980void* nsContentUtils::AllocClassMatchingInfo(nsINode* aRootNode,
6981 const nsString* aClasses) {
6982 nsAttrValue attrValue;
6983 attrValue.ParseAtomArray(*aClasses);
6984 // nsAttrValue::Equals is sensitive to order, so we'll send an array
6985 auto* info = new ClassMatchingInfo;
6986 if (attrValue.Type() == nsAttrValue::eAtomArray) {
6987 info->mClasses = attrValue.GetAtomArrayValue()->mArray.Clone();
6988 } else if (attrValue.Type() == nsAttrValue::eAtom) {
6989 info->mClasses.AppendElement(attrValue.GetAtomValue());
6990 }
6991
6992 info->mCaseTreatment =
6993 aRootNode->OwnerDoc()->GetCompatibilityMode() == eCompatibility_NavQuirks
6994 ? eIgnoreCase
6995 : eCaseMatters;
6996 return info;
6997}
6998
6999bool nsContentUtils::HasScrollgrab(nsIContent* aContent) {
7000 // If we ever standardize this feature we'll want to hook this up properly
7001 // again. For now we're removing all the DOM-side code related to it but
7002 // leaving the layout and APZ handling for it in place.
7003 return false;
7004}
7005
7006void nsContentUtils::FlushLayoutForTree(nsPIDOMWindowOuter* aWindow) {
7007 if (!aWindow) {
7008 return;
7009 }
7010
7011 // Note that because FlushPendingNotifications flushes parents, this
7012 // is O(N^2) in docshell tree depth. However, the docshell tree is
7013 // usually pretty shallow.
7014
7015 if (RefPtr<Document> doc = aWindow->GetDoc()) {
7016 doc->FlushPendingNotifications(FlushType::Layout);
7017 }
7018
7019 if (nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell()) {
7020 int32_t i = 0, i_end;
7021 docShell->GetInProcessChildCount(&i_end);
7022 for (; i < i_end; ++i) {
7023 nsCOMPtr<nsIDocShellTreeItem> item;
7024 if (docShell->GetInProcessChildAt(i, getter_AddRefs(item)) == NS_OK &&
7025 item) {
7026 if (nsCOMPtr<nsPIDOMWindowOuter> win = item->GetWindow()) {
7027 FlushLayoutForTree(win);
7028 }
7029 }
7030 }
7031 }
7032}
7033
7034void nsContentUtils::RemoveNewlines(nsString& aString) { aString.StripCRLF(); }
7035
7036void nsContentUtils::PlatformToDOMLineBreaks(nsString& aString) {
7037 if (!PlatformToDOMLineBreaks(aString, fallible)) {
7038 aString.AllocFailed(aString.Length());
7039 }
7040}
7041
7042bool nsContentUtils::PlatformToDOMLineBreaks(nsString& aString,
7043 const fallible_t& aFallible) {
7044 if (aString.FindChar(char16_t('\r')) != -1) {
7045 // Windows linebreaks: Map CRLF to LF:
7046 if (!aString.ReplaceSubstring(u"\r\n", u"\n", aFallible)) {
7047 return false;
7048 }
7049
7050 // Mac linebreaks: Map any remaining CR to LF:
7051 if (!aString.ReplaceSubstring(u"\r", u"\n", aFallible)) {
7052 return false;
7053 }
7054 }
7055
7056 return true;
7057}
7058
7059already_AddRefed<nsContentList> nsContentUtils::GetElementsByClassName(
7060 nsINode* aRootNode, const nsAString& aClasses) {
7061 MOZ_ASSERT(aRootNode, "Must have root node")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRootNode)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRootNode))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aRootNode" " (" "Must have root node"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7061); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRootNode" ") ("
"Must have root node" ")"); do { *((volatile int*)__null) = 7061
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
7062
7063 return GetFuncStringContentList<nsCacheableFuncStringHTMLCollection>(
7064 aRootNode, MatchClassNames, DestroyClassNameArray, AllocClassMatchingInfo,
7065 aClasses);
7066}
7067
7068PresShell* nsContentUtils::FindPresShellForDocument(const Document* aDocument) {
7069 const Document* doc = aDocument;
7070 Document* displayDoc = doc->GetDisplayDocument();
7071 if (displayDoc) {
7072 doc = displayDoc;
7073 }
7074
7075 PresShell* presShell = doc->GetPresShell();
7076 if (presShell) {
7077 return presShell;
7078 }
7079
7080 nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = doc->GetDocShell();
7081 while (docShellTreeItem) {
7082 // We may be in a display:none subdocument, or we may not have a presshell
7083 // created yet.
7084 // Walk the docshell tree to find the nearest container that has a
7085 // presshell, and return that.
7086 nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(docShellTreeItem);
7087 if (PresShell* presShell = docShell->GetPresShell()) {
7088 return presShell;
7089 }
7090 nsCOMPtr<nsIDocShellTreeItem> parent;
7091 docShellTreeItem->GetInProcessParent(getter_AddRefs(parent));
7092 docShellTreeItem = parent;
7093 }
7094
7095 return nullptr;
7096}
7097
7098/* static */
7099nsPresContext* nsContentUtils::FindPresContextForDocument(
7100 const Document* aDocument) {
7101 if (PresShell* presShell = FindPresShellForDocument(aDocument)) {
7102 return presShell->GetPresContext();
7103 }
7104 return nullptr;
7105}
7106
7107nsIWidget* nsContentUtils::WidgetForDocument(const Document* aDocument) {
7108 PresShell* presShell = FindPresShellForDocument(aDocument);
7109 if (!presShell) {
7110 return nullptr;
7111 }
7112 nsViewManager* vm = presShell->GetViewManager();
7113 if (!vm) {
7114 return nullptr;
7115 }
7116 nsView* rootView = vm->GetRootView();
7117 if (!rootView) {
7118 return nullptr;
7119 }
7120 nsView* displayRoot = nsViewManager::GetDisplayRootFor(rootView);
7121 if (!displayRoot) {
7122 return nullptr;
7123 }
7124 return displayRoot->GetNearestWidget(nullptr);
7125}
7126
7127nsIWidget* nsContentUtils::WidgetForContent(const nsIContent* aContent) {
7128 nsIFrame* frame = aContent->GetPrimaryFrame();
7129 if (frame) {
7130 frame = nsLayoutUtils::GetDisplayRootFrame(frame);
7131
7132 nsView* view = frame->GetView();
7133 if (view) {
7134 return view->GetWidget();
7135 }
7136 }
7137
7138 return nullptr;
7139}
7140
7141WindowRenderer* nsContentUtils::WindowRendererForContent(
7142 const nsIContent* aContent) {
7143 nsIWidget* widget = nsContentUtils::WidgetForContent(aContent);
7144 if (widget) {
7145 return widget->GetWindowRenderer();
7146 }
7147
7148 return nullptr;
7149}
7150
7151WindowRenderer* nsContentUtils::WindowRendererForDocument(
7152 const Document* aDoc) {
7153 nsIWidget* widget = nsContentUtils::WidgetForDocument(aDoc);
7154 if (widget) {
7155 return widget->GetWindowRenderer();
7156 }
7157
7158 return nullptr;
7159}
7160
7161bool nsContentUtils::AllowXULXBLForPrincipal(nsIPrincipal* aPrincipal) {
7162 if (!aPrincipal) {
7163 return false;
7164 }
7165
7166 if (aPrincipal->IsSystemPrincipal()) {
7167 return true;
7168 }
7169
7170 return xpc::IsInAutomation() && IsSitePermAllow(aPrincipal, "allowXULXBL"_ns);
7171}
7172
7173bool nsContentUtils::IsPDFJSEnabled() {
7174 nsCOMPtr<nsIStreamConverter> conv = do_CreateInstance(
7175 "@mozilla.org/streamconv;1?from=application/pdf&to=text/html");
7176 return conv;
7177}
7178
7179bool nsContentUtils::IsPDFJS(nsIPrincipal* aPrincipal) {
7180 if (!aPrincipal || !aPrincipal->SchemeIs("resource")) {
7181 return false;
7182 }
7183 nsAutoCString spec;
7184 nsresult rv = aPrincipal->GetAsciiSpec(spec);
7185 NS_ENSURE_SUCCESS(rv, false)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "false", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7185); return false; } } while (false)
;
7186 return spec.EqualsLiteral("resource://pdf.js/web/viewer.html");
7187}
7188
7189bool nsContentUtils::IsSystemOrPDFJS(JSContext* aCx, JSObject*) {
7190 nsIPrincipal* principal = SubjectPrincipal(aCx);
7191 return principal && (principal->IsSystemPrincipal() || IsPDFJS(principal));
7192}
7193
7194bool nsContentUtils::IsSecureContextOrWebExtension(JSContext* aCx,
7195 JSObject* aGlobal) {
7196 nsIPrincipal* principal = SubjectPrincipal(aCx);
7197 return mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx,
7198 aGlobal) ||
7199 (principal && principal->GetIsAddonOrExpandedAddonPrincipal());
7200}
7201
7202already_AddRefed<nsIDocumentLoaderFactory>
7203nsContentUtils::FindInternalDocumentViewer(const nsACString& aType,
7204 DocumentViewerType* aLoaderType) {
7205 if (aLoaderType) {
7206 *aLoaderType = TYPE_UNSUPPORTED;
7207 }
7208
7209 // one helper factory, please
7210 nsCOMPtr<nsICategoryManager> catMan(
7211 do_GetService(NS_CATEGORYMANAGER_CONTRACTID"@mozilla.org/categorymanager;1"));
7212 if (!catMan) return nullptr;
7213
7214 nsCOMPtr<nsIDocumentLoaderFactory> docFactory;
7215
7216 nsCString contractID;
7217 nsresult rv =
7218 catMan->GetCategoryEntry("Gecko-Content-Viewers", aType, contractID);
7219 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
7220 docFactory = do_GetService(contractID.get());
7221 if (docFactory && aLoaderType) {
7222 if (contractID.EqualsLiteral(CONTENT_DLF_CONTRACTID"@mozilla.org/content/document-loader-factory;1"))
7223 *aLoaderType = TYPE_CONTENT;
7224 else if (contractID.EqualsLiteral(PLUGIN_DLF_CONTRACTID"@mozilla.org/content/plugin/document-loader-factory;1"))
7225 *aLoaderType = TYPE_FALLBACK;
7226 else
7227 *aLoaderType = TYPE_UNKNOWN;
7228 }
7229 return docFactory.forget();
7230 }
7231
7232 // If the type wasn't registered in `Gecko-Content-Viewers`, check if it's
7233 // another type which we may dynamically support, such as `text/*` types or
7234 // video document types. These types are all backed by the nsContentDLF.
7235 if (IsPlainTextType(aType) ||
7236 DecoderTraits::IsSupportedInVideoDocument(aType)) {
7237 docFactory = do_GetService(CONTENT_DLF_CONTRACTID"@mozilla.org/content/document-loader-factory;1");
7238 if (docFactory && aLoaderType) {
7239 *aLoaderType = TYPE_CONTENT;
7240 }
7241 return docFactory.forget();
7242 }
7243
7244 return nullptr;
7245}
7246
7247static void ReportPatternCompileFailure(nsAString& aPattern,
7248 const JS::RegExpFlags& aFlags,
7249 const Document* aDocument,
7250 JS::MutableHandle<JS::Value> error,
7251 JSContext* cx) {
7252 AutoTArray<nsString, 3> strings;
7253
7254 strings.AppendElement(aPattern);
7255
7256 std::stringstream flag_ss;
7257 flag_ss << aFlags;
7258 nsString* flagstr = strings.AppendElement();
7259 AppendUTF8toUTF16(flag_ss.str(), *flagstr);
7260
7261 JS::AutoSaveExceptionState savedExc(cx);
7262 JS::Rooted<JSObject*> exnObj(cx, &error.toObject());
7263 JS::Rooted<JS::Value> messageVal(cx);
7264 if (!JS_GetProperty(cx, exnObj, "message", &messageVal)) {
7265 return;
7266 }
7267 JS::Rooted<JSString*> messageStr(cx, messageVal.toString());
7268 MOZ_ASSERT(messageStr)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(messageStr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(messageStr))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("messageStr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7268); AnnotateMozCrashReason("MOZ_ASSERT" "(" "messageStr"
")"); do { *((volatile int*)__null) = 7268; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7269 if (!AssignJSString(cx, *strings.AppendElement(), messageStr)) {
7270 return;
7271 }
7272
7273 nsContentUtils::ReportToConsole(nsIScriptError::errorFlag, "DOM"_ns,
7274 aDocument, nsContentUtils::eDOM_PROPERTIES,
7275 "PatternAttributeCompileFailurev2", strings);
7276 savedExc.drop();
7277}
7278
7279// static
7280Maybe<bool> nsContentUtils::IsPatternMatching(const nsAString& aValue,
7281 nsString&& aPattern,
7282 const Document* aDocument,
7283 bool aHasMultiple,
7284 JS::RegExpFlags aFlags) {
7285 NS_ASSERTION(aDocument, "aDocument should be a valid pointer (not null)")do { if (!(aDocument)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "aDocument should be a valid pointer (not null)"
, "aDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7285); MOZ_PretendNoReturn(); } } while (0)
;
7286
7287 // The fact that we're using a JS regexp under the hood should not be visible
7288 // to things like window onerror handlers, so we don't initialize our JSAPI
7289 // with the document's window (which may not exist anyway).
7290 AutoJSAPI jsapi;
7291 jsapi.Init();
7292 JSContext* cx = jsapi.cx();
7293 AutoDisableJSInterruptCallback disabler(cx);
7294
7295 // We can use the junk scope here, because we're just using it for regexp
7296 // evaluation, not actual script execution, and we disable statics so that the
7297 // evaluation does not interact with the execution global.
7298 JSAutoRealm ar(cx, xpc::PrivilegedJunkScope());
7299
7300 // Check if the pattern by itself is valid first, and not that it only becomes
7301 // valid once we add ^(?: and )$.
7302 JS::Rooted<JS::Value> error(cx);
7303 if (!JS::CheckRegExpSyntax(cx, aPattern.BeginReading(), aPattern.Length(),
7304 aFlags, &error)) {
7305 return Nothing();
7306 }
7307
7308 if (!error.isUndefined()) {
7309 ReportPatternCompileFailure(aPattern, aFlags, aDocument, &error, cx);
7310 return Some(true);
7311 }
7312
7313 // The pattern has to match the entire value.
7314 aPattern.InsertLiteral(u"^(?:", 0);
7315 aPattern.AppendLiteral(")$");
7316
7317 JS::Rooted<JSObject*> re(
7318 cx, JS::NewUCRegExpObject(cx, aPattern.BeginReading(), aPattern.Length(),
7319 aFlags));
7320 if (!re) {
7321 return Nothing();
7322 }
7323
7324 JS::Rooted<JS::Value> rval(cx, JS::NullValue());
7325 if (!aHasMultiple) {
7326 size_t idx = 0;
7327 if (!JS::ExecuteRegExpNoStatics(cx, re, aValue.BeginReading(),
7328 aValue.Length(), &idx, true, &rval)) {
7329 return Nothing();
7330 }
7331 return Some(!rval.isNull());
7332 }
7333
7334 HTMLSplitOnSpacesTokenizer tokenizer(aValue, ',');
7335 while (tokenizer.hasMoreTokens()) {
7336 const nsAString& value = tokenizer.nextToken();
7337 size_t idx = 0;
7338 if (!JS::ExecuteRegExpNoStatics(cx, re, value.BeginReading(),
7339 value.Length(), &idx, true, &rval)) {
7340 return Nothing();
7341 }
7342 if (rval.isNull()) {
7343 return Some(false);
7344 }
7345 }
7346 return Some(true);
7347}
7348
7349// static
7350nsresult nsContentUtils::URIInheritsSecurityContext(nsIURI* aURI,
7351 bool* aResult) {
7352 // Note: about:blank URIs do NOT inherit the security context from the
7353 // current document, which is what this function tests for...
7354 return NS_URIChainHasFlags(
7355 aURI, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT, aResult);
7356}
7357
7358// static
7359bool nsContentUtils::ChannelShouldInheritPrincipal(
7360 nsIPrincipal* aLoadingPrincipal, nsIURI* aURI, bool aInheritForAboutBlank,
7361 bool aForceInherit) {
7362 MOZ_ASSERT(aLoadingPrincipal,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadingPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadingPrincipal))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aLoadingPrincipal"
" (" "Can not check inheritance without a principal" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7363); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadingPrincipal"
") (" "Can not check inheritance without a principal" ")"); do
{ *((volatile int*)__null) = 7363; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
7363 "Can not check inheritance without a principal")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadingPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadingPrincipal))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aLoadingPrincipal"
" (" "Can not check inheritance without a principal" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7363); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadingPrincipal"
") (" "Can not check inheritance without a principal" ")"); do
{ *((volatile int*)__null) = 7363; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
7364
7365 // Only tell the channel to inherit if it can't provide its own security
7366 // context.
7367 //
7368 // XXX: If this is ever changed, check all callers for what owners
7369 // they're passing in. In particular, see the code and
7370 // comments in nsDocShell::LoadURI where we fall back on
7371 // inheriting the owner if called from chrome. That would be
7372 // very wrong if this code changed anything but channels that
7373 // can't provide their own security context!
7374 //
7375 // If aForceInherit is true, we will inherit, even for a channel that
7376 // can provide its own security context. This is used for srcdoc loads.
7377 bool inherit = aForceInherit;
7378 if (!inherit) {
7379 bool uriInherits;
7380 // We expect URIInheritsSecurityContext to return success for an
7381 // about:blank URI, so don't call NS_IsAboutBlank() if this call fails.
7382 // This condition needs to match the one in nsDocShell::InternalLoad where
7383 // we're checking for things that will use the owner.
7384 inherit =
7385 (NS_SUCCEEDED(URIInheritsSecurityContext(aURI, &uriInherits))((bool)(__builtin_expect(!!(!NS_FAILED_impl(URIInheritsSecurityContext
(aURI, &uriInherits))), 1)))
&&
7386 (uriInherits || (aInheritForAboutBlank &&
7387 NS_IsAboutBlankAllowQueryAndFragment(aURI)))) ||
7388 //
7389 // file: uri special-casing
7390 //
7391 // If this is a file: load opened from another file: then it may need
7392 // to inherit the owner from the referrer so they can script each other.
7393 // If we don't set the owner explicitly then each file: gets an owner
7394 // based on its own codebase later.
7395 //
7396 (URIIsLocalFile(aURI) &&
7397 NS_SUCCEEDED(aLoadingPrincipal->CheckMayLoad(aURI, false))((bool)(__builtin_expect(!!(!NS_FAILED_impl(aLoadingPrincipal
->CheckMayLoad(aURI, false))), 1)))
&&
7398 // One more check here. CheckMayLoad will always return true for the
7399 // system principal, but we do NOT want to inherit in that case.
7400 !aLoadingPrincipal->IsSystemPrincipal());
7401 }
7402 return inherit;
7403}
7404
7405/* static */
7406bool nsContentUtils::IsCutCopyAllowed(Document* aDocument,
7407 nsIPrincipal& aSubjectPrincipal) {
7408 if (StaticPrefs::dom_allow_cut_copy() && aDocument &&
7409 aDocument->HasValidTransientUserGestureActivation()) {
7410 return true;
7411 }
7412
7413 return PrincipalHasPermission(aSubjectPrincipal, nsGkAtoms::clipboardWrite);
7414}
7415
7416/* static */
7417bool nsContentUtils::HaveEqualPrincipals(Document* aDoc1, Document* aDoc2) {
7418 if (!aDoc1 || !aDoc2) {
7419 return false;
7420 }
7421 bool principalsEqual = false;
7422 aDoc1->NodePrincipal()->Equals(aDoc2->NodePrincipal(), &principalsEqual);
7423 return principalsEqual;
7424}
7425
7426/* static */
7427void nsContentUtils::FireMutationEventsForDirectParsing(
7428 Document* aDoc, nsIContent* aDest, int32_t aOldChildCount) {
7429 // Fire mutation events. Optimize for the case when there are no listeners
7430 int32_t newChildCount = aDest->GetChildCount();
7431 if (newChildCount && nsContentUtils::HasMutationListeners(
7432 aDoc, NS_EVENT_BITS_MUTATION_NODEINSERTED0x02)) {
7433 AutoTArray<nsCOMPtr<nsIContent>, 50> childNodes;
7434 NS_ASSERTION(newChildCount - aOldChildCount >= 0,do { if (!(newChildCount - aOldChildCount >= 0)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "What, some unexpected dom mutation has happened?"
, "newChildCount - aOldChildCount >= 0", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7435); MOZ_PretendNoReturn(); } } while (0)
7435 "What, some unexpected dom mutation has happened?")do { if (!(newChildCount - aOldChildCount >= 0)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "What, some unexpected dom mutation has happened?"
, "newChildCount - aOldChildCount >= 0", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7435); MOZ_PretendNoReturn(); } } while (0)
;
7436 childNodes.SetCapacity(newChildCount - aOldChildCount);
7437 for (nsIContent* child = aDest->GetFirstChild(); child;
7438 child = child->GetNextSibling()) {
7439 childNodes.AppendElement(child);
7440 }
7441 FragmentOrElement::FireNodeInserted(aDoc, aDest, childNodes);
7442 }
7443}
7444
7445/* static */
7446const Document* nsContentUtils::GetInProcessSubtreeRootDocument(
7447 const Document* aDoc) {
7448 if (!aDoc) {
7449 return nullptr;
7450 }
7451 const Document* doc = aDoc;
7452 while (doc->GetInProcessParentDocument()) {
7453 doc = doc->GetInProcessParentDocument();
7454 }
7455 return doc;
7456}
7457
7458// static
7459int32_t nsContentUtils::GetAdjustedOffsetInTextControl(nsIFrame* aOffsetFrame,
7460 int32_t aOffset) {
7461 // The structure of the anonymous frames within a text control frame is
7462 // an optional block frame, followed by an optional br frame.
7463
7464 // If the offset frame has a child, then this frame is the block which
7465 // has the text frames (containing the content) as its children. This will
7466 // be the case if we click to the right of any of the text frames, or at the
7467 // bottom of the text area.
7468 nsIFrame* firstChild = aOffsetFrame->PrincipalChildList().FirstChild();
7469 if (firstChild) {
7470 // In this case, the passed-in offset is incorrect, and we want the length
7471 // of the entire content in the text control frame.
7472 return firstChild->GetContent()->Length();
7473 }
7474
7475 if (aOffsetFrame->GetPrevSibling() && !aOffsetFrame->GetNextSibling()) {
7476 // In this case, we're actually within the last frame, which is a br
7477 // frame. Our offset should therefore be the length of the first child of
7478 // our parent.
7479 int32_t aOutOffset = aOffsetFrame->GetParent()
7480 ->PrincipalChildList()
7481 .FirstChild()
7482 ->GetContent()
7483 ->Length();
7484 return aOutOffset;
7485 }
7486
7487 // Otherwise, we're within one of the text frames, in which case our offset
7488 // has already been correctly calculated.
7489 return aOffset;
7490}
7491
7492// static
7493bool nsContentUtils::IsPointInSelection(
7494 const mozilla::dom::Selection& aSelection, const nsINode& aNode,
7495 const uint32_t aOffset, const bool aAllowCrossShadowBoundary) {
7496 const bool selectionIsCollapsed =
7497 !aAllowCrossShadowBoundary
7498 ? aSelection.IsCollapsed()
7499 : aSelection.AreNormalAndCrossShadowBoundaryRangesCollapsed();
7500 if (selectionIsCollapsed) {
7501 return false;
7502 }
7503
7504 const uint32_t rangeCount = aSelection.RangeCount();
7505 for (const uint32_t i : IntegerRange(rangeCount)) {
7506 MOZ_ASSERT(aSelection.RangeCount() == rangeCount)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSelection.RangeCount() == rangeCount)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(aSelection.RangeCount() == rangeCount))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aSelection.RangeCount() == rangeCount"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7506); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSelection.RangeCount() == rangeCount"
")"); do { *((volatile int*)__null) = 7506; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7507 RefPtr<const nsRange> range = aSelection.GetRangeAt(i);
7508 if (NS_WARN_IF(!range)NS_warn_if_impl(!range, "!range", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7508)
) {
7509 // Don't bail yet, iterate through them all
7510 continue;
7511 }
7512
7513 // Done when we find a range that we are in
7514 if (range->IsPointInRange(aNode, aOffset, IgnoreErrors(),
7515 aAllowCrossShadowBoundary)) {
7516 return true;
7517 }
7518 }
7519
7520 return false;
7521}
7522
7523// static
7524void nsContentUtils::GetSelectionInTextControl(Selection* aSelection,
7525 Element* aRoot,
7526 uint32_t& aOutStartOffset,
7527 uint32_t& aOutEndOffset) {
7528 MOZ_ASSERT(aSelection && aRoot)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSelection && aRoot)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aSelection && aRoot)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aSelection && aRoot"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7528); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSelection && aRoot"
")"); do { *((volatile int*)__null) = 7528; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7529
7530 // We don't care which end of this selection is anchor and which is focus. In
7531 // fact, we explicitly want to know which is the _start_ and which is the
7532 // _end_, not anchor vs focus.
7533 const nsRange* range = aSelection->GetAnchorFocusRange();
7534 if (!range) {
7535 // Nothing selected
7536 aOutStartOffset = aOutEndOffset = 0;
7537 return;
7538 }
7539
7540 // All the node pointers here are raw pointers for performance. We shouldn't
7541 // be doing anything in this function that invalidates the node tree.
7542 nsINode* startContainer = range->GetStartContainer();
7543 uint32_t startOffset = range->StartOffset();
7544 nsINode* endContainer = range->GetEndContainer();
7545 uint32_t endOffset = range->EndOffset();
7546
7547 // We have at most two children, consisting of an optional text node followed
7548 // by an optional <br>.
7549 NS_ASSERTION(aRoot->GetChildCount() <= 2, "Unexpected children")do { if (!(aRoot->GetChildCount() <= 2)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Unexpected children", "aRoot->GetChildCount() <= 2"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7549); MOZ_PretendNoReturn(); } } while (0)
;
7550 nsIContent* firstChild = aRoot->GetFirstChild();
7551#ifdef DEBUG1
7552 nsCOMPtr<nsIContent> lastChild = aRoot->GetLastChild();
7553 NS_ASSERTION(startContainer == aRoot || startContainer == firstChild ||do { if (!(startContainer == aRoot || startContainer == firstChild
|| startContainer == lastChild)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected startContainer", "startContainer == aRoot || startContainer == firstChild || startContainer == lastChild"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7555); MOZ_PretendNoReturn(); } } while (0)
7554 startContainer == lastChild,do { if (!(startContainer == aRoot || startContainer == firstChild
|| startContainer == lastChild)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected startContainer", "startContainer == aRoot || startContainer == firstChild || startContainer == lastChild"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7555); MOZ_PretendNoReturn(); } } while (0)
7555 "Unexpected startContainer")do { if (!(startContainer == aRoot || startContainer == firstChild
|| startContainer == lastChild)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected startContainer", "startContainer == aRoot || startContainer == firstChild || startContainer == lastChild"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7555); MOZ_PretendNoReturn(); } } while (0)
;
7556 NS_ASSERTION(endContainer == aRoot || endContainer == firstChild ||do { if (!(endContainer == aRoot || endContainer == firstChild
|| endContainer == lastChild)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected endContainer", "endContainer == aRoot || endContainer == firstChild || endContainer == lastChild"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7558); MOZ_PretendNoReturn(); } } while (0)
7557 endContainer == lastChild,do { if (!(endContainer == aRoot || endContainer == firstChild
|| endContainer == lastChild)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected endContainer", "endContainer == aRoot || endContainer == firstChild || endContainer == lastChild"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7558); MOZ_PretendNoReturn(); } } while (0)
7558 "Unexpected endContainer")do { if (!(endContainer == aRoot || endContainer == firstChild
|| endContainer == lastChild)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected endContainer", "endContainer == aRoot || endContainer == firstChild || endContainer == lastChild"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7558); MOZ_PretendNoReturn(); } } while (0)
;
7559 // firstChild is either text or a <br> (hence an element).
7560 MOZ_ASSERT_IF(firstChild, firstChild->IsText() || firstChild->IsElement())do { if (firstChild) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(firstChild->IsText() || firstChild->IsElement
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(firstChild->IsText() || firstChild->IsElement(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("firstChild->IsText() || firstChild->IsElement()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7560); AnnotateMozCrashReason("MOZ_ASSERT" "(" "firstChild->IsText() || firstChild->IsElement()"
")"); do { *((volatile int*)__null) = 7560; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
7561#endif
7562 if (!firstChild || firstChild->IsElement()) {
7563 // No text node, so everything is 0
7564 startOffset = endOffset = 0;
7565 } else {
7566 // First child is text. If the start/end is already in the text node,
7567 // or the start of the root node, no change needed. If it's in the root
7568 // node but not the start, or in the trailing <br>, we need to set the
7569 // offset to the end.
7570 if ((startContainer == aRoot && startOffset != 0) ||
7571 (startContainer != aRoot && startContainer != firstChild)) {
7572 startOffset = firstChild->Length();
7573 }
7574 if ((endContainer == aRoot && endOffset != 0) ||
7575 (endContainer != aRoot && endContainer != firstChild)) {
7576 endOffset = firstChild->Length();
7577 }
7578 }
7579
7580 MOZ_ASSERT(startOffset <= endOffset)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(startOffset <= endOffset)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(startOffset <= endOffset)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("startOffset <= endOffset"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 7580); AnnotateMozCrashReason("MOZ_ASSERT" "(" "startOffset <= endOffset"
")"); do { *((volatile int*)__null) = 7580; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7581 aOutStartOffset = startOffset;
7582 aOutEndOffset = endOffset;
7583}
7584
7585// static
7586HTMLEditor* nsContentUtils::GetHTMLEditor(nsPresContext* aPresContext) {
7587 if (!aPresContext) {
7588 return nullptr;
7589 }
7590 return GetHTMLEditor(aPresContext->GetDocShell());
7591}
7592
7593// static
7594HTMLEditor* nsContentUtils::GetHTMLEditor(nsDocShell* aDocShell) {
7595 bool isEditable;
7596 if (!aDocShell || NS_FAILED(aDocShell->GetEditable(&isEditable))((bool)(__builtin_expect(!!(NS_FAILED_impl(aDocShell->GetEditable
(&isEditable))), 0)))
||
7597 !isEditable) {
7598 return nullptr;
7599 }
7600 return aDocShell->GetHTMLEditor();
7601}
7602
7603// static
7604EditorBase* nsContentUtils::GetActiveEditor(nsPresContext* aPresContext) {
7605 if (!aPresContext) {
7606 return nullptr;
7607 }
7608
7609 return GetActiveEditor(aPresContext->Document()->GetWindow());
7610}
7611
7612// static
7613EditorBase* nsContentUtils::GetActiveEditor(nsPIDOMWindowOuter* aWindow) {
7614 if (!aWindow || !aWindow->GetExtantDoc()) {
7615 return nullptr;
7616 }
7617
7618 // If it's in designMode, nobody can have focus. Therefore, the HTMLEditor
7619 // handles all events. I.e., it's focused editor in this case.
7620 if (aWindow->GetExtantDoc()->IsInDesignMode()) {
7621 return GetHTMLEditor(nsDocShell::Cast(aWindow->GetDocShell()));
7622 }
7623
7624 // If focused element is associated with TextEditor, it must be <input>
7625 // element or <textarea> element. Let's return it even if it's in a
7626 // contenteditable element.
7627 nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
7628 if (Element* focusedElement = nsFocusManager::GetFocusedDescendant(
7629 aWindow, nsFocusManager::SearchRange::eOnlyCurrentWindow,
7630 getter_AddRefs(focusedWindow))) {
7631 if (TextEditor* textEditor = focusedElement->GetTextEditorInternal()) {
7632 return textEditor;
7633 }
7634 }
7635
7636 // Otherwise, HTMLEditor may handle inputs even non-editable element has
7637 // focus or nobody has focus.
7638 return GetHTMLEditor(nsDocShell::Cast(aWindow->GetDocShell()));
7639}
7640
7641// static
7642TextEditor* nsContentUtils::GetTextEditorFromAnonymousNodeWithoutCreation(
7643 const nsIContent* aAnonymousContent) {
7644 if (!aAnonymousContent) {
7645 return nullptr;
7646 }
7647 nsIContent* parent = aAnonymousContent->FindFirstNonChromeOnlyAccessContent();
7648 if (!parent || parent == aAnonymousContent) {
7649 return nullptr;
7650 }
7651 if (HTMLInputElement* inputElement =
7652 HTMLInputElement::FromNodeOrNull(parent)) {
7653 return inputElement->GetTextEditorWithoutCreation();
7654 }
7655 if (HTMLTextAreaElement* textareaElement =
7656 HTMLTextAreaElement::FromNodeOrNull(parent)) {
7657 return textareaElement->GetTextEditorWithoutCreation();
7658 }
7659 return nullptr;
7660}
7661
7662// static
7663bool nsContentUtils::IsNodeInEditableRegion(nsINode* aNode) {
7664 while (aNode) {
7665 if (aNode->IsEditable()) {
7666 return true;
7667 }
7668 aNode = aNode->GetParent();
7669 }
7670 return false;
7671}
7672
7673// static
7674bool nsContentUtils::IsForbiddenRequestHeader(const nsACString& aHeader,
7675 const nsACString& aValue) {
7676 if (IsForbiddenSystemRequestHeader(aHeader)) {
7677 return true;
7678 }
7679
7680 if ((nsContentUtils::IsOverrideMethodHeader(aHeader) &&
7681 nsContentUtils::ContainsForbiddenMethod(aValue))) {
7682 return true;
7683 }
7684
7685 if (StringBeginsWith(aHeader, "proxy-"_ns,
7686 nsCaseInsensitiveCStringComparator) ||
7687 StringBeginsWith(aHeader, "sec-"_ns,
7688 nsCaseInsensitiveCStringComparator)) {
7689 return true;
7690 }
7691
7692 return false;
7693}
7694
7695// static
7696bool nsContentUtils::IsForbiddenSystemRequestHeader(const nsACString& aHeader) {
7697 static const char* kInvalidHeaders[] = {"accept-charset",
7698 "accept-encoding",
7699 "access-control-request-headers",
7700 "access-control-request-method",
7701 "connection",
7702 "content-length",
7703 "cookie",
7704 "cookie2",
7705 "date",
7706 "dnt",
7707 "expect",
7708 "host",
7709 "keep-alive",
7710 "origin",
7711 "referer",
7712 "set-cookie",
7713 "te",
7714 "trailer",
7715 "transfer-encoding",
7716 "upgrade",
7717 "via"};
7718 for (auto& kInvalidHeader : kInvalidHeaders) {
7719 if (aHeader.LowerCaseEqualsASCII(kInvalidHeader)) {
7720 return true;
7721 }
7722 }
7723 return false;
7724}
7725
7726// static
7727bool nsContentUtils::IsForbiddenResponseHeader(const nsACString& aHeader) {
7728 return (aHeader.LowerCaseEqualsASCII("set-cookie") ||
7729 aHeader.LowerCaseEqualsASCII("set-cookie2"));
7730}
7731
7732// static
7733bool nsContentUtils::IsOverrideMethodHeader(const nsACString& headerName) {
7734 return headerName.EqualsIgnoreCase("x-http-method-override") ||
7735 headerName.EqualsIgnoreCase("x-http-method") ||
7736 headerName.EqualsIgnoreCase("x-method-override");
7737}
7738
7739// static
7740bool nsContentUtils::ContainsForbiddenMethod(const nsACString& headerValue) {
7741 bool hasInsecureMethod = false;
7742 nsCCharSeparatedTokenizer tokenizer(headerValue, ',');
7743
7744 while (tokenizer.hasMoreTokens()) {
7745 const nsDependentCSubstring& value = tokenizer.nextToken();
7746
7747 if (value.EqualsIgnoreCase("connect") || value.EqualsIgnoreCase("trace") ||
7748 value.EqualsIgnoreCase("track")) {
7749 hasInsecureMethod = true;
7750 break;
7751 }
7752 }
7753
7754 return hasInsecureMethod;
7755}
7756
7757Maybe<nsContentUtils::ParsedRange> nsContentUtils::ParseSingleRangeRequest(
7758 const nsACString& aHeaderValue, bool aAllowWhitespace) {
7759 // See https://fetch.spec.whatwg.org/#simple-range-header-value
7760 mozilla::Tokenizer p(aHeaderValue);
7761 Maybe<uint64_t> rangeStart;
7762 Maybe<uint64_t> rangeEnd;
7763
7764 // Step 2 and 3
7765 if (!p.CheckWord("bytes")) {
7766 return Nothing();
7767 }
7768
7769 // Step 4
7770 if (aAllowWhitespace) {
7771 p.SkipWhites();
7772 }
7773
7774 // Step 5 and 6
7775 if (!p.CheckChar('=')) {
7776 return Nothing();
7777 }
7778
7779 // Step 7
7780 if (aAllowWhitespace) {
7781 p.SkipWhites();
7782 }
7783
7784 // Step 8 and 9
7785 uint64_t res;
7786 if (p.ReadInteger(&res)) {
7787 rangeStart = Some(res);
7788 }
7789
7790 // Step 10
7791 if (aAllowWhitespace) {
7792 p.SkipWhites();
7793 }
7794
7795 // Step 11
7796 if (!p.CheckChar('-')) {
7797 return Nothing();
7798 }
7799
7800 // Step 13
7801 if (aAllowWhitespace) {
7802 p.SkipWhites();
7803 }
7804
7805 // Step 14 and 15
7806 if (p.ReadInteger(&res)) {
7807 rangeEnd = Some(res);
7808 }
7809
7810 // Step 16
7811 if (!p.CheckEOF()) {
7812 return Nothing();
7813 }
7814
7815 // Step 17
7816 if (!rangeStart && !rangeEnd) {
7817 return Nothing();
7818 }
7819
7820 // Step 18
7821 if (rangeStart && rangeEnd && *rangeStart > *rangeEnd) {
7822 return Nothing();
7823 }
7824
7825 return Some(ParsedRange(rangeStart, rangeEnd));
7826}
7827
7828// static
7829bool nsContentUtils::IsCorsUnsafeRequestHeaderValue(
7830 const nsACString& aHeaderValue) {
7831 const char* cur = aHeaderValue.BeginReading();
7832 const char* end = aHeaderValue.EndReading();
7833
7834 while (cur != end) {
7835 // Implementation of
7836 // https://fetch.spec.whatwg.org/#cors-unsafe-request-header-byte Is less
7837 // than a space but not a horizontal tab
7838 if ((*cur < ' ' && *cur != '\t') || *cur == '"' || *cur == '(' ||
7839 *cur == ')' || *cur == ':' || *cur == '<' || *cur == '>' ||
7840 *cur == '?' || *cur == '@' || *cur == '[' || *cur == '\\' ||
7841 *cur == ']' || *cur == '{' || *cur == '}' ||
7842 *cur == 0x7F) { // 0x75 is DEL
7843 return true;
7844 }
7845 cur++;
7846 }
7847 return false;
7848}
7849
7850// static
7851bool nsContentUtils::IsAllowedNonCorsAccept(const nsACString& aHeaderValue) {
7852 if (IsCorsUnsafeRequestHeaderValue(aHeaderValue)) {
7853 return false;
7854 }
7855 return true;
7856}
7857
7858// static
7859bool nsContentUtils::IsAllowedNonCorsContentType(
7860 const nsACString& aHeaderValue) {
7861 nsAutoCString contentType;
7862 nsAutoCString unused;
7863
7864 if (IsCorsUnsafeRequestHeaderValue(aHeaderValue)) {
7865 return false;
7866 }
7867
7868 nsresult rv = NS_ParseRequestContentType(aHeaderValue, contentType, unused);
7869 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
7870 return false;
7871 }
7872
7873 return contentType.LowerCaseEqualsLiteral("text/plain") ||
7874 contentType.LowerCaseEqualsLiteral(
7875 "application/x-www-form-urlencoded") ||
7876 contentType.LowerCaseEqualsLiteral("multipart/form-data");
7877}
7878
7879// static
7880bool nsContentUtils::IsAllowedNonCorsLanguage(const nsACString& aHeaderValue) {
7881 const char* cur = aHeaderValue.BeginReading();
7882 const char* end = aHeaderValue.EndReading();
7883
7884 while (cur != end) {
7885 if ((*cur >= '0' && *cur <= '9') || (*cur >= 'A' && *cur <= 'Z') ||
7886 (*cur >= 'a' && *cur <= 'z') || *cur == ' ' || *cur == '*' ||
7887 *cur == ',' || *cur == '-' || *cur == '.' || *cur == ';' ||
7888 *cur == '=') {
7889 cur++;
7890 continue;
7891 }
7892 return false;
7893 }
7894 return true;
7895}
7896
7897bool nsContentUtils::IsAllowedNonCorsRange(const nsACString& aHeaderValue) {
7898 Maybe<ParsedRange> parsedRange = ParseSingleRangeRequest(aHeaderValue, false);
7899 if (!parsedRange) {
7900 return false;
7901 }
7902
7903 if (!parsedRange->Start()) {
7904 return false;
7905 }
7906
7907 return true;
7908}
7909
7910// static
7911bool nsContentUtils::IsCORSSafelistedRequestHeader(const nsACString& aName,
7912 const nsACString& aValue) {
7913 // see https://fetch.spec.whatwg.org/#cors-safelisted-request-header
7914 if (aValue.Length() > 128) {
7915 return false;
7916 }
7917 return (aName.LowerCaseEqualsLiteral("accept") &&
7918 nsContentUtils::IsAllowedNonCorsAccept(aValue)) ||
7919 (aName.LowerCaseEqualsLiteral("accept-language") &&
7920 nsContentUtils::IsAllowedNonCorsLanguage(aValue)) ||
7921 (aName.LowerCaseEqualsLiteral("content-language") &&
7922 nsContentUtils::IsAllowedNonCorsLanguage(aValue)) ||
7923 (aName.LowerCaseEqualsLiteral("content-type") &&
7924 nsContentUtils::IsAllowedNonCorsContentType(aValue)) ||
7925 (aName.LowerCaseEqualsLiteral("range") &&
7926 nsContentUtils::IsAllowedNonCorsRange(aValue));
7927}
7928
7929mozilla::LogModule* nsContentUtils::ResistFingerprintingLog() {
7930 return gResistFingerprintingLog;
7931}
7932mozilla::LogModule* nsContentUtils::DOMDumpLog() { return sDOMDumpLog; }
7933
7934bool nsContentUtils::GetNodeTextContent(const nsINode* aNode, bool aDeep,
7935 nsAString& aResult,
7936 const fallible_t& aFallible) {
7937 aResult.Truncate();
7938 return AppendNodeTextContent(aNode, aDeep, aResult, aFallible);
7939}
7940
7941void nsContentUtils::GetNodeTextContent(const nsINode* aNode, bool aDeep,
7942 nsAString& aResult) {
7943 if (!GetNodeTextContent(aNode, aDeep, aResult, fallible)) {
7944 NS_ABORT_OOM(0); // Unfortunately we don't know the allocation size
7945 }
7946}
7947
7948void nsContentUtils::DestroyMatchString(void* aData) {
7949 if (aData) {
7950 nsString* matchString = static_cast<nsString*>(aData);
7951 delete matchString;
7952 }
7953}
7954
7955// Table ordered from most to least likely JS MIME types.
7956static constexpr std::string_view kJavascriptMIMETypes[] = {
7957 "text/javascript",
7958 "text/ecmascript",
7959 "application/javascript",
7960 "application/ecmascript",
7961 "application/x-javascript",
7962 "application/x-ecmascript",
7963 "text/javascript1.0",
7964 "text/javascript1.1",
7965 "text/javascript1.2",
7966 "text/javascript1.3",
7967 "text/javascript1.4",
7968 "text/javascript1.5",
7969 "text/jscript",
7970 "text/livescript",
7971 "text/x-ecmascript",
7972 "text/x-javascript"};
7973
7974bool nsContentUtils::IsJavascriptMIMEType(const nsAString& aMIMEType) {
7975 for (std::string_view type : kJavascriptMIMETypes) {
7976 if (aMIMEType.LowerCaseEqualsASCII(type.data(), type.length())) {
7977 return true;
7978 }
7979 }
7980 return false;
7981}
7982
7983bool nsContentUtils::IsJavascriptMIMEType(const nsACString& aMIMEType) {
7984 for (std::string_view type : kJavascriptMIMETypes) {
7985 if (aMIMEType.LowerCaseEqualsASCII(type.data(), type.length())) {
7986 return true;
7987 }
7988 }
7989 return false;
7990}
7991
7992bool nsContentUtils::IsJsonMimeType(const nsAString& aMimeType) {
7993 // Table ordered from most to least likely JSON MIME types.
7994 static constexpr std::string_view jsonTypes[] = {"application/json",
7995 "text/json"};
7996
7997 for (std::string_view type : jsonTypes) {
7998 if (aMimeType.LowerCaseEqualsASCII(type.data(), type.length())) {
7999 return true;
8000 }
8001 }
8002
8003 return StringEndsWith(aMimeType, u"+json"_ns);
8004}
8005
8006bool nsContentUtils::PrefetchPreloadEnabled(nsIDocShell* aDocShell) {
8007 //
8008 // SECURITY CHECK: disable prefetching and preloading from mailnews!
8009 //
8010 // walk up the docshell tree to see if any containing
8011 // docshell are of type MAIL.
8012 //
8013
8014 if (!aDocShell) {
8015 return false;
8016 }
8017
8018 nsCOMPtr<nsIDocShell> docshell = aDocShell;
8019 nsCOMPtr<nsIDocShellTreeItem> parentItem;
8020
8021 do {
8022 auto appType = docshell->GetAppType();
8023 if (appType == nsIDocShell::APP_TYPE_MAIL) {
8024 return false; // do not prefetch, preload, preconnect from mailnews
8025 }
8026
8027 docshell->GetInProcessParent(getter_AddRefs(parentItem));
8028 if (parentItem) {
8029 docshell = do_QueryInterface(parentItem);
8030 if (!docshell) {
8031 NS_ERROR("cannot get a docshell from a treeItem!")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "cannot get a docshell from a treeItem!"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8031); MOZ_PretendNoReturn(); } while (0)
;
8032 return false;
8033 }
8034 }
8035 } while (parentItem);
8036
8037 return true;
8038}
8039
8040uint64_t nsContentUtils::GetInnerWindowID(nsIRequest* aRequest) {
8041 // can't do anything if there's no nsIRequest!
8042 if (!aRequest) {
8043 return 0;
8044 }
8045
8046 nsCOMPtr<nsILoadGroup> loadGroup;
8047 nsresult rv = aRequest->GetLoadGroup(getter_AddRefs(loadGroup));
8048
8049 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !loadGroup) {
8050 return 0;
8051 }
8052
8053 return GetInnerWindowID(loadGroup);
8054}
8055
8056uint64_t nsContentUtils::GetInnerWindowID(nsILoadGroup* aLoadGroup) {
8057 if (!aLoadGroup) {
8058 return 0;
8059 }
8060
8061 nsCOMPtr<nsIInterfaceRequestor> callbacks;
8062 nsresult rv = aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
8063 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !callbacks) {
8064 return 0;
8065 }
8066
8067 nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
8068 if (!loadContext) {
8069 return 0;
8070 }
8071
8072 nsCOMPtr<mozIDOMWindowProxy> window;
8073 rv = loadContext->GetAssociatedWindow(getter_AddRefs(window));
8074 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !window) {
8075 return 0;
8076 }
8077
8078 auto* pwindow = nsPIDOMWindowOuter::From(window);
8079 if (!pwindow) {
8080 return 0;
8081 }
8082
8083 nsPIDOMWindowInner* inner = pwindow->GetCurrentInnerWindow();
8084 return inner ? inner->WindowID() : 0;
8085}
8086
8087// static
8088void nsContentUtils::MaybeFixIPv6Host(nsACString& aHost) {
8089 if (aHost.FindChar(':') != -1) { // Escape IPv6 address
8090 MOZ_ASSERT(!aHost.Length() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aHost.Length() || (aHost[0] != '[' && aHost
[aHost.Length() - 1] != ']'))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aHost.Length() || (aHost[0]
!= '[' && aHost[aHost.Length() - 1] != ']')))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!aHost.Length() || (aHost[0] != '[' && aHost[aHost.Length() - 1] != ']')"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8091); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aHost.Length() || (aHost[0] != '[' && aHost[aHost.Length() - 1] != ']')"
")"); do { *((volatile int*)__null) = 8091; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8091 (aHost[0] != '[' && aHost[aHost.Length() - 1] != ']'))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aHost.Length() || (aHost[0] != '[' && aHost
[aHost.Length() - 1] != ']'))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aHost.Length() || (aHost[0]
!= '[' && aHost[aHost.Length() - 1] != ']')))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!aHost.Length() || (aHost[0] != '[' && aHost[aHost.Length() - 1] != ']')"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8091); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aHost.Length() || (aHost[0] != '[' && aHost[aHost.Length() - 1] != ']')"
")"); do { *((volatile int*)__null) = 8091; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8092 aHost.Insert('[', 0);
8093 aHost.Append(']');
8094 }
8095}
8096
8097nsresult nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI,
8098 nsACString& aHost) {
8099 aHost.Truncate();
8100 nsresult rv = aURI->GetHost(aHost);
8101 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { // Some URIs do not have a host
8102 return rv;
8103 }
8104
8105 MaybeFixIPv6Host(aHost);
8106
8107 return NS_OK;
8108}
8109
8110nsresult nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI,
8111 nsAString& aHost) {
8112 nsAutoCString hostname;
8113 nsresult rv = GetHostOrIPv6WithBrackets(aURI, hostname);
8114 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
8115 return rv;
8116 }
8117 CopyUTF8toUTF16(hostname, aHost);
8118 return NS_OK;
8119}
8120
8121nsresult nsContentUtils::GetHostOrIPv6WithBrackets(nsIPrincipal* aPrincipal,
8122 nsACString& aHost) {
8123 nsresult rv = aPrincipal->GetAsciiHost(aHost);
8124 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { // Some URIs do not have a host
8125 return rv;
8126 }
8127
8128 MaybeFixIPv6Host(aHost);
8129 return NS_OK;
8130}
8131
8132CallState nsContentUtils::CallOnAllRemoteChildren(
8133 MessageBroadcaster* aManager,
8134 const std::function<CallState(BrowserParent*)>& aCallback) {
8135 uint32_t browserChildCount = aManager->ChildCount();
8136 for (uint32_t j = 0; j < browserChildCount; ++j) {
8137 RefPtr<MessageListenerManager> childMM = aManager->GetChildAt(j);
8138 if (!childMM) {
8139 continue;
8140 }
8141
8142 RefPtr<MessageBroadcaster> nonLeafMM = MessageBroadcaster::From(childMM);
8143 if (nonLeafMM) {
8144 if (CallOnAllRemoteChildren(nonLeafMM, aCallback) == CallState::Stop) {
8145 return CallState::Stop;
8146 }
8147 continue;
8148 }
8149
8150 mozilla::dom::ipc::MessageManagerCallback* cb = childMM->GetCallback();
8151 if (cb) {
8152 nsFrameLoader* fl = static_cast<nsFrameLoader*>(cb);
8153 BrowserParent* remote = BrowserParent::GetFrom(fl);
8154 if (remote && aCallback) {
8155 if (aCallback(remote) == CallState::Stop) {
8156 return CallState::Stop;
8157 }
8158 }
8159 }
8160 }
8161
8162 return CallState::Continue;
8163}
8164
8165void nsContentUtils::CallOnAllRemoteChildren(
8166 nsPIDOMWindowOuter* aWindow,
8167 const std::function<CallState(BrowserParent*)>& aCallback) {
8168 nsGlobalWindowOuter* window = nsGlobalWindowOuter::Cast(aWindow);
8169 if (window->IsChromeWindow()) {
8170 RefPtr<MessageBroadcaster> windowMM = window->GetMessageManager();
8171 if (windowMM) {
8172 CallOnAllRemoteChildren(windowMM, aCallback);
8173 }
8174 }
8175}
8176
8177bool nsContentUtils::IPCTransferableDataItemHasKnownFlavor(
8178 const IPCTransferableDataItem& aItem) {
8179 // Unknown types are converted to kCustomTypesMime.
8180 if (aItem.flavor().EqualsASCII(kCustomTypesMime"application/x-moz-custom-clipdata")) {
8181 return true;
8182 }
8183
8184 for (const char* format : DataTransfer::kKnownFormats) {
8185 if (aItem.flavor().EqualsASCII(format)) {
8186 return true;
8187 }
8188 }
8189
8190 return false;
8191}
8192
8193nsresult nsContentUtils::IPCTransferableDataToTransferable(
8194 const IPCTransferableData& aTransferableData, bool aAddDataFlavor,
8195 nsITransferable* aTransferable, const bool aFilterUnknownFlavors) {
8196 nsresult rv;
8197 const nsTArray<IPCTransferableDataItem>& items = aTransferableData.items();
8198 for (const auto& item : items) {
8199 if (aFilterUnknownFlavors && !IPCTransferableDataItemHasKnownFlavor(item)) {
8200 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "Ignoring unknown flavor in "
"nsContentUtils::IPCTransferableDataToTransferable", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8202)
8201 "Ignoring unknown flavor in "NS_DebugBreak(NS_DEBUG_WARNING, "Ignoring unknown flavor in "
"nsContentUtils::IPCTransferableDataToTransferable", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8202)
8202 "nsContentUtils::IPCTransferableDataToTransferable")NS_DebugBreak(NS_DEBUG_WARNING, "Ignoring unknown flavor in "
"nsContentUtils::IPCTransferableDataToTransferable", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8202)
;
8203 continue;
8204 }
8205
8206 if (aAddDataFlavor) {
8207 aTransferable->AddDataFlavor(item.flavor().get());
8208 }
8209
8210 nsCOMPtr<nsISupports> transferData;
8211 switch (item.data().type()) {
8212 case IPCTransferableDataType::TIPCTransferableDataString: {
8213 const auto& data = item.data().get_IPCTransferableDataString();
8214 nsCOMPtr<nsISupportsString> dataWrapper =
8215 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID"@mozilla.org/supports-string;1", &rv);
8216 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8216); return rv; } } while (false)
;
8217 rv = dataWrapper->SetData(nsDependentSubstring(
8218 reinterpret_cast<const char16_t*>(data.data().Data()),
8219 data.data().Size() / sizeof(char16_t)));
8220 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8220); return rv; } } while (false)
;
8221 transferData = dataWrapper;
8222 break;
8223 }
8224 case IPCTransferableDataType::TIPCTransferableDataCString: {
8225 const auto& data = item.data().get_IPCTransferableDataCString();
8226 nsCOMPtr<nsISupportsCString> dataWrapper =
8227 do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID"@mozilla.org/supports-cstring;1", &rv);
8228 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8228); return rv; } } while (false)
;
8229 rv = dataWrapper->SetData(nsDependentCSubstring(
8230 reinterpret_cast<const char*>(data.data().Data()),
8231 data.data().Size()));
8232 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8232); return rv; } } while (false)
;
8233 transferData = dataWrapper;
8234 break;
8235 }
8236 case IPCTransferableDataType::TIPCTransferableDataInputStream: {
8237 const auto& data = item.data().get_IPCTransferableDataInputStream();
8238 nsCOMPtr<nsIInputStream> stream;
8239 rv = NS_NewByteInputStream(getter_AddRefs(stream),
8240 AsChars(data.data().AsSpan()),
8241 NS_ASSIGNMENT_COPY);
8242 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8242); return rv; } } while (false)
;
8243 transferData = stream.forget();
8244 break;
8245 }
8246 case IPCTransferableDataType::TIPCTransferableDataImageContainer: {
8247 const auto& data = item.data().get_IPCTransferableDataImageContainer();
8248 nsCOMPtr<imgIContainer> container;
8249 rv = DeserializeTransferableDataImageContainer(
8250 data, getter_AddRefs(container));
8251 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8251); return rv; } } while (false)
;
8252 transferData = container;
8253 break;
8254 }
8255 case IPCTransferableDataType::TIPCTransferableDataBlob: {
8256 const auto& data = item.data().get_IPCTransferableDataBlob();
8257 transferData = IPCBlobUtils::Deserialize(data.blob());
8258 break;
8259 }
8260 case IPCTransferableDataType::T__None:
8261 MOZ_ASSERT_UNREACHABLE()do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8261); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " ")"); do { *((volatile int*)__null
) = 8261; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
8262 return NS_ERROR_FAILURE;
8263 }
8264
8265 rv = aTransferable->SetTransferData(item.flavor().get(), transferData);
8266 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8266); return rv; } } while (false)
;
8267 }
8268 return NS_OK;
8269}
8270
8271nsresult nsContentUtils::IPCTransferableToTransferable(
8272 const IPCTransferable& aIPCTransferable, bool aAddDataFlavor,
8273 nsITransferable* aTransferable, const bool aFilterUnknownFlavors) {
8274 // Note that we need to set privacy status of transferable before adding any
8275 // data into it.
8276 aTransferable->SetIsPrivateData(aIPCTransferable.isPrivateData());
8277
8278 nsresult rv =
8279 IPCTransferableDataToTransferable(aIPCTransferable.data(), aAddDataFlavor,
8280 aTransferable, aFilterUnknownFlavors);
8281 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8281); return rv; } } while (false)
;
8282
8283 if (aIPCTransferable.cookieJarSettings().isSome()) {
8284 nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
8285 net::CookieJarSettings::Deserialize(
8286 aIPCTransferable.cookieJarSettings().ref(),
8287 getter_AddRefs(cookieJarSettings));
8288 aTransferable->SetCookieJarSettings(cookieJarSettings);
8289 }
8290 aTransferable->SetReferrerInfo(aIPCTransferable.referrerInfo());
8291 aTransferable->SetDataPrincipal(aIPCTransferable.dataPrincipal());
8292 aTransferable->SetContentPolicyType(aIPCTransferable.contentPolicyType());
8293
8294 return NS_OK;
8295}
8296
8297nsresult nsContentUtils::IPCTransferableDataItemToVariant(
8298 const IPCTransferableDataItem& aItem, nsIWritableVariant* aVariant) {
8299 MOZ_ASSERT(aVariant)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aVariant)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aVariant))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aVariant", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8299); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aVariant" ")"
); do { *((volatile int*)__null) = 8299; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8300
8301 switch (aItem.data().type()) {
8302 case IPCTransferableDataType::TIPCTransferableDataString: {
8303 const auto& data = aItem.data().get_IPCTransferableDataString();
8304 return aVariant->SetAsAString(nsDependentSubstring(
8305 reinterpret_cast<const char16_t*>(data.data().Data()),
8306 data.data().Size() / sizeof(char16_t)));
8307 }
8308 case IPCTransferableDataType::TIPCTransferableDataCString: {
8309 const auto& data = aItem.data().get_IPCTransferableDataCString();
8310 return aVariant->SetAsACString(nsDependentCSubstring(
8311 reinterpret_cast<const char*>(data.data().Data()),
8312 data.data().Size()));
8313 }
8314 case IPCTransferableDataType::TIPCTransferableDataInputStream: {
8315 const auto& data = aItem.data().get_IPCTransferableDataInputStream();
8316 nsCOMPtr<nsIInputStream> stream;
8317 nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream),
8318 AsChars(data.data().AsSpan()),
8319 NS_ASSIGNMENT_COPY);
8320 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8320); return rv; } } while (false)
;
8321 return aVariant->SetAsISupports(stream);
8322 }
8323 case IPCTransferableDataType::TIPCTransferableDataImageContainer: {
8324 const auto& data = aItem.data().get_IPCTransferableDataImageContainer();
8325 nsCOMPtr<imgIContainer> container;
8326 nsresult rv = DeserializeTransferableDataImageContainer(
8327 data, getter_AddRefs(container));
8328 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8328); return rv; } } while (false)
;
8329 return aVariant->SetAsISupports(container);
8330 }
8331 case IPCTransferableDataType::TIPCTransferableDataBlob: {
8332 const auto& data = aItem.data().get_IPCTransferableDataBlob();
8333 RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(data.blob());
8334 return aVariant->SetAsISupports(blobImpl);
8335 }
8336 case IPCTransferableDataType::T__None:
8337 break;
8338 }
8339
8340 MOZ_ASSERT_UNREACHABLE()do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8340); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " ")"); do { *((volatile int*)__null
) = 8340; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
8341 return NS_ERROR_UNEXPECTED;
8342}
8343
8344void nsContentUtils::TransferablesToIPCTransferableDatas(
8345 nsIArray* aTransferables, nsTArray<IPCTransferableData>& aIPC,
8346 bool aInSyncMessage, mozilla::dom::ContentParent* aParent) {
8347 aIPC.Clear();
8348 if (aTransferables) {
8349 uint32_t transferableCount = 0;
8350 aTransferables->GetLength(&transferableCount);
8351 for (uint32_t i = 0; i < transferableCount; ++i) {
8352 IPCTransferableData* dt = aIPC.AppendElement();
8353 nsCOMPtr<nsITransferable> transferable =
8354 do_QueryElementAt(aTransferables, i);
8355 TransferableToIPCTransferableData(transferable, dt, aInSyncMessage,
8356 aParent);
8357 }
8358 }
8359}
8360
8361nsresult nsContentUtils::CalculateBufferSizeForImage(
8362 const uint32_t& aStride, const IntSize& aImageSize,
8363 const SurfaceFormat& aFormat, size_t* aMaxBufferSize,
8364 size_t* aUsedBufferSize) {
8365 CheckedInt32 requiredBytes =
8366 CheckedInt32(aStride) * CheckedInt32(aImageSize.height);
8367
8368 CheckedInt32 usedBytes =
8369 requiredBytes - aStride +
8370 (CheckedInt32(aImageSize.width) * BytesPerPixel(aFormat));
8371 if (!usedBytes.isValid()) {
8372 return NS_ERROR_FAILURE;
8373 }
8374
8375 MOZ_ASSERT(requiredBytes.isValid(), "usedBytes valid but not required?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(requiredBytes.isValid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(requiredBytes.isValid()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("requiredBytes.isValid()"
" (" "usedBytes valid but not required?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8375); AnnotateMozCrashReason("MOZ_ASSERT" "(" "requiredBytes.isValid()"
") (" "usedBytes valid but not required?" ")"); do { *((volatile
int*)__null) = 8375; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
8376 *aMaxBufferSize = requiredBytes.value();
8377 *aUsedBufferSize = usedBytes.value();
8378 return NS_OK;
8379}
8380
8381static already_AddRefed<DataSourceSurface> BigBufferToDataSurface(
8382 const BigBuffer& aData, uint32_t aStride, const IntSize& aImageSize,
8383 SurfaceFormat aFormat) {
8384 if (!aData.Size() || !aImageSize.width || !aImageSize.height) {
8385 return nullptr;
8386 }
8387
8388 // Validate shared memory buffer size
8389 size_t imageBufLen = 0;
8390 size_t maxBufLen = 0;
8391 if (NS_FAILED(nsContentUtils::CalculateBufferSizeForImage(((bool)(__builtin_expect(!!(NS_FAILED_impl(nsContentUtils::CalculateBufferSizeForImage
( aStride, aImageSize, aFormat, &maxBufLen, &imageBufLen
))), 0)))
8392 aStride, aImageSize, aFormat, &maxBufLen, &imageBufLen))((bool)(__builtin_expect(!!(NS_FAILED_impl(nsContentUtils::CalculateBufferSizeForImage
( aStride, aImageSize, aFormat, &maxBufLen, &imageBufLen
))), 0)))
) {
8393 return nullptr;
8394 }
8395 if (imageBufLen > aData.Size()) {
8396 return nullptr;
8397 }
8398 return CreateDataSourceSurfaceFromData(aImageSize, aFormat, aData.Data(),
8399 aStride);
8400}
8401
8402nsresult nsContentUtils::DeserializeTransferableDataImageContainer(
8403 const IPCTransferableDataImageContainer& aData,
8404 imgIContainer** aContainer) {
8405 RefPtr<DataSourceSurface> surface = IPCImageToSurface(aData.image());
8406 if (!surface) {
8407 return NS_ERROR_FAILURE;
8408 }
8409
8410 RefPtr<gfxDrawable> drawable =
8411 new gfxSurfaceDrawable(surface, surface->GetSize());
8412 nsCOMPtr<imgIContainer> imageContainer =
8413 image::ImageOps::CreateFromDrawable(drawable);
8414 imageContainer.forget(aContainer);
8415
8416 return NS_OK;
8417}
8418
8419bool nsContentUtils::IsFlavorImage(const nsACString& aFlavor) {
8420 return aFlavor.EqualsLiteral(kNativeImageMime"application/x-moz-nativeimage") ||
8421 aFlavor.EqualsLiteral(kJPEGImageMime"image/jpeg") ||
8422 aFlavor.EqualsLiteral(kJPGImageMime"image/jpg") ||
8423 aFlavor.EqualsLiteral(kPNGImageMime"image/png") ||
8424 aFlavor.EqualsLiteral(kGIFImageMime"image/gif");
8425}
8426
8427// FIXME: This can probably be removed once bug 1783240 lands, as `nsString`
8428// will be implicitly serialized in shmem when sent over IPDL directly.
8429static IPCTransferableDataString AsIPCTransferableDataString(
8430 Span<const char16_t> aInput) {
8431 return IPCTransferableDataString{BigBuffer(AsBytes(aInput))};
8432}
8433
8434// FIXME: This can probably be removed once bug 1783240 lands, as `nsCString`
8435// will be implicitly serialized in shmem when sent over IPDL directly.
8436static IPCTransferableDataCString AsIPCTransferableDataCString(
8437 Span<const char> aInput) {
8438 return IPCTransferableDataCString{BigBuffer(AsBytes(aInput))};
8439}
8440
8441void nsContentUtils::TransferableToIPCTransferableData(
8442 nsITransferable* aTransferable, IPCTransferableData* aTransferableData,
8443 bool aInSyncMessage, mozilla::dom::ContentParent* aParent) {
8444 MOZ_ASSERT_IF(XRE_IsParentProcess(), aParent)do { if (XRE_IsParentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(aParent)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aParent))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aParent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8444); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent" ")"
); do { *((volatile int*)__null) = 8444; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
8445
8446 if (aTransferable) {
8447 nsTArray<nsCString> flavorList;
8448 aTransferable->FlavorsTransferableCanExport(flavorList);
8449
8450 for (uint32_t j = 0; j < flavorList.Length(); ++j) {
8451 nsCString& flavorStr = flavorList[j];
8452 if (!flavorStr.Length()) {
8453 continue;
8454 }
8455
8456 nsCOMPtr<nsISupports> data;
8457 nsresult rv =
8458 aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(data));
8459
8460 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !data) {
8461 if (aInSyncMessage) {
8462 // Can't do anything.
8463 // FIXME: This shouldn't be the case anymore!
8464 continue;
8465 }
8466
8467 // This is a hack to support kFilePromiseMime.
8468 // On Windows there just needs to be an entry for it,
8469 // and for OSX we need to create
8470 // nsContentAreaDragDropDataProvider as nsIFlavorDataProvider.
8471 if (flavorStr.EqualsLiteral(kFilePromiseMime"application/x-moz-file-promise")) {
8472 IPCTransferableDataItem* item =
8473 aTransferableData->items().AppendElement();
8474 item->flavor() = flavorStr;
8475 item->data() =
8476 AsIPCTransferableDataString(NS_ConvertUTF8toUTF16(flavorStr));
8477 continue;
8478 }
8479
8480 // Empty element, transfer only the flavor
8481 IPCTransferableDataItem* item =
8482 aTransferableData->items().AppendElement();
8483 item->flavor() = flavorStr;
8484 item->data() = AsIPCTransferableDataString(EmptyString());
8485 continue;
8486 }
8487
8488 // We need to handle nsIInputStream before nsISupportsCString, otherwise
8489 // nsStringInputStream would be converted into a wrong type.
8490 if (nsCOMPtr<nsIInputStream> stream = do_QueryInterface(data)) {
8491 IPCTransferableDataItem* item =
8492 aTransferableData->items().AppendElement();
8493 item->flavor() = flavorStr;
8494 nsCString imageData;
8495 DebugOnly<nsresult> rv =
8496 NS_ConsumeStream(stream, UINT32_MAX(4294967295U), imageData);
8497 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(rv != NS_BASE_STREAM_WOULD_BLOCK)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(rv != NS_BASE_STREAM_WOULD_BLOCK
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"rv != NS_BASE_STREAM_WOULD_BLOCK" " (" "cannot use async input streams in nsITransferable right now"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8499); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rv != NS_BASE_STREAM_WOULD_BLOCK"
") (" "cannot use async input streams in nsITransferable right now"
")"); do { *((volatile int*)__null) = 8499; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8498 rv != NS_BASE_STREAM_WOULD_BLOCK,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(rv != NS_BASE_STREAM_WOULD_BLOCK)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(rv != NS_BASE_STREAM_WOULD_BLOCK
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"rv != NS_BASE_STREAM_WOULD_BLOCK" " (" "cannot use async input streams in nsITransferable right now"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8499); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rv != NS_BASE_STREAM_WOULD_BLOCK"
") (" "cannot use async input streams in nsITransferable right now"
")"); do { *((volatile int*)__null) = 8499; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8499 "cannot use async input streams in nsITransferable right now")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(rv != NS_BASE_STREAM_WOULD_BLOCK)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(rv != NS_BASE_STREAM_WOULD_BLOCK
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"rv != NS_BASE_STREAM_WOULD_BLOCK" " (" "cannot use async input streams in nsITransferable right now"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8499); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rv != NS_BASE_STREAM_WOULD_BLOCK"
") (" "cannot use async input streams in nsITransferable right now"
")"); do { *((volatile int*)__null) = 8499; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8500 // FIXME: This can probably be simplified once bug 1783240 lands, as
8501 // `nsCString` will be implicitly serialized in shmem when sent over
8502 // IPDL directly.
8503 item->data() =
8504 IPCTransferableDataInputStream(BigBuffer(AsBytes(Span(imageData))));
8505 continue;
8506 }
8507
8508 if (nsCOMPtr<nsISupportsString> text = do_QueryInterface(data)) {
8509 nsAutoString dataAsString;
8510 MOZ_ALWAYS_SUCCEEDS(text->GetData(dataAsString))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(text->GetData(dataAsString))), 1)))), 1))) { } else { do {
static_assert( mozilla::detail::AssertionConditionType<decltype
(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(false))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("false" " (" "NS_SUCCEEDED(text->GetData(dataAsString))" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8510); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(text->GetData(dataAsString))" ")"); do
{ *((volatile int*)__null) = 8510; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false); } } while (false
)
;
8511
8512 IPCTransferableDataItem* item =
8513 aTransferableData->items().AppendElement();
8514 item->flavor() = flavorStr;
8515 item->data() = AsIPCTransferableDataString(dataAsString);
8516 continue;
8517 }
8518
8519 if (nsCOMPtr<nsISupportsCString> ctext = do_QueryInterface(data)) {
8520 nsAutoCString dataAsString;
8521 MOZ_ALWAYS_SUCCEEDS(ctext->GetData(dataAsString))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(ctext->GetData(dataAsString))), 1)))), 1))) { } else { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(ctext->GetData(dataAsString))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8521); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(ctext->GetData(dataAsString))" ")"); do
{ *((volatile int*)__null) = 8521; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false); } } while (false
)
;
8522
8523 IPCTransferableDataItem* item =
8524 aTransferableData->items().AppendElement();
8525 item->flavor() = flavorStr;
8526 item->data() = AsIPCTransferableDataCString(dataAsString);
8527 continue;
8528 }
8529
8530 if (nsCOMPtr<imgIContainer> image = do_QueryInterface(data)) {
8531 // Images to be placed on the clipboard are imgIContainers.
8532 RefPtr<mozilla::gfx::SourceSurface> surface = image->GetFrame(
8533 imgIContainer::FRAME_CURRENT,
8534 imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY);
8535 if (!surface) {
8536 continue;
8537 }
8538 RefPtr<mozilla::gfx::DataSourceSurface> dataSurface =
8539 surface->GetDataSurface();
8540 if (!dataSurface) {
8541 continue;
8542 }
8543
8544 auto imageData = nsContentUtils::SurfaceToIPCImage(*dataSurface);
8545 if (!imageData) {
8546 continue;
8547 }
8548
8549 IPCTransferableDataItem* item =
8550 aTransferableData->items().AppendElement();
8551 item->flavor() = flavorStr;
8552 item->data() = IPCTransferableDataImageContainer(std::move(*imageData));
8553 continue;
8554 }
8555
8556 // Otherwise, handle this as a file.
8557 nsCOMPtr<BlobImpl> blobImpl;
8558 if (nsCOMPtr<nsIFile> file = do_QueryInterface(data)) {
8559 if (aParent) {
8560 bool isDir = false;
8561 if (NS_SUCCEEDED(file->IsDirectory(&isDir))((bool)(__builtin_expect(!!(!NS_FAILED_impl(file->IsDirectory
(&isDir))), 1)))
&& isDir) {
8562 nsAutoString path;
8563 if (NS_WARN_IF(NS_FAILED(file->GetPath(path)))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(file
->GetPath(path))), 0))), "NS_FAILED(file->GetPath(path))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8563)
) {
8564 continue;
8565 }
8566
8567 RefPtr<FileSystemSecurity> fss = FileSystemSecurity::GetOrCreate();
8568 fss->GrantAccessToContentProcess(aParent->ChildID(), path);
8569 }
8570 }
8571
8572 blobImpl = new FileBlobImpl(file);
8573
8574 IgnoredErrorResult rv;
8575
8576 // Ensure that file data is cached no that the content process
8577 // has this data available to it when passed over:
8578 blobImpl->GetSize(rv);
8579 if (NS_WARN_IF(rv.Failed())NS_warn_if_impl(rv.Failed(), "rv.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8579)
) {
8580 continue;
8581 }
8582
8583 blobImpl->GetLastModified(rv);
8584 if (NS_WARN_IF(rv.Failed())NS_warn_if_impl(rv.Failed(), "rv.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8584)
) {
8585 continue;
8586 }
8587 } else {
8588 if (aInSyncMessage) {
8589 // Can't do anything.
8590 // FIXME: This shouldn't be the case anymore!
8591 continue;
8592 }
8593
8594 blobImpl = do_QueryInterface(data);
8595 }
8596
8597 if (blobImpl) {
8598 // If we failed to create the blob actor, then this blob probably
8599 // can't get the file size for the underlying file, ignore it for
8600 // now. TODO pass this through anyway.
8601 IPCBlob ipcBlob;
8602 nsresult rv = IPCBlobUtils::Serialize(blobImpl, ipcBlob);
8603 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8603)
) {
8604 continue;
8605 }
8606
8607 IPCTransferableDataItem* item =
8608 aTransferableData->items().AppendElement();
8609 item->flavor() = flavorStr;
8610 item->data() = IPCTransferableDataBlob(ipcBlob);
8611 }
8612 }
8613 }
8614}
8615
8616void nsContentUtils::TransferableToIPCTransferable(
8617 nsITransferable* aTransferable, IPCTransferable* aIPCTransferable,
8618 bool aInSyncMessage, mozilla::dom::ContentParent* aParent) {
8619 IPCTransferableData ipcTransferableData;
8620 TransferableToIPCTransferableData(aTransferable, &ipcTransferableData,
8621 aInSyncMessage, aParent);
8622
8623 Maybe<net::CookieJarSettingsArgs> cookieJarSettingsArgs;
8624 if (nsCOMPtr<nsICookieJarSettings> cookieJarSettings =
8625 aTransferable->GetCookieJarSettings()) {
8626 net::CookieJarSettingsArgs args;
8627 net::CookieJarSettings::Cast(cookieJarSettings)->Serialize(args);
8628 cookieJarSettingsArgs = Some(std::move(args));
8629 }
8630
8631 aIPCTransferable->data() = std::move(ipcTransferableData);
8632 aIPCTransferable->isPrivateData() = aTransferable->GetIsPrivateData();
8633 aIPCTransferable->dataPrincipal() = aTransferable->GetDataPrincipal();
8634 aIPCTransferable->cookieJarSettings() = std::move(cookieJarSettingsArgs);
8635 aIPCTransferable->contentPolicyType() = aTransferable->GetContentPolicyType();
8636 aIPCTransferable->referrerInfo() = aTransferable->GetReferrerInfo();
8637}
8638
8639Maybe<BigBuffer> nsContentUtils::GetSurfaceData(DataSourceSurface& aSurface,
8640 size_t* aLength,
8641 int32_t* aStride) {
8642 mozilla::gfx::DataSourceSurface::MappedSurface map;
8643 if (!aSurface.Map(mozilla::gfx::DataSourceSurface::MapType::READ, &map)) {
8644 return Nothing();
8645 }
8646
8647 size_t bufLen = 0;
8648 size_t maxBufLen = 0;
8649 nsresult rv = nsContentUtils::CalculateBufferSizeForImage(
8650 map.mStride, aSurface.GetSize(), aSurface.GetFormat(), &maxBufLen,
8651 &bufLen);
8652 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
8653 aSurface.Unmap();
8654 return Nothing();
8655 }
8656
8657 BigBuffer surfaceData(maxBufLen);
8658 memcpy(surfaceData.Data(), map.mData, bufLen);
8659 memset(surfaceData.Data() + bufLen, 0, maxBufLen - bufLen);
8660
8661 *aLength = maxBufLen;
8662 *aStride = map.mStride;
8663
8664 aSurface.Unmap();
8665 return Some(std::move(surfaceData));
8666}
8667
8668Maybe<IPCImage> nsContentUtils::SurfaceToIPCImage(DataSourceSurface& aSurface) {
8669 size_t len = 0;
8670 int32_t stride = 0;
8671 auto mem = GetSurfaceData(aSurface, &len, &stride);
8672 if (!mem) {
8673 return Nothing();
8674 }
8675 return Some(IPCImage{std::move(*mem), uint32_t(stride), aSurface.GetFormat(),
8676 ImageIntSize::FromUnknownSize(aSurface.GetSize())});
8677}
8678
8679already_AddRefed<DataSourceSurface> nsContentUtils::IPCImageToSurface(
8680 const IPCImage& aImage) {
8681 return BigBufferToDataSurface(aImage.data(), aImage.stride(),
8682 aImage.size().ToUnknownSize(), aImage.format());
8683}
8684
8685Modifiers nsContentUtils::GetWidgetModifiers(int32_t aModifiers) {
8686 Modifiers result = 0;
8687 if (aModifiers & nsIDOMWindowUtils::MODIFIER_SHIFT) {
8688 result |= mozilla::MODIFIER_SHIFT;
8689 }
8690 if (aModifiers & nsIDOMWindowUtils::MODIFIER_CONTROL) {
8691 result |= mozilla::MODIFIER_CONTROL;
8692 }
8693 if (aModifiers & nsIDOMWindowUtils::MODIFIER_ALT) {
8694 result |= mozilla::MODIFIER_ALT;
8695 }
8696 if (aModifiers & nsIDOMWindowUtils::MODIFIER_META) {
8697 result |= mozilla::MODIFIER_META;
8698 }
8699 if (aModifiers & nsIDOMWindowUtils::MODIFIER_ALTGRAPH) {
8700 result |= mozilla::MODIFIER_ALTGRAPH;
8701 }
8702 if (aModifiers & nsIDOMWindowUtils::MODIFIER_CAPSLOCK) {
8703 result |= mozilla::MODIFIER_CAPSLOCK;
8704 }
8705 if (aModifiers & nsIDOMWindowUtils::MODIFIER_FN) {
8706 result |= mozilla::MODIFIER_FN;
8707 }
8708 if (aModifiers & nsIDOMWindowUtils::MODIFIER_FNLOCK) {
8709 result |= mozilla::MODIFIER_FNLOCK;
8710 }
8711 if (aModifiers & nsIDOMWindowUtils::MODIFIER_NUMLOCK) {
8712 result |= mozilla::MODIFIER_NUMLOCK;
8713 }
8714 if (aModifiers & nsIDOMWindowUtils::MODIFIER_SCROLLLOCK) {
8715 result |= mozilla::MODIFIER_SCROLLLOCK;
8716 }
8717 if (aModifiers & nsIDOMWindowUtils::MODIFIER_SYMBOL) {
8718 result |= mozilla::MODIFIER_SYMBOL;
8719 }
8720 if (aModifiers & nsIDOMWindowUtils::MODIFIER_SYMBOLLOCK) {
8721 result |= mozilla::MODIFIER_SYMBOLLOCK;
8722 }
8723 return result;
8724}
8725
8726nsIWidget* nsContentUtils::GetWidget(PresShell* aPresShell, nsPoint* aOffset) {
8727 if (!aPresShell) {
8728 return nullptr;
8729 }
8730 nsIFrame* frame = aPresShell->GetRootFrame();
8731 if (!frame) {
8732 return nullptr;
8733 }
8734 return frame->GetView()->GetNearestWidget(aOffset);
8735}
8736
8737int16_t nsContentUtils::GetButtonsFlagForButton(int32_t aButton) {
8738 switch (aButton) {
8739 case -1:
8740 return MouseButtonsFlag::eNoButtons;
8741 case MouseButton::ePrimary:
8742 return MouseButtonsFlag::ePrimaryFlag;
8743 case MouseButton::eMiddle:
8744 return MouseButtonsFlag::eMiddleFlag;
8745 case MouseButton::eSecondary:
8746 return MouseButtonsFlag::eSecondaryFlag;
8747 case 3:
8748 return MouseButtonsFlag::e4thFlag;
8749 case 4:
8750 return MouseButtonsFlag::e5thFlag;
8751 case MouseButton::eEraser:
8752 return MouseButtonsFlag::eEraserFlag;
8753 default:
8754 NS_ERROR("Button not known.")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Button not known.", "Error"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8754); MOZ_PretendNoReturn(); } while (0)
;
8755 return 0;
8756 }
8757}
8758
8759LayoutDeviceIntPoint nsContentUtils::ToWidgetPoint(
8760 const CSSPoint& aPoint, const nsPoint& aOffset,
8761 nsPresContext* aPresContext) {
8762 nsPoint layoutRelative = CSSPoint::ToAppUnits(aPoint) + aOffset;
8763 nsPoint visualRelative =
8764 ViewportUtils::LayoutToVisual(layoutRelative, aPresContext->PresShell());
8765 return LayoutDeviceIntPoint::FromAppUnitsRounded(
8766 visualRelative, aPresContext->AppUnitsPerDevPixel());
8767}
8768
8769nsView* nsContentUtils::GetViewToDispatchEvent(nsPresContext* aPresContext,
8770 PresShell** aPresShell) {
8771 if (!aPresContext || !aPresShell) {
8772 return nullptr;
8773 }
8774 RefPtr<PresShell> presShell = aPresContext->PresShell();
8775 if (NS_WARN_IF(!presShell)NS_warn_if_impl(!presShell, "!presShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8775)
) {
8776 *aPresShell = nullptr;
8777 return nullptr;
8778 }
8779 nsViewManager* viewManager = presShell->GetViewManager();
8780 if (!viewManager) {
8781 presShell.forget(aPresShell); // XXX Is this intentional?
8782 return nullptr;
8783 }
8784 presShell.forget(aPresShell);
8785 return viewManager->GetRootView();
8786}
8787
8788nsresult nsContentUtils::SendMouseEvent(
8789 mozilla::PresShell* aPresShell, const nsAString& aType, float aX, float aY,
8790 int32_t aButton, int32_t aButtons, int32_t aClickCount, int32_t aModifiers,
8791 bool aIgnoreRootScrollFrame, float aPressure,
8792 unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow,
8793 PreventDefaultResult* aPreventDefault, bool aIsDOMEventSynthesized,
8794 bool aIsWidgetEventSynthesized) {
8795 nsPoint offset;
8796 nsCOMPtr<nsIWidget> widget = GetWidget(aPresShell, &offset);
8797 if (!widget) return NS_ERROR_FAILURE;
8798
8799 EventMessage msg;
8800 Maybe<WidgetMouseEvent::ExitFrom> exitFrom;
8801 bool contextMenuKey = false;
8802 if (aType.EqualsLiteral("mousedown")) {
8803 msg = eMouseDown;
8804 } else if (aType.EqualsLiteral("mouseup")) {
8805 msg = eMouseUp;
8806 } else if (aType.EqualsLiteral("mousemove")) {
8807 msg = eMouseMove;
8808 } else if (aType.EqualsLiteral("mouseover")) {
8809 msg = eMouseEnterIntoWidget;
8810 } else if (aType.EqualsLiteral("mouseout")) {
8811 msg = eMouseExitFromWidget;
8812 exitFrom = Some(WidgetMouseEvent::ePlatformChild);
8813 } else if (aType.EqualsLiteral("mousecancel")) {
8814 msg = eMouseExitFromWidget;
8815 exitFrom = Some(XRE_IsParentProcess() ? WidgetMouseEvent::ePlatformTopLevel
8816 : WidgetMouseEvent::ePuppet);
8817 } else if (aType.EqualsLiteral("mouselongtap")) {
8818 msg = eMouseLongTap;
8819 } else if (aType.EqualsLiteral("contextmenu")) {
8820 msg = eContextMenu;
8821 contextMenuKey = !aButton && aInputSourceArg !=
8822 dom::MouseEvent_Binding::MOZ_SOURCE_TOUCH;
8823 } else if (aType.EqualsLiteral("MozMouseHittest")) {
8824 msg = eMouseHitTest;
8825 } else if (aType.EqualsLiteral("MozMouseExploreByTouch")) {
8826 msg = eMouseExploreByTouch;
8827 } else {
8828 return NS_ERROR_FAILURE;
8829 }
8830
8831 if (aInputSourceArg == MouseEvent_Binding::MOZ_SOURCE_UNKNOWN) {
8832 aInputSourceArg = MouseEvent_Binding::MOZ_SOURCE_MOUSE;
8833 }
8834
8835 Maybe<WidgetPointerEvent> pointerEvent;
8836 Maybe<WidgetMouseEvent> mouseEvent;
8837 if (IsPointerEventMessage(msg)) {
8838 MOZ_ASSERT(!aIsWidgetEventSynthesized,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIsWidgetEventSynthesized)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIsWidgetEventSynthesized))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aIsWidgetEventSynthesized"
" (" "The event shouldn't be dispatched as a synthesized event"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8839); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIsWidgetEventSynthesized"
") (" "The event shouldn't be dispatched as a synthesized event"
")"); do { *((volatile int*)__null) = 8839; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8839 "The event shouldn't be dispatched as a synthesized event")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIsWidgetEventSynthesized)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIsWidgetEventSynthesized))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aIsWidgetEventSynthesized"
" (" "The event shouldn't be dispatched as a synthesized event"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8839); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIsWidgetEventSynthesized"
") (" "The event shouldn't be dispatched as a synthesized event"
")"); do { *((volatile int*)__null) = 8839; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8840 if (MOZ_UNLIKELY(aIsWidgetEventSynthesized)(__builtin_expect(!!(aIsWidgetEventSynthesized), 0))) {
8841 // `click`, `auxclick` nor `contextmenu` should not be dispatched as a
8842 // synthesized event.
8843 return NS_ERROR_INVALID_ARG;
8844 }
8845 pointerEvent.emplace(true, msg, widget,
8846 contextMenuKey ? WidgetMouseEvent::eContextMenuKey
8847 : WidgetMouseEvent::eNormal);
8848 } else {
8849 mouseEvent.emplace(true, msg, widget,
8850 aIsWidgetEventSynthesized
8851 ? WidgetMouseEvent::eSynthesized
8852 : WidgetMouseEvent::eReal,
8853 contextMenuKey ? WidgetMouseEvent::eContextMenuKey
8854 : WidgetMouseEvent::eNormal);
8855 }
8856 WidgetMouseEvent& mouseOrPointerEvent =
8857 pointerEvent.isSome() ? pointerEvent.ref() : mouseEvent.ref();
8858 mouseOrPointerEvent.pointerId = aIdentifier;
8859 mouseOrPointerEvent.mModifiers = GetWidgetModifiers(aModifiers);
8860 mouseOrPointerEvent.mButton = aButton;
8861 mouseOrPointerEvent.mButtons =
8862 aButtons != nsIDOMWindowUtils::MOUSE_BUTTONS_NOT_SPECIFIED ? aButtons
8863 : msg == eMouseUp ? 0
8864 : GetButtonsFlagForButton(aButton);
8865 mouseOrPointerEvent.mPressure = aPressure;
8866 mouseOrPointerEvent.mInputSource = aInputSourceArg;
8867 mouseOrPointerEvent.mClickCount = aClickCount;
8868 mouseOrPointerEvent.mFlags.mIsSynthesizedForTests = aIsDOMEventSynthesized;
8869 mouseOrPointerEvent.mExitFrom = exitFrom;
8870
8871 nsPresContext* presContext = aPresShell->GetPresContext();
8872 if (!presContext) return NS_ERROR_FAILURE;
8873
8874 mouseOrPointerEvent.mRefPoint =
8875 ToWidgetPoint(CSSPoint(aX, aY), offset, presContext);
8876 mouseOrPointerEvent.mIgnoreRootScrollFrame = aIgnoreRootScrollFrame;
8877
8878 nsEventStatus status = nsEventStatus_eIgnore;
8879 if (aToWindow) {
8880 RefPtr<PresShell> presShell;
8881 nsView* view =
8882 GetViewToDispatchEvent(presContext, getter_AddRefs(presShell));
8883 if (!presShell || !view) {
8884 return NS_ERROR_FAILURE;
8885 }
8886 return presShell->HandleEvent(view->GetFrame(), &mouseOrPointerEvent, false,
8887 &status);
8888 }
8889 if (StaticPrefs::test_events_async_enabled()) {
8890 status = widget->DispatchInputEvent(&mouseOrPointerEvent).mContentStatus;
8891 } else {
8892 nsresult rv = widget->DispatchEvent(&mouseOrPointerEvent, status);
8893 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8893); return rv; } } while (false)
;
8894 }
8895 if (aPreventDefault) {
8896 if (status == nsEventStatus_eConsumeNoDefault) {
8897 if (mouseOrPointerEvent.mFlags.mDefaultPreventedByContent) {
8898 *aPreventDefault = PreventDefaultResult::ByContent;
8899 } else {
8900 *aPreventDefault = PreventDefaultResult::ByChrome;
8901 }
8902 } else {
8903 *aPreventDefault = PreventDefaultResult::No;
8904 }
8905 }
8906
8907 return NS_OK;
8908}
8909
8910/* static */
8911void nsContentUtils::FirePageHideEventForFrameLoaderSwap(
8912 nsIDocShellTreeItem* aItem, EventTarget* aChromeEventHandler,
8913 bool aOnlySystemGroup) {
8914 MOZ_DIAGNOSTIC_ASSERT(aItem)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aItem)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aItem))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aItem", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8914); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aItem"
")"); do { *((volatile int*)__null) = 8914; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8915 MOZ_DIAGNOSTIC_ASSERT(aChromeEventHandler)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChromeEventHandler)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aChromeEventHandler))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("aChromeEventHandler"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 8915); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aChromeEventHandler"
")"); do { *((volatile int*)__null) = 8915; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8916
8917 if (RefPtr<Document> doc = aItem->GetDocument()) {
8918 doc->OnPageHide(true, aChromeEventHandler, aOnlySystemGroup);
8919 }
8920
8921 int32_t childCount = 0;
8922 aItem->GetInProcessChildCount(&childCount);
8923 AutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> kids;
8924 kids.AppendElements(childCount);
8925 for (int32_t i = 0; i < childCount; ++i) {
8926 aItem->GetInProcessChildAt(i, getter_AddRefs(kids[i]));
8927 }
8928
8929 for (uint32_t i = 0; i < kids.Length(); ++i) {
8930 if (kids[i]) {
8931 FirePageHideEventForFrameLoaderSwap(kids[i], aChromeEventHandler,
8932 aOnlySystemGroup);
8933 }
8934 }
8935}
8936
8937// The pageshow event is fired for a given document only if IsShowing() returns
8938// the same thing as aFireIfShowing. This gives us a way to fire pageshow only
8939// on documents that are still loading or only on documents that are already
8940// loaded.
8941/* static */
8942void nsContentUtils::FirePageShowEventForFrameLoaderSwap(
8943 nsIDocShellTreeItem* aItem, EventTarget* aChromeEventHandler,
8944 bool aFireIfShowing, bool aOnlySystemGroup) {
8945 int32_t childCount = 0;
8946 aItem->GetInProcessChildCount(&childCount);
8947 AutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> kids;
8948 kids.AppendElements(childCount);
8949 for (int32_t i = 0; i < childCount; ++i) {
8950 aItem->GetInProcessChildAt(i, getter_AddRefs(kids[i]));
8951 }
8952
8953 for (uint32_t i = 0; i < kids.Length(); ++i) {
8954 if (kids[i]) {
8955 FirePageShowEventForFrameLoaderSwap(kids[i], aChromeEventHandler,
8956 aFireIfShowing, aOnlySystemGroup);
8957 }
8958 }
8959
8960 RefPtr<Document> doc = aItem->GetDocument();
8961 if (doc && doc->IsShowing() == aFireIfShowing) {
8962 doc->OnPageShow(true, aChromeEventHandler, aOnlySystemGroup);
8963 }
8964}
8965
8966/* static */
8967already_AddRefed<nsPIWindowRoot> nsContentUtils::GetWindowRoot(Document* aDoc) {
8968 if (aDoc) {
8969 if (nsPIDOMWindowOuter* win = aDoc->GetWindow()) {
8970 return win->GetTopWindowRoot();
8971 }
8972 }
8973 return nullptr;
8974}
8975
8976/* static */
8977bool nsContentUtils::LinkContextIsURI(const nsAString& aAnchor,
8978 nsIURI* aDocURI) {
8979 if (aAnchor.IsEmpty()) {
8980 // anchor parameter not present or empty -> same document reference
8981 return true;
8982 }
8983
8984 // the document URI might contain a fragment identifier ("#...')
8985 // we want to ignore that because it's invisible to the server
8986 // and just affects the local interpretation in the recipient
8987 nsCOMPtr<nsIURI> contextUri;
8988 nsresult rv = NS_GetURIWithoutRef(aDocURI, getter_AddRefs(contextUri));
8989
8990 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
8991 // copying failed
8992 return false;
8993 }
8994
8995 // resolve anchor against context
8996 nsCOMPtr<nsIURI> resolvedUri;
8997 rv = NS_NewURI(getter_AddRefs(resolvedUri), aAnchor, nullptr, contextUri);
8998
8999 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
9000 // resolving failed
9001 return false;
9002 }
9003
9004 bool same;
9005 rv = contextUri->Equals(resolvedUri, &same);
9006 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
9007 // comparison failed
9008 return false;
9009 }
9010
9011 return same;
9012}
9013
9014/* static */
9015bool nsContentUtils::IsPreloadType(nsContentPolicyType aType) {
9016 return (aType == nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD ||
9017 aType == nsIContentPolicy::TYPE_INTERNAL_MODULE_PRELOAD ||
9018 aType == nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD ||
9019 aType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD ||
9020 aType == nsIContentPolicy::TYPE_INTERNAL_FONT_PRELOAD ||
9021 aType == nsIContentPolicy::TYPE_INTERNAL_FETCH_PRELOAD);
9022}
9023
9024// static
9025ReferrerPolicy nsContentUtils::GetReferrerPolicyFromChannel(
9026 nsIChannel* aChannel) {
9027 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
9028 if (!httpChannel) {
9029 return ReferrerPolicy::_empty;
9030 }
9031
9032 nsresult rv;
9033 nsAutoCString headerValue;
9034 rv = httpChannel->GetResponseHeader("referrer-policy"_ns, headerValue);
9035 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || headerValue.IsEmpty()) {
9036 return ReferrerPolicy::_empty;
9037 }
9038
9039 return ReferrerInfo::ReferrerPolicyFromHeaderString(
9040 NS_ConvertUTF8toUTF16(headerValue));
9041}
9042
9043// static
9044bool nsContentUtils::IsNonSubresourceRequest(nsIChannel* aChannel) {
9045 nsLoadFlags loadFlags = 0;
9046 aChannel->GetLoadFlags(&loadFlags);
9047 if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI) {
9048 return true;
9049 }
9050
9051 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
9052 nsContentPolicyType type = loadInfo->InternalContentPolicyType();
9053 return IsNonSubresourceInternalPolicyType(type);
9054}
9055
9056// static
9057bool nsContentUtils::IsNonSubresourceInternalPolicyType(
9058 nsContentPolicyType aType) {
9059 return aType == nsIContentPolicy::TYPE_DOCUMENT ||
9060 aType == nsIContentPolicy::TYPE_INTERNAL_IFRAME ||
9061 aType == nsIContentPolicy::TYPE_INTERNAL_FRAME ||
9062 aType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
9063 aType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER;
9064}
9065
9066// static public
9067bool nsContentUtils::IsThirdPartyTrackingResourceWindow(
9068 nsPIDOMWindowInner* aWindow) {
9069 MOZ_ASSERT(aWindow)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWindow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWindow))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aWindow", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 9069); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow" ")"
); do { *((volatile int*)__null) = 9069; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9070
9071 Document* document = aWindow->GetExtantDoc();
9072 if (!document) {
9073 return false;
9074 }
9075
9076 nsCOMPtr<nsIClassifiedChannel> classifiedChannel =
9077 do_QueryInterface(document->GetChannel());
9078 if (!classifiedChannel) {
9079 return false;
9080 }
9081
9082 return classifiedChannel->IsThirdPartyTrackingResource();
9083}
9084
9085// static public
9086bool nsContentUtils::IsFirstPartyTrackingResourceWindow(
9087 nsPIDOMWindowInner* aWindow) {
9088 MOZ_ASSERT(aWindow)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWindow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWindow))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aWindow", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 9088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow" ")"
); do { *((volatile int*)__null) = 9088; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9089
9090 Document* document = aWindow->GetExtantDoc();
9091 if (!document) {
9092 return false;
9093 }
9094
9095 nsCOMPtr<nsIClassifiedChannel> classifiedChannel =
9096 do_QueryInterface(document->GetChannel());
9097 if (!classifiedChannel) {
9098 return false;
9099 }
9100
9101 uint32_t classificationFlags =
9102 classifiedChannel->GetFirstPartyClassificationFlags();
9103
9104 return mozilla::net::UrlClassifierCommon::IsTrackingClassificationFlag(
9105 classificationFlags, NS_UsePrivateBrowsing(document->GetChannel()));
9106}
9107
9108namespace {
9109
9110// We put StringBuilder in the anonymous namespace to prevent anything outside
9111// this file from accidentally being linked against it.
9112class BulkAppender {
9113 using size_type = typename nsAString::size_type;
9114
9115 public:
9116 explicit BulkAppender(BulkWriteHandle<char16_t>&& aHandle)
9117 : mHandle(std::move(aHandle)), mPosition(0) {}
9118 ~BulkAppender() = default;
9119
9120 template <int N>
9121 void AppendLiteral(const char16_t (&aStr)[N]) {
9122 size_t len = N - 1;
9123 MOZ_ASSERT(mPosition + len <= mHandle.Length())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mPosition + len <= mHandle.Length())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mPosition + len <= mHandle.Length()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mPosition + len <= mHandle.Length()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 9123); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPosition + len <= mHandle.Length()"
")"); do { *((volatile int*)__null) = 9123; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9124 memcpy(mHandle.Elements() + mPosition, aStr, len * sizeof(char16_t));
9125 mPosition += len;
9126 }
9127
9128 void Append(Span<const char16_t> aStr) {
9129 size_t len = aStr.Length();
9130 MOZ_ASSERT(mPosition + len <= mHandle.Length())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mPosition + len <= mHandle.Length())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mPosition + len <= mHandle.Length()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mPosition + len <= mHandle.Length()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 9130); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPosition + len <= mHandle.Length()"
")"); do { *((volatile int*)__null) = 9130; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9131 // Both mHandle.Elements() and aStr.Elements() are guaranteed
9132 // to be non-null (by the string implementation and by Span,
9133 // respectively), so not checking the pointers for null before
9134 // memcpy does not lead to UB even if len was zero.
9135 memcpy(mHandle.Elements() + mPosition, aStr.Elements(),
9136 len * sizeof(char16_t));
9137 mPosition += len;
9138 }
9139
9140 void Append(Span<const char> aStr) {
9141 size_t len = aStr.Length();
9142 MOZ_ASSERT(mPosition + len <= mHandle.Length())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mPosition + len <= mHandle.Length())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mPosition + len <= mHandle.Length()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mPosition + len <= mHandle.Length()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 9142); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPosition + len <= mHandle.Length()"
")"); do { *((volatile int*)__null) = 9142; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9143 ConvertLatin1toUtf16(aStr, mHandle.AsSpan().From(mPosition));
9144 mPosition += len;
9145 }
9146
9147 void Finish() { mHandle.Finish(mPosition, false); }
9148
9149 private:
9150 BulkWriteHandle<char16_t> mHandle;
9151 size_type mPosition;
9152};
9153
9154class StringBuilder {
9155 private:
9156 class Unit {
9157 public:
9158 Unit() : mAtom(nullptr) { MOZ_COUNT_CTOR(StringBuilder::Unit)do { static_assert(std::is_class_v<StringBuilder::Unit>
, "Token '" "StringBuilder::Unit" "' is not a class type."); static_assert
(!std::is_base_of<nsISupports, StringBuilder::Unit>::value
, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "StringBuilder::Unit"
, sizeof(*this)); } while (0)
; }
9159 ~Unit() {
9160 if (mType == Type::String || mType == Type::StringWithEncode) {
9161 mString.~nsString();
9162 }
9163 MOZ_COUNT_DTOR(StringBuilder::Unit)do { static_assert(std::is_class_v<StringBuilder::Unit>
, "Token '" "StringBuilder::Unit" "' is not a class type."); static_assert
(!std::is_base_of<nsISupports, StringBuilder::Unit>::value
, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "StringBuilder::Unit"
, sizeof(*this)); } while (0)
;
9164 }
9165
9166 enum class Type : uint8_t {
9167 Unknown,
9168 Atom,
9169 String,
9170 StringWithEncode,
9171 Literal,
9172 TextFragment,
9173 TextFragmentWithEncode,
9174 };
9175
9176 struct LiteralSpan {
9177 const char16_t* mData;
9178 uint32_t mLength;
9179
9180 Span<const char16_t> AsSpan() { return Span(mData, mLength); }
9181 };
9182
9183 union {
9184 nsAtom* mAtom;
9185 LiteralSpan mLiteral;
9186 nsString mString;
9187 const nsTextFragment* mTextFragment;
9188 };
9189 Type mType = Type::Unknown;
9190 };
9191
9192 static_assert(sizeof(void*) != 8 || sizeof(Unit) <= 3 * sizeof(void*),
9193 "Unit should remain small");
9194
9195 public:
9196 // Try to keep the size of StringBuilder close to a jemalloc bucket size (the
9197 // 16kb one in this case).
9198 static constexpr uint32_t TARGET_SIZE = 16 * 1024;
9199
9200 // The number of units we need to remove from the inline buffer so that the
9201 // rest of the builder members fit. A more precise approach would be to
9202 // calculate that extra size and use (TARGET_SIZE - OTHER_SIZE) / sizeof(Unit)
9203 // or so, but this is simpler.
9204 static constexpr uint32_t PADDING_UNITS = sizeof(void*) == 8 ? 1 : 2;
9205
9206 static constexpr uint32_t STRING_BUFFER_UNITS =
9207 TARGET_SIZE / sizeof(Unit) - PADDING_UNITS;
9208
9209 StringBuilder() : mLast(this), mLength(0) { MOZ_COUNT_CTOR(StringBuilder)do { static_assert(std::is_class_v<StringBuilder>, "Token '"
"StringBuilder" "' is not a class type."); static_assert(!std
::is_base_of<nsISupports, StringBuilder>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "StringBuilder",
sizeof(*this)); } while (0)
; }
9210
9211 MOZ_COUNTED_DTOR(StringBuilder)~StringBuilder() { do { static_assert(std::is_class_v<StringBuilder
>, "Token '" "StringBuilder" "' is not a class type."); static_assert
(!std::is_base_of<nsISupports, StringBuilder>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "StringBuilder",
sizeof(*this)); } while (0); }
9212
9213 void Append(nsAtom* aAtom) {
9214 Unit* u = AddUnit();
9215 u->mAtom = aAtom;
9216 u->mType = Unit::Type::Atom;
9217 uint32_t len = aAtom->GetLength();
9218 mLength += len;
9219 }
9220
9221 template <int N>
9222 void Append(const char16_t (&aLiteral)[N]) {
9223 constexpr uint32_t len = N - 1;
9224 Unit* u = AddUnit();
9225 u->mLiteral = {aLiteral, len};
9226 u->mType = Unit::Type::Literal;
9227 mLength += len;
9228 }
9229
9230 void Append(nsString&& aString) {
9231 Unit* u = AddUnit();
9232 uint32_t len = aString.Length();
9233 new (&u->mString) nsString(std::move(aString));
9234 u->mType = Unit::Type::String;
9235 mLength += len;
9236 }
9237
9238 // aLen can be !isValid(), which will get propagated into mLength.
9239 void AppendWithAttrEncode(nsString&& aString, CheckedInt<uint32_t> aLen) {
9240 Unit* u = AddUnit();
9241 new (&u->mString) nsString(std::move(aString));
9242 u->mType = Unit::Type::StringWithEncode;
9243 mLength += aLen;
9244 }
9245
9246 void Append(const nsTextFragment* aTextFragment) {
9247 Unit* u = AddUnit();
9248 u->mTextFragment = aTextFragment;
9249 u->mType = Unit::Type::TextFragment;
9250 uint32_t len = aTextFragment->GetLength();
9251 mLength += len;
9252 }
9253
9254 // aLen can be !isValid(), which will get propagated into mLength.
9255 void AppendWithEncode(const nsTextFragment* aTextFragment,
9256 CheckedInt<uint32_t> aLen) {
9257 Unit* u = AddUnit();
9258 u->mTextFragment = aTextFragment;
9259 u->mType = Unit::Type::TextFragmentWithEncode;
9260 mLength += aLen;
9261 }
9262
9263 bool ToString(nsAString& aOut) {
9264 if (!mLength.isValid()) {
9265 return false;
9266 }
9267 auto appenderOrErr = aOut.BulkWrite(mLength.value(), 0, true);
9268 if (appenderOrErr.isErr()) {
9269 return false;
9270 }
9271
9272 BulkAppender appender{appenderOrErr.unwrap()};
9273
9274 for (StringBuilder* current = this; current;
9275 current = current->mNext.get()) {
9276 uint32_t len = current->mUnits.Length();
9277 for (uint32_t i = 0; i < len; ++i) {
9278 Unit& u = current->mUnits[i];
9279 switch (u.mType) {
9280 case Unit::Type::Atom:
9281 appender.Append(*(u.mAtom));
9282 break;
9283 case Unit::Type::String:
9284 appender.Append(u.mString);
9285 break;
9286 case Unit::Type::StringWithEncode:
9287 EncodeAttrString(u.mString, appender);
9288 break;
9289 case Unit::Type::Literal:
9290 appender.Append(u.mLiteral.AsSpan());
9291 break;
9292 case Unit::Type::TextFragment:
9293 if (u.mTextFragment->Is2b()) {
9294 appender.Append(
9295 Span(u.mTextFragment->Get2b(), u.mTextFragment->GetLength()));
9296 } else {
9297 appender.Append(
9298 Span(u.mTextFragment->Get1b(), u.mTextFragment->GetLength()));
9299 }
9300 break;
9301 case Unit::Type::TextFragmentWithEncode:
9302 if (u.mTextFragment->Is2b()) {
9303 EncodeTextFragment(
9304 Span(u.mTextFragment->Get2b(), u.mTextFragment->GetLength()),
9305 appender);
9306 } else {
9307 EncodeTextFragment(
9308 Span(u.mTextFragment->Get1b(), u.mTextFragment->GetLength()),
9309 appender);
9310 }
9311 break;
9312 default:
9313 MOZ_CRASH("Unknown unit type?")do { do { } while (false); MOZ_ReportCrash("" "Unknown unit type?"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 9313); AnnotateMozCrashReason("MOZ_CRASH(" "Unknown unit type?"
")"); do { *((volatile int*)__null) = 9313; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
9314 }
9315 }
9316 }
9317 appender.Finish();
9318 return true;
9319 }
9320
9321 private:
9322 Unit* AddUnit() {
9323 if (mLast->mUnits.Length() == STRING_BUFFER_UNITS) {
9324 new StringBuilder(this);
9325 }
9326 return mLast->mUnits.AppendElement();
9327 }
9328
9329 explicit StringBuilder(StringBuilder* aFirst) : mLast(nullptr), mLength(0) {
9330 MOZ_COUNT_CTOR(StringBuilder)do { static_assert(std::is_class_v<StringBuilder>, "Token '"
"StringBuilder" "' is not a class type."); static_assert(!std
::is_base_of<nsISupports, StringBuilder>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "StringBuilder",
sizeof(*this)); } while (0)
;
9331 aFirst->mLast->mNext = WrapUnique(this);
9332 aFirst->mLast = this;
9333 }
9334
9335 void EncodeAttrString(Span<const char16_t> aStr, BulkAppender& aAppender) {
9336 size_t flushedUntil = 0;
9337 size_t currentPosition = 0;
9338 for (char16_t c : aStr) {
9339 switch (c) {
9340 case '"':
9341 aAppender.Append(aStr.FromTo(flushedUntil, currentPosition));
9342 aAppender.AppendLiteral(u"&quot;");
9343 flushedUntil = currentPosition + 1;
9344 break;
9345 case '&':
9346 aAppender.Append(aStr.FromTo(flushedUntil, currentPosition));
9347 aAppender.AppendLiteral(u"&amp;");
9348 flushedUntil = currentPosition + 1;
9349 break;
9350 case 0x00A0:
9351 aAppender.Append(aStr.FromTo(flushedUntil, currentPosition));
9352 aAppender.AppendLiteral(u"&nbsp;");
9353 flushedUntil = currentPosition + 1;
9354 break;
9355 default:
9356 break;
9357 }
9358 currentPosition++;
9359 }
9360 if (currentPosition > flushedUntil) {
9361 aAppender.Append(aStr.FromTo(flushedUntil, currentPosition));
9362 }
9363 }
9364
9365 template <class T>
9366 void EncodeTextFragment(Span<const T> aStr, BulkAppender& aAppender) {
9367 size_t flushedUntil = 0;
9368 size_t currentPosition = 0;
9369 for (T c : aStr) {
9370 switch (c) {
9371 case '<':
9372 aAppender.Append(aStr.FromTo(flushedUntil, currentPosition));
9373 aAppender.AppendLiteral(u"&lt;");
9374 flushedUntil = currentPosition + 1;
9375 break;
9376 case '>':
9377 aAppender.Append(aStr.FromTo(flushedUntil, currentPosition));
9378 aAppender.AppendLiteral(u"&gt;");
9379 flushedUntil = currentPosition + 1;
9380 break;
9381 case '&':
9382 aAppender.Append(aStr.FromTo(flushedUntil, currentPosition));
9383 aAppender.AppendLiteral(u"&amp;");
9384 flushedUntil = currentPosition + 1;
9385 break;
9386 case T(0xA0):
9387 aAppender.Append(aStr.FromTo(flushedUntil, currentPosition));
9388 aAppender.AppendLiteral(u"&nbsp;");
9389 flushedUntil = currentPosition + 1;
9390 break;
9391 default:
9392 break;
9393 }
9394 currentPosition++;
9395 }
9396 if (currentPosition > flushedUntil) {
9397 aAppender.Append(aStr.FromTo(flushedUntil, currentPosition));
9398 }
9399 }
9400
9401 AutoTArray<Unit, STRING_BUFFER_UNITS> mUnits;
9402 UniquePtr<StringBuilder> mNext;
9403 StringBuilder* mLast;
9404 // mLength is used only in the first StringBuilder object in the linked list.
9405 CheckedInt<uint32_t> mLength;
9406};
9407
9408static_assert(sizeof(StringBuilder) <= StringBuilder::TARGET_SIZE,
9409 "StringBuilder should fit in the target bucket");
9410
9411} // namespace
9412
9413static void AppendEncodedCharacters(const nsTextFragment* aText,
9414 StringBuilder& aBuilder) {
9415 uint32_t numEncodedChars = 0;
9416 uint32_t len = aText->GetLength();
9417 if (aText->Is2b()) {
9418 const char16_t* data = aText->Get2b();
9419 for (uint32_t i = 0; i < len; ++i) {
9420 const char16_t c = data[i];
9421 switch (c) {
9422 case '<':
9423 case '>':
9424 case '&':
9425 case 0x00A0:
9426 ++numEncodedChars;
9427 break;
9428 default:
9429 break;
9430 }
9431 }
9432 } else {
9433 const char* data = aText->Get1b();
9434 for (uint32_t i = 0; i < len; ++i) {
9435 const unsigned char c = data[i];
9436 switch (c) {
9437 case '<':
9438 case '>':
9439 case '&':
9440 case 0x00A0:
9441 ++numEncodedChars;
9442 break;
9443 default:
9444 break;
9445 }
9446 }
9447 }
9448
9449 if (numEncodedChars) {
9450 // For simplicity, conservatively estimate the size of the string after
9451 // encoding. This will result in reserving more memory than we actually
9452 // need, but that should be fine unless the string has an enormous number of
9453 // eg < in it. We subtract 1 for the null terminator, then 1 more for the
9454 // existing character that will be replaced.
9455 constexpr uint32_t maxCharExtraSpace =
9456 std::max({ArrayLength("&lt;"), ArrayLength("&gt;"),
9457 ArrayLength("&amp;"), ArrayLength("&nbsp;")}) -
9458 2;
9459 static_assert(maxCharExtraSpace < 100, "Possible underflow");
9460 CheckedInt<uint32_t> maxExtraSpace =
9461 CheckedInt<uint32_t>(numEncodedChars) * maxCharExtraSpace;
9462 aBuilder.AppendWithEncode(aText, maxExtraSpace + len);
9463 } else {
9464 aBuilder.Append(aText);
9465 }
9466}
9467
9468static CheckedInt<uint32_t> ExtraSpaceNeededForAttrEncoding(
9469 const nsAString& aValue) {
9470 const char16_t* c = aValue.BeginReading();
9471 const char16_t* end = aValue.EndReading();
9472
9473 uint32_t numEncodedChars = 0;
9474 while (c < end) {
9475 switch (*c) {
9476 case '"':
9477 case '&':
9478 case 0x00A0:
9479 ++numEncodedChars;
9480 break;
9481 default:
9482 break;
9483 }
9484 ++c;
9485 }
9486
9487 if (!numEncodedChars) {
9488 return 0;
9489 }
9490
9491 // For simplicity, conservatively estimate the size of the string after
9492 // encoding. This will result in reserving more memory than we actually
9493 // need, but that should be fine unless the string has an enormous number of
9494 // & in it. We subtract 1 for the null terminator, then 1 more for the
9495 // existing character that will be replaced.
9496 constexpr uint32_t maxCharExtraSpace =
9497 std::max({ArrayLength("&quot;"), ArrayLength("&amp;"),
9498 ArrayLength("&nbsp;")}) -
9499 2;
9500 static_assert(maxCharExtraSpace < 100, "Possible underflow");
9501 return CheckedInt<uint32_t>(numEncodedChars) * maxCharExtraSpace;
9502}
9503
9504static void AppendEncodedAttributeValue(const nsAttrValue& aValue,
9505 StringBuilder& aBuilder) {
9506 if (nsAtom* atom = aValue.GetStoredAtom()) {
9507 nsDependentAtomString atomStr(atom);
9508 auto space = ExtraSpaceNeededForAttrEncoding(atomStr);
9509 if (space.isValid() && !space.value()) {
9510 aBuilder.Append(atom);
9511 } else {
9512 aBuilder.AppendWithAttrEncode(nsString(atomStr),
9513 space + atomStr.Length());
9514 }
9515 return;
9516 }
9517 // NOTE(emilio): In most cases this will just be a reference to the stored
9518 // nsStringBuffer.
9519 nsString str;
9520 aValue.ToString(str);
9521 auto space = ExtraSpaceNeededForAttrEncoding(str);
9522 if (!space.isValid() || space.value()) {
9523 aBuilder.AppendWithAttrEncode(std::move(str), space + str.Length());
9524 } else {
9525 aBuilder.Append(std::move(str));
9526 }
9527}
9528
9529static void StartElement(Element* aElement, StringBuilder& aBuilder) {
9530 nsAtom* localName = aElement->NodeInfo()->NameAtom();
9531 const int32_t tagNS = aElement->GetNameSpaceID();
9532
9533 aBuilder.Append(u"<");
9534 if (tagNS == kNameSpaceID_XHTML3 || tagNS == kNameSpaceID_SVG9 ||
9535 tagNS == kNameSpaceID_MathML6) {
9536 aBuilder.Append(localName);
9537 } else {
9538 aBuilder.Append(nsString(aElement->NodeName()));
9539 }
9540
9541 if (CustomElementData* ceData = aElement->GetCustomElementData()) {
9542 nsAtom* isAttr = ceData->GetIs(aElement);
9543 if (isAttr && !aElement->HasAttr(nsGkAtoms::is)) {
9544 aBuilder.Append(uR"( is=")");
9545 aBuilder.Append(isAttr);
9546 aBuilder.Append(uR"(")");
9547 }
9548 }
9549
9550 uint32_t i = 0;
9551 while (BorrowedAttrInfo info = aElement->GetAttrInfoAt(i++)) {
9552 const nsAttrName* name = info.mName;
9553
9554 int32_t attNs = name->NamespaceID();
9555 nsAtom* attName = name->LocalName();
9556
9557 // Filter out any attribute starting with [-|_]moz
9558 // FIXME(emilio): Do we still need this?
9559 nsDependentAtomString attrNameStr(attName);
9560 if (StringBeginsWith(attrNameStr, u"_moz"_ns) ||
9561 StringBeginsWith(attrNameStr, u"-moz"_ns)) {
9562 continue;
9563 }
9564
9565 aBuilder.Append(u" ");
9566
9567 if (MOZ_LIKELY(attNs == kNameSpaceID_None)(__builtin_expect(!!(attNs == kNameSpaceID_None), 1)) ||
9568 (attNs == kNameSpaceID_XMLNS1 && attName == nsGkAtoms::xmlns)) {
9569 // Nothing else required
9570 } else if (attNs == kNameSpaceID_XML2) {
9571 aBuilder.Append(u"xml:");
9572 } else if (attNs == kNameSpaceID_XMLNS1) {
9573 aBuilder.Append(u"xmlns:");
9574 } else if (attNs == kNameSpaceID_XLink4) {
9575 aBuilder.Append(u"xlink:");
9576 } else if (nsAtom* prefix = name->GetPrefix()) {
9577 aBuilder.Append(prefix);
9578 aBuilder.Append(u":");
9579 }
9580
9581 aBuilder.Append(attName);
9582 aBuilder.Append(uR"(=")");
9583 AppendEncodedAttributeValue(*info.mValue, aBuilder);
9584 aBuilder.Append(uR"(")");
9585 }
9586
9587 aBuilder.Append(u">");
9588
9589 /*
9590 // Per HTML spec we should append one \n if the first child of
9591 // pre/textarea/listing is a textnode and starts with a \n.
9592 // But because browsers haven't traditionally had that behavior,
9593 // we're not changing our behavior either - yet.
9594 if (aContent->IsHTMLElement()) {
9595 if (localName == nsGkAtoms::pre || localName == nsGkAtoms::textarea ||
9596 localName == nsGkAtoms::listing) {
9597 nsIContent* fc = aContent->GetFirstChild();
9598 if (fc &&
9599 (fc->NodeType() == nsINode::TEXT_NODE ||
9600 fc->NodeType() == nsINode::CDATA_SECTION_NODE)) {
9601 const nsTextFragment* text = fc->GetText();
9602 if (text && text->GetLength() && text->CharAt(0) == char16_t('\n')) {
9603 aBuilder.Append("\n");
9604 }
9605 }
9606 }
9607 }*/
9608}
9609
9610static inline bool ShouldEscape(nsIContent* aParent) {
9611 if (!aParent || !aParent->IsHTMLElement()) {
9612 return true;
9613 }
9614
9615 static const nsAtom* nonEscapingElements[] = {
9616 nsGkAtoms::style, nsGkAtoms::script, nsGkAtoms::xmp,
9617 nsGkAtoms::iframe, nsGkAtoms::noembed, nsGkAtoms::noframes,
9618 nsGkAtoms::plaintext, nsGkAtoms::noscript};
9619 static mozilla::BitBloomFilter<12, nsAtom> sFilter;
9620 static bool sInitialized = false;
9621 if (!sInitialized) {
9622 sInitialized = true;
9623 for (auto& nonEscapingElement : nonEscapingElements) {
9624 sFilter.add(nonEscapingElement);
9625 }
9626 }
9627
9628 nsAtom* tag = aParent->NodeInfo()->NameAtom();
9629 if (sFilter.mightContain(tag)) {
9630 for (auto& nonEscapingElement : nonEscapingElements) {
9631 if (tag == nonEscapingElement) {
9632 if (MOZ_UNLIKELY(tag == nsGkAtoms::noscript)(__builtin_expect(!!(tag == nsGkAtoms::noscript), 0)) &&
9633 MOZ_UNLIKELY(!aParent->OwnerDoc()->IsScriptEnabled())(__builtin_expect(!!(!aParent->OwnerDoc()->IsScriptEnabled
()), 0))
) {
9634 return true;
9635 }
9636 return false;
9637 }
9638 }
9639 }
9640 return true;
9641}
9642
9643static inline bool IsVoidTag(Element* aElement) {
9644 if (!aElement->IsHTMLElement()) {
9645 return false;
9646 }
9647 return FragmentOrElement::IsHTMLVoid(aElement->NodeInfo()->NameAtom());
9648}
9649
9650static bool StartSerializingShadowDOM(
9651 nsINode* aNode, StringBuilder& aBuilder, bool aSerializableShadowRoots,
9652 const Sequence<OwningNonNull<ShadowRoot>>& aShadowRoots) {
9653 ShadowRoot* shadow = aNode->GetShadowRoot();
9654 if (!shadow || ((!aSerializableShadowRoots || !shadow->Serializable()) &&
9655 !aShadowRoots.Contains(shadow))) {
9656 return false;
9657 }
9658
9659 aBuilder.Append(u"<template shadowrootmode=\"");
9660 if (shadow->IsClosed()) {
9661 aBuilder.Append(u"closed\"");
9662 } else {
9663 aBuilder.Append(u"open\"");
9664 }
9665
9666 if (shadow->DelegatesFocus()) {
9667 aBuilder.Append(u" shadowrootdelegatesfocus=\"\"");
9668 }
9669 if (shadow->Serializable()) {
9670 aBuilder.Append(u" shadowrootserializable=\"\"");
9671 }
9672 if (shadow->Clonable()) {
9673 aBuilder.Append(u" shadowrootclonable=\"\"");
9674 }
9675
9676 aBuilder.Append(u">");
9677
9678 if (!shadow->HasChildren()) {
9679 aBuilder.Append(u"</template>");
9680 return false;
9681 }
9682 return true;
9683}
9684
9685template <SerializeShadowRoots ShouldSerializeShadowRoots>
9686static void SerializeNodeToMarkupInternal(
9687 nsINode* aRoot, bool aDescendantsOnly, StringBuilder& aBuilder,
9688 bool aSerializableShadowRoots,
9689 const Sequence<OwningNonNull<ShadowRoot>>& aShadowRoots) {
9690 nsINode* current =
9691 aDescendantsOnly ? aRoot->GetFirstChildOfTemplateOrNode() : aRoot;
9692 if (!current) {
9693 return;
9694 }
9695
9696 nsIContent* next;
9697 while (true) {
9698 bool isVoid = false;
9699 switch (current->NodeType()) {
9700 case nsINode::ELEMENT_NODE: {
9701 Element* elem = current->AsElement();
9702 StartElement(elem, aBuilder);
9703
9704 if constexpr (ShouldSerializeShadowRoots == SerializeShadowRoots::Yes) {
9705 if (StartSerializingShadowDOM(
9706 current, aBuilder, aSerializableShadowRoots, aShadowRoots)) {
9707 current = current->GetShadowRoot()->GetFirstChild();
9708 continue;
9709 }
9710 }
9711
9712 isVoid = IsVoidTag(elem);
9713 if (!isVoid && (next = current->GetFirstChildOfTemplateOrNode())) {
9714 current = next;
9715 continue;
9716 }
9717 break;
9718 }
9719
9720 case nsINode::TEXT_NODE:
9721 case nsINode::CDATA_SECTION_NODE: {
9722 const nsTextFragment* text = &current->AsText()->TextFragment();
9723 nsIContent* parent = current->GetParent();
9724 if (ShouldEscape(parent)) {
9725 AppendEncodedCharacters(text, aBuilder);
9726 } else {
9727 aBuilder.Append(text);
9728 }
9729 break;
9730 }
9731
9732 case nsINode::COMMENT_NODE: {
9733 aBuilder.Append(u"<!--");
9734 aBuilder.Append(static_cast<nsIContent*>(current)->GetText());
9735 aBuilder.Append(u"-->");
9736 break;
9737 }
9738
9739 case nsINode::DOCUMENT_TYPE_NODE: {
9740 aBuilder.Append(u"<!DOCTYPE ");
9741 aBuilder.Append(nsString(current->NodeName()));
9742 aBuilder.Append(u">");
9743 break;
9744 }
9745
9746 case nsINode::PROCESSING_INSTRUCTION_NODE: {
9747 aBuilder.Append(u"<?");
9748 aBuilder.Append(nsString(current->NodeName()));
9749 aBuilder.Append(u" ");
9750 aBuilder.Append(static_cast<nsIContent*>(current)->GetText());
9751 aBuilder.Append(u">");
9752 break;
9753 }
9754 }
9755
9756 while (true) {
9757 if (!isVoid && current->NodeType() == nsINode::ELEMENT_NODE) {
9758 aBuilder.Append(u"</");
9759 nsIContent* elem = static_cast<nsIContent*>(current);
9760 if (elem->IsHTMLElement() || elem->IsSVGElement() ||
9761 elem->IsMathMLElement()) {
9762 aBuilder.Append(elem->NodeInfo()->NameAtom());
9763 } else {
9764 aBuilder.Append(nsString(current->NodeName()));
9765 }
9766 aBuilder.Append(u">");
9767 }
9768 isVoid = false;
9769
9770 if (current == aRoot) {
9771 return;
9772 }
9773
9774 if ((next = current->GetNextSibling())) {
9775 current = next;
9776 break;
9777 }
9778
9779 if constexpr (ShouldSerializeShadowRoots == SerializeShadowRoots::Yes) {
9780 // If the current node is a shadow root, then we must go to its host.
9781 // Since shadow DOMs are serialized declaratively as template elements,
9782 // we serialize the end tag of the template before going back to
9783 // serializing the shadow host.
9784 if (current->IsShadowRoot()) {
9785 current = current->GetContainingShadowHost();
9786 aBuilder.Append(u"</template>");
9787
9788 if (current->HasChildren()) {
9789 current = current->GetFirstChildOfTemplateOrNode();
9790 break;
9791 }
9792 continue;
9793 }
9794 }
9795
9796 current = current->GetParentNode();
9797
9798 // Handle template element. If the parent is a template's content,
9799 // then adjust the parent to be the template element.
9800 if (current != aRoot &&
9801 current->NodeType() == nsINode::DOCUMENT_FRAGMENT_NODE) {
9802 DocumentFragment* frag = static_cast<DocumentFragment*>(current);
9803 nsIContent* fragHost = frag->GetHost();
9804 if (fragHost && fragHost->IsTemplateElement()) {
9805 current = fragHost;
9806 }
9807 }
9808
9809 if (aDescendantsOnly && current == aRoot) {
9810 return;
9811 }
9812 }
9813 }
9814}
9815
9816template <SerializeShadowRoots ShouldSerializeShadowRoots>
9817bool nsContentUtils::SerializeNodeToMarkup(
9818 nsINode* aRoot, bool aDescendantsOnly, nsAString& aOut,
9819 bool aSerializableShadowRoots,
9820 const Sequence<OwningNonNull<ShadowRoot>>& aShadowRoots) {
9821 // If you pass in a DOCUMENT_NODE, you must pass aDescendentsOnly as true
9822 MOZ_ASSERT(aDescendantsOnly || aRoot->NodeType() != nsINode::DOCUMENT_NODE)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDescendantsOnly || aRoot->NodeType() != nsINode::
DOCUMENT_NODE)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aDescendantsOnly || aRoot->NodeType
() != nsINode::DOCUMENT_NODE))), 0))) { do { } while (false);
MOZ_ReportAssertionFailure("aDescendantsOnly || aRoot->NodeType() != nsINode::DOCUMENT_NODE"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 9822); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDescendantsOnly || aRoot->NodeType() != nsINode::DOCUMENT_NODE"
")"); do { *((volatile int*)__null) = 9822; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9823
9824 StringBuilder builder;
9825 if constexpr (ShouldSerializeShadowRoots == SerializeShadowRoots::Yes) {
9826 if (aDescendantsOnly &&
9827 StartSerializingShadowDOM(aRoot, builder, aSerializableShadowRoots,
9828 aShadowRoots)) {
9829 SerializeNodeToMarkupInternal<SerializeShadowRoots::Yes>(
9830 aRoot->GetShadowRoot()->GetFirstChild(), false, builder,
9831 aSerializableShadowRoots, aShadowRoots);
9832 // The template tag is opened in StartSerializingShadowDOM, so we need
9833 // to close it here before serializing any children of aRoot.
9834 builder.Append(u"</template>");
9835 }
9836 }
9837
9838 SerializeNodeToMarkupInternal<ShouldSerializeShadowRoots>(
9839 aRoot, aDescendantsOnly, builder, aSerializableShadowRoots, aShadowRoots);
9840 return builder.ToString(aOut);
9841}
9842
9843template bool nsContentUtils::SerializeNodeToMarkup<SerializeShadowRoots::No>(
9844 nsINode* aRoot, bool aDescendantsOnly, nsAString& aOut,
9845 bool aSerializableShadowRoots,
9846 const Sequence<OwningNonNull<ShadowRoot>>& aShadowRoots);
9847template bool nsContentUtils::SerializeNodeToMarkup<SerializeShadowRoots::Yes>(
9848 nsINode* aRoot, bool aDescendantsOnly, nsAString& aOut,
9849 bool aSerializableShadowRoots,
9850 const Sequence<OwningNonNull<ShadowRoot>>& aShadowRoots);
9851
9852bool nsContentUtils::IsSpecificAboutPage(JSObject* aGlobal, const char* aUri) {
9853 // aUri must start with about: or this isn't the right function to be using.
9854 MOZ_ASSERT(strncmp(aUri, "about:", 6) == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(strncmp(aUri, "about:", 6) == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(strncmp(aUri, "about:", 6) ==
0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("strncmp(aUri, \"about:\", 6) == 0", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 9854); AnnotateMozCrashReason("MOZ_ASSERT" "(" "strncmp(aUri, \"about:\", 6) == 0"
")"); do { *((volatile int*)__null) = 9854; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9855
9856 // Make sure the global is a window
9857 MOZ_DIAGNOSTIC_ASSERT(JS_IsGlobalObject(aGlobal))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(JS_IsGlobalObject(aGlobal))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(JS_IsGlobalObject(aGlobal)))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("JS_IsGlobalObject(aGlobal)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 9857); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "JS_IsGlobalObject(aGlobal)"
")"); do { *((volatile int*)__null) = 9857; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9858 nsGlobalWindowInner* win = xpc::WindowOrNull(aGlobal);
9859 if (!win) {
9860 return false;
9861 }
9862
9863 nsCOMPtr<nsIPrincipal> principal = win->GetPrincipal();
9864 NS_ENSURE_TRUE(principal, false)do { if ((__builtin_expect(!!(!(principal)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "principal" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 9864); return false; } } while (false)
;
9865
9866 // First check the scheme to avoid getting long specs in the common case.
9867 if (!principal->SchemeIs("about")) {
9868 return false;
9869 }
9870
9871 nsAutoCString spec;
9872 principal->GetAsciiSpec(spec);
9873
9874 return spec.EqualsASCII(aUri);
9875}
9876
9877/* static */
9878void nsContentUtils::SetScrollbarsVisibility(nsIDocShell* aDocShell,
9879 bool aVisible) {
9880 if (!aDocShell) {
9881 return;
9882 }
9883 auto pref = aVisible ? ScrollbarPreference::Auto : ScrollbarPreference::Never;
9884 nsDocShell::Cast(aDocShell)->SetScrollbarPreference(pref);
9885}
9886
9887/* static */
9888nsIDocShell* nsContentUtils::GetDocShellForEventTarget(EventTarget* aTarget) {
9889 if (!aTarget) {
9890 return nullptr;
9891 }
9892
9893 nsCOMPtr<nsPIDOMWindowInner> innerWindow;
9894 if (nsCOMPtr<nsINode> node = nsINode::FromEventTarget(aTarget)) {
9895 bool ignore;
9896 innerWindow =
9897 do_QueryInterface(node->OwnerDoc()->GetScriptHandlingObject(ignore));
9898 } else if ((innerWindow = nsPIDOMWindowInner::FromEventTarget(aTarget))) {
9899 // Nothing else to do
9900 } else if (nsCOMPtr<DOMEventTargetHelper> helper =
9901 do_QueryInterface(aTarget)) {
9902 innerWindow = helper->GetOwnerWindow();
9903 }
9904
9905 if (innerWindow) {
9906 return innerWindow->GetDocShell();
9907 }
9908
9909 return nullptr;
9910}
9911
9912/*
9913 * Note: this function only relates to figuring out HTTPS state, which is an
9914 * input to the Secure Context algorithm. We are not actually implementing any
9915 * part of the Secure Context algorithm itself here.
9916 *
9917 * This is a bit of a hack. Ideally we'd propagate HTTPS state through
9918 * nsIChannel as described in the Fetch and HTML specs, but making channels
9919 * know about whether they should inherit HTTPS state, propagating information
9920 * about who the channel's "client" is, exposing GetHttpsState API on channels
9921 * and modifying the various cache implementations to store and retrieve HTTPS
9922 * state involves a huge amount of code (see bug 1220687). We avoid that for
9923 * now using this function.
9924 *
9925 * This function takes advantage of the observation that we can return true if
9926 * nsIContentSecurityManager::IsOriginPotentiallyTrustworthy returns true for
9927 * the document's origin (e.g. the origin has a scheme of 'https' or host
9928 * 'localhost' etc.). Since we generally propagate a creator document's origin
9929 * onto data:, blob:, etc. documents, this works for them too.
9930 *
9931 * The scenario where this observation breaks down is sandboxing without the
9932 * 'allow-same-origin' flag, since in this case a document is given a unique
9933 * origin (IsOriginPotentiallyTrustworthy would return false). We handle that
9934 * by using the origin that the document would have had had it not been
9935 * sandboxed.
9936 *
9937 * DEFICIENCIES: Note that this function uses nsIScriptSecurityManager's
9938 * getChannelResultPrincipalIfNotSandboxed, and that method's ignoring of
9939 * sandboxing is limited to the immediate sandbox. In the case that aDocument
9940 * should inherit its origin (e.g. data: URI) but its parent has ended up
9941 * with a unique origin due to sandboxing further up the parent chain we may
9942 * end up returning false when we would ideally return true (since we will
9943 * examine the parent's origin for 'https' and not finding it.) This means
9944 * that we may restrict the privileges of some pages unnecessarily in this
9945 * edge case.
9946 */
9947/* static */
9948bool nsContentUtils::HttpsStateIsModern(Document* aDocument) {
9949 if (!aDocument) {
9950 return false;
9951 }
9952
9953 nsCOMPtr<nsIPrincipal> principal = aDocument->NodePrincipal();
9954
9955 if (principal->IsSystemPrincipal()) {
9956 return true;
9957 }
9958
9959 // If aDocument is sandboxed, try and get the principal that it would have
9960 // been given had it not been sandboxed:
9961 if (principal->GetIsNullPrincipal() &&
9962 (aDocument->GetSandboxFlags() & SANDBOXED_ORIGIN)) {
9963 nsIChannel* channel = aDocument->GetChannel();
9964 if (channel) {
9965 nsCOMPtr<nsIScriptSecurityManager> ssm =
9966 nsContentUtils::GetSecurityManager();
9967 nsresult rv = ssm->GetChannelResultPrincipalIfNotSandboxed(
9968 channel, getter_AddRefs(principal));
9969 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
9970 return false;
9971 }
9972 if (principal->IsSystemPrincipal()) {
9973 // If a document with the system principal is sandboxing a subdocument
9974 // that would normally inherit the embedding element's principal (e.g.
9975 // a srcdoc document) then the embedding document does not trust the
9976 // content that is written to the embedded document. Unlike when the
9977 // embedding document is https, in this case we have no indication as
9978 // to whether the embedded document's contents are delivered securely
9979 // or not, and the sandboxing would possibly indicate that they were
9980 // not. To play it safe we return false here. (See bug 1162772
9981 // comment 73-80.)
9982 return false;
9983 }
9984 }
9985 }
9986
9987 if (principal->GetIsNullPrincipal()) {
9988 return false;
9989 }
9990
9991 MOZ_ASSERT(principal->GetIsContentPrincipal())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(principal->GetIsContentPrincipal())>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(principal->GetIsContentPrincipal()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("principal->GetIsContentPrincipal()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 9991); AnnotateMozCrashReason("MOZ_ASSERT" "(" "principal->GetIsContentPrincipal()"
")"); do { *((volatile int*)__null) = 9991; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9992
9993 return principal->GetIsOriginPotentiallyTrustworthy();
9994}
9995
9996/* static */
9997bool nsContentUtils::ComputeIsSecureContext(nsIChannel* aChannel) {
9998 MOZ_ASSERT(aChannel)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChannel)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aChannel))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aChannel", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 9998); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChannel" ")"
); do { *((volatile int*)__null) = 9998; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9999
10000 nsCOMPtr<nsIScriptSecurityManager> ssm = nsContentUtils::GetSecurityManager();
10001 nsCOMPtr<nsIPrincipal> principal;
10002 nsresult rv = ssm->GetChannelResultPrincipalIfNotSandboxed(
10003 aChannel, getter_AddRefs(principal));
10004 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
10005 return false;
10006 }
10007
10008 const RefPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
10009
10010 if (principal->IsSystemPrincipal()) {
10011 // If the load would've been sandboxed, treat this load as an untrusted
10012 // load, as system code considers sandboxed resources insecure.
10013 return !loadInfo->GetLoadingSandboxed();
10014 }
10015
10016 if (principal->GetIsNullPrincipal()) {
10017 return false;
10018 }
10019
10020 if (const RefPtr<WindowContext> windowContext =
10021 WindowContext::GetById(loadInfo->GetInnerWindowID())) {
10022 if (!windowContext->GetIsSecureContext()) {
10023 return false;
10024 }
10025 }
10026
10027 return principal->GetIsOriginPotentiallyTrustworthy();
10028}
10029
10030/* static */
10031void nsContentUtils::TryToUpgradeElement(Element* aElement) {
10032 NodeInfo* nodeInfo = aElement->NodeInfo();
10033 RefPtr<nsAtom> typeAtom =
10034 aElement->GetCustomElementData()->GetCustomElementType();
10035
10036 MOZ_ASSERT(nodeInfo->NameAtom()->Equals(nodeInfo->LocalName()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nodeInfo->NameAtom()->Equals(nodeInfo->LocalName
()))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(nodeInfo->NameAtom()->Equals(nodeInfo->LocalName
())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("nodeInfo->NameAtom()->Equals(nodeInfo->LocalName())"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10036); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nodeInfo->NameAtom()->Equals(nodeInfo->LocalName())"
")"); do { *((volatile int*)__null) = 10036; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10037 CustomElementDefinition* definition =
10038 nsContentUtils::LookupCustomElementDefinition(
10039 nodeInfo->GetDocument(), nodeInfo->NameAtom(),
10040 nodeInfo->NamespaceID(), typeAtom);
10041 if (definition) {
10042 nsContentUtils::EnqueueUpgradeReaction(aElement, definition);
10043 } else {
10044 // Add an unresolved custom element that is a candidate for upgrade when a
10045 // custom element is connected to the document.
10046 nsContentUtils::RegisterUnresolvedElement(aElement, typeAtom);
10047 }
10048}
10049
10050MOZ_CAN_RUN_SCRIPT
10051static void DoCustomElementCreate(Element** aElement, JSContext* aCx,
10052 Document* aDoc, NodeInfo* aNodeInfo,
10053 CustomElementConstructor* aConstructor,
10054 ErrorResult& aRv, FromParser aFromParser) {
10055 JS::Rooted<JS::Value> constructResult(aCx);
10056 aConstructor->Construct(&constructResult, aRv, "Custom Element Create",
10057 CallbackFunction::eRethrowExceptions);
10058 if (aRv.Failed()) {
10059 return;
10060 }
10061
10062 RefPtr<Element> element;
10063 // constructResult is an ObjectValue because construction with a callback
10064 // always forms the return value from a JSObject.
10065 UNWRAP_OBJECT(Element, &constructResult, element)mozilla::dom::binding_detail::UnwrapObjectWithCrossOriginAsserts
< mozilla::dom::prototypes::id::Element, mozilla::dom::Element_Binding
::NativeType>(&constructResult, element)
;
10066 if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML3)) {
10067 if (!element || !element->IsHTMLElement()) {
10068 aRv.ThrowTypeError<MSG_DOES_NOT_IMPLEMENT_INTERFACE>("\"this\"",
10069 "HTMLElement");
10070 return;
10071 }
10072 } else {
10073 if (!element || !element->IsXULElement()) {
10074 aRv.ThrowTypeError<MSG_DOES_NOT_IMPLEMENT_INTERFACE>("\"this\"",
10075 "XULElement");
10076 return;
10077 }
10078 }
10079
10080 nsAtom* localName = aNodeInfo->NameAtom();
10081
10082 if (aDoc != element->OwnerDoc() || element->GetParentNode() ||
10083 element->HasChildren() || element->GetAttrCount() ||
10084 element->NodeInfo()->NameAtom() != localName) {
10085 aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
10086 return;
10087 }
10088
10089 if (element->IsHTMLElement()) {
10090 static_cast<HTMLElement*>(&*element)->InhibitRestoration(
10091 !(aFromParser & FROM_PARSER_NETWORK));
10092 }
10093
10094 element.forget(aElement);
10095}
10096
10097/* static */
10098nsresult nsContentUtils::NewXULOrHTMLElement(
10099 Element** aResult, mozilla::dom::NodeInfo* aNodeInfo,
10100 FromParser aFromParser, nsAtom* aIsAtom,
10101 mozilla::dom::CustomElementDefinition* aDefinition) {
10102 RefPtr<mozilla::dom::NodeInfo> nodeInfo = aNodeInfo;
10103 MOZ_ASSERT(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nodeInfo->NamespaceEquals(3) || nodeInfo->NamespaceEquals
(8))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(nodeInfo->NamespaceEquals(3) || nodeInfo->NamespaceEquals
(8)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("nodeInfo->NamespaceEquals(3) || nodeInfo->NamespaceEquals(8)"
" (" "Can only create XUL or XHTML elements." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nodeInfo->NamespaceEquals(3) || nodeInfo->NamespaceEquals(8)"
") (" "Can only create XUL or XHTML elements." ")"); do { *(
(volatile int*)__null) = 10105; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
10104 nodeInfo->NamespaceEquals(kNameSpaceID_XUL),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nodeInfo->NamespaceEquals(3) || nodeInfo->NamespaceEquals
(8))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(nodeInfo->NamespaceEquals(3) || nodeInfo->NamespaceEquals
(8)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("nodeInfo->NamespaceEquals(3) || nodeInfo->NamespaceEquals(8)"
" (" "Can only create XUL or XHTML elements." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nodeInfo->NamespaceEquals(3) || nodeInfo->NamespaceEquals(8)"
") (" "Can only create XUL or XHTML elements." ")"); do { *(
(volatile int*)__null) = 10105; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
10105 "Can only create XUL or XHTML elements.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nodeInfo->NamespaceEquals(3) || nodeInfo->NamespaceEquals
(8))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(nodeInfo->NamespaceEquals(3) || nodeInfo->NamespaceEquals
(8)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("nodeInfo->NamespaceEquals(3) || nodeInfo->NamespaceEquals(8)"
" (" "Can only create XUL or XHTML elements." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nodeInfo->NamespaceEquals(3) || nodeInfo->NamespaceEquals(8)"
") (" "Can only create XUL or XHTML elements." ")"); do { *(
(volatile int*)__null) = 10105; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
10106
10107 nsAtom* name = nodeInfo->NameAtom();
10108 int32_t tag = eHTMLTag_unknown;
10109 bool isCustomElementName = false;
10110 if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML3)) {
10111 tag = nsHTMLTags::CaseSensitiveAtomTagToId(name);
10112 isCustomElementName =
10113 (tag == eHTMLTag_userdefined &&
10114 nsContentUtils::IsCustomElementName(name, kNameSpaceID_XHTML3));
10115 } else { // kNameSpaceID_XUL
10116 if (aIsAtom) {
10117 // Make sure the customized built-in element to be constructed confirms
10118 // to our naming requirement, i.e. [is] must be a dashed name and
10119 // the tag name must not.
10120 // if so, set isCustomElementName to false to kick off all the logics
10121 // that pick up aIsAtom.
10122 if (nsContentUtils::IsNameWithDash(aIsAtom) &&
10123 !nsContentUtils::IsNameWithDash(name)) {
10124 isCustomElementName = false;
10125 } else {
10126 isCustomElementName =
10127 nsContentUtils::IsCustomElementName(name, kNameSpaceID_XUL8);
10128 }
10129 } else {
10130 isCustomElementName =
10131 nsContentUtils::IsCustomElementName(name, kNameSpaceID_XUL8);
10132 }
10133 }
10134
10135 nsAtom* tagAtom = nodeInfo->NameAtom();
10136 nsAtom* typeAtom = nullptr;
10137 bool isCustomElement = isCustomElementName || aIsAtom;
10138 if (isCustomElement) {
10139 typeAtom = isCustomElementName ? tagAtom : aIsAtom;
10140 }
10141
10142 MOZ_ASSERT_IF(aDefinition, isCustomElement)do { if (aDefinition) { do { static_assert( mozilla::detail::
AssertionConditionType<decltype(isCustomElement)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(isCustomElement))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("isCustomElement", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10142); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isCustomElement"
")"); do { *((volatile int*)__null) = 10142; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false); } } while
(false)
;
10143
10144 // https://dom.spec.whatwg.org/#concept-create-element
10145 // We only handle the "synchronous custom elements flag is set" now.
10146 // For the unset case (e.g. cloning a node), see bug 1319342 for that.
10147 // Step 4.
10148 RefPtr<CustomElementDefinition> definition = aDefinition;
10149 if (isCustomElement && !definition) {
10150 MOZ_ASSERT(nodeInfo->NameAtom()->Equals(nodeInfo->LocalName()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nodeInfo->NameAtom()->Equals(nodeInfo->LocalName
()))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(nodeInfo->NameAtom()->Equals(nodeInfo->LocalName
())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("nodeInfo->NameAtom()->Equals(nodeInfo->LocalName())"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10150); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nodeInfo->NameAtom()->Equals(nodeInfo->LocalName())"
")"); do { *((volatile int*)__null) = 10150; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10151 definition = nsContentUtils::LookupCustomElementDefinition(
10152 nodeInfo->GetDocument(), nodeInfo->NameAtom(), nodeInfo->NamespaceID(),
10153 typeAtom);
10154 }
10155
10156 // It might be a problem that parser synchronously calls constructor, so filed
10157 // bug 1378079 to figure out what we should do for parser case.
10158 if (definition) {
10159 /*
10160 * Synchronous custom elements flag is determined by 3 places in spec,
10161 * 1) create an element for a token, the flag is determined by
10162 * "will execute script" which is not originally created
10163 * for the HTML fragment parsing algorithm.
10164 * 2) createElement and createElementNS, the flag is the same as
10165 * NOT_FROM_PARSER.
10166 * 3) clone a node, our implementation will not go into this function.
10167 * For the unset case which is non-synchronous only applied for
10168 * inner/outerHTML.
10169 */
10170 bool synchronousCustomElements = aFromParser != dom::FROM_PARSER_FRAGMENT;
10171 // Per discussion in https://github.com/w3c/webcomponents/issues/635,
10172 // use entry global in those places that are called from JS APIs and use the
10173 // node document's global object if it is called from parser.
10174 nsIGlobalObject* global;
10175 if (aFromParser == dom::NOT_FROM_PARSER) {
10176 global = GetEntryGlobal();
10177
10178 // Documents created from the PrototypeDocumentSink always use
10179 // NOT_FROM_PARSER for non-XUL elements. We can get the global from the
10180 // document in that case.
10181 if (!global) {
10182 Document* doc = nodeInfo->GetDocument();
10183 if (doc && doc->LoadedFromPrototype()) {
10184 global = doc->GetScopeObject();
10185 }
10186 }
10187 } else {
10188 global = nodeInfo->GetDocument()->GetScopeObject();
10189 }
10190 if (!global) {
10191 // In browser chrome code, one may have access to a document which doesn't
10192 // have scope object anymore.
10193 return NS_ERROR_FAILURE;
10194 }
10195
10196 AutoAllowLegacyScriptExecution exemption;
10197 AutoEntryScript aes(global, "create custom elements");
10198 JSContext* cx = aes.cx();
10199 ErrorResult rv;
10200
10201 // Step 5.
10202 if (definition->IsCustomBuiltIn()) {
10203 // SetupCustomElement() should be called with an element that don't have
10204 // CustomElementData setup, if not we will hit the assertion in
10205 // SetCustomElementData().
10206 // Built-in element
10207 if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML3)) {
10208 *aResult =
10209 CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take();
10210 } else {
10211 NS_IF_ADDREF(*aResult = nsXULElement::Construct(nodeInfo.forget()))ns_if_addref(*aResult = nsXULElement::Construct(nodeInfo.forget
()))
;
10212 }
10213 (*aResult)->SetCustomElementData(MakeUnique<CustomElementData>(typeAtom));
10214 if (synchronousCustomElements) {
10215 CustomElementRegistry::Upgrade(*aResult, definition, rv);
10216 if (rv.MaybeSetPendingException(cx)) {
10217 aes.ReportException();
10218 }
10219 } else {
10220 nsContentUtils::EnqueueUpgradeReaction(*aResult, definition);
10221 }
10222
10223 return NS_OK;
10224 }
10225
10226 // Step 6.1.
10227 if (synchronousCustomElements) {
10228 definition->mPrefixStack.AppendElement(nodeInfo->GetPrefixAtom());
10229 RefPtr<Document> doc = nodeInfo->GetDocument();
10230 DoCustomElementCreate(aResult, cx, doc, nodeInfo,
10231 MOZ_KnownLive(definition->mConstructor)(definition->mConstructor), rv,
10232 aFromParser);
10233 if (rv.MaybeSetPendingException(cx)) {
10234 if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML3)) {
10235 NS_IF_ADDREF(*aResult = NS_NewHTMLUnknownElement(nodeInfo.forget(),ns_if_addref(*aResult = NS_NewHTMLUnknownElement(nodeInfo.forget
(), aFromParser))
10236 aFromParser))ns_if_addref(*aResult = NS_NewHTMLUnknownElement(nodeInfo.forget
(), aFromParser))
;
10237 } else {
10238 NS_IF_ADDREF(*aResult = nsXULElement::Construct(nodeInfo.forget()))ns_if_addref(*aResult = nsXULElement::Construct(nodeInfo.forget
()))
;
10239 }
10240 (*aResult)->SetDefined(false);
10241 }
10242 definition->mPrefixStack.RemoveLastElement();
10243 return NS_OK;
10244 }
10245
10246 // Step 6.2.
10247 if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML3)) {
10248 NS_IF_ADDREF(*aResult =ns_if_addref(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser
))
10249 NS_NewHTMLElement(nodeInfo.forget(), aFromParser))ns_if_addref(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser
))
;
10250 } else {
10251 NS_IF_ADDREF(*aResult = nsXULElement::Construct(nodeInfo.forget()))ns_if_addref(*aResult = nsXULElement::Construct(nodeInfo.forget
()))
;
10252 }
10253 (*aResult)->SetCustomElementData(
10254 MakeUnique<CustomElementData>(definition->mType));
10255 nsContentUtils::EnqueueUpgradeReaction(*aResult, definition);
10256 return NS_OK;
10257 }
10258
10259 if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML3)) {
10260 // Per the Custom Element specification, unknown tags that are valid custom
10261 // element names should be HTMLElement instead of HTMLUnknownElement.
10262 if (isCustomElementName) {
10263 NS_IF_ADDREF(*aResult =ns_if_addref(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser
))
10264 NS_NewHTMLElement(nodeInfo.forget(), aFromParser))ns_if_addref(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser
))
;
10265 } else {
10266 *aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take();
10267 }
10268 } else {
10269 NS_IF_ADDREF(*aResult = nsXULElement::Construct(nodeInfo.forget()))ns_if_addref(*aResult = nsXULElement::Construct(nodeInfo.forget
()))
;
10270 }
10271
10272 if (!*aResult) {
10273 return NS_ERROR_OUT_OF_MEMORY;
10274 }
10275
10276 if (isCustomElement) {
10277 (*aResult)->SetCustomElementData(MakeUnique<CustomElementData>(typeAtom));
10278 nsContentUtils::RegisterCallbackUpgradeElement(*aResult, typeAtom);
10279 }
10280
10281 return NS_OK;
10282}
10283
10284CustomElementRegistry* nsContentUtils::GetCustomElementRegistry(
10285 Document* aDoc) {
10286 MOZ_ASSERT(aDoc)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDoc)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aDoc))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aDoc", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10286); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDoc" ")")
; do { *((volatile int*)__null) = 10286; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10287
10288 if (!aDoc->GetDocShell()) {
10289 return nullptr;
10290 }
10291
10292 nsPIDOMWindowInner* window = aDoc->GetInnerWindow();
10293 if (!window) {
10294 return nullptr;
10295 }
10296
10297 return window->CustomElements();
10298}
10299
10300/* static */
10301CustomElementDefinition* nsContentUtils::LookupCustomElementDefinition(
10302 Document* aDoc, nsAtom* aNameAtom, uint32_t aNameSpaceID,
10303 nsAtom* aTypeAtom) {
10304 if (aNameSpaceID != kNameSpaceID_XUL8 && aNameSpaceID != kNameSpaceID_XHTML3) {
10305 return nullptr;
10306 }
10307
10308 RefPtr<CustomElementRegistry> registry = GetCustomElementRegistry(aDoc);
10309 if (!registry) {
10310 return nullptr;
10311 }
10312
10313 return registry->LookupCustomElementDefinition(aNameAtom, aNameSpaceID,
10314 aTypeAtom);
10315}
10316
10317/* static */
10318void nsContentUtils::RegisterCallbackUpgradeElement(Element* aElement,
10319 nsAtom* aTypeName) {
10320 MOZ_ASSERT(aElement)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aElement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aElement))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aElement", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10320); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElement" ")"
); do { *((volatile int*)__null) = 10320; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10321
10322 Document* doc = aElement->OwnerDoc();
10323 CustomElementRegistry* registry = GetCustomElementRegistry(doc);
10324 if (registry) {
10325 registry->RegisterCallbackUpgradeElement(aElement, aTypeName);
10326 }
10327}
10328
10329/* static */
10330void nsContentUtils::RegisterUnresolvedElement(Element* aElement,
10331 nsAtom* aTypeName) {
10332 MOZ_ASSERT(aElement)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aElement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aElement))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aElement", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10332); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElement" ")"
); do { *((volatile int*)__null) = 10332; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10333
10334 Document* doc = aElement->OwnerDoc();
10335 CustomElementRegistry* registry = GetCustomElementRegistry(doc);
10336 if (registry) {
10337 registry->RegisterUnresolvedElement(aElement, aTypeName);
10338 }
10339}
10340
10341/* static */
10342void nsContentUtils::UnregisterUnresolvedElement(Element* aElement) {
10343 MOZ_ASSERT(aElement)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aElement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aElement))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aElement", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10343); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElement" ")"
); do { *((volatile int*)__null) = 10343; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10344
10345 nsAtom* typeAtom = aElement->GetCustomElementData()->GetCustomElementType();
10346 Document* doc = aElement->OwnerDoc();
10347 CustomElementRegistry* registry = GetCustomElementRegistry(doc);
10348 if (registry) {
10349 registry->UnregisterUnresolvedElement(aElement, typeAtom);
10350 }
10351}
10352
10353/* static */
10354void nsContentUtils::EnqueueUpgradeReaction(
10355 Element* aElement, CustomElementDefinition* aDefinition) {
10356 MOZ_ASSERT(aElement)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aElement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aElement))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aElement", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10356); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElement" ")"
); do { *((volatile int*)__null) = 10356; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10357
10358 Document* doc = aElement->OwnerDoc();
10359
10360 // No DocGroup means no custom element reactions stack.
10361 if (!doc->GetDocGroup()) {
10362 return;
10363 }
10364
10365 CustomElementReactionsStack* stack =
10366 doc->GetDocGroup()->CustomElementReactionsStack();
10367 stack->EnqueueUpgradeReaction(aElement, aDefinition);
10368}
10369
10370/* static */
10371void nsContentUtils::EnqueueLifecycleCallback(
10372 ElementCallbackType aType, Element* aCustomElement,
10373 const LifecycleCallbackArgs& aArgs, CustomElementDefinition* aDefinition) {
10374 // No DocGroup means no custom element reactions stack.
10375 if (!aCustomElement->OwnerDoc()->GetDocGroup()) {
10376 return;
10377 }
10378
10379 CustomElementRegistry::EnqueueLifecycleCallback(aType, aCustomElement, aArgs,
10380 aDefinition);
10381}
10382
10383/* static */
10384CustomElementFormValue nsContentUtils::ConvertToCustomElementFormValue(
10385 const Nullable<OwningFileOrUSVStringOrFormData>& aState) {
10386 if (aState.IsNull()) {
10387 return void_t{};
10388 }
10389 const auto& state = aState.Value();
10390 if (state.IsFile()) {
10391 RefPtr<BlobImpl> impl = state.GetAsFile()->Impl();
10392 return {std::move(impl)};
10393 }
10394 if (state.IsUSVString()) {
10395 return state.GetAsUSVString();
10396 }
10397 return state.GetAsFormData()->ConvertToCustomElementFormValue();
10398}
10399
10400/* static */
10401Nullable<OwningFileOrUSVStringOrFormData>
10402nsContentUtils::ExtractFormAssociatedCustomElementValue(
10403 nsIGlobalObject* aGlobal,
10404 const mozilla::dom::CustomElementFormValue& aCEValue) {
10405 MOZ_ASSERT(aGlobal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGlobal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aGlobal))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aGlobal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10405); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGlobal" ")"
); do { *((volatile int*)__null) = 10405; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10406
10407 OwningFileOrUSVStringOrFormData value;
10408 switch (aCEValue.type()) {
10409 case CustomElementFormValue::TBlobImpl: {
10410 RefPtr<File> file = File::Create(aGlobal, aCEValue.get_BlobImpl());
10411 if (NS_WARN_IF(!file)NS_warn_if_impl(!file, "!file", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10411)
) {
10412 return {};
10413 }
10414 value.SetAsFile() = file;
10415 } break;
10416
10417 case CustomElementFormValue::TnsString:
10418 value.SetAsUSVString() = aCEValue.get_nsString();
10419 break;
10420
10421 case CustomElementFormValue::TArrayOfFormDataTuple: {
10422 const auto& array = aCEValue.get_ArrayOfFormDataTuple();
10423 auto formData = MakeRefPtr<FormData>();
10424
10425 for (auto i = 0ul; i < array.Length(); ++i) {
10426 const auto& item = array.ElementAt(i);
10427 switch (item.value().type()) {
10428 case FormDataValue::TnsString:
10429 formData->AddNameValuePair(item.name(),
10430 item.value().get_nsString());
10431 break;
10432
10433 case FormDataValue::TBlobImpl: {
10434 auto blobImpl = item.value().get_BlobImpl();
10435 auto* blob = Blob::Create(aGlobal, blobImpl);
10436 formData->AddNameBlobPair(item.name(), blob);
10437 } break;
10438
10439 default:
10440 continue;
10441 }
10442 }
10443
10444 value.SetAsFormData() = formData;
10445 } break;
10446 case CustomElementFormValue::Tvoid_t:
10447 return {};
10448 default:
10449 NS_WARNING("Invalid CustomElementContentData type!")NS_DebugBreak(NS_DEBUG_WARNING, "Invalid CustomElementContentData type!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10449)
;
10450 return {};
10451 }
10452 return value;
10453}
10454
10455/* static */
10456void nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
10457 Document* aDocument, nsTArray<nsIContent*>& aElements) {
10458 MOZ_ASSERT(aDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDocument))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10458); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocument"
")"); do { *((volatile int*)__null) = 10458; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10459#ifdef DEBUG1
10460 size_t oldLength = aElements.Length();
10461#endif
10462
10463 if (PresShell* presShell = aDocument->GetPresShell()) {
10464 if (ScrollContainerFrame* rootScrollContainerFrame =
10465 presShell->GetRootScrollContainerFrame()) {
10466 rootScrollContainerFrame->AppendAnonymousContentTo(aElements, 0);
10467 }
10468 if (nsCanvasFrame* canvasFrame = presShell->GetCanvasFrame()) {
10469 canvasFrame->AppendAnonymousContentTo(aElements, 0);
10470 }
10471 }
10472
10473#ifdef DEBUG1
10474 for (size_t i = oldLength; i < aElements.Length(); i++) {
10475 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aElements[i]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aElements[i]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aElements[i]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent)"
" (" "Someone here has lied, or missed to flag the node" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10477); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElements[i]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent)"
") (" "Someone here has lied, or missed to flag the node" ")"
); do { *((volatile int*)__null) = 10477; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
10476 aElements[i]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aElements[i]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aElements[i]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aElements[i]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent)"
" (" "Someone here has lied, or missed to flag the node" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10477); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElements[i]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent)"
") (" "Someone here has lied, or missed to flag the node" ")"
); do { *((volatile int*)__null) = 10477; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
10477 "Someone here has lied, or missed to flag the node")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aElements[i]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aElements[i]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aElements[i]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent)"
" (" "Someone here has lied, or missed to flag the node" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10477); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElements[i]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent)"
") (" "Someone here has lied, or missed to flag the node" ")"
); do { *((volatile int*)__null) = 10477; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10478 }
10479#endif
10480}
10481
10482static void AppendNativeAnonymousChildrenFromFrame(nsIFrame* aFrame,
10483 nsTArray<nsIContent*>& aKids,
10484 uint32_t aFlags) {
10485 if (nsIAnonymousContentCreator* ac = do_QueryFrame(aFrame)) {
10486 ac->AppendAnonymousContentTo(aKids, aFlags);
10487 }
10488}
10489
10490/* static */
10491void nsContentUtils::AppendNativeAnonymousChildren(const nsIContent* aContent,
10492 nsTArray<nsIContent*>& aKids,
10493 uint32_t aFlags) {
10494 if (aContent->MayHaveAnonymousChildren()) {
10495 if (nsIFrame* primaryFrame = aContent->GetPrimaryFrame()) {
10496 // NAC created by the element's primary frame.
10497 AppendNativeAnonymousChildrenFromFrame(primaryFrame, aKids, aFlags);
10498
10499 // NAC created by any other non-primary frames for the element.
10500 AutoTArray<nsIFrame::OwnedAnonBox, 8> ownedAnonBoxes;
10501 primaryFrame->AppendOwnedAnonBoxes(ownedAnonBoxes);
10502 for (nsIFrame::OwnedAnonBox& box : ownedAnonBoxes) {
10503 MOZ_ASSERT(box.mAnonBoxFrame->GetContent() == aContent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(box.mAnonBoxFrame->GetContent() == aContent)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(box.mAnonBoxFrame->GetContent() == aContent))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("box.mAnonBoxFrame->GetContent() == aContent"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10503); AnnotateMozCrashReason("MOZ_ASSERT" "(" "box.mAnonBoxFrame->GetContent() == aContent"
")"); do { *((volatile int*)__null) = 10503; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10504 AppendNativeAnonymousChildrenFromFrame(box.mAnonBoxFrame, aKids,
10505 aFlags);
10506 }
10507 }
10508
10509 // Get manually created NAC (editor resize handles, etc.).
10510 if (auto nac = static_cast<ManualNACArray*>(
10511 aContent->GetProperty(nsGkAtoms::manualNACProperty))) {
10512 aKids.AppendElements(*nac);
10513 }
10514 }
10515
10516 // The root scroll frame is not the primary frame of the root element.
10517 // Detect and handle this case.
10518 if (!(aFlags & nsIContent::eSkipDocumentLevelNativeAnonymousContent) &&
10519 aContent == aContent->OwnerDoc()->GetRootElement()) {
10520 AppendDocumentLevelNativeAnonymousContentTo(aContent->OwnerDoc(), aKids);
10521 }
10522}
10523
10524bool nsContentUtils::IsImageAvailable(nsIContent* aLoadingNode, nsIURI* aURI,
10525 nsIPrincipal* aDefaultTriggeringPrincipal,
10526 CORSMode aCORSMode) {
10527 nsCOMPtr<nsIPrincipal> triggeringPrincipal;
10528 QueryTriggeringPrincipal(aLoadingNode, aDefaultTriggeringPrincipal,
10529 getter_AddRefs(triggeringPrincipal));
10530 MOZ_ASSERT(triggeringPrincipal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(triggeringPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(triggeringPrincipal))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("triggeringPrincipal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10530); AnnotateMozCrashReason("MOZ_ASSERT" "(" "triggeringPrincipal"
")"); do { *((volatile int*)__null) = 10530; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10531
10532 Document* doc = aLoadingNode->OwnerDoc();
10533 return IsImageAvailable(aURI, triggeringPrincipal, aCORSMode, doc);
10534}
10535
10536bool nsContentUtils::IsImageAvailable(nsIURI* aURI,
10537 nsIPrincipal* aTriggeringPrincipal,
10538 CORSMode aCORSMode, Document* aDoc) {
10539 imgLoader* imgLoader = GetImgLoaderForDocument(aDoc);
10540 return imgLoader->IsImageAvailable(aURI, aTriggeringPrincipal, aCORSMode,
10541 aDoc);
10542}
10543
10544/* static */
10545bool nsContentUtils::QueryTriggeringPrincipal(
10546 nsIContent* aLoadingNode, nsIPrincipal* aDefaultPrincipal,
10547 nsIPrincipal** aTriggeringPrincipal) {
10548 MOZ_ASSERT(aLoadingNode)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLoadingNode)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLoadingNode))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aLoadingNode", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10548); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadingNode"
")"); do { *((volatile int*)__null) = 10548; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10549 MOZ_ASSERT(aTriggeringPrincipal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTriggeringPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTriggeringPrincipal))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("aTriggeringPrincipal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10549); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTriggeringPrincipal"
")"); do { *((volatile int*)__null) = 10549; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10550
10551 bool result = false;
10552 nsCOMPtr<nsIPrincipal> loadingPrincipal = aDefaultPrincipal;
10553 if (!loadingPrincipal) {
10554 loadingPrincipal = aLoadingNode->NodePrincipal();
10555 }
10556
10557 // If aLoadingNode is content, bail out early.
10558 if (!aLoadingNode->NodePrincipal()->IsSystemPrincipal()) {
10559 loadingPrincipal.forget(aTriggeringPrincipal);
10560 return result;
10561 }
10562
10563 nsAutoString loadingStr;
10564 if (aLoadingNode->IsElement()) {
10565 aLoadingNode->AsElement()->GetAttr(
10566 kNameSpaceID_None, nsGkAtoms::triggeringprincipal, loadingStr);
10567 }
10568
10569 // Fall back if 'triggeringprincipal' isn't specified,
10570 if (loadingStr.IsEmpty()) {
10571 loadingPrincipal.forget(aTriggeringPrincipal);
10572 return result;
10573 }
10574
10575 nsCString binary;
10576 nsCOMPtr<nsIPrincipal> serializedPrin =
10577 BasePrincipal::FromJSON(NS_ConvertUTF16toUTF8(loadingStr));
10578 if (serializedPrin) {
10579 result = true;
10580 serializedPrin.forget(aTriggeringPrincipal);
10581 }
10582
10583 if (!result) {
10584 // Fallback if the deserialization is failed.
10585 loadingPrincipal.forget(aTriggeringPrincipal);
10586 }
10587
10588 return result;
10589}
10590
10591/* static */
10592void nsContentUtils::GetContentPolicyTypeForUIImageLoading(
10593 nsIContent* aLoadingNode, nsIPrincipal** aTriggeringPrincipal,
10594 nsContentPolicyType& aContentPolicyType, uint64_t* aRequestContextID) {
10595 MOZ_ASSERT(aRequestContextID)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRequestContextID)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRequestContextID))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aRequestContextID"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10595); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRequestContextID"
")"); do { *((volatile int*)__null) = 10595; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10596
10597 bool result = QueryTriggeringPrincipal(aLoadingNode, aTriggeringPrincipal);
10598 if (result) {
10599 // Set the content policy type to TYPE_INTERNAL_IMAGE_FAVICON for
10600 // indicating it's a favicon loading.
10601 aContentPolicyType = nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON;
10602
10603 nsAutoString requestContextID;
10604 if (aLoadingNode->IsElement()) {
10605 aLoadingNode->AsElement()->GetAttr(
10606 kNameSpaceID_None, nsGkAtoms::requestcontextid, requestContextID);
10607 }
10608 nsresult rv;
10609 int64_t val = requestContextID.ToInteger64(&rv);
10610 *aRequestContextID = NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) ? val : 0;
10611 } else {
10612 aContentPolicyType = nsIContentPolicy::TYPE_INTERNAL_IMAGE;
10613 }
10614}
10615
10616/* static */
10617nsresult nsContentUtils::CreateJSValueFromSequenceOfObject(
10618 JSContext* aCx, const Sequence<JSObject*>& aTransfer,
10619 JS::MutableHandle<JS::Value> aValue) {
10620 if (aTransfer.IsEmpty()) {
10621 return NS_OK;
10622 }
10623
10624 JS::Rooted<JSObject*> array(aCx, JS::NewArrayObject(aCx, aTransfer.Length()));
10625 if (!array) {
10626 return NS_ERROR_OUT_OF_MEMORY;
10627 }
10628
10629 for (uint32_t i = 0; i < aTransfer.Length(); ++i) {
10630 JS::Rooted<JSObject*> object(aCx, aTransfer[i]);
10631 if (!object) {
10632 continue;
10633 }
10634
10635 if (NS_WARN_IF(NS_warn_if_impl(!JS_DefineElement(aCx, array, i, object, JSPROP_ENUMERATE
), "!JS_DefineElement(aCx, array, i, object, JSPROP_ENUMERATE)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10636)
10636 !JS_DefineElement(aCx, array, i, object, JSPROP_ENUMERATE))NS_warn_if_impl(!JS_DefineElement(aCx, array, i, object, JSPROP_ENUMERATE
), "!JS_DefineElement(aCx, array, i, object, JSPROP_ENUMERATE)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10636)
) {
10637 return NS_ERROR_OUT_OF_MEMORY;
10638 }
10639 }
10640
10641 aValue.setObject(*array);
10642 return NS_OK;
10643}
10644
10645/* static */
10646void nsContentUtils::StructuredClone(JSContext* aCx, nsIGlobalObject* aGlobal,
10647 JS::Handle<JS::Value> aValue,
10648 const StructuredSerializeOptions& aOptions,
10649 JS::MutableHandle<JS::Value> aRetval,
10650 ErrorResult& aError) {
10651 JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue());
10652 aError = nsContentUtils::CreateJSValueFromSequenceOfObject(
10653 aCx, aOptions.mTransfer, &transferArray);
10654 if (NS_WARN_IF(aError.Failed())NS_warn_if_impl(aError.Failed(), "aError.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10654)
) {
10655 return;
10656 }
10657
10658 JS::CloneDataPolicy clonePolicy;
10659 // We are definitely staying in the same agent cluster.
10660 clonePolicy.allowIntraClusterClonableSharedObjects();
10661 if (aGlobal->IsSharedMemoryAllowed()) {
10662 clonePolicy.allowSharedMemoryObjects();
10663 }
10664
10665 StructuredCloneHolder holder(StructuredCloneHolder::CloningSupported,
10666 StructuredCloneHolder::TransferringSupported,
10667 JS::StructuredCloneScope::SameProcess);
10668 holder.Write(aCx, aValue, transferArray, clonePolicy, aError);
10669 if (NS_WARN_IF(aError.Failed())NS_warn_if_impl(aError.Failed(), "aError.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10669)
) {
10670 return;
10671 }
10672
10673 holder.Read(aGlobal, aCx, aRetval, clonePolicy, aError);
10674 if (NS_WARN_IF(aError.Failed())NS_warn_if_impl(aError.Failed(), "aError.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10674)
) {
10675 return;
10676 }
10677
10678 nsTArray<RefPtr<MessagePort>> ports = holder.TakeTransferredPorts();
10679 Unused << ports;
10680}
10681
10682/* static */
10683bool nsContentUtils::ShouldBlockReservedKeys(WidgetKeyboardEvent* aKeyEvent) {
10684 nsCOMPtr<nsIPrincipal> principal;
10685 RefPtr<Element> targetElement =
10686 Element::FromEventTargetOrNull(aKeyEvent->mOriginalTarget);
10687 nsCOMPtr<nsIBrowser> targetBrowser;
10688 if (targetElement) {
10689 targetBrowser = targetElement->AsBrowser();
10690 }
10691 bool isRemoteBrowser = false;
10692 if (targetBrowser) {
10693 targetBrowser->GetIsRemoteBrowser(&isRemoteBrowser);
10694 }
10695
10696 if (isRemoteBrowser) {
10697 targetBrowser->GetContentPrincipal(getter_AddRefs(principal));
10698 return principal ? nsContentUtils::IsSitePermDeny(principal, "shortcuts"_ns)
10699 : false;
10700 }
10701
10702 if (targetElement) {
10703 Document* doc = targetElement->GetUncomposedDoc();
10704 if (doc) {
10705 RefPtr<WindowContext> wc = doc->GetWindowContext();
10706 if (wc) {
10707 return wc->TopWindowContext()->GetShortcutsPermission() ==
10708 nsIPermissionManager::DENY_ACTION;
10709 }
10710 }
10711 }
10712
10713 return false;
10714}
10715
10716/**
10717 * Checks whether the given type is a supported document type for
10718 * loading within the nsObjectLoadingContent specified by aContent.
10719 *
10720 * NOTE Helper method for nsContentUtils::HtmlObjectContentTypeForMIMEType.
10721 * NOTE Does not take content policy or capabilities into account
10722 */
10723static bool HtmlObjectContentSupportsDocument(const nsCString& aMimeType) {
10724 nsCOMPtr<nsIWebNavigationInfo> info(
10725 do_GetService(NS_WEBNAVIGATION_INFO_CONTRACTID"@mozilla.org/webnavigation-info;1"));
10726 if (!info) {
10727 return false;
10728 }
10729
10730 uint32_t supported;
10731 nsresult rv = info->IsTypeSupported(aMimeType, &supported);
10732
10733 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
10734 return false;
10735 }
10736
10737 if (supported != nsIWebNavigationInfo::UNSUPPORTED) {
10738 // Don't want to support plugins as documents
10739 return supported != nsIWebNavigationInfo::FALLBACK;
10740 }
10741
10742 // Try a stream converter
10743 // NOTE: We treat any type we can convert from as a supported type. If a
10744 // type is not actually supported, the URI loader will detect that and
10745 // return an error, and we'll fallback.
10746 nsCOMPtr<nsIStreamConverterService> convServ =
10747 do_GetService("@mozilla.org/streamConverters;1");
10748 bool canConvert = false;
10749 if (convServ) {
10750 rv = convServ->CanConvert(aMimeType.get(), "*/*", &canConvert);
10751 }
10752 return NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && canConvert;
10753}
10754
10755/* static */
10756uint32_t nsContentUtils::HtmlObjectContentTypeForMIMEType(
10757 const nsCString& aMIMEType) {
10758 if (aMIMEType.IsEmpty()) {
10759 return nsIObjectLoadingContent::TYPE_FALLBACK;
10760 }
10761
10762 if (imgLoader::SupportImageWithMimeType(aMIMEType)) {
10763 return nsIObjectLoadingContent::TYPE_DOCUMENT;
10764 }
10765
10766 // Faking support of the PDF content as a document for EMBED tags
10767 // when internal PDF viewer is enabled.
10768 if (aMIMEType.LowerCaseEqualsLiteral("application/pdf") && IsPDFJSEnabled()) {
10769 return nsIObjectLoadingContent::TYPE_DOCUMENT;
10770 }
10771
10772 if (HtmlObjectContentSupportsDocument(aMIMEType)) {
10773 return nsIObjectLoadingContent::TYPE_DOCUMENT;
10774 }
10775
10776 return nsIObjectLoadingContent::TYPE_FALLBACK;
10777}
10778
10779/* static */
10780bool nsContentUtils::IsLocalRefURL(const nsAString& aString) {
10781 return !aString.IsEmpty() && aString[0] == '#';
10782}
10783
10784// We use only 53 bits for the ID so that it can be converted to and from a JS
10785// value without loss of precision. The upper bits of the ID hold the process
10786// ID. The lower bits identify the object itself.
10787static constexpr uint64_t kIdTotalBits = 53;
10788static constexpr uint64_t kIdProcessBits = 22;
10789static constexpr uint64_t kIdBits = kIdTotalBits - kIdProcessBits;
10790
10791/* static */
10792uint64_t nsContentUtils::GenerateProcessSpecificId(uint64_t aId) {
10793 uint64_t processId = 0;
10794 if (XRE_IsContentProcess()) {
10795 ContentChild* cc = ContentChild::GetSingleton();
10796 processId = cc->GetID();
10797 }
10798
10799 MOZ_RELEASE_ASSERT(processId < (uint64_t(1) << kIdProcessBits))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(processId < (uint64_t(1) << kIdProcessBits)
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(processId < (uint64_t(1) << kIdProcessBits)
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"processId < (uint64_t(1) << kIdProcessBits)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10799); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "processId < (uint64_t(1) << kIdProcessBits)"
")"); do { *((volatile int*)__null) = 10799; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10800 uint64_t processBits = processId & ((uint64_t(1) << kIdProcessBits) - 1);
10801
10802 uint64_t id = aId;
10803 MOZ_RELEASE_ASSERT(id < (uint64_t(1) << kIdBits))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(id < (uint64_t(1) << kIdBits))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(id < (uint64_t(1) << kIdBits)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("id < (uint64_t(1) << kIdBits)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10803); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "id < (uint64_t(1) << kIdBits)"
")"); do { *((volatile int*)__null) = 10803; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10804 uint64_t bits = id & ((uint64_t(1) << kIdBits) - 1);
10805
10806 return (processBits << kIdBits) | bits;
10807}
10808
10809/* static */
10810std::tuple<uint64_t, uint64_t> nsContentUtils::SplitProcessSpecificId(
10811 uint64_t aId) {
10812 return {aId >> kIdBits, aId & ((uint64_t(1) << kIdBits) - 1)};
10813}
10814
10815// Next process-local Tab ID.
10816static uint64_t gNextTabId = 0;
10817
10818/* static */
10819uint64_t nsContentUtils::GenerateTabId() {
10820 return GenerateProcessSpecificId(++gNextTabId);
10821}
10822
10823// Next process-local Browser ID.
10824static uint64_t gNextBrowserId = 0;
10825
10826/* static */
10827uint64_t nsContentUtils::GenerateBrowserId() {
10828 return GenerateProcessSpecificId(++gNextBrowserId);
10829}
10830
10831// Next process-local Browsing Context ID.
10832static uint64_t gNextBrowsingContextId = 0;
10833
10834/* static */
10835uint64_t nsContentUtils::GenerateBrowsingContextId() {
10836 return GenerateProcessSpecificId(++gNextBrowsingContextId);
10837}
10838
10839// Next process-local Window ID.
10840static uint64_t gNextWindowId = 0;
10841
10842/* static */
10843uint64_t nsContentUtils::GenerateWindowId() {
10844 return GenerateProcessSpecificId(++gNextWindowId);
10845}
10846
10847// Next process-local load.
10848static Atomic<uint64_t> gNextLoadIdentifier(0);
10849
10850/* static */
10851uint64_t nsContentUtils::GenerateLoadIdentifier() {
10852 return GenerateProcessSpecificId(++gNextLoadIdentifier);
10853}
10854
10855/* static */
10856bool nsContentUtils::GetUserIsInteracting() {
10857 return UserInteractionObserver::sUserActive;
10858}
10859
10860/* static */
10861bool nsContentUtils::GetSourceMapURL(nsIHttpChannel* aChannel,
10862 nsACString& aResult) {
10863 nsresult rv = aChannel->GetResponseHeader("SourceMap"_ns, aResult);
10864 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
10865 rv = aChannel->GetResponseHeader("X-SourceMap"_ns, aResult);
10866 }
10867 return NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)));
10868}
10869
10870/* static */
10871bool nsContentUtils::IsMessageInputEvent(const IPC::Message& aMsg) {
10872 if ((aMsg.type() & mozilla::dom::PBrowser::PBrowserStart) ==
10873 mozilla::dom::PBrowser::PBrowserStart) {
10874 switch (aMsg.type()) {
10875 case mozilla::dom::PBrowser::Msg_RealMouseMoveEvent__ID:
10876 case mozilla::dom::PBrowser::Msg_RealMouseButtonEvent__ID:
10877 case mozilla::dom::PBrowser::Msg_RealMouseEnterExitWidgetEvent__ID:
10878 case mozilla::dom::PBrowser::Msg_RealKeyEvent__ID:
10879 case mozilla::dom::PBrowser::Msg_MouseWheelEvent__ID:
10880 case mozilla::dom::PBrowser::Msg_RealTouchEvent__ID:
10881 case mozilla::dom::PBrowser::Msg_RealTouchMoveEvent__ID:
10882 case mozilla::dom::PBrowser::Msg_RealDragEvent__ID:
10883 case mozilla::dom::PBrowser::Msg_UpdateDimensions__ID:
10884 return true;
10885 }
10886 }
10887 return false;
10888}
10889
10890/* static */
10891bool nsContentUtils::IsMessageCriticalInputEvent(const IPC::Message& aMsg) {
10892 if ((aMsg.type() & mozilla::dom::PBrowser::PBrowserStart) ==
10893 mozilla::dom::PBrowser::PBrowserStart) {
10894 switch (aMsg.type()) {
10895 case mozilla::dom::PBrowser::Msg_RealMouseButtonEvent__ID:
10896 case mozilla::dom::PBrowser::Msg_RealKeyEvent__ID:
10897 case mozilla::dom::PBrowser::Msg_MouseWheelEvent__ID:
10898 case mozilla::dom::PBrowser::Msg_RealTouchEvent__ID:
10899 case mozilla::dom::PBrowser::Msg_RealDragEvent__ID:
10900 return true;
10901 }
10902 }
10903 return false;
10904}
10905
10906static const char* kUserInteractionInactive = "user-interaction-inactive";
10907static const char* kUserInteractionActive = "user-interaction-active";
10908
10909void nsContentUtils::UserInteractionObserver::Init() {
10910 // Listen for the observer messages from EventStateManager which are telling
10911 // us whether or not the user is interacting.
10912 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
10913 obs->AddObserver(this, kUserInteractionInactive, false);
10914 obs->AddObserver(this, kUserInteractionActive, false);
10915
10916 // We can't register ourselves as an annotator yet, as the
10917 // BackgroundHangMonitor hasn't started yet. It will have started by the
10918 // time we have the chance to spin the event loop.
10919 RefPtr<UserInteractionObserver> self = this;
10920 NS_DispatchToMainThread(NS_NewRunnableFunction(
10921 "nsContentUtils::UserInteractionObserver::Init",
10922 [=]() { BackgroundHangMonitor::RegisterAnnotator(*self); }));
10923}
10924
10925void nsContentUtils::UserInteractionObserver::Shutdown() {
10926 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
10927 if (obs) {
10928 obs->RemoveObserver(this, kUserInteractionInactive);
10929 obs->RemoveObserver(this, kUserInteractionActive);
10930 }
10931
10932 BackgroundHangMonitor::UnregisterAnnotator(*this);
10933}
10934
10935/**
10936 * NB: This function is always called by the BackgroundHangMonitor thread.
10937 * Plan accordingly
10938 */
10939void nsContentUtils::UserInteractionObserver::AnnotateHang(
10940 BackgroundHangAnnotations& aAnnotations) {
10941 // NOTE: Only annotate the hang report if the user is known to be interacting.
10942 if (sUserActive) {
10943 aAnnotations.AddAnnotation(u"UserInteracting"_ns, true);
10944 }
10945}
10946
10947NS_IMETHODIMPnsresult
10948nsContentUtils::UserInteractionObserver::Observe(nsISupports* aSubject,
10949 const char* aTopic,
10950 const char16_t* aData) {
10951 if (!strcmp(aTopic, kUserInteractionInactive)) {
10952 if (sUserActive && XRE_IsParentProcess()) {
10953 glean::RecordPowerMetrics();
10954 }
10955 sUserActive = false;
10956 } else if (!strcmp(aTopic, kUserInteractionActive)) {
10957 if (!sUserActive && XRE_IsParentProcess()) {
10958 glean::RecordPowerMetrics();
10959
10960 nsCOMPtr<nsIUserIdleServiceInternal> idleService =
10961 do_GetService("@mozilla.org/widget/useridleservice;1");
10962 if (idleService) {
10963 idleService->ResetIdleTimeOut(0);
10964 }
10965 }
10966
10967 sUserActive = true;
10968 } else {
10969 NS_WARNING("Unexpected observer notification")NS_DebugBreak(NS_DEBUG_WARNING, "Unexpected observer notification"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10969)
;
10970 }
10971 return NS_OK;
10972}
10973
10974Atomic<bool> nsContentUtils::UserInteractionObserver::sUserActive(false);
10975NS_IMPL_ISUPPORTS(nsContentUtils::UserInteractionObserver, nsIObserver)MozExternalRefCountType nsContentUtils::UserInteractionObserver
::AddRef(void) { static_assert(!std::is_destructible_v<nsContentUtils
::UserInteractionObserver>, "Reference-counted class " "nsContentUtils::UserInteractionObserver"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10975); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
10975; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsContentUtils::UserInteractionObserver" != nullptr
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("nsContentUtils::UserInteractionObserver" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsContentUtils::UserInteractionObserver\" != nullptr" " ("
"Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10975); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsContentUtils::UserInteractionObserver\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 10975; __attribute__((nomerge)) ::abort(); } while (false
); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsContentUtils::UserInteractionObserver" " not thread-safe"
); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"nsContentUtils::UserInteractionObserver"), (uint32_t)(sizeof
(*this))); return count; } MozExternalRefCountType nsContentUtils
::UserInteractionObserver::Release(void) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10975); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 10975
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsContentUtils::UserInteractionObserver" != nullptr
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("nsContentUtils::UserInteractionObserver" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsContentUtils::UserInteractionObserver\" != nullptr" " ("
"Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10975); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsContentUtils::UserInteractionObserver\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 10975; __attribute__((nomerge)) ::abort(); } while (false
); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsContentUtils::UserInteractionObserver" " not thread-safe"
); const char* const nametmp = "nsContentUtils::UserInteractionObserver"
; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (
nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return
0; } return count; } nsresult nsContentUtils::UserInteractionObserver
::QueryInterface(const nsIID& aIID, void** aInstancePtr) {
do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 10975); MOZ_PretendNoReturn(); } } while (0); nsresult rv =
NS_ERROR_FAILURE; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsContentUtils::UserInteractionObserver,
nsIObserver>, int32_t( reinterpret_cast<char*>(static_cast
<nsIObserver*>((nsContentUtils::UserInteractionObserver
*)0x1000)) - reinterpret_cast<char*>((nsContentUtils::UserInteractionObserver
*)0x1000))}, {&mozilla::detail::kImplementedIID<nsContentUtils
::UserInteractionObserver, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
nsIObserver*>((nsContentUtils::UserInteractionObserver*)0x1000
))) - reinterpret_cast<char*>((nsContentUtils::UserInteractionObserver
*)0x1000))}, { nullptr, 0 } } ; static_assert((sizeof(table) /
sizeof(table[0])) > 1, "need at least 1 interface"); rv =
NS_TableDrivenQI(static_cast<void*>(this), aIID, aInstancePtr
, table); return rv; }
10976
10977/* static */
10978bool nsContentUtils::IsSpecialName(const nsAString& aName) {
10979 return aName.LowerCaseEqualsLiteral("_blank") ||
10980 aName.LowerCaseEqualsLiteral("_top") ||
10981 aName.LowerCaseEqualsLiteral("_parent") ||
10982 aName.LowerCaseEqualsLiteral("_self");
10983}
10984
10985/* static */
10986bool nsContentUtils::IsOverridingWindowName(const nsAString& aName) {
10987 return !aName.IsEmpty() && !IsSpecialName(aName);
10988}
10989
10990// Unfortunately, we can't unwrap an IDL object using only a concrete type.
10991// We need to calculate type data based on the IDL typename. Which means
10992// wrapping our templated function in a macro.
10993#define EXTRACT_EXN_VALUES(T, ...) \
10994 ExtractExceptionValues<mozilla::dom::prototypes::id::T, \
10995 T##_Binding::NativeType, T>(__VA_ARGS__) \
10996 .isOk()
10997
10998template <prototypes::ID PrototypeID, class NativeType, typename T>
10999static Result<Ok, nsresult> ExtractExceptionValues(
11000 JSContext* aCx, JS::Handle<JSObject*> aObj, nsACString& aSourceSpecOut,
11001 uint32_t* aLineOut, uint32_t* aColumnOut, nsString& aMessageOut) {
11002 AssertStaticUnwrapOK<PrototypeID>();
11003 RefPtr<T> exn;
11004 MOZ_TRY((UnwrapObject<PrototypeID, NativeType>(aObj, exn, nullptr)))do { auto mozTryTempResult_ = ::mozilla::ToResult((UnwrapObject
<PrototypeID, NativeType>(aObj, exn, nullptr))); if ((__builtin_expect
(!!(mozTryTempResult_.isErr()), 0))) { return mozTryTempResult_
.propagateErr(); } } while (0)
;
11005
11006 exn->GetFilename(aCx, aSourceSpecOut);
11007 if (!aSourceSpecOut.IsEmpty()) {
11008 *aLineOut = exn->LineNumber(aCx);
11009 *aColumnOut = exn->ColumnNumber();
11010 }
11011
11012 exn->GetName(aMessageOut);
11013 aMessageOut.AppendLiteral(": ");
11014
11015 nsAutoString message;
11016 exn->GetMessageMoz(message);
11017 aMessageOut.Append(message);
11018 return Ok();
11019}
11020
11021/* static */
11022void nsContentUtils::ExtractErrorValues(
11023 JSContext* aCx, JS::Handle<JS::Value> aValue, nsACString& aSourceSpecOut,
11024 uint32_t* aLineOut, uint32_t* aColumnOut, nsString& aMessageOut) {
11025 MOZ_ASSERT(aLineOut)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLineOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLineOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aLineOut", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11025); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLineOut" ")"
); do { *((volatile int*)__null) = 11025; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
11026 MOZ_ASSERT(aColumnOut)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aColumnOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aColumnOut))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aColumnOut", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11026); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aColumnOut"
")"); do { *((volatile int*)__null) = 11026; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11027
11028 if (aValue.isObject()) {
11029 JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
11030
11031 // Try to process as an Error object. Use the file/line/column values
11032 // from the Error as they will be more specific to the root cause of
11033 // the problem.
11034 JSErrorReport* err = obj ? JS_ErrorFromException(aCx, obj) : nullptr;
11035 if (err) {
11036 // Use xpc to extract the error message only. We don't actually send
11037 // this report anywhere.
11038 RefPtr<xpc::ErrorReport> report = new xpc::ErrorReport();
11039 report->Init(err,
11040 nullptr, // toString result
11041 false, // chrome
11042 0); // window ID
11043
11044 if (!report->mFileName.IsEmpty()) {
11045 aSourceSpecOut = report->mFileName;
11046 *aLineOut = report->mLineNumber;
11047 *aColumnOut = report->mColumn;
11048 }
11049 aMessageOut.Assign(report->mErrorMsg);
11050 }
11051
11052 // Next, try to unwrap the rejection value as a DOMException.
11053 else if (EXTRACT_EXN_VALUES(DOMException, aCx, obj, aSourceSpecOut,
11054 aLineOut, aColumnOut, aMessageOut)) {
11055 return;
11056 }
11057
11058 // Next, try to unwrap the rejection value as an XPC Exception.
11059 else if (EXTRACT_EXN_VALUES(Exception, aCx, obj, aSourceSpecOut, aLineOut,
11060 aColumnOut, aMessageOut)) {
11061 return;
11062 }
11063 }
11064
11065 // If we could not unwrap a specific error type, then perform default safe
11066 // string conversions on primitives. Objects will result in "[Object]"
11067 // unfortunately.
11068 if (aMessageOut.IsEmpty()) {
11069 nsAutoJSString jsString;
11070 if (jsString.init(aCx, aValue)) {
11071 aMessageOut = jsString;
11072 } else {
11073 JS_ClearPendingException(aCx);
11074 }
11075 }
11076}
11077
11078#undef EXTRACT_EXN_VALUES
11079
11080/* static */
11081bool nsContentUtils::ContentIsLink(nsIContent* aContent) {
11082 if (!aContent || !aContent->IsElement()) {
11083 return false;
11084 }
11085
11086 if (aContent->IsHTMLElement(nsGkAtoms::a)) {
11087 return true;
11088 }
11089
11090 return aContent->AsElement()->AttrValueIs(kNameSpaceID_XLink4, nsGkAtoms::type,
11091 nsGkAtoms::simple, eCaseMatters);
11092}
11093
11094/* static */
11095already_AddRefed<ContentFrameMessageManager>
11096nsContentUtils::TryGetBrowserChildGlobal(nsISupports* aFrom) {
11097 RefPtr<nsFrameLoaderOwner> frameLoaderOwner = do_QueryObject(aFrom);
11098 if (!frameLoaderOwner) {
11099 return nullptr;
11100 }
11101
11102 RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
11103 if (!frameLoader) {
11104 return nullptr;
11105 }
11106
11107 RefPtr<ContentFrameMessageManager> manager =
11108 frameLoader->GetBrowserChildMessageManager();
11109 return manager.forget();
11110}
11111
11112/* static */
11113uint32_t nsContentUtils::InnerOrOuterWindowCreated() {
11114 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11114); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 11114; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11115 ++sInnerOrOuterWindowCount;
11116 return ++sInnerOrOuterWindowSerialCounter;
11117}
11118
11119/* static */
11120void nsContentUtils::InnerOrOuterWindowDestroyed() {
11121 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11121); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 11121; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11122 MOZ_ASSERT(sInnerOrOuterWindowCount > 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sInnerOrOuterWindowCount > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sInnerOrOuterWindowCount >
0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("sInnerOrOuterWindowCount > 0", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11122); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sInnerOrOuterWindowCount > 0"
")"); do { *((volatile int*)__null) = 11122; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11123 --sInnerOrOuterWindowCount;
11124}
11125
11126/* static */
11127nsresult nsContentUtils::AnonymizeURI(nsIURI* aURI, nsCString& aAnonymizedURI) {
11128 MOZ_ASSERT(aURI)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aURI)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aURI))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aURI", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11128); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aURI" ")")
; do { *((volatile int*)__null) = 11128; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
11129
11130 if (aURI->SchemeIs("data")) {
11131 aAnonymizedURI.Assign("data:..."_ns);
11132 return NS_OK;
11133 }
11134 // Anonymize the URL.
11135 // Strip the URL of any possible username/password and make it ready to be
11136 // presented in the UI.
11137 nsCOMPtr<nsIURI> exposableURI = net::nsIOService::CreateExposableURI(aURI);
11138 return exposableURI->GetSpec(aAnonymizedURI);
11139}
11140
11141static bool JSONCreator(const char16_t* aBuf, uint32_t aLen, void* aData) {
11142 nsAString* result = static_cast<nsAString*>(aData);
11143 return result->Append(aBuf, aLen, fallible);
11144}
11145
11146/* static */
11147bool nsContentUtils::StringifyJSON(JSContext* aCx, JS::Handle<JS::Value> aValue,
11148 nsAString& aOutStr, JSONBehavior aBehavior) {
11149 MOZ_ASSERT(aCx)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aCx)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aCx))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aCx", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11149); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCx" ")");
do { *((volatile int*)__null) = 11149; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
11150 switch (aBehavior) {
11151 case UndefinedIsNullStringLiteral: {
11152 aOutStr.Truncate();
11153 JS::Rooted<JS::Value> value(aCx, aValue);
11154 return JS_Stringify(aCx, &value, nullptr, JS::NullHandleValue,
11155 JSONCreator, &aOutStr);
11156 }
11157 case UndefinedIsVoidString: {
11158 aOutStr.SetIsVoid(true);
11159 return JS::ToJSON(aCx, aValue, nullptr, JS::NullHandleValue, JSONCreator,
11160 &aOutStr);
11161 }
11162 default:
11163 MOZ_ASSERT_UNREACHABLE("Invalid value for aBehavior")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Invalid value for aBehavior" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11163); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Invalid value for aBehavior" ")"
); do { *((volatile int*)__null) = 11163; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
11164 return false;
11165 }
11166}
11167
11168/* static */
11169bool nsContentUtils::
11170 HighPriorityEventPendingForTopLevelDocumentBeforeContentfulPaint(
11171 Document* aDocument) {
11172 MOZ_ASSERT(XRE_IsContentProcess(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsContentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsContentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsContentProcess()"
" (" "This function only makes sense in content processes" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11173); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsContentProcess()"
") (" "This function only makes sense in content processes" ")"
); do { *((volatile int*)__null) = 11173; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
11173 "This function only makes sense in content processes")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsContentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsContentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsContentProcess()"
" (" "This function only makes sense in content processes" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11173); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsContentProcess()"
") (" "This function only makes sense in content processes" ")"
); do { *((volatile int*)__null) = 11173; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
11174
11175 if (aDocument && !aDocument->IsLoadedAsData()) {
11176 if (nsPresContext* presContext = FindPresContextForDocument(aDocument)) {
11177 MOZ_ASSERT(!presContext->IsChrome(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!presContext->IsChrome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!presContext->IsChrome())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!presContext->IsChrome()"
" (" "Should never have a chrome PresContext in a content process"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11178); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!presContext->IsChrome()"
") (" "Should never have a chrome PresContext in a content process"
")"); do { *((volatile int*)__null) = 11178; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
11178 "Should never have a chrome PresContext in a content process")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!presContext->IsChrome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!presContext->IsChrome())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!presContext->IsChrome()"
" (" "Should never have a chrome PresContext in a content process"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11178); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!presContext->IsChrome()"
") (" "Should never have a chrome PresContext in a content process"
")"); do { *((volatile int*)__null) = 11178; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11179
11180 return !presContext->GetInProcessRootContentDocumentPresContext()
11181 ->HadFirstContentfulPaint() &&
11182 nsThreadManager::MainThreadHasPendingHighPriorityEvents();
11183 }
11184 }
11185 return false;
11186}
11187
11188static nsGlobalWindowInner* GetInnerWindowForGlobal(nsIGlobalObject* aGlobal) {
11189 NS_ENSURE_TRUE(aGlobal, nullptr)do { if ((__builtin_expect(!!(!(aGlobal)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aGlobal" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11189); return nullptr; } } while (false)
;
11190
11191 if (auto* window = aGlobal->GetAsInnerWindow()) {
11192 return nsGlobalWindowInner::Cast(window);
11193 }
11194
11195 // When Extensions run content scripts inside a sandbox, it uses
11196 // sandboxPrototype to make them appear as though they're running in the
11197 // scope of the page. So when a content script invokes postMessage, it expects
11198 // the |source| of the received message to be the window set as the
11199 // sandboxPrototype. This used to work incidentally for unrelated reasons, but
11200 // now we need to do some special handling to support it.
11201 JS::Rooted<JSObject*> scope(RootingCx(), aGlobal->GetGlobalJSObject());
11202 NS_ENSURE_TRUE(scope, nullptr)do { if ((__builtin_expect(!!(!(scope)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "scope" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11202); return nullptr; } } while (false)
;
11203
11204 if (xpc::IsSandbox(scope)) {
11205 AutoJSAPI jsapi;
11206 MOZ_ALWAYS_TRUE(jsapi.Init(scope))do { if ((__builtin_expect(!!(jsapi.Init(scope)), 1))) { } else
{ do { static_assert( mozilla::detail::AssertionConditionType
<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "jsapi.Init(scope)"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11206); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "jsapi.Init(scope)" ")"); do { *((volatile int*)__null
) = 11206; __attribute__((nomerge)) ::abort(); } while (false
); } } while (false); } } while (false)
;
11207 JSContext* cx = jsapi.cx();
11208 // Our current Realm on aCx is the sandbox. Using that for unwrapping
11209 // makes sense: if the sandbox can unwrap the window, we can use it.
11210 return xpc::SandboxWindowOrNull(scope, cx);
11211 }
11212
11213 // The calling window must be holding a reference, so we can return a weak
11214 // pointer.
11215 return nsGlobalWindowInner::Cast(aGlobal->GetAsInnerWindow());
11216}
11217
11218/* static */
11219nsGlobalWindowInner* nsContentUtils::IncumbentInnerWindow() {
11220 return GetInnerWindowForGlobal(GetIncumbentGlobal());
11221}
11222
11223/* static */
11224nsGlobalWindowInner* nsContentUtils::EntryInnerWindow() {
11225 return GetInnerWindowForGlobal(GetEntryGlobal());
11226}
11227
11228/* static */
11229bool nsContentUtils::IsURIInPrefList(nsIURI* aURI, const char* aPrefName) {
11230 MOZ_ASSERT(aPrefName)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPrefName)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPrefName))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aPrefName", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11230); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrefName"
")"); do { *((volatile int*)__null) = 11230; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11231
11232 nsAutoCString list;
11233 Preferences::GetCString(aPrefName, list);
11234 ToLowerCase(list);
11235 return IsURIInList(aURI, list);
11236}
11237
11238/* static */
11239bool nsContentUtils::IsURIInList(nsIURI* aURI, const nsCString& aList) {
11240#ifdef DEBUG1
11241 nsAutoCString listLowerCase(aList);
11242 ToLowerCase(listLowerCase);
11243 MOZ_ASSERT(listLowerCase.Equals(aList),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(listLowerCase.Equals(aList))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(listLowerCase.Equals(aList))
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("listLowerCase.Equals(aList)"
" (" "The aList argument should be lower-case" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11244); AnnotateMozCrashReason("MOZ_ASSERT" "(" "listLowerCase.Equals(aList)"
") (" "The aList argument should be lower-case" ")"); do { *
((volatile int*)__null) = 11244; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
11244 "The aList argument should be lower-case")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(listLowerCase.Equals(aList))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(listLowerCase.Equals(aList))
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("listLowerCase.Equals(aList)"
" (" "The aList argument should be lower-case" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11244); AnnotateMozCrashReason("MOZ_ASSERT" "(" "listLowerCase.Equals(aList)"
") (" "The aList argument should be lower-case" ")"); do { *
((volatile int*)__null) = 11244; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
11245#endif
11246
11247 if (!aURI) {
11248 return false;
11249 }
11250
11251 if (aList.IsEmpty()) {
11252 return false;
11253 }
11254
11255 nsAutoCString scheme;
11256 aURI->GetScheme(scheme);
11257 if (!scheme.EqualsLiteral("http") && !scheme.EqualsLiteral("https")) {
11258 return false;
11259 }
11260
11261 // The list is comma separated domain list. Each item may start with "*.".
11262 // If starts with "*.", it matches any sub-domains.
11263
11264 nsCCharSeparatedTokenizer tokenizer(aList, ',');
11265 while (tokenizer.hasMoreTokens()) {
11266 const nsCString token(tokenizer.nextToken());
11267
11268 nsAutoCString host;
11269 aURI->GetHost(host);
11270 if (host.IsEmpty()) {
11271 return false;
11272 }
11273 ToLowerCase(host);
11274
11275 for (;;) {
11276 int32_t index = token.Find(host);
11277 if (index >= 0 &&
11278 static_cast<uint32_t>(index) + host.Length() <= token.Length()) {
11279 // If we found a full match, return true.
11280 size_t indexAfterHost = index + host.Length();
11281 if (index == 0 && indexAfterHost == token.Length()) {
11282 return true;
11283 }
11284 // If next character is '/', we need to check the path too.
11285 // We assume the path in the list means "/foo" + "*".
11286 if (token[indexAfterHost] == '/') {
11287 nsDependentCSubstring pathInList(
11288 token, indexAfterHost,
11289 static_cast<nsDependentCSubstring::size_type>(-1));
11290 nsAutoCString filePath;
11291 aURI->GetFilePath(filePath);
11292 ToLowerCase(filePath);
11293 if (StringBeginsWith(filePath, pathInList) &&
11294 (filePath.Length() == pathInList.Length() ||
11295 pathInList.EqualsLiteral("/") ||
11296 filePath[pathInList.Length() - 1] == '/' ||
11297 filePath[pathInList.Length() - 1] == '?' ||
11298 filePath[pathInList.Length() - 1] == '#')) {
11299 return true;
11300 }
11301 }
11302 }
11303 int32_t startIndexOfCurrentLevel = host[0] == '*' ? 1 : 0;
11304 int32_t startIndexOfNextLevel =
11305 host.Find(".", startIndexOfCurrentLevel + 1);
11306 if (startIndexOfNextLevel <= 0) {
11307 break;
11308 }
11309 host.ReplaceLiteral(0, startIndexOfNextLevel, "*");
11310 }
11311 }
11312
11313 return false;
11314}
11315
11316/* static */
11317ScreenIntMargin nsContentUtils::GetWindowSafeAreaInsets(
11318 nsIScreen* aScreen, const ScreenIntMargin& aSafeAreaInsets,
11319 const LayoutDeviceIntRect& aWindowRect) {
11320 // This calculates safe area insets of window from screen rectangle, window
11321 // rectangle and safe area insets of screen.
11322 //
11323 // +----------------------------------------+ <-- screen
11324 // | +-------------------------------+ <------- window
11325 // | | window's safe area inset top) | |
11326 // +--+-------------------------------+--+ |
11327 // | | | |<------ safe area rectangle of
11328 // | | | | | screen
11329 // +--+-------------------------------+--+ |
11330 // | |window's safe area inset bottom| |
11331 // | +-------------------------------+ |
11332 // +----------------------------------------+
11333 //
11334 ScreenIntMargin windowSafeAreaInsets;
11335
11336 if (windowSafeAreaInsets == aSafeAreaInsets) {
11337 // no safe area insets.
11338 return windowSafeAreaInsets;
11339 }
11340
11341 int32_t screenLeft, screenTop, screenWidth, screenHeight;
11342 nsresult rv =
11343 aScreen->GetRect(&screenLeft, &screenTop, &screenWidth, &screenHeight);
11344 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11344)
) {
11345 return windowSafeAreaInsets;
11346 }
11347
11348 const ScreenIntRect screenRect(screenLeft, screenTop, screenWidth,
11349 screenHeight);
11350
11351 ScreenIntRect safeAreaRect = screenRect;
11352 safeAreaRect.Deflate(aSafeAreaInsets);
11353
11354 ScreenIntRect windowRect = ViewAs<ScreenPixel>(
11355 aWindowRect, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
11356
11357 // FIXME(bug 1754323): This can trigger because the screen rect is not
11358 // orientation-aware.
11359 // MOZ_ASSERT(screenRect.Contains(windowRect),
11360 // "Screen doesn't contain window rect? Something seems off");
11361
11362 // window's rect of safe area
11363 safeAreaRect = safeAreaRect.Intersect(windowRect);
11364
11365 windowSafeAreaInsets.top = safeAreaRect.y - aWindowRect.y;
11366 windowSafeAreaInsets.left = safeAreaRect.x - aWindowRect.x;
11367 windowSafeAreaInsets.right =
11368 aWindowRect.x + aWindowRect.width - (safeAreaRect.x + safeAreaRect.width);
11369 windowSafeAreaInsets.bottom = aWindowRect.y + aWindowRect.height -
11370 (safeAreaRect.y + safeAreaRect.height);
11371
11372 windowSafeAreaInsets.EnsureAtLeast(ScreenIntMargin());
11373 // This shouldn't be needed, but it wallpapers orientation issues, see bug
11374 // 1754323.
11375 windowSafeAreaInsets.EnsureAtMost(aSafeAreaInsets);
11376
11377 return windowSafeAreaInsets;
11378}
11379
11380/* static */
11381nsContentUtils::SubresourceCacheValidationInfo
11382nsContentUtils::GetSubresourceCacheValidationInfo(nsIRequest* aRequest,
11383 nsIURI* aURI) {
11384 SubresourceCacheValidationInfo info;
11385 if (nsCOMPtr<nsICacheInfoChannel> cache = do_QueryInterface(aRequest)) {
11386 uint32_t value = 0;
11387 if (NS_SUCCEEDED(cache->GetCacheTokenExpirationTime(&value))((bool)(__builtin_expect(!!(!NS_FAILED_impl(cache->GetCacheTokenExpirationTime
(&value))), 1)))
) {
11388 // NOTE: If the cache doesn't expire, the value should be
11389 // nsICacheEntry::NO_EXPIRATION_TIME.
11390 info.mExpirationTime.emplace(CacheExpirationTime::ExpireAt(value));
11391 }
11392 }
11393
11394 // Determine whether the cache entry must be revalidated when we try to use
11395 // it. Currently, only HTTP specifies this information...
11396 if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest)) {
11397 Unused << httpChannel->IsNoStoreResponse(&info.mMustRevalidate);
11398
11399 if (!info.mMustRevalidate) {
11400 Unused << httpChannel->IsNoCacheResponse(&info.mMustRevalidate);
11401 }
11402 }
11403
11404 // data: URIs are safe to cache across documents under any circumstance, so we
11405 // special-case them here even though the channel itself doesn't have any
11406 // caching policy. Same for chrome:// uris.
11407 //
11408 // TODO(emilio): Figure out which other schemes that don't have caching
11409 // policies are safe to cache. Blobs should be...
11410 const bool knownCacheable = [&] {
11411 if (!aURI) {
11412 return false;
11413 }
11414 if (aURI->SchemeIs("data") || aURI->SchemeIs("moz-page-thumb") ||
11415 aURI->SchemeIs("moz-extension")) {
11416 return true;
11417 }
11418 if (aURI->SchemeIs("chrome") || aURI->SchemeIs("resource")) {
11419 return !StaticPrefs::nglayout_debug_disable_xul_cache();
11420 }
11421 return false;
11422 }();
11423
11424 if (knownCacheable) {
11425 MOZ_ASSERT(!info.mExpirationTime)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!info.mExpirationTime)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!info.mExpirationTime))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!info.mExpirationTime"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11425); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!info.mExpirationTime"
")"); do { *((volatile int*)__null) = 11425; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11426 MOZ_ASSERT(!info.mMustRevalidate)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!info.mMustRevalidate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!info.mMustRevalidate))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!info.mMustRevalidate"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11426); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!info.mMustRevalidate"
")"); do { *((volatile int*)__null) = 11426; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11427 info.mExpirationTime = Some(CacheExpirationTime::Never());
11428 }
11429
11430 return info;
11431}
11432
11433CacheExpirationTime nsContentUtils::GetSubresourceCacheExpirationTime(
11434 nsIRequest* aRequest, nsIURI* aURI) {
11435 auto info = GetSubresourceCacheValidationInfo(aRequest, aURI);
11436
11437 // For now, we never cache entries that we have to revalidate, or whose
11438 // channel don't support caching.
11439 if (info.mMustRevalidate || !info.mExpirationTime) {
11440 return CacheExpirationTime::AlreadyExpired();
11441 }
11442 return *info.mExpirationTime;
11443}
11444
11445/* static */
11446bool nsContentUtils::ShouldBypassSubResourceCache(Document* aDoc) {
11447 RefPtr<nsILoadGroup> lg = aDoc->GetDocumentLoadGroup();
11448 if (!lg) {
11449 return false;
11450 }
11451 nsLoadFlags flags;
11452 if (NS_FAILED(lg->GetLoadFlags(&flags))((bool)(__builtin_expect(!!(NS_FAILED_impl(lg->GetLoadFlags
(&flags))), 0)))
) {
11453 return false;
11454 }
11455 return flags & (nsIRequest::LOAD_BYPASS_CACHE |
11456 nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE);
11457}
11458
11459nsCString nsContentUtils::TruncatedURLForDisplay(nsIURI* aURL, size_t aMaxLen) {
11460 nsCString spec;
11461 if (aURL) {
11462 aURL->GetSpec(spec);
11463 spec.Truncate(std::min(aMaxLen, spec.Length()));
11464 }
11465 return spec;
11466}
11467
11468/* static */
11469nsresult nsContentUtils::AnonymizeId(nsAString& aId,
11470 const nsACString& aOriginKey,
11471 OriginFormat aFormat) {
11472 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11472); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 11472; __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11473
11474 nsresult rv;
11475 nsCString rawKey;
11476 if (aFormat == OriginFormat::Base64) {
11477 rv = Base64Decode(aOriginKey, rawKey);
11478 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11478); return rv; } } while (false)
;
11479 } else {
11480 rawKey = aOriginKey;
11481 }
11482
11483 HMAC hmac;
11484 rv = hmac.Begin(
11485 SEC_OID_SHA256,
11486 Span(reinterpret_cast<const uint8_t*>(rawKey.get()), rawKey.Length()));
11487 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11487); return rv; } } while (false)
;
11488
11489 NS_ConvertUTF16toUTF8 id(aId);
11490 rv = hmac.Update(reinterpret_cast<const uint8_t*>(id.get()), id.Length());
11491 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11491); return rv; } } while (false)
;
11492
11493 nsTArray<uint8_t> macBytes;
11494 rv = hmac.End(macBytes);
11495 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11495); return rv; } } while (false)
;
11496
11497 nsCString macBase64;
11498 rv = Base64Encode(
11499 nsDependentCSubstring(reinterpret_cast<const char*>(macBytes.Elements()),
11500 macBytes.Length()),
11501 macBase64);
11502 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11502); return rv; } } while (false)
;
11503
11504 CopyUTF8toUTF16(macBase64, aId);
11505 return NS_OK;
11506}
11507
11508void nsContentUtils::RequestGeckoTaskBurst() {
11509 nsCOMPtr<nsIAppShell> appShell = do_GetService(NS_APPSHELL_CID{ 0x2d96b3df, 0xc051, 0x11d1, { 0xa8, 0x27, 0x00, 0x40, 0x95,
0x9a, 0x28, 0xc9 } }
);
11510 if (appShell) {
11511 appShell->GeckoTaskBurst();
11512 }
11513}
11514
11515nsIContent* nsContentUtils::GetClosestLinkInFlatTree(nsIContent* aContent) {
11516 for (nsIContent* content = aContent; content;
11517 content = content->GetFlattenedTreeParent()) {
11518 if (nsContentUtils::IsDraggableLink(content)) {
11519 return content;
11520 }
11521 }
11522 return nullptr;
11523}
11524
11525template <TreeKind aKind>
11526MOZ_ALWAYS_INLINEinline const nsINode* GetParent(const nsINode* aNode) {
11527 if constexpr (aKind == TreeKind::DOM) {
11528 return aNode->GetParentNode();
11529 } else {
11530 return aNode->GetFlattenedTreeParentNode();
11531 }
11532}
11533
11534template <TreeKind aKind>
11535MOZ_ALWAYS_INLINEinline Maybe<uint32_t> GetIndexInParent(const nsINode* aParent,
11536 const nsINode* aNode) {
11537 if constexpr (aKind == TreeKind::DOM) {
11538 return aParent->ComputeIndexOf(aNode);
11539 } else {
11540 return aParent->ComputeFlatTreeIndexOf(aNode);
11541 }
11542}
11543
11544template <TreeKind aTreeKind>
11545int32_t nsContentUtils::CompareTreePosition(const nsINode* aNode1,
11546 const nsINode* aNode2,
11547 const nsINode* aCommonAncestor) {
11548 MOZ_ASSERT(aNode1, "aNode1 must not be null")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNode1)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aNode1))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aNode1" " (" "aNode1 must not be null"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11548); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNode1" ") ("
"aNode1 must not be null" ")"); do { *((volatile int*)__null
) = 11548; __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
11549 MOZ_ASSERT(aNode2, "aNode2 must not be null")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNode2)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aNode2))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aNode2" " (" "aNode2 must not be null"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11549); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNode2" ") ("
"aNode2 must not be null" ")"); do { *((volatile int*)__null
) = 11549; __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
11550
11551 if (NS_WARN_IF(aNode1 == aNode2)NS_warn_if_impl(aNode1 == aNode2, "aNode1 == aNode2", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11551)
) {
11552 return 0;
11553 }
11554
11555 AutoTArray<const nsINode*, 32> node1Ancestors;
11556 const nsINode* c1;
11557 for (c1 = aNode1; c1 && c1 != aCommonAncestor;
11558 c1 = GetParent<aTreeKind>(c1)) {
11559 node1Ancestors.AppendElement(c1);
11560 }
11561 if (!c1 && aCommonAncestor) {
11562 // So, it turns out aCommonAncestor was not an ancestor of c1. Oops.
11563 // Never mind. We can continue as if aCommonAncestor was null.
11564 aCommonAncestor = nullptr;
11565 }
11566
11567 AutoTArray<const nsINode*, 32> node2Ancestors;
11568 const nsINode* c2;
11569 for (c2 = aNode2; c2 && c2 != aCommonAncestor;
11570 c2 = GetParent<aTreeKind>(c2)) {
11571 node2Ancestors.AppendElement(c2);
11572 }
11573 if (!c2 && aCommonAncestor) {
11574 // So, it turns out aCommonAncestor was not an ancestor of c2.
11575 // We need to retry with no common ancestor hint.
11576 return CompareTreePosition<aTreeKind>(aNode1, aNode2, nullptr);
11577 }
11578
11579 int last1 = node1Ancestors.Length() - 1;
11580 int last2 = node2Ancestors.Length() - 1;
11581 const nsINode* node1Ancestor = nullptr;
11582 const nsINode* node2Ancestor = nullptr;
11583 while (last1 >= 0 && last2 >= 0 &&
11584 ((node1Ancestor = node1Ancestors.ElementAt(last1)) ==
11585 (node2Ancestor = node2Ancestors.ElementAt(last2)))) {
11586 last1--;
11587 last2--;
11588 }
11589
11590 if (last1 < 0) {
11591 if (last2 < 0) {
11592 NS_ASSERTION(aNode1 == aNode2, "internal error?")do { if (!(aNode1 == aNode2)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "internal error?", "aNode1 == aNode2", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11592); MOZ_PretendNoReturn(); } } while (0)
;
11593 return 0;
11594 }
11595 // aContent1 is an ancestor of aContent2
11596 return -1;
11597 }
11598
11599 if (last2 < 0) {
11600 // aContent2 is an ancestor of aContent1
11601 return 1;
11602 }
11603
11604 // node1Ancestor != node2Ancestor, so they must be siblings with the
11605 // same parent
11606 const nsINode* parent = GetParent<aTreeKind>(node1Ancestor);
11607 if (NS_WARN_IF(!parent)NS_warn_if_impl(!parent, "!parent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp"
, 11607)
) { // different documents??
11608 return 0;
11609 }
11610
11611 const Maybe<uint32_t> index1 =
11612 GetIndexInParent<aTreeKind>(parent, node1Ancestor);
11613 const Maybe<uint32_t> index2 =
11614 GetIndexInParent<aTreeKind>(parent, node2Ancestor);
11615
11616 // None of the nodes are anonymous, just do a regular comparison.
11617 if (index1.isSome() && index2.isSome()) {
11618 return static_cast<int32_t>(static_cast<int64_t>(*index1) - *index2);
11619 }
11620
11621 // Otherwise handle pseudo-element and anonymous node ordering.
11622 // ::marker -> ::before -> anon siblings -> regular siblings -> ::after
11623 auto PseudoIndex = [](const nsINode* aNode,
11624 const Maybe<uint32_t>& aNodeIndex) -> int32_t {
11625 if (aNodeIndex.isSome()) {
11626 return 1; // Not a pseudo.
11627 }
11628 if (aNode->IsGeneratedContentContainerForMarker()) {
11629 return -2;
11630 }
11631 if (aNode->IsGeneratedContentContainerForBefore()) {
11632 return -1;
11633 }
11634 if (aNode->IsGeneratedContentContainerForAfter()) {
11635 return 2;
11636 }
11637 return 0;
11638 };
11639
11640 return PseudoIndex(node1Ancestor, index1) -
11641 PseudoIndex(node2Ancestor, index2);
11642}
11643
11644nsIContent* nsContentUtils::AttachDeclarativeShadowRoot(nsIContent* aHost,
11645 ShadowRootMode aMode,
11646 bool aIsClonable,
11647 bool aIsSerializable,
11648 bool aDelegatesFocus) {
11649 RefPtr<Element> host = mozilla::dom::Element::FromNodeOrNull(aHost);
11650 if (!host || host->GetShadowRoot()) {
11651 // https://html.spec.whatwg.org/#parsing-main-inhead:shadow-host
11652 return nullptr;
11653 }
11654
11655 ShadowRootInit init;
11656 init.mMode = aMode;
11657 init.mDelegatesFocus = aDelegatesFocus;
11658 init.mSlotAssignment = SlotAssignmentMode::Named;
11659 init.mClonable = aIsClonable;
11660 init.mSerializable = aIsSerializable;
11661
11662 RefPtr shadowRoot = host->AttachShadow(init, IgnoreErrors());
11663 if (shadowRoot) {
11664 shadowRoot->SetIsDeclarative(
11665 nsGenericHTMLFormControlElement::ShadowRootDeclarative::Yes);
11666 // https://html.spec.whatwg.org/#parsing-main-inhead:available-to-element-internals
11667 shadowRoot->SetAvailableToElementInternals();
11668 }
11669 return shadowRoot;
11670}
11671
11672template int32_t nsContentUtils::CompareTreePosition<TreeKind::DOM>(
11673 const nsINode*, const nsINode*, const nsINode*);
11674template int32_t nsContentUtils::CompareTreePosition<TreeKind::Flat>(
11675 const nsINode*, const nsINode*, const nsINode*);
11676
11677namespace mozilla {
11678std::ostream& operator<<(std::ostream& aOut,
11679 const PreventDefaultResult aPreventDefaultResult) {
11680 switch (aPreventDefaultResult) {
11681 case PreventDefaultResult::No:
11682 aOut << "unhandled";
11683 break;
11684 case PreventDefaultResult::ByContent:
11685 aOut << "handled-by-content";
11686 break;
11687 case PreventDefaultResult::ByChrome:
11688 aOut << "handled-by-chrome";
11689 break;
11690 }
11691 return aOut;
11692}
11693} // namespace mozilla

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h

1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7/* A class for optional values and in-place lazy construction. */
8
9#ifndef mozilla_Maybe_h
10#define mozilla_Maybe_h
11
12#include <functional>
13#include <new> // for placement new
14#include <ostream>
15#include <type_traits>
16#include <utility>
17
18#include "mozilla/Alignment.h"
19#include "mozilla/Assertions.h"
20#include "mozilla/Attributes.h"
21#include "mozilla/MaybeStorageBase.h"
22#include "mozilla/MemoryChecking.h"
23#include "mozilla/OperatorNewExtensions.h"
24#include "mozilla/Poison.h"
25#include "mozilla/ThreadSafety.h"
26
27class nsCycleCollectionTraversalCallback;
28
29template <typename T>
30inline void CycleCollectionNoteChild(
31 nsCycleCollectionTraversalCallback& aCallback, T* aChild, const char* aName,
32 uint32_t aFlags);
33
34namespace mozilla {
35
36struct Nothing {};
37
38inline constexpr bool operator==(const Nothing&, const Nothing&) {
39 return true;
40}
41
42template <class T>
43class Maybe;
44
45namespace detail {
46
47// You would think that poisoning Maybe instances could just be a call
48// to mozWritePoison. Unfortunately, using a simple call to
49// mozWritePoison generates poor code on MSVC for small structures. The
50// generated code contains (always not-taken) branches and does a bunch
51// of setup for `rep stos{l,q}`, even though we know at compile time
52// exactly how many words we're poisoning. Instead, we're going to
53// force MSVC to generate the code we want via recursive templates.
54
55// Write the given poisonValue into p at offset*sizeof(uintptr_t).
56template <size_t offset>
57inline void WritePoisonAtOffset(void* p, const uintptr_t poisonValue) {
58 memcpy(static_cast<char*>(p) + offset * sizeof(poisonValue), &poisonValue,
59 sizeof(poisonValue));
60}
61
62template <size_t Offset, size_t NOffsets>
63struct InlinePoisoner {
64 static void poison(void* p, const uintptr_t poisonValue) {
65 WritePoisonAtOffset<Offset>(p, poisonValue);
66 InlinePoisoner<Offset + 1, NOffsets>::poison(p, poisonValue);
67 }
68};
69
70template <size_t N>
71struct InlinePoisoner<N, N> {
72 static void poison(void*, const uintptr_t) {
73 // All done!
74 }
75};
76
77// We can't generate inline code for large structures, though, because we'll
78// blow out recursive template instantiation limits, and the code would be
79// bloated to boot. So provide a fallback to the out-of-line poisoner.
80template <size_t ObjectSize>
81struct OutOfLinePoisoner {
82 static MOZ_NEVER_INLINE__attribute__((noinline)) void poison(void* p, const uintptr_t) {
83 mozWritePoison(p, ObjectSize);
84 }
85};
86
87template <typename T>
88inline void PoisonObject(T* p) {
89 const uintptr_t POISON = mozPoisonValue();
90 std::conditional_t<(sizeof(T) <= 8 * sizeof(POISON)),
91 InlinePoisoner<0, sizeof(T) / sizeof(POISON)>,
92 OutOfLinePoisoner<sizeof(T)>>::poison(p, POISON);
93}
94
95template <typename T>
96struct MaybePoisoner {
97 static const size_t N = sizeof(T);
98
99 static void poison(void* aPtr) {
100#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED1
101 if (N >= sizeof(uintptr_t)) {
102 PoisonObject(static_cast<std::remove_cv_t<T>*>(aPtr));
103 }
104#endif
105 MOZ_MAKE_MEM_UNDEFINED(aPtr, N)do { } while (0);
106 }
107};
108
109template <typename T,
110 bool TriviallyDestructibleAndCopyable =
111 IsTriviallyDestructibleAndCopyable<T>,
112 bool Copyable = std::is_copy_constructible_v<T>,
113 bool Movable = std::is_move_constructible_v<T>>
114class Maybe_CopyMove_Enabler;
115
116#define MOZ_MAYBE_COPY_OPS() \
117 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler& aOther) { \
118 if (downcast(aOther).isSome()) { \
119 downcast(*this).emplace(*downcast(aOther)); \
120 } \
121 } \
122 \
123 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler& aOther) { \
124 return downcast(*this).template operator= <T>(downcast(aOther)); \
125 }
126
127#define MOZ_MAYBE_MOVE_OPS() \
128 constexpr Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) { \
129 if (downcast(aOther).isSome()) { \
130 downcast(*this).emplace(std::move(*downcast(aOther))); \
131 downcast(aOther).reset(); \
132 } \
133 } \
134 \
135 constexpr Maybe_CopyMove_Enabler& operator=( \
136 Maybe_CopyMove_Enabler&& aOther) { \
137 downcast(*this).template operator= <T>(std::move(downcast(aOther))); \
138 \
139 return *this; \
140 }
141
142#define MOZ_MAYBE_DOWNCAST() \
143 static constexpr Maybe<T>& downcast(Maybe_CopyMove_Enabler& aObj) { \
144 return static_cast<Maybe<T>&>(aObj); \
145 } \
146 static constexpr const Maybe<T>& downcast( \
147 const Maybe_CopyMove_Enabler& aObj) { \
148 return static_cast<const Maybe<T>&>(aObj); \
149 }
150
151template <typename T>
152class Maybe_CopyMove_Enabler<T, true, true, true> {
153 public:
154 Maybe_CopyMove_Enabler() = default;
155
156 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = default;
157 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = default;
158 constexpr Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) {
159 downcast(aOther).reset();
160 }
161 constexpr Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&& aOther) {
162 downcast(aOther).reset();
163 return *this;
164 }
165
166 private:
167 MOZ_MAYBE_DOWNCAST()
168};
169
170template <typename T>
171class Maybe_CopyMove_Enabler<T, true, false, true> {
172 public:
173 Maybe_CopyMove_Enabler() = default;
174
175 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = delete;
176 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = delete;
177 constexpr Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) {
178 downcast(aOther).reset();
179 }
180 constexpr Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&& aOther) {
181 downcast(aOther).reset();
182 return *this;
183 }
184
185 private:
186 MOZ_MAYBE_DOWNCAST()
187};
188
189template <typename T>
190class Maybe_CopyMove_Enabler<T, false, true, true> {
191 public:
192 Maybe_CopyMove_Enabler() = default;
193
194 MOZ_MAYBE_COPY_OPS()
195 MOZ_MAYBE_MOVE_OPS()
196
197 private:
198 MOZ_MAYBE_DOWNCAST()
199};
200
201template <typename T>
202class Maybe_CopyMove_Enabler<T, false, false, true> {
203 public:
204 Maybe_CopyMove_Enabler() = default;
205
206 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = delete;
207 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = delete;
208 MOZ_MAYBE_MOVE_OPS()
209
210 private:
211 MOZ_MAYBE_DOWNCAST()
212};
213
214template <typename T>
215class Maybe_CopyMove_Enabler<T, false, true, false> {
216 public:
217 Maybe_CopyMove_Enabler() = default;
218
219 MOZ_MAYBE_COPY_OPS()
220 Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&&) = delete;
221 Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&&) = delete;
222
223 private:
224 MOZ_MAYBE_DOWNCAST()
225};
226
227template <typename T, bool TriviallyDestructibleAndCopyable>
228class Maybe_CopyMove_Enabler<T, TriviallyDestructibleAndCopyable, false,
229 false> {
230 public:
231 Maybe_CopyMove_Enabler() = default;
232
233 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = delete;
234 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = delete;
235 Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&&) = delete;
236 Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&&) = delete;
237};
238
239#undef MOZ_MAYBE_COPY_OPS
240#undef MOZ_MAYBE_MOVE_OPS
241#undef MOZ_MAYBE_DOWNCAST
242
243template <typename T, bool TriviallyDestructibleAndCopyable =
244 IsTriviallyDestructibleAndCopyable<T>>
245struct MaybeStorage;
246
247template <typename T>
248struct MaybeStorage<T, false> : MaybeStorageBase<T> {
249 protected:
250 char mIsSome = false; // not bool -- guarantees minimal space consumption
251
252 MaybeStorage() = default;
7
Calling defaulted default constructor for 'MaybeStorageBase<mozilla::AutoProfileRunnable, false>'
12
Returning from default constructor for 'MaybeStorageBase<mozilla::AutoProfileRunnable, false>'
13
Returning without writing to 'this->mStorage.val.mStartTime.mValue'
253 explicit MaybeStorage(const T& aVal)
254 : MaybeStorageBase<T>{aVal}, mIsSome{true} {}
255 explicit MaybeStorage(T&& aVal)
256 : MaybeStorageBase<T>{std::move(aVal)}, mIsSome{true} {}
257
258 template <typename... Args>
259 explicit MaybeStorage(std::in_place_t, Args&&... aArgs)
260 : MaybeStorageBase<T>{std::in_place, std::forward<Args>(aArgs)...},
261 mIsSome{true} {}
262
263 public:
264 // Copy and move operations are no-ops, since copying is moving is implemented
265 // by Maybe_CopyMove_Enabler.
266
267 MaybeStorage(const MaybeStorage&) : MaybeStorageBase<T>{} {}
268 MaybeStorage& operator=(const MaybeStorage&) { return *this; }
269 MaybeStorage(MaybeStorage&&) : MaybeStorageBase<T>{} {}
270 MaybeStorage& operator=(MaybeStorage&&) { return *this; }
271
272 ~MaybeStorage() {
273 if (mIsSome
20.1
Field 'mIsSome' is 0
20.1
Field 'mIsSome' is 0
20.1
Field 'mIsSome' is 0
20.1
Field 'mIsSome' is 0
20.1
Field 'mIsSome' is 0
20.1
Field 'mIsSome' is 0
20.1
Field 'mIsSome' is 0
) {
21
Taking false branch
274 this->addr()->T::~T();
275 }
276 }
22
Calling implicit destructor for 'MaybeStorageBase<mozilla::AutoProfileRunnable, false>'
23
Calling '~Union'
277};
278
279template <typename T>
280struct MaybeStorage<T, true> : MaybeStorageBase<T> {
281 protected:
282 char mIsSome = false; // not bool -- guarantees minimal space consumption
283
284 constexpr MaybeStorage() = default;
285 constexpr explicit MaybeStorage(const T& aVal)
286 : MaybeStorageBase<T>{aVal}, mIsSome{true} {}
287 constexpr explicit MaybeStorage(T&& aVal)
288 : MaybeStorageBase<T>{std::move(aVal)}, mIsSome{true} {}
289
290 template <typename... Args>
291 constexpr explicit MaybeStorage(std::in_place_t, Args&&... aArgs)
292 : MaybeStorageBase<T>{std::in_place, std::forward<Args>(aArgs)...},
293 mIsSome{true} {}
294};
295
296template <typename T>
297struct IsMaybeImpl : std::false_type {};
298
299template <typename T>
300struct IsMaybeImpl<Maybe<T>> : std::true_type {};
301
302template <typename T>
303using IsMaybe = IsMaybeImpl<std::decay_t<T>>;
304
305} // namespace detail
306
307template <typename T, typename U = typename std::remove_cv<
308 typename std::remove_reference<T>::type>::type>
309constexpr Maybe<U> Some(T&& aValue);
310
311/*
312 * Maybe is a container class which contains either zero or one elements. It
313 * serves two roles. It can represent values which are *semantically* optional,
314 * augmenting a type with an explicit 'Nothing' value. In this role, it provides
315 * methods that make it easy to work with values that may be missing, along with
316 * equality and comparison operators so that Maybe values can be stored in
317 * containers. Maybe values can be constructed conveniently in expressions using
318 * type inference, as follows:
319 *
320 * void doSomething(Maybe<Foo> aFoo) {
321 * if (aFoo) // Make sure that aFoo contains a value...
322 * aFoo->takeAction(); // and then use |aFoo->| to access it.
323 * } // |*aFoo| also works!
324 *
325 * doSomething(Nothing()); // Passes a Maybe<Foo> containing no value.
326 * doSomething(Some(Foo(100))); // Passes a Maybe<Foo> containing |Foo(100)|.
327 *
328 * You'll note that it's important to check whether a Maybe contains a value
329 * before using it, using conversion to bool, |isSome()|, or |isNothing()|. You
330 * can avoid these checks, and sometimes write more readable code, using
331 * |valueOr()|, |ptrOr()|, and |refOr()|, which allow you to retrieve the value
332 * in the Maybe and provide a default for the 'Nothing' case. You can also use
333 * |apply()| to call a function only if the Maybe holds a value, and |map()| to
334 * transform the value in the Maybe, returning another Maybe with a possibly
335 * different type.
336 *
337 * Maybe's other role is to support lazily constructing objects without using
338 * dynamic storage. A Maybe directly contains storage for a value, but it's
339 * empty by default. |emplace()|, as mentioned above, can be used to construct a
340 * value in Maybe's storage. The value a Maybe contains can be destroyed by
341 * calling |reset()|; this will happen automatically if a Maybe is destroyed
342 * while holding a value.
343 *
344 * It's a common idiom in C++ to use a pointer as a 'Maybe' type, with a null
345 * value meaning 'Nothing' and any other value meaning 'Some'. You can convert
346 * from such a pointer to a Maybe value using 'ToMaybe()'.
347 *
348 * Maybe is inspired by similar types in the standard library of many other
349 * languages (e.g. Haskell's Maybe and Rust's Option). In the C++ world it's
350 * very similar to std::optional, which was proposed for C++14 and originated in
351 * Boost. The most important differences between Maybe and std::optional are:
352 *
353 * - std::optional<T> may be compared with T. We deliberately forbid that.
354 * - std::optional has |valueOr()|, equivalent to Maybe's |valueOr()|, but
355 * lacks corresponding methods for |refOr()| and |ptrOr()|.
356 * - std::optional lacks |map()| and |apply()|, making it less suitable for
357 * functional-style code.
358 * - std::optional lacks many convenience functions that Maybe has. Most
359 * unfortunately, it lacks equivalents of the type-inferred constructor
360 * functions |Some()| and |Nothing()|.
361 */
362template <class T>
363class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe
364 : private detail::MaybeStorage<T>,
365 public detail::Maybe_CopyMove_Enabler<T> {
366 template <typename, bool, bool, bool>
367 friend class detail::Maybe_CopyMove_Enabler;
368
369 template <typename U, typename V>
370 friend constexpr Maybe<V> Some(U&& aValue);
371
372 struct SomeGuard {};
373
374 template <typename U>
375 constexpr Maybe(U&& aValue, SomeGuard)
376 : detail::MaybeStorage<T>{std::forward<U>(aValue)} {}
377
378 using detail::MaybeStorage<T>::mIsSome;
379 using detail::MaybeStorage<T>::mStorage;
380
381 void poisonData() { detail::MaybePoisoner<T>::poison(&mStorage.val); }
382
383 public:
384 using ValueType = T;
385
386 MOZ_ALLOW_TEMPORARY constexpr Maybe() = default;
6
Calling defaulted default constructor for 'MaybeStorage<mozilla::AutoProfileRunnable, false>'
14
Returning from default constructor for 'MaybeStorage<mozilla::AutoProfileRunnable, false>'
15
Returning without writing to 'this->mStorage.val.mStartTime.mValue'
387
388 MOZ_ALLOW_TEMPORARY MOZ_IMPLICIT constexpr Maybe(Nothing) : Maybe{} {}
389
390 template <typename... Args>
391 constexpr explicit Maybe(std::in_place_t, Args&&... aArgs)
392 : detail::MaybeStorage<T>{std::in_place, std::forward<Args>(aArgs)...} {}
393
394 /**
395 * Maybe<T> can be copy-constructed from a Maybe<U> if T is constructible from
396 * a const U&.
397 */
398 template <typename U,
399 std::enable_if_t<std::is_constructible_v<T, const U&>, bool> = true>
400 MOZ_IMPLICIT Maybe(const Maybe<U>& aOther) {
401 if (aOther.isSome()) {
402 emplace(*aOther);
403 }
404 }
405
406 template <typename U, std::enable_if_t<!std::is_constructible_v<T, const U&>,
407 bool> = true>
408 explicit Maybe(const Maybe<U>& aOther) = delete;
409
410 /**
411 * Maybe<T> can be move-constructed from a Maybe<U> if T is constructible from
412 * a U&&.
413 */
414 template <typename U,
415 std::enable_if_t<std::is_constructible_v<T, U&&>, bool> = true>
416 MOZ_IMPLICIT Maybe(Maybe<U>&& aOther) {
417 if (aOther.isSome()) {
418 emplace(std::move(*aOther));
419 aOther.reset();
420 }
421 }
422 template <typename U,
423 std::enable_if_t<!std::is_constructible_v<T, U&&>, bool> = true>
424 explicit Maybe(Maybe<U>&& aOther) = delete;
425
426 template <typename U,
427 std::enable_if_t<std::is_constructible_v<T, const U&>, bool> = true>
428 Maybe& operator=(const Maybe<U>& aOther) {
429 if (aOther.isSome()) {
430 if (mIsSome) {
431 ref() = aOther.ref();
432 } else {
433 emplace(*aOther);
434 }
435 } else {
436 reset();
437 }
438 return *this;
439 }
440
441 template <typename U, std::enable_if_t<!std::is_constructible_v<T, const U&>,
442 bool> = true>
443 Maybe& operator=(const Maybe<U>& aOther) = delete;
444
445 template <typename U,
446 std::enable_if_t<std::is_constructible_v<T, U&&>, bool> = true>
447 Maybe& operator=(Maybe<U>&& aOther) {
448 if (aOther.isSome()) {
449 if (mIsSome) {
450 ref() = std::move(aOther.ref());
451 } else {
452 emplace(std::move(*aOther));
453 }
454 aOther.reset();
455 } else {
456 reset();
457 }
458
459 return *this;
460 }
461
462 template <typename U,
463 std::enable_if_t<!std::is_constructible_v<T, U&&>, bool> = true>
464 Maybe& operator=(Maybe<U>&& aOther) = delete;
465
466 constexpr Maybe& operator=(Nothing) {
467 reset();
468 return *this;
469 }
470
471 /* Methods that check whether this Maybe contains a value */
472 constexpr explicit operator bool() const { return isSome(); }
473 constexpr bool isSome() const { return mIsSome; }
474 constexpr bool isNothing() const { return !mIsSome; }
475
476 /* Returns the contents of this Maybe<T> by value. Unsafe unless |isSome()|.
477 */
478 constexpr T value() const&;
479 constexpr T value() &&;
480 constexpr T value() const&&;
481
482 /**
483 * Move the contents of this Maybe<T> out of internal storage and return it
484 * without calling the destructor. The internal storage is also reset to
485 * avoid multiple calls. Unsafe unless |isSome()|.
486 */
487 constexpr T extract() {
488 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 488); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 488; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
489 T v = std::move(mStorage.val);
490 reset();
491 return v;
492 }
493
494 /**
495 * Returns the value (possibly |Nothing()|) by moving it out of this Maybe<T>
496 * and leaving |Nothing()| in its place.
497 */
498 Maybe<T> take() { return std::exchange(*this, Nothing()); }
499
500 /*
501 * Returns the contents of this Maybe<T> by value. If |isNothing()|, returns
502 * the default value provided.
503 *
504 * Note: If the value passed to aDefault is not the result of a trivial
505 * expression, but expensive to evaluate, e.g. |valueOr(ExpensiveFunction())|,
506 * use |valueOrFrom| instead, e.g.
507 * |valueOrFrom([arg] { return ExpensiveFunction(arg); })|. This ensures
508 * that the expensive expression is only evaluated when its result will
509 * actually be used.
510 */
511 template <typename V>
512 constexpr T valueOr(V&& aDefault) const {
513 if (isSome()) {
514 return ref();
515 }
516 return std::forward<V>(aDefault);
517 }
518
519 /*
520 * Returns the contents of this Maybe<T> by value. If |isNothing()|, returns
521 * the value returned from the function or functor provided.
522 */
523 template <typename F>
524 constexpr T valueOrFrom(F&& aFunc) const {
525 if (isSome()) {
526 return ref();
527 }
528 return aFunc();
529 }
530
531 /* Returns the contents of this Maybe<T> by pointer. Unsafe unless |isSome()|.
532 */
533 T* ptr();
534 constexpr const T* ptr() const;
535
536 /*
537 * Returns the contents of this Maybe<T> by pointer. If |isNothing()|,
538 * returns the default value provided.
539 */
540 T* ptrOr(T* aDefault) {
541 if (isSome()) {
542 return ptr();
543 }
544 return aDefault;
545 }
546
547 constexpr const T* ptrOr(const T* aDefault) const {
548 if (isSome()) {
549 return ptr();
550 }
551 return aDefault;
552 }
553
554 /*
555 * Returns the contents of this Maybe<T> by pointer. If |isNothing()|,
556 * returns the value returned from the function or functor provided.
557 */
558 template <typename F>
559 T* ptrOrFrom(F&& aFunc) {
560 if (isSome()) {
561 return ptr();
562 }
563 return aFunc();
564 }
565
566 template <typename F>
567 const T* ptrOrFrom(F&& aFunc) const {
568 if (isSome()) {
569 return ptr();
570 }
571 return aFunc();
572 }
573
574 constexpr T* operator->();
575 constexpr const T* operator->() const;
576
577 /* Returns the contents of this Maybe<T> by ref. Unsafe unless |isSome()|. */
578 constexpr T& ref() &;
579 constexpr const T& ref() const&;
580 constexpr T&& ref() &&;
581 constexpr const T&& ref() const&&;
582
583 /*
584 * Returns the contents of this Maybe<T> by ref. If |isNothing()|, returns
585 * the default value provided.
586 */
587 constexpr T& refOr(T& aDefault) {
588 if (isSome()) {
589 return ref();
590 }
591 return aDefault;
592 }
593
594 constexpr const T& refOr(const T& aDefault) const {
595 if (isSome()) {
596 return ref();
597 }
598 return aDefault;
599 }
600
601 /*
602 * Returns the contents of this Maybe<T> by ref. If |isNothing()|, returns the
603 * value returned from the function or functor provided.
604 */
605 template <typename F>
606 constexpr T& refOrFrom(F&& aFunc) {
607 if (isSome()) {
608 return ref();
609 }
610 return aFunc();
611 }
612
613 template <typename F>
614 constexpr const T& refOrFrom(F&& aFunc) const {
615 if (isSome()) {
616 return ref();
617 }
618 return aFunc();
619 }
620
621 constexpr T& operator*() &;
622 constexpr const T& operator*() const&;
623 constexpr T&& operator*() &&;
624 constexpr const T&& operator*() const&&;
625
626 /* If |isSome()|, runs the provided function or functor on the contents of
627 * this Maybe. */
628 template <typename Func>
629 constexpr Maybe& apply(Func&& aFunc) & {
630 if (isSome()) {
631 std::forward<Func>(aFunc)(ref());
632 }
633 return *this;
634 }
635
636 template <typename Func>
637 constexpr const Maybe& apply(Func&& aFunc) const& {
638 if (isSome()) {
639 std::forward<Func>(aFunc)(ref());
640 }
641 return *this;
642 }
643
644 template <typename Func>
645 constexpr Maybe& apply(Func&& aFunc) && {
646 if (isSome()) {
647 std::forward<Func>(aFunc)(extract());
648 }
649 return *this;
650 }
651
652 template <typename Func>
653 constexpr Maybe& apply(Func&& aFunc) const&& {
654 if (isSome()) {
655 std::forward<Func>(aFunc)(extract());
656 }
657 return *this;
658 }
659
660 /*
661 * If |isSome()|, runs the provided function and returns the result wrapped
662 * in a Maybe. If |isNothing()|, returns an empty Maybe value with the same
663 * value type as what the provided function would have returned.
664 */
665 template <typename Func>
666 constexpr auto map(Func&& aFunc) & {
667 if (isSome()) {
668 return Some(std::forward<Func>(aFunc)(ref()));
669 }
670 return Maybe<decltype(std::forward<Func>(aFunc)(ref()))>{};
671 }
672
673 template <typename Func>
674 constexpr auto map(Func&& aFunc) const& {
675 if (isSome()) {
676 return Some(std::forward<Func>(aFunc)(ref()));
677 }
678 return Maybe<decltype(std::forward<Func>(aFunc)(ref()))>{};
679 }
680
681 template <typename Func>
682 constexpr auto map(Func&& aFunc) && {
683 if (isSome()) {
684 return Some(std::forward<Func>(aFunc)(extract()));
685 }
686 return Maybe<decltype(std::forward<Func>(aFunc)(extract()))>{};
687 }
688
689 template <typename Func>
690 constexpr auto map(Func&& aFunc) const&& {
691 if (isSome()) {
692 return Some(std::forward<Func>(aFunc)(extract()));
693 }
694 return Maybe<decltype(std::forward<Func>(aFunc)(extract()))>{};
695 }
696
697 /*
698 * If |isSome()|, runs the provided function or functor on the contents of
699 * this Maybe and returns the result. Note that the provided function or
700 * functor must return a Maybe<U> of any type U.
701 * If |isNothing()|, returns an empty Maybe value with the same type as what
702 * the provided function would have returned.
703 */
704 template <typename Func>
705 constexpr auto andThen(Func&& aFunc) & {
706 static_assert(std::is_invocable_v<Func, T&>);
707 using U = std::invoke_result_t<Func, T&>;
708 static_assert(detail::IsMaybe<U>::value);
709 if (isSome()) {
710 return std::invoke(std::forward<Func>(aFunc), ref());
711 }
712 return std::remove_cv_t<std::remove_reference_t<U>>{};
713 }
714
715 template <typename Func>
716 constexpr auto andThen(Func&& aFunc) const& {
717 static_assert(std::is_invocable_v<Func, const T&>);
718 using U = std::invoke_result_t<Func, const T&>;
719 static_assert(detail::IsMaybe<U>::value);
720 if (isSome()) {
721 return std::invoke(std::forward<Func>(aFunc), ref());
722 }
723 return std::remove_cv_t<std::remove_reference_t<U>>{};
724 }
725
726 template <typename Func>
727 constexpr auto andThen(Func&& aFunc) && {
728 static_assert(std::is_invocable_v<Func, T&&>);
729 using U = std::invoke_result_t<Func, T&&>;
730 static_assert(detail::IsMaybe<U>::value);
731 if (isSome()) {
732 return std::invoke(std::forward<Func>(aFunc), extract());
733 }
734 return std::remove_cv_t<std::remove_reference_t<U>>{};
735 }
736
737 template <typename Func>
738 constexpr auto andThen(Func&& aFunc) const&& {
739 static_assert(std::is_invocable_v<Func, const T&&>);
740 using U = std::invoke_result_t<Func, const T&&>;
741 static_assert(detail::IsMaybe<U>::value);
742 if (isSome()) {
743 return std::invoke(std::forward<Func>(aFunc), extract());
744 }
745 return std::remove_cv_t<std::remove_reference_t<U>>{};
746 }
747
748 /*
749 * If |isNothing()|, runs the provided function or functor and returns its
750 * result. If |isSome()|, returns the contained value wrapped in a Maybe.
751 */
752 template <typename Func>
753 constexpr Maybe orElse(Func&& aFunc) & {
754 static_assert(std::is_invocable_v<Func>);
755 using U = std::invoke_result_t<Func>;
756 static_assert(
757 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
758 if (isSome()) {
759 return *this;
760 }
761 return std::invoke(std::forward<Func>(aFunc));
762 }
763
764 template <typename Func>
765 constexpr Maybe orElse(Func&& aFunc) const& {
766 static_assert(std::is_invocable_v<Func>);
767 using U = std::invoke_result_t<Func>;
768 static_assert(
769 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
770 if (isSome()) {
771 return *this;
772 }
773 return std::invoke(std::forward<Func>(aFunc));
774 }
775
776 template <typename Func>
777 constexpr Maybe orElse(Func&& aFunc) && {
778 static_assert(std::is_invocable_v<Func>);
779 using U = std::invoke_result_t<Func>;
780 static_assert(
781 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
782 if (isSome()) {
783 return std::move(*this);
784 }
785 return std::invoke(std::forward<Func>(aFunc));
786 }
787
788 template <typename Func>
789 constexpr Maybe orElse(Func&& aFunc) const&& {
790 static_assert(std::is_invocable_v<Func>);
791 using U = std::invoke_result_t<Func>;
792 static_assert(
793 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
794 if (isSome()) {
795 return std::move(*this);
796 }
797 return std::invoke(std::forward<Func>(aFunc));
798 }
799
800 /* If |isSome()|, empties this Maybe and destroys its contents. */
801 constexpr void reset() {
802 if (isSome()) {
803 if constexpr (!std::is_trivially_destructible_v<T>) {
804 /*
805 * Static analyzer gets confused if we have Maybe<MutexAutoLock>,
806 * so we suppress thread-safety warnings here
807 */
808 MOZ_PUSH_IGNORE_THREAD_SAFETYGCC diagnostic push GCC diagnostic ignored "-Wthread-safety"
809 ref().T::~T();
810 MOZ_POP_THREAD_SAFETYGCC diagnostic pop
811 poisonData();
812 }
813 mIsSome = false;
814 }
815 }
816
817 /*
818 * Constructs a T value in-place in this empty Maybe<T>'s storage. The
819 * arguments to |emplace()| are the parameters to T's constructor.
820 */
821 template <typename... Args>
822 constexpr void emplace(Args&&... aArgs);
823
824 template <typename U>
825 constexpr std::enable_if_t<std::is_same_v<T, U> &&
826 std::is_copy_constructible_v<U> &&
827 !std::is_move_constructible_v<U>>
828 emplace(U&& aArgs) {
829 emplace(aArgs);
830 }
831
832 friend std::ostream& operator<<(std::ostream& aStream,
833 const Maybe<T>& aMaybe) {
834 if (aMaybe) {
835 aStream << aMaybe.ref();
836 } else {
837 aStream << "<Nothing>";
838 }
839 return aStream;
840 }
841};
842
843template <typename T>
844class Maybe<T&> {
845 public:
846 constexpr Maybe() = default;
847 constexpr MOZ_IMPLICIT Maybe(Nothing) {}
848
849 void emplace(T& aRef) { mValue = &aRef; }
850
851 /* Methods that check whether this Maybe contains a value */
852 constexpr explicit operator bool() const { return isSome(); }
853 constexpr bool isSome() const { return mValue; }
854 constexpr bool isNothing() const { return !mValue; }
855
856 T& ref() const {
857 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 857); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 857; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
858 return *mValue;
859 }
860
861 T* operator->() const { return &ref(); }
862 T& operator*() const { return ref(); }
863
864 // Deliberately not defining value and ptr accessors, as these may be
865 // confusing on a reference-typed Maybe.
866
867 // XXX Should we define refOr?
868
869 void reset() { mValue = nullptr; }
870
871 template <typename Func>
872 const Maybe& apply(Func&& aFunc) const {
873 if (isSome()) {
874 std::forward<Func>(aFunc)(ref());
875 }
876 return *this;
877 }
878
879 template <typename Func>
880 auto map(Func&& aFunc) const {
881 Maybe<decltype(std::forward<Func>(aFunc)(ref()))> val;
882 if (isSome()) {
883 val.emplace(std::forward<Func>(aFunc)(ref()));
884 }
885 return val;
886 }
887
888 template <typename Func>
889 constexpr auto andThen(Func&& aFunc) const {
890 static_assert(std::is_invocable_v<Func, T&>);
891 using U = std::invoke_result_t<Func, T&>;
892 static_assert(detail::IsMaybe<U>::value);
893 if (isSome()) {
894 return std::invoke(std::forward<Func>(aFunc), ref());
895 }
896 return std::remove_cv_t<std::remove_reference_t<U>>{};
897 }
898
899 template <typename Func>
900 constexpr Maybe orElse(Func&& aFunc) const {
901 static_assert(std::is_invocable_v<Func>);
902 using U = std::invoke_result_t<Func>;
903 static_assert(
904 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
905 if (isSome()) {
906 return *this;
907 }
908 return std::invoke(std::forward<Func>(aFunc));
909 }
910
911 bool refEquals(const Maybe<T&>& aOther) const {
912 return mValue == aOther.mValue;
913 }
914
915 bool refEquals(const T& aOther) const { return mValue == &aOther; }
916
917 private:
918 T* mValue = nullptr;
919};
920
921template <typename T>
922constexpr T Maybe<T>::value() const& {
923 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 923); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 923; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
924 return ref();
925}
926
927template <typename T>
928constexpr T Maybe<T>::value() && {
929 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 929); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 929; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
930 return std::move(ref());
931}
932
933template <typename T>
934constexpr T Maybe<T>::value() const&& {
935 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 935); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 935; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
936 return std::move(ref());
937}
938
939template <typename T>
940T* Maybe<T>::ptr() {
941 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 941); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 941; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
942 return &ref();
943}
944
945template <typename T>
946constexpr const T* Maybe<T>::ptr() const {
947 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 947); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 947; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
948 return &ref();
949}
950
951template <typename T>
952constexpr T* Maybe<T>::operator->() {
953 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 953); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 953; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
954 return ptr();
955}
956
957template <typename T>
958constexpr const T* Maybe<T>::operator->() const {
959 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 959); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 959; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
960 return ptr();
961}
962
963template <typename T>
964constexpr T& Maybe<T>::ref() & {
965 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 965); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 965; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
966 return mStorage.val;
967}
968
969template <typename T>
970constexpr const T& Maybe<T>::ref() const& {
971 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 971); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 971; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
972 return mStorage.val;
973}
974
975template <typename T>
976constexpr T&& Maybe<T>::ref() && {
977 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 977); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 977; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
978 return std::move(mStorage.val);
979}
980
981template <typename T>
982constexpr const T&& Maybe<T>::ref() const&& {
983 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 983); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 983; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
984 return std::move(mStorage.val);
985}
986
987template <typename T>
988constexpr T& Maybe<T>::operator*() & {
989 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 989); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 989; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
990 return ref();
991}
992
993template <typename T>
994constexpr const T& Maybe<T>::operator*() const& {
995 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 995); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 995; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
996 return ref();
997}
998
999template <typename T>
1000constexpr T&& Maybe<T>::operator*() && {
1001 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 1001); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 1001; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1002 return std::move(ref());
1003}
1004
1005template <typename T>
1006constexpr const T&& Maybe<T>::operator*() const&& {
1007 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 1007); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 1007; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1008 return std::move(ref());
1009}
1010
1011template <typename T>
1012template <typename... Args>
1013constexpr void Maybe<T>::emplace(Args&&... aArgs) {
1014 MOZ_RELEASE_ASSERT(!isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 1014); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!isSome()"
")"); do { *((volatile int*)__null) = 1014; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1015 ::new (KnownNotNull, &mStorage.val) T(std::forward<Args>(aArgs)...);
1016 mIsSome = true;
1017}
1018
1019/*
1020 * Some() creates a Maybe<T> value containing the provided T value. If T has a
1021 * move constructor, it's used to make this as efficient as possible.
1022 *
1023 * Some() selects the type of Maybe it returns by removing any const, volatile,
1024 * or reference qualifiers from the type of the value you pass to it. This gives
1025 * it more intuitive behavior when used in expressions, but it also means that
1026 * if you need to construct a Maybe value that holds a const, volatile, or
1027 * reference value, you need to use emplace() instead.
1028 */
1029template <typename T, typename U>
1030constexpr Maybe<U> Some(T&& aValue) {
1031 return {std::forward<T>(aValue), typename Maybe<U>::SomeGuard{}};
1032}
1033
1034template <typename T>
1035constexpr Maybe<T&> SomeRef(T& aValue) {
1036 Maybe<T&> value;
1037 value.emplace(aValue);
1038 return value;
1039}
1040
1041template <typename T>
1042constexpr Maybe<T&> ToMaybeRef(T* const aPtr) {
1043 return aPtr ? SomeRef(*aPtr) : Nothing{};
1044}
1045
1046template <typename T>
1047Maybe<std::remove_cv_t<std::remove_reference_t<T>>> ToMaybe(T* aPtr) {
1048 if (aPtr) {
1049 return Some(*aPtr);
1050 }
1051 return Nothing();
1052}
1053
1054/*
1055 * Two Maybe<T> values are equal if
1056 * - both are Nothing, or
1057 * - both are Some, and the values they contain are equal.
1058 */
1059template <typename T>
1060constexpr bool operator==(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1061 static_assert(!std::is_reference_v<T>,
1062 "operator== is not defined for Maybe<T&>, compare values or "
1063 "addresses explicitly instead");
1064 if (aLHS.isNothing() != aRHS.isNothing()) {
1065 return false;
1066 }
1067 return aLHS.isNothing() || *aLHS == *aRHS;
1068}
1069
1070template <typename T>
1071constexpr bool operator!=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1072 return !(aLHS == aRHS);
1073}
1074
1075/*
1076 * We support comparison to Nothing to allow reasonable expressions like:
1077 * if (maybeValue == Nothing()) { ... }
1078 */
1079template <typename T>
1080constexpr bool operator==(const Maybe<T>& aLHS, const Nothing& aRHS) {
1081 return aLHS.isNothing();
1082}
1083
1084template <typename T>
1085constexpr bool operator!=(const Maybe<T>& aLHS, const Nothing& aRHS) {
1086 return !(aLHS == aRHS);
1087}
1088
1089template <typename T>
1090constexpr bool operator==(const Nothing& aLHS, const Maybe<T>& aRHS) {
1091 return aRHS.isNothing();
1092}
1093
1094template <typename T>
1095constexpr bool operator!=(const Nothing& aLHS, const Maybe<T>& aRHS) {
1096 return !(aLHS == aRHS);
1097}
1098
1099/*
1100 * Maybe<T> values are ordered in the same way T values are ordered, except that
1101 * Nothing comes before anything else.
1102 */
1103template <typename T>
1104constexpr bool operator<(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1105 if (aLHS.isNothing()) {
1106 return aRHS.isSome();
1107 }
1108 if (aRHS.isNothing()) {
1109 return false;
1110 }
1111 return *aLHS < *aRHS;
1112}
1113
1114template <typename T>
1115constexpr bool operator>(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1116 return !(aLHS < aRHS || aLHS == aRHS);
1117}
1118
1119template <typename T>
1120constexpr bool operator<=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1121 return aLHS < aRHS || aLHS == aRHS;
1122}
1123
1124template <typename T>
1125constexpr bool operator>=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1126 return !(aLHS < aRHS);
1127}
1128
1129template <typename T>
1130inline void ImplCycleCollectionTraverse(
1131 nsCycleCollectionTraversalCallback& aCallback, mozilla::Maybe<T>& aField,
1132 const char* aName, uint32_t aFlags = 0) {
1133 if (aField) {
1134 ImplCycleCollectionTraverse(aCallback, aField.ref(), aName, aFlags);
1135 }
1136}
1137
1138template <typename T>
1139inline void ImplCycleCollectionUnlink(mozilla::Maybe<T>& aField) {
1140 if (aField) {
1141 ImplCycleCollectionUnlink(aField.ref());
1142 }
1143}
1144
1145} // namespace mozilla
1146
1147#endif /* mozilla_Maybe_h */

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MaybeStorageBase.h

1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7/* Internal storage class used e.g. by Maybe and Result. This file doesn't
8 * contain any public declarations. */
9
10#ifndef mfbt_MaybeStorageBase_h
11#define mfbt_MaybeStorageBase_h
12
13#include <type_traits>
14#include <utility>
15
16namespace mozilla::detail {
17
18template <typename T>
19constexpr bool IsTriviallyDestructibleAndCopyable =
20 std::is_trivially_destructible_v<T> &&
21 (std::is_trivially_copy_constructible_v<T> ||
22 !std::is_copy_constructible_v<T>);
23
24template <typename T, bool TriviallyDestructibleAndCopyable =
25 IsTriviallyDestructibleAndCopyable<T>>
26struct MaybeStorageBase;
27
28template <typename T>
29struct MaybeStorageBase<T, false> {
30 protected:
31 using NonConstT = std::remove_const_t<T>;
32
33 union Union {
34 Union() {}
9
Returning without writing to 'this->val.mStartTime.mValue'
35 explicit Union(const T& aVal) : val{aVal} {}
36 template <typename U,
37 typename = std::enable_if_t<std::is_move_constructible_v<U>>>
38 explicit Union(U&& aVal) : val{std::forward<U>(aVal)} {}
39 template <typename... Args>
40 explicit Union(std::in_place_t, Args&&... aArgs)
41 : val{std::forward<Args>(aArgs)...} {}
42
43 ~Union() {}
24
Calling '~AutoProfileRunnable'
44
45 NonConstT val;
46 } mStorage;
47
48 public:
49 MaybeStorageBase() = default;
8
Calling default constructor for 'Union'
10
Returning from default constructor for 'Union'
11
Returning without writing to 'this->mStorage.val.mStartTime.mValue'
50 explicit MaybeStorageBase(const T& aVal) : mStorage{aVal} {}
51 explicit MaybeStorageBase(T&& aVal) : mStorage{std::move(aVal)} {}
52 template <typename... Args>
53 explicit MaybeStorageBase(std::in_place_t, Args&&... aArgs)
54 : mStorage{std::in_place, std::forward<Args>(aArgs)...} {}
55
56 const T* addr() const { return &mStorage.val; }
57 T* addr() { return &mStorage.val; }
58};
59
60template <typename T>
61struct MaybeStorageBase<T, true> {
62 protected:
63 using NonConstT = std::remove_const_t<T>;
64
65 union Union {
66 constexpr Union() : dummy() {}
67 constexpr explicit Union(const T& aVal) : val{aVal} {}
68 constexpr explicit Union(T&& aVal) : val{std::move(aVal)} {}
69 template <typename... Args>
70 constexpr explicit Union(std::in_place_t, Args&&... aArgs)
71 : val{std::forward<Args>(aArgs)...} {}
72
73 NonConstT val;
74 char dummy;
75 } mStorage;
76
77 public:
78 constexpr MaybeStorageBase() = default;
79 constexpr explicit MaybeStorageBase(const T& aVal) : mStorage{aVal} {}
80 constexpr explicit MaybeStorageBase(T&& aVal) : mStorage{std::move(aVal)} {}
81
82 template <typename... Args>
83 constexpr explicit MaybeStorageBase(std::in_place_t, Args&&... aArgs)
84 : mStorage{std::in_place, std::forward<Args>(aArgs)...} {}
85
86 constexpr const T* addr() const { return &mStorage.val; }
87 constexpr T* addr() { return &mStorage.val; }
88};
89
90} // namespace mozilla::detail
91
92#endif

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/dom/BlobURLProtocolHandler.h

1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#ifndef mozilla_dom_BlobURLProtocolHandler_h
8#define mozilla_dom_BlobURLProtocolHandler_h
9
10#include "mozilla/Attributes.h"
11#include "nsIProtocolHandler.h"
12#include "nsIURI.h"
13#include "nsCOMPtr.h"
14#include "nsTArray.h"
15#include "nsWeakReference.h"
16#include <functional>
17
18#define BLOBURI_SCHEME"blob" "blob"
19
20class nsIPrincipal;
21
22namespace mozilla {
23class BlobURLsReporter;
24class OriginAttributes;
25template <class T>
26class Maybe;
27
28namespace dom {
29
30class BlobImpl;
31class BlobURLRegistrationData;
32class ContentParent;
33class MediaSource;
34
35class BlobURLProtocolHandler final : public nsIProtocolHandler,
36 public nsSupportsWeakReference {
37 public:
38 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
39 NS_DECL_NSIPROTOCOLHANDLERvirtual nsresult GetScheme(nsACString& aScheme) override;
virtual nsresult NewChannel(nsIURI *aURI, nsILoadInfo *aLoadinfo
, nsIChannel **_retval) override; virtual nsresult AllowPort(
int32_t port, const char * scheme, bool *_retval) override;
40
41 BlobURLProtocolHandler();
42
43 static nsresult CreateNewURI(const nsACString& aSpec, const char* aCharset,
44 nsIURI* aBaseURI, nsIURI** result);
45
46 // Methods for managing uri->object mapping
47 // AddDataEntry creates the URI with the given scheme and returns it in aUri
48 static nsresult AddDataEntry(BlobImpl*, nsIPrincipal*,
49 const nsCString& aPartitionKey,
50 nsACString& aUri);
51 static nsresult AddDataEntry(MediaSource*, nsIPrincipal*,
52 const nsCString& aPartitionKey,
53 nsACString& aUri);
54 // IPC only
55 static void AddDataEntry(const nsACString& aURI, nsIPrincipal* aPrincipal,
56 const nsCString& aPartitionKey, BlobImpl* aBlobImpl);
57
58 // These methods revoke a blobURL. Because some operations could still be in
59 // progress, the revoking consists in marking the blobURL as revoked and in
60 // removing it after RELEASING_TIMER milliseconds.
61 static void RemoveDataEntry(const nsACString& aUri,
62 bool aBroadcastToOTherProcesses = true);
63 // Returns true if the entry was allowed to be removed.
64 static bool RemoveDataEntry(const nsACString& aUri, nsIPrincipal* aPrincipal,
65 const nsCString& aPartitionKey);
66
67 static void RemoveDataEntries();
68
69 static bool HasDataEntry(const nsACString& aUri);
70
71 static bool GetDataEntry(const nsACString& aUri, BlobImpl** aBlobImpl,
72 nsIPrincipal* aLoadingPrincipal,
73 nsIPrincipal* aTriggeringPrincipal,
74 const OriginAttributes& aOriginAttributes,
75 uint64_t aInnerWindowId,
76 const nsCString& aPartitionKey,
77 bool aAlsoIfRevoked = false);
78
79 static void Traverse(const nsACString& aUri,
80 nsCycleCollectionTraversalCallback& aCallback);
81
82 // Main-thread only method to invoke a helper function that gets called for
83 // every known and recently revoked Blob URL. The helper function should
84 // return true to keep going or false to stop enumerating (presumably because
85 // of an unexpected XPCOM or IPC error). This method returns false if already
86 // shutdown or if the helper method returns false, true otherwise.
87 static bool ForEachBlobURL(
88 std::function<bool(BlobImpl*, nsIPrincipal*, const nsCString&,
89 const nsACString&, bool aRevoked)>&& aCb);
90
91 // This method returns false if aURI is not a known BlobURL. Otherwise it
92 // returns true.
93 //
94 // When true is returned, the aPrincipal out param is meaningful. It gets
95 // set to the principal that a channel loaded from the blob would get if
96 // the blob is not already revoked and to a NullPrincipal if the blob is
97 // revoked.
98 //
99 // This means that for a revoked blob URL this method may either return
100 // false or return true and hand out a NullPrincipal in aPrincipal,
101 // depending on whether the "remove it from the hashtable" timer has
102 // fired. See RemoveDataEntry().
103 static bool GetBlobURLPrincipal(nsIURI* aURI, nsIPrincipal** aPrincipal);
104
105 // Check if metadata about Blob URLs created with this principal should be
106 // broadcast into every content process. This is currently the case for
107 // extension blob URLs and system principal blob URLs, as they can be loaded
108 // by system code and content scripts respectively.
109 static bool IsBlobURLBroadcastPrincipal(nsIPrincipal* aPrincipal);
110
111 private:
112 ~BlobURLProtocolHandler();
113
114 static void Init();
115
116 // If principal is not null, its origin will be used to generate the URI.
117 static nsresult GenerateURIString(nsIPrincipal* aPrincipal, nsACString& aUri);
118};
119
120bool IsBlobURI(nsIURI* aUri);
121bool IsMediaSourceURI(nsIURI* aUri);
122
123// Return true if inner scheme of blobURL is http or https, false otherwise.
124bool BlobURLSchemeIsHTTPOrHTTPS(const nsACString& aUri);
125
126} // namespace dom
127} // namespace mozilla
128
129extern nsresult NS_GetBlobForBlobURI(nsIURI* aURI,
130 mozilla::dom::BlobImpl** aBlob);
131
132extern nsresult NS_GetBlobForBlobURISpec(const nsACString& aSpec,
133 mozilla::dom::BlobImpl** aBlob,
134 bool aAlsoIfRevoked = false);
135
136extern nsresult NS_SetChannelContentRangeForBlobURI(nsIChannel* aChannel,
137 nsIURI* aURI,
138 nsACString& aRangeHeader);
139
140extern nsresult NS_GetSourceForMediaSourceURI(
141 nsIURI* aURI, mozilla::dom::MediaSource** aSource);
142
143#endif /* mozilla_dom_BlobURLProtocolHandler_h */

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/ProfilerRunnable.h

1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#ifndef ProfilerRunnable_h
8#define ProfilerRunnable_h
9
10#include "GeckoProfiler.h"
11#include "nsIThreadPool.h"
12
13#if !defined(MOZ_GECKO_PROFILER1) || !defined(MOZ_COLLECTING_RUNNABLE_TELEMETRY)
14# define AUTO_PROFILE_FOLLOWING_RUNNABLE(runnable)mozilla::Maybe<mozilla::AutoProfileRunnable> raiiRunnableMarker
; if (profiler_thread_is_being_profiled_for_markers()) { raiiRunnableMarker
.emplace(runnable); }
15#else
16# define AUTO_PROFILE_FOLLOWING_RUNNABLE(runnable)mozilla::Maybe<mozilla::AutoProfileRunnable> raiiRunnableMarker
; if (profiler_thread_is_being_profiled_for_markers()) { raiiRunnableMarker
.emplace(runnable); }
\
17 mozilla::Maybe<mozilla::AutoProfileRunnable> raiiRunnableMarker; \
18 if (profiler_thread_is_being_profiled_for_markers()) { \
19 raiiRunnableMarker.emplace(runnable); \
20 }
21
22namespace mozilla {
23
24class MOZ_RAII AutoProfileRunnable {
25 public:
26 explicit AutoProfileRunnable(Runnable* aRunnable)
27 : mStartTime(TimeStamp::Now()) {
28 aRunnable->GetName(mName);
29 }
30 explicit AutoProfileRunnable(nsIRunnable* aRunnable)
31 : mStartTime(TimeStamp::Now()) {
32 nsCOMPtr<nsIThreadPool> threadPool = do_QueryInterface(aRunnable);
33 if (threadPool) {
34 // nsThreadPool::Run has its own call to AUTO_PROFILE_FOLLOWING_RUNNABLE,
35 // avoid nesting runnable markers.
36 return;
37 }
38
39 nsCOMPtr<nsINamed> named = do_QueryInterface(aRunnable);
40 if (named) {
41 named->GetName(mName);
42 }
43 }
44 explicit AutoProfileRunnable(nsACString& aName)
45 : mStartTime(TimeStamp::Now()), mName(aName) {}
46
47 ~AutoProfileRunnable() {
48 if (mName.IsEmpty()) {
25
Assuming the condition is false
26
Taking false branch
49 return;
50 }
51
52 AUTO_PROFILER_LABEL("AutoProfileRunnable", PROFILER)mozilla::AutoProfilerLabel raiiObject52( "AutoProfileRunnable"
, nullptr, JS::ProfilingCategoryPair::PROFILER)
;
53 AUTO_PROFILER_STATS(AUTO_PROFILE_RUNNABLE);
54 profiler_add_marker("Runnable", ::mozilla::baseprofiler::category::OTHER,do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Runnable", ::mozilla::baseprofiler::category::OTHER, MarkerTiming
::IntervalUntilNowFrom(mStartTime), geckoprofiler::markers::TextMarker
{}, mName); } } while (false)
27
Taking true branch
28
Calling 'MarkerTiming::IntervalUntilNowFrom'
55 MarkerTiming::IntervalUntilNowFrom(mStartTime),do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Runnable", ::mozilla::baseprofiler::category::OTHER, MarkerTiming
::IntervalUntilNowFrom(mStartTime), geckoprofiler::markers::TextMarker
{}, mName); } } while (false)
56 geckoprofiler::markers::TextMarker{}, mName)do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Runnable", ::mozilla::baseprofiler::category::OTHER, MarkerTiming
::IntervalUntilNowFrom(mStartTime), geckoprofiler::markers::TextMarker
{}, mName); } } while (false)
;
57 }
58
59 protected:
60 TimeStamp mStartTime;
61 nsAutoCString mName;
62};
63
64} // namespace mozilla
65
66#endif
67
68#endif // ProfilerRunnable_h

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h

1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7// This header contains basic definitions required to create marker types, and
8// to add markers to the profiler buffers.
9//
10// In most cases, #include "mozilla/BaseProfilerMarkers.h" instead, or
11// #include "mozilla/BaseProfilerMarkerTypes.h" for common marker types.
12
13#ifndef BaseProfilerMarkersPrerequisites_h
14#define BaseProfilerMarkersPrerequisites_h
15
16namespace mozilla {
17
18enum class StackCaptureOptions {
19 NoStack, // No stack captured.
20 Full, // Capture a full stack, including label frames, JS frames and
21 // native frames.
22 NonNative, // Capture a stack without native frames for reduced overhead.
23};
24
25}
26
27#include "BaseProfileJSONWriter.h"
28#include "BaseProfilingCategory.h"
29#include "mozilla/Maybe.h"
30#include "mozilla/ProfileChunkedBuffer.h"
31#include "mozilla/BaseProfilerState.h"
32#include "mozilla/TimeStamp.h"
33#include "mozilla/UniquePtr.h"
34#include "mozilla/Variant.h"
35
36#include <initializer_list>
37#include <string_view>
38#include <string>
39#include <type_traits>
40#include <utility>
41#include <vector>
42
43namespace mozilla {
44
45// Return a NotNull<const CHAR*> pointing at the literal empty string `""`.
46template <typename CHAR>
47constexpr const CHAR* LiteralEmptyStringPointer() {
48 static_assert(std::is_same_v<CHAR, char> || std::is_same_v<CHAR, char16_t>,
49 "Only char and char16_t are supported in Firefox");
50 if constexpr (std::is_same_v<CHAR, char>) {
51 return "";
52 }
53 if constexpr (std::is_same_v<CHAR, char16_t>) {
54 return u"";
55 }
56}
57
58// Return a string_view<CHAR> pointing at the literal empty string.
59template <typename CHAR>
60constexpr std::basic_string_view<CHAR> LiteralEmptyStringView() {
61 static_assert(std::is_same_v<CHAR, char> || std::is_same_v<CHAR, char16_t>,
62 "Only char and char16_t are supported in Firefox");
63 // Use `operator""sv()` from <string_view>.
64 using namespace std::literals::string_view_literals;
65 if constexpr (std::is_same_v<CHAR, char>) {
66 return ""sv;
67 }
68 if constexpr (std::is_same_v<CHAR, char16_t>) {
69 return u""sv;
70 }
71}
72
73// General string view, optimized for short on-stack life before serialization,
74// and between deserialization and JSON-streaming.
75template <typename CHAR>
76class MOZ_STACK_CLASS ProfilerStringView {
77 public:
78 // Default constructor points at "" (literal empty string).
79 constexpr ProfilerStringView() = default;
80
81 // Don't allow copy.
82 ProfilerStringView(const ProfilerStringView&) = delete;
83 ProfilerStringView& operator=(const ProfilerStringView&) = delete;
84
85 // Allow move. For consistency the moved-from string is always reset to "".
86 constexpr ProfilerStringView(ProfilerStringView&& aOther)
87 : mStringView(std::move(aOther.mStringView)),
88 mOwnership(aOther.mOwnership) {
89 if (mOwnership == Ownership::OwnedThroughStringView) {
90 // We now own the buffer, make the other point at the literal "".
91 aOther.mStringView = LiteralEmptyStringView<CHAR>();
92 aOther.mOwnership = Ownership::Literal;
93 }
94 }
95 constexpr ProfilerStringView& operator=(ProfilerStringView&& aOther) {
96 mStringView = std::move(aOther.mStringView);
97 mOwnership = aOther.mOwnership;
98 if (mOwnership == Ownership::OwnedThroughStringView) {
99 // We now own the buffer, make the other point at the literal "".
100 aOther.mStringView = LiteralEmptyStringView<CHAR>();
101 aOther.mOwnership = Ownership::Literal;
102 }
103 return *this;
104 }
105
106 ~ProfilerStringView() {
107 if (MOZ_UNLIKELY(mOwnership == Ownership::OwnedThroughStringView)(__builtin_expect(!!(mOwnership == Ownership::OwnedThroughStringView
), 0))
) {
108 // We own the buffer pointed at by mStringView, destroy it.
109 // This is only used between deserialization and streaming.
110 delete mStringView.data();
111 }
112 }
113
114 // Implicit construction from nullptr, points at "" (literal empty string).
115 constexpr MOZ_IMPLICIT ProfilerStringView(decltype(nullptr)) {}
116
117 // Implicit constructor from a literal string.
118 template <size_t Np1>
119 constexpr MOZ_IMPLICIT ProfilerStringView(const CHAR (&aLiteralString)[Np1])
120 : ProfilerStringView(aLiteralString, Np1 - 1, Ownership::Literal) {}
121
122 // Constructor from a non-literal string.
123 constexpr ProfilerStringView(const CHAR* aString, size_t aLength)
124 : ProfilerStringView(aString, aLength, Ownership::Reference) {}
125
126 // Implicit constructor from a string_view.
127 constexpr MOZ_IMPLICIT ProfilerStringView(
128 const std::basic_string_view<CHAR>& aStringView)
129 : ProfilerStringView(aStringView.data(), aStringView.length(),
130 Ownership::Reference) {}
131
132 // Implicit constructor from an expiring string_view. We assume that the
133 // pointed-at string will outlive this ProfilerStringView.
134 constexpr MOZ_IMPLICIT ProfilerStringView(
135 std::basic_string_view<CHAR>&& aStringView)
136 : ProfilerStringView(aStringView.data(), aStringView.length(),
137 Ownership::Reference) {}
138
139 // Implicit constructor from std::string.
140 constexpr MOZ_IMPLICIT ProfilerStringView(
141 const std::basic_string<CHAR>& aString)
142 : ProfilerStringView(aString.data(), aString.length(),
143 Ownership::Reference) {}
144
145 // Construction from a raw pointer to a null-terminated string.
146 // This is a named class-static function to make it more obvious where work is
147 // being done (to determine the string length), and encourage users to instead
148 // provide a length, if already known.
149 // TODO: Find callers and convert them to constructor instead if possible.
150 static constexpr ProfilerStringView WrapNullTerminatedString(
151 const CHAR* aString) {
152 return ProfilerStringView(
153 aString, aString ? std::char_traits<CHAR>::length(aString) : 0,
154 Ownership::Reference);
155 }
156
157 // Implicit constructor for an object with member functions `Data()`
158 // `Length()`, and `IsLiteral()`, common in xpcom strings.
159 template <
160 typename String,
161 typename DataReturnType = decltype(std::declval<const String>().Data()),
162 typename LengthReturnType =
163 decltype(std::declval<const String>().Length()),
164 typename IsLiteralReturnType =
165 decltype(std::declval<const String>().IsLiteral()),
166 typename =
167 std::enable_if_t<std::is_convertible_v<DataReturnType, const CHAR*> &&
168 std::is_integral_v<LengthReturnType> &&
169 std::is_same_v<IsLiteralReturnType, bool>>>
170 constexpr MOZ_IMPLICIT ProfilerStringView(const String& aString)
171 : ProfilerStringView(
172 static_cast<const CHAR*>(aString.Data()), aString.Length(),
173 aString.IsLiteral() ? Ownership::Literal : Ownership::Reference) {}
174
175 [[nodiscard]] constexpr const std::basic_string_view<CHAR>& StringView()
176 const {
177 return mStringView;
178 }
179
180 [[nodiscard]] constexpr size_t Length() const { return mStringView.length(); }
181
182 [[nodiscard]] constexpr bool IsLiteral() const {
183 return mOwnership == Ownership::Literal;
184 }
185 [[nodiscard]] constexpr bool IsReference() const {
186 return mOwnership == Ownership::Reference;
187 }
188 // No `IsOwned...()` because it's a secret, only used internally!
189
190 [[nodiscard]] Span<const CHAR> AsSpan() const {
191 return Span<const CHAR>(mStringView.data(), mStringView.length());
192 }
193 [[nodiscard]] operator Span<const CHAR>() const { return AsSpan(); }
194
195 private:
196 enum class Ownership { Literal, Reference, OwnedThroughStringView };
197
198 // Allow deserializer to store anything here.
199 friend ProfileBufferEntryReader::Deserializer<ProfilerStringView>;
200
201 constexpr ProfilerStringView(const CHAR* aString, size_t aLength,
202 Ownership aOwnership)
203 : mStringView(aString ? std::basic_string_view<CHAR>(aString, aLength)
204 : LiteralEmptyStringView<CHAR>()),
205 mOwnership(aString ? aOwnership : Ownership::Literal) {}
206
207 // String view to an outside string (literal or reference).
208 // We may actually own the pointed-at buffer, but it is only used internally
209 // between deserialization and JSON streaming.
210 std::basic_string_view<CHAR> mStringView = LiteralEmptyStringView<CHAR>();
211
212 Ownership mOwnership = Ownership::Literal;
213};
214
215using ProfilerString8View = ProfilerStringView<char>;
216using ProfilerString16View = ProfilerStringView<char16_t>;
217
218// This compulsory marker parameter contains the required category information.
219class MarkerCategory {
220 public:
221 // Constructor from category pair (includes both super- and sub-categories).
222 constexpr explicit MarkerCategory(
223 baseprofiler::ProfilingCategoryPair aCategoryPair)
224 : mCategoryPair(aCategoryPair) {}
225
226 // Returns the stored category pair.
227 constexpr baseprofiler::ProfilingCategoryPair CategoryPair() const {
228 return mCategoryPair;
229 }
230
231 // Returns the super-category from the stored category pair.
232 baseprofiler::ProfilingCategory GetCategory() const {
233 return GetProfilingCategoryPairInfo(mCategoryPair).mCategory;
234 }
235
236 private:
237 baseprofiler::ProfilingCategoryPair mCategoryPair =
238 baseprofiler::ProfilingCategoryPair::OTHER;
239};
240
241namespace baseprofiler::category {
242
243// Each category pair name constructs a MarkerCategory.
244// E.g.: mozilla::baseprofiler::category::OTHER_Profiling
245// Profiler macros will take the category name alone without namespace.
246// E.g.: `PROFILER_MARKER_UNTYPED("name", OTHER_Profiling)`
247#define CATEGORY_ENUM_BEGIN_CATEGORY(name, labelAsString, color)
248#define CATEGORY_ENUM_SUBCATEGORY(supercategory, name, labelAsString) \
249 static constexpr MarkerCategory name{ProfilingCategoryPair::name};
250#define CATEGORY_ENUM_END_CATEGORY
251MOZ_PROFILING_CATEGORY_LIST(CATEGORY_ENUM_BEGIN_CATEGORY,CATEGORY_ENUM_BEGIN_CATEGORY(IDLE, "Idle", "transparent") CATEGORY_ENUM_SUBCATEGORY
(IDLE, IDLE, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(OTHER, "Other", "grey") CATEGORY_ENUM_SUBCATEGORY(OTHER, OTHER
, "Other") CATEGORY_ENUM_SUBCATEGORY(OTHER, OTHER_PreferenceRead
, "Preference Read") CATEGORY_ENUM_SUBCATEGORY(OTHER, OTHER_Profiling
, "Profiling") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(TEST, "Test", "darkgray") CATEGORY_ENUM_SUBCATEGORY(TEST, TEST
, "Test") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(LAYOUT, "Layout", "purple") CATEGORY_ENUM_SUBCATEGORY(LAYOUT
, LAYOUT, "Other") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_FrameConstruction
, "Frame construction") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_Reflow
, "Reflow") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_CSSParsing
, "CSS parsing") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_SelectorQuery
, "Selector query") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_StyleComputation
, "Style computation") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_Destroy
, "Layout cleanup") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_Printing
, "Printing") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(JS, "JavaScript", "yellow") CATEGORY_ENUM_SUBCATEGORY(JS, JS
, "Other") CATEGORY_ENUM_SUBCATEGORY(JS, JS_Parsing, "Parsing"
) CATEGORY_ENUM_SUBCATEGORY(JS, JS_BaselineCompilation, "JIT Compile (baseline)"
) CATEGORY_ENUM_SUBCATEGORY(JS, JS_IonCompilation, "JIT Compile (ion)"
) CATEGORY_ENUM_SUBCATEGORY(JS, JS_Interpreter, "Interpreter"
) CATEGORY_ENUM_SUBCATEGORY(JS, JS_BaselineInterpret, "JIT (baseline-interpreter)"
) CATEGORY_ENUM_SUBCATEGORY(JS, JS_Baseline, "JIT (baseline)"
) CATEGORY_ENUM_SUBCATEGORY(JS, JS_IonMonkey, "JIT (ion)") CATEGORY_ENUM_SUBCATEGORY
(JS, JS_Builtin, "Builtin API") CATEGORY_ENUM_SUBCATEGORY(JS,
JS_WasmIon, "Wasm (ion)") CATEGORY_ENUM_SUBCATEGORY(JS, JS_WasmBaseline
, "Wasm (baseline)") CATEGORY_ENUM_SUBCATEGORY(JS, JS_WasmOther
, "Wasm (other)") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(GCCC, "GC / CC", "orange") CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC
, "Other") CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_MinorGC, "Minor GC"
) CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_MajorGC, "Major GC (Other)"
) CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_MajorGC_Mark, "Major GC (Mark)"
) CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_MajorGC_Sweep, "Major GC (Sweep)"
) CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_MajorGC_Compact, "Major GC (Compact)"
) CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_UnmarkGray, "Unmark Gray"
) CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_Barrier, "Barrier") CATEGORY_ENUM_SUBCATEGORY
(GCCC, GCCC_FreeSnowWhite, "CC (Free Snow White)") CATEGORY_ENUM_SUBCATEGORY
(GCCC, GCCC_BuildGraph, "CC (Build Graph)") CATEGORY_ENUM_SUBCATEGORY
(GCCC, GCCC_ScanRoots, "CC (Scan Roots)") CATEGORY_ENUM_SUBCATEGORY
(GCCC, GCCC_CollectWhite, "CC (Collect White)") CATEGORY_ENUM_SUBCATEGORY
(GCCC, GCCC_Finalize, "CC (Finalize)") CATEGORY_ENUM_END_CATEGORY
CATEGORY_ENUM_BEGIN_CATEGORY(NETWORK, "Network", "lightblue"
) CATEGORY_ENUM_SUBCATEGORY(NETWORK, NETWORK, "Other") CATEGORY_ENUM_END_CATEGORY
CATEGORY_ENUM_BEGIN_CATEGORY(GRAPHICS, "Graphics", "green") CATEGORY_ENUM_SUBCATEGORY
(GRAPHICS, GRAPHICS, "Other") CATEGORY_ENUM_SUBCATEGORY(GRAPHICS
, GRAPHICS_DisplayListBuilding, "DisplayList building") CATEGORY_ENUM_SUBCATEGORY
(GRAPHICS, GRAPHICS_DisplayListMerging, "DisplayList merging"
) CATEGORY_ENUM_SUBCATEGORY(GRAPHICS, GRAPHICS_LayerBuilding,
"Layer building") CATEGORY_ENUM_SUBCATEGORY(GRAPHICS, GRAPHICS_TileAllocation
, "Tile allocation") CATEGORY_ENUM_SUBCATEGORY(GRAPHICS, GRAPHICS_WRDisplayList
, "WebRender display list") CATEGORY_ENUM_SUBCATEGORY(GRAPHICS
, GRAPHICS_Rasterization, "Rasterization") CATEGORY_ENUM_SUBCATEGORY
(GRAPHICS, GRAPHICS_FlushingAsyncPaints, "Flushing async paints"
) CATEGORY_ENUM_SUBCATEGORY(GRAPHICS, GRAPHICS_ImageDecoding,
"Image decoding") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(DOM, "DOM", "blue") CATEGORY_ENUM_SUBCATEGORY(DOM, DOM, "Other"
) CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY(JAVA_ANDROID
, "Android", "yellow") CATEGORY_ENUM_SUBCATEGORY(JAVA_ANDROID
, JAVA_ANDROID, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(JAVA_ANDROIDX, "AndroidX", "orange") CATEGORY_ENUM_SUBCATEGORY
(JAVA_ANDROIDX, JAVA_ANDROIDX, "Other") CATEGORY_ENUM_END_CATEGORY
CATEGORY_ENUM_BEGIN_CATEGORY(JAVA_LANGUAGE, "Java", "blue") CATEGORY_ENUM_SUBCATEGORY
(JAVA_LANGUAGE, JAVA_LANGUAGE, "Other") CATEGORY_ENUM_END_CATEGORY
CATEGORY_ENUM_BEGIN_CATEGORY(JAVA_MOZILLA, "Mozilla", "green"
) CATEGORY_ENUM_SUBCATEGORY(JAVA_MOZILLA, JAVA_MOZILLA, "Other"
) CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY(JAVA_KOTLIN
, "Kotlin", "purple") CATEGORY_ENUM_SUBCATEGORY(JAVA_KOTLIN, JAVA_KOTLIN
, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(JAVA_BLOCKED, "Blocked", "lightblue") CATEGORY_ENUM_SUBCATEGORY
(JAVA_BLOCKED, JAVA_BLOCKED, "Other") CATEGORY_ENUM_END_CATEGORY
CATEGORY_ENUM_BEGIN_CATEGORY(IPC, "IPC", "lightgreen") CATEGORY_ENUM_SUBCATEGORY
(IPC, IPC, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(MEDIA, "Media", "orange") CATEGORY_ENUM_SUBCATEGORY(MEDIA, MEDIA
, "Other") CATEGORY_ENUM_SUBCATEGORY(MEDIA, MEDIA_CUBEB, "Cubeb"
) CATEGORY_ENUM_SUBCATEGORY(MEDIA, MEDIA_PLAYBACK, "Playback"
) CATEGORY_ENUM_SUBCATEGORY(MEDIA, MEDIA_RT, "Real-time rendering"
) CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY(A11Y
, "Accessibility", "brown") CATEGORY_ENUM_SUBCATEGORY(A11Y, A11Y
, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(PROFILER, "Profiler", "lightred") CATEGORY_ENUM_SUBCATEGORY(
PROFILER, PROFILER, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(TIMER, "Timer", "grey") CATEGORY_ENUM_SUBCATEGORY(TIMER, TIMER
, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(REMOTE_PROTOCOL, "Remote-Protocol", "grey") CATEGORY_ENUM_SUBCATEGORY
(REMOTE_PROTOCOL, REMOTE_PROTOCOL, "Other") CATEGORY_ENUM_END_CATEGORY
CATEGORY_ENUM_BEGIN_CATEGORY(SANDBOX, "Sandbox", "grey") CATEGORY_ENUM_SUBCATEGORY
(SANDBOX, SANDBOX, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(TELEMETRY, "Telemetry", "grey") CATEGORY_ENUM_SUBCATEGORY(TELEMETRY
, TELEMETRY, "Other") CATEGORY_ENUM_END_CATEGORY
252 CATEGORY_ENUM_SUBCATEGORY,CATEGORY_ENUM_BEGIN_CATEGORY(IDLE, "Idle", "transparent") CATEGORY_ENUM_SUBCATEGORY
(IDLE, IDLE, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(OTHER, "Other", "grey") CATEGORY_ENUM_SUBCATEGORY(OTHER, OTHER
, "Other") CATEGORY_ENUM_SUBCATEGORY(OTHER, OTHER_PreferenceRead
, "Preference Read") CATEGORY_ENUM_SUBCATEGORY(OTHER, OTHER_Profiling
, "Profiling") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(TEST, "Test", "darkgray") CATEGORY_ENUM_SUBCATEGORY(TEST, TEST
, "Test") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(LAYOUT, "Layout", "purple") CATEGORY_ENUM_SUBCATEGORY(LAYOUT
, LAYOUT, "Other") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_FrameConstruction
, "Frame construction") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_Reflow
, "Reflow") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_CSSParsing
, "CSS parsing") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_SelectorQuery
, "Selector query") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_StyleComputation
, "Style computation") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_Destroy
, "Layout cleanup") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_Printing
, "Printing") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(JS, "JavaScript", "yellow") CATEGORY_ENUM_SUBCATEGORY(JS, JS
, "Other") CATEGORY_ENUM_SUBCATEGORY(JS, JS_Parsing, "Parsing"
) CATEGORY_ENUM_SUBCATEGORY(JS, JS_BaselineCompilation, "JIT Compile (baseline)"
) CATEGORY_ENUM_SUBCATEGORY(JS, JS_IonCompilation, "JIT Compile (ion)"
) CATEGORY_ENUM_SUBCATEGORY(JS, JS_Interpreter, "Interpreter"
) CATEGORY_ENUM_SUBCATEGORY(JS, JS_BaselineInterpret, "JIT (baseline-interpreter)"
) CATEGORY_ENUM_SUBCATEGORY(JS, JS_Baseline, "JIT (baseline)"
) CATEGORY_ENUM_SUBCATEGORY(JS, JS_IonMonkey, "JIT (ion)") CATEGORY_ENUM_SUBCATEGORY
(JS, JS_Builtin, "Builtin API") CATEGORY_ENUM_SUBCATEGORY(JS,
JS_WasmIon, "Wasm (ion)") CATEGORY_ENUM_SUBCATEGORY(JS, JS_WasmBaseline
, "Wasm (baseline)") CATEGORY_ENUM_SUBCATEGORY(JS, JS_WasmOther
, "Wasm (other)") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(GCCC, "GC / CC", "orange") CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC
, "Other") CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_MinorGC, "Minor GC"
) CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_MajorGC, "Major GC (Other)"
) CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_MajorGC_Mark, "Major GC (Mark)"
) CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_MajorGC_Sweep, "Major GC (Sweep)"
) CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_MajorGC_Compact, "Major GC (Compact)"
) CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_UnmarkGray, "Unmark Gray"
) CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_Barrier, "Barrier") CATEGORY_ENUM_SUBCATEGORY
(GCCC, GCCC_FreeSnowWhite, "CC (Free Snow White)") CATEGORY_ENUM_SUBCATEGORY
(GCCC, GCCC_BuildGraph, "CC (Build Graph)") CATEGORY_ENUM_SUBCATEGORY
(GCCC, GCCC_ScanRoots, "CC (Scan Roots)") CATEGORY_ENUM_SUBCATEGORY
(GCCC, GCCC_CollectWhite, "CC (Collect White)") CATEGORY_ENUM_SUBCATEGORY
(GCCC, GCCC_Finalize, "CC (Finalize)") CATEGORY_ENUM_END_CATEGORY
CATEGORY_ENUM_BEGIN_CATEGORY(NETWORK, "Network", "lightblue"
) CATEGORY_ENUM_SUBCATEGORY(NETWORK, NETWORK, "Other") CATEGORY_ENUM_END_CATEGORY
CATEGORY_ENUM_BEGIN_CATEGORY(GRAPHICS, "Graphics", "green") CATEGORY_ENUM_SUBCATEGORY
(GRAPHICS, GRAPHICS, "Other") CATEGORY_ENUM_SUBCATEGORY(GRAPHICS
, GRAPHICS_DisplayListBuilding, "DisplayList building") CATEGORY_ENUM_SUBCATEGORY
(GRAPHICS, GRAPHICS_DisplayListMerging, "DisplayList merging"
) CATEGORY_ENUM_SUBCATEGORY(GRAPHICS, GRAPHICS_LayerBuilding,
"Layer building") CATEGORY_ENUM_SUBCATEGORY(GRAPHICS, GRAPHICS_TileAllocation
, "Tile allocation") CATEGORY_ENUM_SUBCATEGORY(GRAPHICS, GRAPHICS_WRDisplayList
, "WebRender display list") CATEGORY_ENUM_SUBCATEGORY(GRAPHICS
, GRAPHICS_Rasterization, "Rasterization") CATEGORY_ENUM_SUBCATEGORY
(GRAPHICS, GRAPHICS_FlushingAsyncPaints, "Flushing async paints"
) CATEGORY_ENUM_SUBCATEGORY(GRAPHICS, GRAPHICS_ImageDecoding,
"Image decoding") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(DOM, "DOM", "blue") CATEGORY_ENUM_SUBCATEGORY(DOM, DOM, "Other"
) CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY(JAVA_ANDROID
, "Android", "yellow") CATEGORY_ENUM_SUBCATEGORY(JAVA_ANDROID
, JAVA_ANDROID, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(JAVA_ANDROIDX, "AndroidX", "orange") CATEGORY_ENUM_SUBCATEGORY
(JAVA_ANDROIDX, JAVA_ANDROIDX, "Other") CATEGORY_ENUM_END_CATEGORY
CATEGORY_ENUM_BEGIN_CATEGORY(JAVA_LANGUAGE, "Java", "blue") CATEGORY_ENUM_SUBCATEGORY
(JAVA_LANGUAGE, JAVA_LANGUAGE, "Other") CATEGORY_ENUM_END_CATEGORY
CATEGORY_ENUM_BEGIN_CATEGORY(JAVA_MOZILLA, "Mozilla", "green"
) CATEGORY_ENUM_SUBCATEGORY(JAVA_MOZILLA, JAVA_MOZILLA, "Other"
) CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY(JAVA_KOTLIN
, "Kotlin", "purple") CATEGORY_ENUM_SUBCATEGORY(JAVA_KOTLIN, JAVA_KOTLIN
, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(JAVA_BLOCKED, "Blocked", "lightblue") CATEGORY_ENUM_SUBCATEGORY
(JAVA_BLOCKED, JAVA_BLOCKED, "Other") CATEGORY_ENUM_END_CATEGORY
CATEGORY_ENUM_BEGIN_CATEGORY(IPC, "IPC", "lightgreen") CATEGORY_ENUM_SUBCATEGORY
(IPC, IPC, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(MEDIA, "Media", "orange") CATEGORY_ENUM_SUBCATEGORY(MEDIA, MEDIA
, "Other") CATEGORY_ENUM_SUBCATEGORY(MEDIA, MEDIA_CUBEB, "Cubeb"
) CATEGORY_ENUM_SUBCATEGORY(MEDIA, MEDIA_PLAYBACK, "Playback"
) CATEGORY_ENUM_SUBCATEGORY(MEDIA, MEDIA_RT, "Real-time rendering"
) CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY(A11Y
, "Accessibility", "brown") CATEGORY_ENUM_SUBCATEGORY(A11Y, A11Y
, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(PROFILER, "Profiler", "lightred") CATEGORY_ENUM_SUBCATEGORY(
PROFILER, PROFILER, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(TIMER, "Timer", "grey") CATEGORY_ENUM_SUBCATEGORY(TIMER, TIMER
, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(REMOTE_PROTOCOL, "Remote-Protocol", "grey") CATEGORY_ENUM_SUBCATEGORY
(REMOTE_PROTOCOL, REMOTE_PROTOCOL, "Other") CATEGORY_ENUM_END_CATEGORY
CATEGORY_ENUM_BEGIN_CATEGORY(SANDBOX, "Sandbox", "grey") CATEGORY_ENUM_SUBCATEGORY
(SANDBOX, SANDBOX, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(TELEMETRY, "Telemetry", "grey") CATEGORY_ENUM_SUBCATEGORY(TELEMETRY
, TELEMETRY, "Other") CATEGORY_ENUM_END_CATEGORY
253 CATEGORY_ENUM_END_CATEGORY)CATEGORY_ENUM_BEGIN_CATEGORY(IDLE, "Idle", "transparent") CATEGORY_ENUM_SUBCATEGORY
(IDLE, IDLE, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(OTHER, "Other", "grey") CATEGORY_ENUM_SUBCATEGORY(OTHER, OTHER
, "Other") CATEGORY_ENUM_SUBCATEGORY(OTHER, OTHER_PreferenceRead
, "Preference Read") CATEGORY_ENUM_SUBCATEGORY(OTHER, OTHER_Profiling
, "Profiling") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(TEST, "Test", "darkgray") CATEGORY_ENUM_SUBCATEGORY(TEST, TEST
, "Test") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(LAYOUT, "Layout", "purple") CATEGORY_ENUM_SUBCATEGORY(LAYOUT
, LAYOUT, "Other") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_FrameConstruction
, "Frame construction") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_Reflow
, "Reflow") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_CSSParsing
, "CSS parsing") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_SelectorQuery
, "Selector query") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_StyleComputation
, "Style computation") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_Destroy
, "Layout cleanup") CATEGORY_ENUM_SUBCATEGORY(LAYOUT, LAYOUT_Printing
, "Printing") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(JS, "JavaScript", "yellow") CATEGORY_ENUM_SUBCATEGORY(JS, JS
, "Other") CATEGORY_ENUM_SUBCATEGORY(JS, JS_Parsing, "Parsing"
) CATEGORY_ENUM_SUBCATEGORY(JS, JS_BaselineCompilation, "JIT Compile (baseline)"
) CATEGORY_ENUM_SUBCATEGORY(JS, JS_IonCompilation, "JIT Compile (ion)"
) CATEGORY_ENUM_SUBCATEGORY(JS, JS_Interpreter, "Interpreter"
) CATEGORY_ENUM_SUBCATEGORY(JS, JS_BaselineInterpret, "JIT (baseline-interpreter)"
) CATEGORY_ENUM_SUBCATEGORY(JS, JS_Baseline, "JIT (baseline)"
) CATEGORY_ENUM_SUBCATEGORY(JS, JS_IonMonkey, "JIT (ion)") CATEGORY_ENUM_SUBCATEGORY
(JS, JS_Builtin, "Builtin API") CATEGORY_ENUM_SUBCATEGORY(JS,
JS_WasmIon, "Wasm (ion)") CATEGORY_ENUM_SUBCATEGORY(JS, JS_WasmBaseline
, "Wasm (baseline)") CATEGORY_ENUM_SUBCATEGORY(JS, JS_WasmOther
, "Wasm (other)") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(GCCC, "GC / CC", "orange") CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC
, "Other") CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_MinorGC, "Minor GC"
) CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_MajorGC, "Major GC (Other)"
) CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_MajorGC_Mark, "Major GC (Mark)"
) CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_MajorGC_Sweep, "Major GC (Sweep)"
) CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_MajorGC_Compact, "Major GC (Compact)"
) CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_UnmarkGray, "Unmark Gray"
) CATEGORY_ENUM_SUBCATEGORY(GCCC, GCCC_Barrier, "Barrier") CATEGORY_ENUM_SUBCATEGORY
(GCCC, GCCC_FreeSnowWhite, "CC (Free Snow White)") CATEGORY_ENUM_SUBCATEGORY
(GCCC, GCCC_BuildGraph, "CC (Build Graph)") CATEGORY_ENUM_SUBCATEGORY
(GCCC, GCCC_ScanRoots, "CC (Scan Roots)") CATEGORY_ENUM_SUBCATEGORY
(GCCC, GCCC_CollectWhite, "CC (Collect White)") CATEGORY_ENUM_SUBCATEGORY
(GCCC, GCCC_Finalize, "CC (Finalize)") CATEGORY_ENUM_END_CATEGORY
CATEGORY_ENUM_BEGIN_CATEGORY(NETWORK, "Network", "lightblue"
) CATEGORY_ENUM_SUBCATEGORY(NETWORK, NETWORK, "Other") CATEGORY_ENUM_END_CATEGORY
CATEGORY_ENUM_BEGIN_CATEGORY(GRAPHICS, "Graphics", "green") CATEGORY_ENUM_SUBCATEGORY
(GRAPHICS, GRAPHICS, "Other") CATEGORY_ENUM_SUBCATEGORY(GRAPHICS
, GRAPHICS_DisplayListBuilding, "DisplayList building") CATEGORY_ENUM_SUBCATEGORY
(GRAPHICS, GRAPHICS_DisplayListMerging, "DisplayList merging"
) CATEGORY_ENUM_SUBCATEGORY(GRAPHICS, GRAPHICS_LayerBuilding,
"Layer building") CATEGORY_ENUM_SUBCATEGORY(GRAPHICS, GRAPHICS_TileAllocation
, "Tile allocation") CATEGORY_ENUM_SUBCATEGORY(GRAPHICS, GRAPHICS_WRDisplayList
, "WebRender display list") CATEGORY_ENUM_SUBCATEGORY(GRAPHICS
, GRAPHICS_Rasterization, "Rasterization") CATEGORY_ENUM_SUBCATEGORY
(GRAPHICS, GRAPHICS_FlushingAsyncPaints, "Flushing async paints"
) CATEGORY_ENUM_SUBCATEGORY(GRAPHICS, GRAPHICS_ImageDecoding,
"Image decoding") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(DOM, "DOM", "blue") CATEGORY_ENUM_SUBCATEGORY(DOM, DOM, "Other"
) CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY(JAVA_ANDROID
, "Android", "yellow") CATEGORY_ENUM_SUBCATEGORY(JAVA_ANDROID
, JAVA_ANDROID, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(JAVA_ANDROIDX, "AndroidX", "orange") CATEGORY_ENUM_SUBCATEGORY
(JAVA_ANDROIDX, JAVA_ANDROIDX, "Other") CATEGORY_ENUM_END_CATEGORY
CATEGORY_ENUM_BEGIN_CATEGORY(JAVA_LANGUAGE, "Java", "blue") CATEGORY_ENUM_SUBCATEGORY
(JAVA_LANGUAGE, JAVA_LANGUAGE, "Other") CATEGORY_ENUM_END_CATEGORY
CATEGORY_ENUM_BEGIN_CATEGORY(JAVA_MOZILLA, "Mozilla", "green"
) CATEGORY_ENUM_SUBCATEGORY(JAVA_MOZILLA, JAVA_MOZILLA, "Other"
) CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY(JAVA_KOTLIN
, "Kotlin", "purple") CATEGORY_ENUM_SUBCATEGORY(JAVA_KOTLIN, JAVA_KOTLIN
, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(JAVA_BLOCKED, "Blocked", "lightblue") CATEGORY_ENUM_SUBCATEGORY
(JAVA_BLOCKED, JAVA_BLOCKED, "Other") CATEGORY_ENUM_END_CATEGORY
CATEGORY_ENUM_BEGIN_CATEGORY(IPC, "IPC", "lightgreen") CATEGORY_ENUM_SUBCATEGORY
(IPC, IPC, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(MEDIA, "Media", "orange") CATEGORY_ENUM_SUBCATEGORY(MEDIA, MEDIA
, "Other") CATEGORY_ENUM_SUBCATEGORY(MEDIA, MEDIA_CUBEB, "Cubeb"
) CATEGORY_ENUM_SUBCATEGORY(MEDIA, MEDIA_PLAYBACK, "Playback"
) CATEGORY_ENUM_SUBCATEGORY(MEDIA, MEDIA_RT, "Real-time rendering"
) CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY(A11Y
, "Accessibility", "brown") CATEGORY_ENUM_SUBCATEGORY(A11Y, A11Y
, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(PROFILER, "Profiler", "lightred") CATEGORY_ENUM_SUBCATEGORY(
PROFILER, PROFILER, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(TIMER, "Timer", "grey") CATEGORY_ENUM_SUBCATEGORY(TIMER, TIMER
, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(REMOTE_PROTOCOL, "Remote-Protocol", "grey") CATEGORY_ENUM_SUBCATEGORY
(REMOTE_PROTOCOL, REMOTE_PROTOCOL, "Other") CATEGORY_ENUM_END_CATEGORY
CATEGORY_ENUM_BEGIN_CATEGORY(SANDBOX, "Sandbox", "grey") CATEGORY_ENUM_SUBCATEGORY
(SANDBOX, SANDBOX, "Other") CATEGORY_ENUM_END_CATEGORY CATEGORY_ENUM_BEGIN_CATEGORY
(TELEMETRY, "Telemetry", "grey") CATEGORY_ENUM_SUBCATEGORY(TELEMETRY
, TELEMETRY, "Other") CATEGORY_ENUM_END_CATEGORY
254#undef CATEGORY_ENUM_BEGIN_CATEGORY
255#undef CATEGORY_ENUM_SUBCATEGORY
256#undef CATEGORY_ENUM_END_CATEGORY
257
258// Import `MarkerCategory` into this namespace. This will allow using this type
259// dynamically in macros that prepend `::mozilla::baseprofiler::category::` to
260// the given category, e.g.:
261// `PROFILER_MARKER_UNTYPED("name", MarkerCategory(...))`
262using MarkerCategory = ::mozilla::MarkerCategory;
263
264} // namespace baseprofiler::category
265
266// The classes below are all embedded in a `MarkerOptions` object.
267class MarkerOptions;
268
269// This marker option captures a given thread id.
270// If left unspecified (by default construction) during the add-marker call, the
271// current thread id will be used then.
272class MarkerThreadId {
273 public:
274 // Default constructor, keeps the thread id unspecified.
275 constexpr MarkerThreadId() = default;
276
277 // Constructor from a given thread id.
278 constexpr explicit MarkerThreadId(
279 baseprofiler::BaseProfilerThreadId aThreadId)
280 : mThreadId(aThreadId) {}
281
282 // Use the current thread's id.
283 static MarkerThreadId CurrentThread() {
284 return MarkerThreadId(baseprofiler::profiler_current_thread_id());
285 }
286
287 // Use the main thread's id. This can be useful to record a marker from a
288 // possibly-unregistered thread, and display it in the main thread track.
289 static MarkerThreadId MainThread() {
290 return MarkerThreadId(baseprofiler::profiler_main_thread_id());
291 }
292
293 [[nodiscard]] constexpr baseprofiler::BaseProfilerThreadId ThreadId() const {
294 return mThreadId;
295 }
296
297 [[nodiscard]] constexpr bool IsUnspecified() const {
298 return !mThreadId.IsSpecified();
299 }
300
301 private:
302 baseprofiler::BaseProfilerThreadId mThreadId;
303};
304
305// This marker option contains marker timing information.
306// This class encapsulates the logic for correctly storing a marker based on its
307// Use the static methods to create the MarkerTiming. This is a transient object
308// that is being used to enforce the constraints of the combinations of the
309// data.
310class MarkerTiming {
311 public:
312 // The following static methods are used to create the MarkerTiming based on
313 // the type that it is.
314
315 static MarkerTiming InstantAt(const TimeStamp& aTime) {
316 MOZ_ASSERT(!aTime.IsNull(), "Time is null for an instant marker.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aTime.IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aTime.IsNull()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!aTime.IsNull()"
" (" "Time is null for an instant marker." ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 316); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aTime.IsNull()"
") (" "Time is null for an instant marker." ")"); do { *((volatile
int*)__null) = 316; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
317 return MarkerTiming{aTime, TimeStamp{}, MarkerTiming::Phase::Instant};
318 }
319
320 static MarkerTiming InstantNow() { return InstantAt(TimeStamp::Now()); }
321
322 static MarkerTiming Interval(const TimeStamp& aStartTime,
323 const TimeStamp& aEndTime) {
324 MOZ_ASSERT(!aStartTime.IsNull(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aStartTime.IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aStartTime.IsNull()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("!aStartTime.IsNull()"
" (" "Start time is null for an interval marker." ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 325); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aStartTime.IsNull()"
") (" "Start time is null for an interval marker." ")"); do {
*((volatile int*)__null) = 325; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
30
Calling 'TimeStamp::IsNull'
325 "Start time is null for an interval marker.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aStartTime.IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aStartTime.IsNull()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("!aStartTime.IsNull()"
" (" "Start time is null for an interval marker." ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 325); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aStartTime.IsNull()"
") (" "Start time is null for an interval marker." ")"); do {
*((volatile int*)__null) = 325; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
326 MOZ_ASSERT(!aEndTime.IsNull(), "End time is null for an interval marker.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEndTime.IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aEndTime.IsNull()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!aEndTime.IsNull()"
" (" "End time is null for an interval marker." ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 326); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEndTime.IsNull()"
") (" "End time is null for an interval marker." ")"); do { *
((volatile int*)__null) = 326; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
327 return MarkerTiming{aStartTime, aEndTime, MarkerTiming::Phase::Interval};
328 }
329
330 static MarkerTiming IntervalUntilNowFrom(const TimeStamp& aStartTime) {
331 return Interval(aStartTime, TimeStamp::Now());
29
Calling 'MarkerTiming::Interval'
332 }
333
334 static MarkerTiming IntervalStart(const TimeStamp& aTime = TimeStamp::Now()) {
335 MOZ_ASSERT(!aTime.IsNull(), "Time is null for an interval start marker.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aTime.IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aTime.IsNull()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!aTime.IsNull()"
" (" "Time is null for an interval start marker." ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 335); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aTime.IsNull()"
") (" "Time is null for an interval start marker." ")"); do {
*((volatile int*)__null) = 335; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
336 return MarkerTiming{aTime, TimeStamp{}, MarkerTiming::Phase::IntervalStart};
337 }
338
339 static MarkerTiming IntervalEnd(const TimeStamp& aTime = TimeStamp::Now()) {
340 MOZ_ASSERT(!aTime.IsNull(), "Time is null for an interval end marker.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aTime.IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aTime.IsNull()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!aTime.IsNull()"
" (" "Time is null for an interval end marker." ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 340); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aTime.IsNull()"
") (" "Time is null for an interval end marker." ")"); do { *
((volatile int*)__null) = 340; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
341 return MarkerTiming{TimeStamp{}, aTime, MarkerTiming::Phase::IntervalEnd};
342 }
343
344 // Set the interval end in this timing.
345 // If there was already a start time, this makes it a full interval.
346 void SetIntervalEnd(const TimeStamp& aTime = TimeStamp::Now()) {
347 MOZ_ASSERT(!aTime.IsNull(), "Time is null for an interval end marker.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aTime.IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aTime.IsNull()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!aTime.IsNull()"
" (" "Time is null for an interval end marker." ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 347); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aTime.IsNull()"
") (" "Time is null for an interval end marker." ")"); do { *
((volatile int*)__null) = 347; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
348 mEndTime = aTime;
349 mPhase = mStartTime.IsNull() ? Phase::IntervalEnd : Phase::Interval;
350 }
351
352 [[nodiscard]] const TimeStamp& StartTime() const { return mStartTime; }
353 [[nodiscard]] const TimeStamp& EndTime() const { return mEndTime; }
354
355 // The phase differentiates Instant markers from Interval markers.
356 // Interval markers can either carry both timestamps on a single marker,
357 // or they can be split into individual Start and End markers, which are
358 // associated with each other via the marker name.
359 //
360 // The numeric representation of this enum value is also exposed in the
361 // ETW trace event's Phase field.
362 enum class Phase : uint8_t {
363 Instant = 0,
364 Interval = 1,
365 IntervalStart = 2,
366 IntervalEnd = 3,
367 };
368
369 [[nodiscard]] Phase MarkerPhase() const {
370 MOZ_ASSERT(!IsUnspecified())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsUnspecified())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsUnspecified()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!IsUnspecified()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 370); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsUnspecified()"
")"); do { *((volatile int*)__null) = 370; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
371 return mPhase;
372 }
373
374 // The following getter methods are used to put the value into the buffer for
375 // storage.
376 [[nodiscard]] double GetStartTime() const {
377 MOZ_ASSERT(!IsUnspecified())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsUnspecified())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsUnspecified()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!IsUnspecified()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 377); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsUnspecified()"
")"); do { *((volatile int*)__null) = 377; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
378 // If mStartTime is null (e.g., for IntervalEnd), this will output 0.0 as
379 // expected.
380 return MarkerTiming::timeStampToDouble(mStartTime);
381 }
382
383 [[nodiscard]] double GetEndTime() const {
384 MOZ_ASSERT(!IsUnspecified())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsUnspecified())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsUnspecified()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!IsUnspecified()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 384); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsUnspecified()"
")"); do { *((volatile int*)__null) = 384; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
385 // If mEndTime is null (e.g., for Instant or IntervalStart), this will
386 // output 0.0 as expected.
387 return MarkerTiming::timeStampToDouble(mEndTime);
388 }
389
390 [[nodiscard]] uint8_t GetPhase() const {
391 MOZ_ASSERT(!IsUnspecified())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsUnspecified())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsUnspecified()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!IsUnspecified()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 391); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsUnspecified()"
")"); do { *((volatile int*)__null) = 391; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
392 return static_cast<uint8_t>(mPhase);
393 }
394
395 // This is a constructor for Rust FFI bindings. It must not be used outside of
396 // this! Please see the other static constructors above.
397 static void UnsafeConstruct(MarkerTiming* aMarkerTiming,
398 const TimeStamp& aStartTime,
399 const TimeStamp& aEndTime, Phase aPhase) {
400 new (aMarkerTiming) MarkerTiming{aStartTime, aEndTime, aPhase};
401 }
402
403 private:
404 friend ProfileBufferEntryWriter::Serializer<MarkerTiming>;
405 friend ProfileBufferEntryReader::Deserializer<MarkerTiming>;
406 friend MarkerOptions;
407
408 // Default timing leaves it internally "unspecified", serialization getters
409 // and add-marker functions will default to `InstantNow()`.
410 constexpr MarkerTiming() = default;
411
412 // This should only be used by internal profiler code.
413 [[nodiscard]] bool IsUnspecified() const {
414 return mStartTime.IsNull() && mEndTime.IsNull();
415 }
416
417 // Full constructor, used by static factory functions.
418 constexpr MarkerTiming(const TimeStamp& aStartTime, const TimeStamp& aEndTime,
419 Phase aPhase)
420 : mStartTime(aStartTime), mEndTime(aEndTime), mPhase(aPhase) {}
421
422 static double timeStampToDouble(const TimeStamp& time) {
423 if (time.IsNull()) {
424 // The Phase lets us know not to use this value.
425 return 0;
426 }
427 return (time - TimeStamp::ProcessCreation()).ToMilliseconds();
428 }
429
430 TimeStamp mStartTime;
431 TimeStamp mEndTime;
432 Phase mPhase = Phase::Instant;
433};
434
435// This marker option allows three cases:
436// - By default, no stacks are captured.
437// - The caller can request a stack capture, and the add-marker code will take
438// care of it in the most efficient way.
439// - The caller can still provide an existing backtrace, for cases where a
440// marker reports something that happened elsewhere.
441class MarkerStack {
442 public:
443 // Default constructor, no capture.
444 constexpr MarkerStack() = default;
445
446 // Disallow copy.
447 MarkerStack(const MarkerStack&) = delete;
448 MarkerStack& operator=(const MarkerStack&) = delete;
449
450 // Allow move.
451 MarkerStack(MarkerStack&& aOther)
452 : mCaptureOptions(aOther.mCaptureOptions),
453 mOptionalChunkedBufferStorage(
454 std::move(aOther.mOptionalChunkedBufferStorage)),
455 mChunkedBuffer(aOther.mChunkedBuffer) {
456 AssertInvariants();
457 aOther.Clear();
458 }
459 MarkerStack& operator=(MarkerStack&& aOther) {
460 mCaptureOptions = aOther.mCaptureOptions;
461 mOptionalChunkedBufferStorage =
462 std::move(aOther.mOptionalChunkedBufferStorage);
463 mChunkedBuffer = aOther.mChunkedBuffer;
464 AssertInvariants();
465 aOther.Clear();
466 return *this;
467 }
468
469 // Take ownership of a backtrace. If null or empty, equivalent to NoStack().
470 explicit MarkerStack(UniquePtr<ProfileChunkedBuffer>&& aExternalChunkedBuffer)
471 : mOptionalChunkedBufferStorage(
472 (!aExternalChunkedBuffer || aExternalChunkedBuffer->IsEmpty())
473 ? nullptr
474 : std::move(aExternalChunkedBuffer)),
475 mChunkedBuffer(mOptionalChunkedBufferStorage.get()) {
476 AssertInvariants();
477 }
478
479 // Use an existing backtrace stored elsewhere, which the user must guarantee
480 // is alive during the add-marker call. If empty, equivalent to NoStack().
481 explicit MarkerStack(ProfileChunkedBuffer& aExternalChunkedBuffer)
482 : mChunkedBuffer(aExternalChunkedBuffer.IsEmpty()
483 ? nullptr
484 : &aExternalChunkedBuffer) {
485 AssertInvariants();
486 }
487
488 // Don't capture a stack in this marker.
489 static MarkerStack NoStack() {
490 return MarkerStack(StackCaptureOptions::NoStack);
491 }
492
493 // Capture a stack when adding this marker.
494 static MarkerStack Capture(
495 StackCaptureOptions aCaptureOptions = StackCaptureOptions::Full) {
496 // Actual capture will be handled inside profiler_add_marker.
497 return MarkerStack(aCaptureOptions);
498 }
499
500 // Optionally capture a stack, useful for avoiding long-winded ternaries.
501 static MarkerStack MaybeCapture(bool aDoCapture) {
502 return aDoCapture ? Capture() : NoStack();
503 }
504
505 // Use an existing backtrace stored elsewhere, which the user must guarantee
506 // is alive during the add-marker call. If empty, equivalent to NoStack().
507 static MarkerStack UseBacktrace(
508 ProfileChunkedBuffer& aExternalChunkedBuffer) {
509 return MarkerStack(aExternalChunkedBuffer);
510 }
511
512 // Take ownership of a backtrace previously captured with
513 // `profiler_capture_backtrace()`. If null, equivalent to NoStack().
514 static MarkerStack TakeBacktrace(
515 UniquePtr<ProfileChunkedBuffer>&& aExternalChunkedBuffer) {
516 return MarkerStack(std::move(aExternalChunkedBuffer));
517 }
518
519 // Construct with the given capture options.
520 static MarkerStack WithCaptureOptions(StackCaptureOptions aCaptureOptions) {
521 return MarkerStack(aCaptureOptions);
522 }
523
524 [[nodiscard]] StackCaptureOptions CaptureOptions() const {
525 return mCaptureOptions;
526 }
527
528 ProfileChunkedBuffer* GetChunkedBuffer() const { return mChunkedBuffer; }
529
530 // Use backtrace after a request. If null, equivalent to NoStack().
531 void UseRequestedBacktrace(ProfileChunkedBuffer* aExternalChunkedBuffer) {
532 MOZ_RELEASE_ASSERT(mCaptureOptions != StackCaptureOptions::NoStack)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCaptureOptions != StackCaptureOptions::NoStack)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mCaptureOptions != StackCaptureOptions::NoStack))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mCaptureOptions != StackCaptureOptions::NoStack"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 532); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "mCaptureOptions != StackCaptureOptions::NoStack"
")"); do { *((volatile int*)__null) = 532; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
533 mCaptureOptions = StackCaptureOptions::NoStack;
534 if (aExternalChunkedBuffer && !aExternalChunkedBuffer->IsEmpty()) {
535 // We only need to use the provided buffer if it is not empty.
536 mChunkedBuffer = aExternalChunkedBuffer;
537 }
538 AssertInvariants();
539 }
540
541 void Clear() {
542 mCaptureOptions = StackCaptureOptions::NoStack;
543 mOptionalChunkedBufferStorage.reset();
544 mChunkedBuffer = nullptr;
545 AssertInvariants();
546 }
547
548 private:
549 explicit MarkerStack(StackCaptureOptions aCaptureOptions)
550 : mCaptureOptions(aCaptureOptions) {
551 AssertInvariants();
552 }
553
554 // This should be called after every constructor and non-const function.
555 void AssertInvariants() const {
556#ifdef DEBUG1
557 if (mCaptureOptions != StackCaptureOptions::NoStack) {
558 MOZ_ASSERT(!mOptionalChunkedBufferStorage,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mOptionalChunkedBufferStorage)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mOptionalChunkedBufferStorage
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!mOptionalChunkedBufferStorage" " (" "We should not hold a buffer when capture is requested"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 559); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mOptionalChunkedBufferStorage"
") (" "We should not hold a buffer when capture is requested"
")"); do { *((volatile int*)__null) = 559; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
559 "We should not hold a buffer when capture is requested")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mOptionalChunkedBufferStorage)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mOptionalChunkedBufferStorage
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!mOptionalChunkedBufferStorage" " (" "We should not hold a buffer when capture is requested"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 559); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mOptionalChunkedBufferStorage"
") (" "We should not hold a buffer when capture is requested"
")"); do { *((volatile int*)__null) = 559; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
560 MOZ_ASSERT(!mChunkedBuffer,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mChunkedBuffer)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mChunkedBuffer))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mChunkedBuffer"
" (" "We should not point at a buffer when capture is requested"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 561); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mChunkedBuffer"
") (" "We should not point at a buffer when capture is requested"
")"); do { *((volatile int*)__null) = 561; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
561 "We should not point at a buffer when capture is requested")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mChunkedBuffer)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mChunkedBuffer))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mChunkedBuffer"
" (" "We should not point at a buffer when capture is requested"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 561); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mChunkedBuffer"
") (" "We should not point at a buffer when capture is requested"
")"); do { *((volatile int*)__null) = 561; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
562 } else {
563 if (mOptionalChunkedBufferStorage) {
564 MOZ_ASSERT(mChunkedBuffer == mOptionalChunkedBufferStorage.get(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mChunkedBuffer == mOptionalChunkedBufferStorage.get(
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mChunkedBuffer == mOptionalChunkedBufferStorage.get(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mChunkedBuffer == mOptionalChunkedBufferStorage.get()" " ("
"Non-null mOptionalChunkedBufferStorage must be pointed-at "
"by mChunkedBuffer" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 566); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChunkedBuffer == mOptionalChunkedBufferStorage.get()"
") (" "Non-null mOptionalChunkedBufferStorage must be pointed-at "
"by mChunkedBuffer" ")"); do { *((volatile int*)__null) = 566
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
565 "Non-null mOptionalChunkedBufferStorage must be pointed-at "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mChunkedBuffer == mOptionalChunkedBufferStorage.get(
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mChunkedBuffer == mOptionalChunkedBufferStorage.get(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mChunkedBuffer == mOptionalChunkedBufferStorage.get()" " ("
"Non-null mOptionalChunkedBufferStorage must be pointed-at "
"by mChunkedBuffer" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 566); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChunkedBuffer == mOptionalChunkedBufferStorage.get()"
") (" "Non-null mOptionalChunkedBufferStorage must be pointed-at "
"by mChunkedBuffer" ")"); do { *((volatile int*)__null) = 566
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
566 "by mChunkedBuffer")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mChunkedBuffer == mOptionalChunkedBufferStorage.get(
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mChunkedBuffer == mOptionalChunkedBufferStorage.get(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mChunkedBuffer == mOptionalChunkedBufferStorage.get()" " ("
"Non-null mOptionalChunkedBufferStorage must be pointed-at "
"by mChunkedBuffer" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 566); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChunkedBuffer == mOptionalChunkedBufferStorage.get()"
") (" "Non-null mOptionalChunkedBufferStorage must be pointed-at "
"by mChunkedBuffer" ")"); do { *((volatile int*)__null) = 566
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
567 }
568 if (mChunkedBuffer) {
569 MOZ_ASSERT(!mChunkedBuffer->IsEmpty(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mChunkedBuffer->IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mChunkedBuffer->IsEmpty(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mChunkedBuffer->IsEmpty()" " (" "Non-null mChunkedBuffer must not be empty"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 570); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mChunkedBuffer->IsEmpty()"
") (" "Non-null mChunkedBuffer must not be empty" ")"); do {
*((volatile int*)__null) = 570; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
570 "Non-null mChunkedBuffer must not be empty")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mChunkedBuffer->IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mChunkedBuffer->IsEmpty(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mChunkedBuffer->IsEmpty()" " (" "Non-null mChunkedBuffer must not be empty"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/BaseProfilerMarkersPrerequisites.h"
, 570); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mChunkedBuffer->IsEmpty()"
") (" "Non-null mChunkedBuffer must not be empty" ")"); do {
*((volatile int*)__null) = 570; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
571 }
572 }
573#endif // DEBUG
574 }
575
576 StackCaptureOptions mCaptureOptions = StackCaptureOptions::NoStack;
577
578 // Optional storage for the backtrace, in case it was captured before the
579 // add-marker call.
580 UniquePtr<ProfileChunkedBuffer> mOptionalChunkedBufferStorage;
581
582 // If not null, this points to the backtrace. It may point to a backtrace
583 // temporarily stored on the stack, or to mOptionalChunkedBufferStorage.
584 ProfileChunkedBuffer* mChunkedBuffer = nullptr;
585};
586
587// This marker option captures a given inner window id.
588class MarkerInnerWindowId {
589 public:
590 // Default constructor, it leaves the id unspecified.
591 constexpr MarkerInnerWindowId() = default;
592
593 // Constructor with a specified inner window id.
594 constexpr explicit MarkerInnerWindowId(uint64_t i) : mInnerWindowId(i) {}
595
596 // Constructor with either specified inner window id or Nothing.
597 constexpr explicit MarkerInnerWindowId(const Maybe<uint64_t>& i)
598 : mInnerWindowId(i.valueOr(scNoId)) {}
599
600 // Explicit option with unspecified id.
601 constexpr static MarkerInnerWindowId NoId() { return MarkerInnerWindowId{}; }
602
603 [[nodiscard]] bool IsUnspecified() const { return mInnerWindowId == scNoId; }
604
605 [[nodiscard]] constexpr uint64_t Id() const { return mInnerWindowId; }
606
607 private:
608 static constexpr uint64_t scNoId = 0;
609 uint64_t mInnerWindowId = scNoId;
610};
611
612// This class combines each of the possible marker options above.
613class MarkerOptions {
614 public:
615 // Constructor from individual options (including none).
616 // Implicit to allow `{}` and one option type as-is.
617 // Options that are not provided here are defaulted. In particular, timing
618 // defaults to `MarkerTiming::InstantNow()` when the marker is recorded.
619 template <typename... Options>
620 MOZ_IMPLICIT MarkerOptions(Options&&... aOptions) {
621 (Set(std::forward<Options>(aOptions)), ...);
622 }
623
624 // Disallow copy.
625 MarkerOptions(const MarkerOptions&) = delete;
626 MarkerOptions& operator=(const MarkerOptions&) = delete;
627
628 // Allow move.
629 MarkerOptions(MarkerOptions&&) = default;
630 MarkerOptions& operator=(MarkerOptions&&) = default;
631
632 // The embedded `MarkerTiming` hasn't been specified yet.
633 [[nodiscard]] bool IsTimingUnspecified() const {
634 return mTiming.IsUnspecified();
635 }
636
637 // Each option may be added in a chain by e.g.:
638 // `options.Set(MarkerThreadId(123)).Set(MarkerTiming::IntervalEnd())`.
639 // When passed to an add-marker function, it must be an rvalue, either created
640 // on the spot, or `std::move`d from storage, e.g.:
641 // `PROFILER_MARKER_UNTYPED("...", std::move(options).Set(...))`;
642 //
643 // Options can be read by their name (without "Marker"), e.g.: `o.ThreadId()`.
644 // Add "Ref" for a non-const reference, e.g.: `o.ThreadIdRef() = ...;`
645#define FUNCTIONS_ON_MEMBER(NAME) \
646 MarkerOptions& Set(Marker##NAME&& a##NAME)& { \
647 m##NAME = std::move(a##NAME); \
648 return *this; \
649 } \
650 \
651 MarkerOptions&& Set(Marker##NAME&& a##NAME)&& { \
652 m##NAME = std::move(a##NAME); \
653 return std::move(*this); \
654 } \
655 \
656 const Marker##NAME& NAME() const { return m##NAME; } \
657 \
658 Marker##NAME& NAME##Ref() { return m##NAME; }
659
660 FUNCTIONS_ON_MEMBER(ThreadId);
661 FUNCTIONS_ON_MEMBER(Timing);
662 FUNCTIONS_ON_MEMBER(Stack);
663 FUNCTIONS_ON_MEMBER(InnerWindowId);
664#undef FUNCTIONS_ON_MEMBER
665
666 private:
667 friend ProfileBufferEntryReader::Deserializer<MarkerOptions>;
668
669 MarkerThreadId mThreadId;
670 MarkerTiming mTiming;
671 MarkerStack mStack;
672 MarkerInnerWindowId mInnerWindowId;
673};
674
675} // namespace mozilla
676
677namespace mozilla::baseprofiler::markers {
678
679// Default marker payload types, with no extra information, not even a marker
680// type and payload. This is intended for label-only markers.
681struct NoPayload final {};
682
683} // namespace mozilla::baseprofiler::markers
684
685namespace mozilla {
686
687class JSONWriter;
688
689// This class collects all the information necessary to stream the JSON schema
690// that informs the front-end how to display a type of markers.
691// It will be created and populated in `MarkerTypeDisplay()` functions in each
692// marker type definition, see Add/Set functions.
693class MarkerSchema {
694 public:
695 // This is used to describe a C++ type that is expected to be specified to
696 // the marker and used in PayloadField. This type is the expected input type
697 // to the marker data.
698 enum class InputType {
699 Uint64,
700 Uint32,
701 Uint8,
702 Boolean,
703 CString,
704 String,
705 TimeStamp,
706 TimeDuration
707 };
708
709 enum class Location : unsigned {
710 MarkerChart,
711 MarkerTable,
712 // This adds markers to the main marker timeline in the header.
713 TimelineOverview,
714 // In the timeline, this is a section that breaks out markers that are
715 // related to memory. When memory counters are enabled, this is its own
716 // track, otherwise it is displayed with the main thread.
717 TimelineMemory,
718 // This adds markers to the IPC timeline area in the header.
719 TimelineIPC,
720 // This adds markers to the FileIO timeline area in the header.
721 TimelineFileIO,
722 // TODO - This is not supported yet.
723 StackChart
724 };
725
726 // Used as constructor parameter, to explicitly specify that the location (and
727 // other display options) are handled as a special case in the front-end.
728 // In this case, *no* schema will be output for this type.
729 struct SpecialFrontendLocation {};
730
731 enum class Format {
732 // ----------------------------------------------------
733 // String types.
734
735 // Show the URL, and handle PII sanitization
736 Url,
737 // Show the file path, and handle PII sanitization.
738 FilePath,
739 // Show arbitrary string and handle PII sanitization
740 SanitizedString,
741 // Important, do not put URL or file path information here, as it will not
742 // be sanitized. Please be careful with including other types of PII here as
743 // well.
744 // e.g. "Label: Some String"
745 String,
746
747 // Show a string from a UniqueStringArray given an index in the profile.
748 // e.g. 1, given string table ["hello", "world"] will show "world"
749 UniqueString,
750
751 // ----------------------------------------------------
752 // Numeric types
753
754 // For time data that represents a duration of time.
755 // e.g. "Label: 5s, 5ms, 5μs"
756 Duration,
757 // Data that happened at a specific time, relative to the start of the
758 // profile. e.g. "Label: 15.5s, 20.5ms, 30.5μs"
759 Time,
760 // The following are alternatives to display a time only in a specific unit
761 // of time.
762 Seconds, // "Label: 5s"
763 Milliseconds, // "Label: 5ms"
764 Microseconds, // "Label: 5μs"
765 Nanoseconds, // "Label: 5ns"
766 // e.g. "Label: 5.55mb, 5 bytes, 312.5kb"
767 Bytes,
768 // This should be a value between 0 and 1.
769 // "Label: 50%"
770 Percentage,
771 // The integer should be used for generic representations of numbers.
772 // Do not use it for time information.
773 // "Label: 52, 5,323, 1,234,567"
774 Integer,
775 // The decimal should be used for generic representations of numbers.
776 // Do not use it for time information.
777 // "Label: 52.23, 0.0054, 123,456.78"
778 Decimal
779 };
780
781 // This represents groups of markers which MarkerTypes can expose to indicate
782 // what group they belong to (multiple groups are allowed combined in bitwise
783 // or). This is currently only used for ETW filtering. In the long run this
784 // should be generalized to gecko markers.
785 enum class ETWMarkerGroup : uint64_t {
786 Generic = 1,
787 UserMarkers = 1 << 1,
788 Memory = 1 << 2,
789 Scheduling = 1 << 3,
790 Text = 1 << 4,
791 Tracing = 1 << 5
792 };
793
794 // Flags which describe additional information for a PayloadField.
795 enum class PayloadFlags : uint32_t { None = 0, Searchable = 1 };
796
797 // This is one field of payload to be used for additional marker data.
798 struct PayloadField {
799 // Key identifying the marker.
800 const char* Key;
801 // Input type, this represents the data type specified.
802 InputType InputTy;
803 // Label, additional description.
804 const char* Label = nullptr;
805 // Format as written to the JSON.
806 Format Fmt = Format::String;
807 // Optional PayloadFlags.
808 PayloadFlags Flags = PayloadFlags::None;
809 };
810
811 enum class Searchable { NotSearchable, Searchable };
812 enum class GraphType { Line, Bar, FilledLine };
813 enum class GraphColor {
814 Blue,
815 Green,
816 Grey,
817 Ink,
818 Magenta,
819 Orange,
820 Purple,
821 Red,
822 Teal,
823 Yellow
824 };
825
826 // Marker schema, with a non-empty list of locations where markers should be
827 // shown.
828 // Tech note: Even though `aLocations` are templated arguments, they are
829 // assigned to an `enum class` object, so they can only be of that enum type.
830 template <typename... Locations>
831 explicit MarkerSchema(Location aLocation, Locations... aLocations)
832 : mLocations{aLocation, aLocations...} {}
833
834 // Alternative constructor for MarkerSchema.
835 explicit MarkerSchema(const mozilla::MarkerSchema::Location* aLocations,
836 size_t aLength)
837 : mLocations(aLocations, aLocations + aLength) {}
838
839 // Marker schema for types that have special frontend handling.
840 // Nothing else should be set in this case.
841 // Implicit to allow quick return from MarkerTypeDisplay functions.
842 MOZ_IMPLICIT MarkerSchema(SpecialFrontendLocation) {}
843
844 // Caller must specify location(s) or SpecialFrontendLocation above.
845 MarkerSchema() = delete;
846
847 // Optional labels in the marker chart, the chart tooltip, and the marker
848 // table. If not provided, the marker "name" will be used. The given string
849 // can contain element keys in braces to include data elements streamed by
850 // `StreamJSONMarkerData()`. E.g.: "This is {text}"
851
852#define LABEL_SETTER(name) \
853 MarkerSchema& Set##name(std::string a##name) { \
854 m##name = std::move(a##name); \
855 return *this; \
856 }
857
858 LABEL_SETTER(ChartLabel)
859 LABEL_SETTER(TooltipLabel)
860 LABEL_SETTER(TableLabel)
861
862#undef LABEL_SETTER
863
864 MarkerSchema& SetAllLabels(std::string aText) {
865 // Here we set the same text in each label.
866 // TODO: Move to a single "label" field once the front-end allows it.
867 SetChartLabel(aText);
868 SetTooltipLabel(aText);
869 SetTableLabel(std::move(aText));
870 return *this;
871 }
872
873 // Each data element that is streamed by `StreamJSONMarkerData()` can be
874 // displayed as indicated by using one of the `Add...` function below.
875 // Each `Add...` will add a line in the full marker description. Parameters:
876 // - `aKey`: Element property name as streamed by `StreamJSONMarkerData()`.
877 // - `aLabel`: Optional prefix. Defaults to the key name.
878 // - `aFormat`: How to format the data element value, see `Format` above.
879 // - `aSearchable`: Optional, indicates if the value is used in searches,
880 // defaults to false.
881
882 MarkerSchema& AddKeyFormat(std::string aKey, Format aFormat) {
883 mData.emplace_back(mozilla::VariantType<DynamicData>{},
884 DynamicData{std::move(aKey), mozilla::Nothing{}, aFormat,
885 mozilla::Nothing{}});
886 return *this;
887 }
888
889 MarkerSchema& AddKeyLabelFormat(std::string aKey, std::string aLabel,
890 Format aFormat) {
891 mData.emplace_back(
892 mozilla::VariantType<DynamicData>{},
893 DynamicData{std::move(aKey), mozilla::Some(std::move(aLabel)), aFormat,
894 mozilla::Nothing{}});
895 return *this;
896 }
897
898 MarkerSchema& AddKeyFormatSearchable(std::string aKey, Format aFormat,
899 Searchable aSearchable) {
900 mData.emplace_back(mozilla::VariantType<DynamicData>{},
901 DynamicData{std::move(aKey), mozilla::Nothing{}, aFormat,
902 mozilla::Some(aSearchable)});
903 return *this;
904 }
905
906 MarkerSchema& AddKeyLabelFormatSearchable(std::string aKey,
907 std::string aLabel, Format aFormat,
908 Searchable aSearchable) {
909 mData.emplace_back(
910 mozilla::VariantType<DynamicData>{},
911 DynamicData{std::move(aKey), mozilla::Some(std::move(aLabel)), aFormat,
912 mozilla::Some(aSearchable)});
913 return *this;
914 }
915
916 // The display may also include static rows.
917
918 MarkerSchema& AddStaticLabelValue(std::string aLabel, std::string aValue) {
919 mData.emplace_back(mozilla::VariantType<StaticData>{},
920 StaticData{std::move(aLabel), std::move(aValue)});
921 return *this;
922 }
923
924 // Markers can be shown as timeline tracks.
925
926 MarkerSchema& AddChart(std::string aKey, GraphType aType) {
927 mGraphs.emplace_back(GraphData{std::move(aKey), aType, mozilla::Nothing{}});
928 return *this;
929 }
930
931 MarkerSchema& AddChartColor(std::string aKey, GraphType aType,
932 GraphColor aColor) {
933 mGraphs.emplace_back(
934 GraphData{std::move(aKey), aType, mozilla::Some(aColor)});
935 return *this;
936 }
937
938 // Internal streaming function.
939 MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) void Stream(JSONWriter& aWriter, const Span<const char>& aName) &&;
940
941 private:
942 MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) static Span<const char> LocationToStringSpan(Location aLocation);
943 MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) static Span<const char> FormatToStringSpan(Format aFormat);
944 MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) static Span<const char> GraphTypeToStringSpan(GraphType aType);
945 MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) static Span<const char> GraphColorToStringSpan(GraphColor aColor);
946
947 // List of marker display locations. Empty for SpecialFrontendLocation.
948 std::vector<Location> mLocations;
949 // Labels for different places.
950 std::string mChartLabel;
951 std::string mTooltipLabel;
952 std::string mTableLabel;
953 // Main display, made of zero or more rows of key+label+format or label+value.
954 private:
955 struct DynamicData {
956 std::string mKey;
957 mozilla::Maybe<std::string> mLabel;
958 Format mFormat;
959 mozilla::Maybe<Searchable> mSearchable;
960 };
961 struct StaticData {
962 std::string mLabel;
963 std::string mValue;
964 };
965 using DataRow = mozilla::Variant<DynamicData, StaticData>;
966 using DataRowVector = std::vector<DataRow>;
967
968 DataRowVector mData;
969
970 struct GraphData {
971 std::string mKey;
972 GraphType mType;
973 mozilla::Maybe<GraphColor> mColor;
974 };
975 std::vector<GraphData> mGraphs;
976};
977
978namespace detail {
979// GCC doesn't allow this to live inside the class.
980template <typename PayloadType>
981static void StreamPayload(baseprofiler::SpliceableJSONWriter& aWriter,
982 const Span<const char> aKey,
983 const PayloadType& aPayload) {
984 aWriter.StringProperty(aKey, aPayload);
985}
986
987template <typename PayloadType>
988inline void StreamPayload(baseprofiler::SpliceableJSONWriter& aWriter,
989 const Span<const char> aKey,
990 const Maybe<PayloadType>& aPayload) {
991 if (aPayload.isSome()) {
992 StreamPayload(aWriter, aKey, *aPayload);
993 } else {
994 aWriter.NullProperty(aKey);
995 }
996}
997
998template <>
999inline void StreamPayload<bool>(baseprofiler::SpliceableJSONWriter& aWriter,
1000 const Span<const char> aKey,
1001 const bool& aPayload) {
1002 aWriter.BoolProperty(aKey, aPayload);
1003}
1004
1005template <>
1006inline void StreamPayload<ProfilerString8View>(
1007 baseprofiler::SpliceableJSONWriter& aWriter, const Span<const char> aKey,
1008 const ProfilerString8View& aPayload) {
1009 aWriter.StringProperty(aKey, aPayload);
1010}
1011} // namespace detail
1012
1013// This helper class is used by MarkerTypes that want to support the general
1014// MarkerType object schema. When using this the markers will also transmit
1015// their payload to the ETW tracer as well as requiring less inline code.
1016// This is a curiously recurring template, the template argument is the child
1017// class itself.
1018template <typename T>
1019struct BaseMarkerType {
1020 static constexpr const char* AllLabels = nullptr;
1021 static constexpr const char* ChartLabel = nullptr;
1022 static constexpr const char* TableLabel = nullptr;
1023 static constexpr const char* TooltipLabel = nullptr;
1024
1025 // This indicates whether this marker type wants the names passed to the
1026 // individual marker calls stores along with the marker.
1027 static constexpr bool StoreName = false;
1028
1029 static constexpr MarkerSchema::ETWMarkerGroup Group =
1030 MarkerSchema::ETWMarkerGroup::Generic;
1031
1032 static MarkerSchema MarkerTypeDisplay() {
1033 using MS = MarkerSchema;
1034 MS schema{T::Locations, std::size(T::Locations)};
1035 if (T::AllLabels) {
1036 schema.SetAllLabels(T::AllLabels);
1037 }
1038 if (T::ChartLabel) {
1039 schema.SetChartLabel(T::ChartLabel);
1040 }
1041 if (T::TableLabel) {
1042 schema.SetTableLabel(T::TableLabel);
1043 }
1044 if (T::TooltipLabel) {
1045 schema.SetTooltipLabel(T::TooltipLabel);
1046 }
1047 for (const MS::PayloadField field : T::PayloadFields) {
1048 if (field.Label) {
1049 if (uint32_t(field.Flags) & uint32_t(MS::PayloadFlags::Searchable)) {
1050 schema.AddKeyLabelFormatSearchable(field.Key, field.Label, field.Fmt,
1051 MS::Searchable::Searchable);
1052 } else {
1053 schema.AddKeyLabelFormat(field.Key, field.Label, field.Fmt);
1054 }
1055 } else {
1056 if (uint32_t(field.Flags) & uint32_t(MS::PayloadFlags::Searchable)) {
1057 schema.AddKeyFormatSearchable(field.Key, field.Fmt,
1058 MS::Searchable::Searchable);
1059 } else {
1060 schema.AddKeyFormat(field.Key, field.Fmt);
1061 }
1062 }
1063 }
1064 if (T::Description) {
1065 schema.AddStaticLabelValue("Description", T::Description);
1066 }
1067 return schema;
1068 }
1069
1070 static constexpr Span<const char> MarkerTypeName() {
1071 return MakeStringSpan(T::Name);
1072 }
1073
1074 // This is called by the child class since the child class version of this
1075 // function is used to infer the argument types by the profile buffer and
1076 // allows the child to do any special data conversion it needs to do.
1077 // Optionally the child can opt not to use this at all and write the data
1078 // out itself.
1079 template <typename... PayloadArguments>
1080 static void StreamJSONMarkerDataImpl(
1081 baseprofiler::SpliceableJSONWriter& aWriter,
1082 const PayloadArguments&... aPayloadArguments) {
1083 size_t i = 0;
1084 (detail::StreamPayload(aWriter, MakeStringSpan(T::PayloadFields[i++].Key),
1085 aPayloadArguments),
1086 ...);
1087 }
1088};
1089} // namespace mozilla
1090
1091#endif // BaseProfilerMarkersPrerequisites_h

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/TimeStamp.h

1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#ifndef mozilla_TimeStamp_h
8#define mozilla_TimeStamp_h
9
10#include "mozilla/Assertions.h"
11#include "mozilla/Attributes.h"
12#include "mozilla/FloatingPoint.h"
13#include "mozilla/Types.h"
14#include <algorithm> // for std::min, std::max
15#include <ostream>
16#include <stdint.h>
17#include <type_traits>
18
19namespace IPC {
20template <typename T>
21struct ParamTraits;
22} // namespace IPC
23
24#ifdef XP_WIN
25// defines TimeStampValue as a complex value keeping both
26// GetTickCount and QueryPerformanceCounter values
27# include "TimeStamp_windows.h"
28
29# include "mozilla/Maybe.h" // For TimeStamp::RawQueryPerformanceCounterValue
30#endif
31
32namespace mozilla {
33
34#ifndef XP_WIN
35typedef uint64_t TimeStampValue;
36#endif
37
38class TimeStamp;
39class TimeStampTests;
40
41/**
42 * Platform-specific implementation details of BaseTimeDuration.
43 */
44class BaseTimeDurationPlatformUtils {
45 public:
46 static MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) double ToSeconds(int64_t aTicks);
47 static MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) double ToSecondsSigDigits(int64_t aTicks);
48 static MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) int64_t TicksFromMilliseconds(double aMilliseconds);
49 static MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) int64_t ResolutionInTicks();
50};
51
52/**
53 * Instances of this class represent the length of an interval of time.
54 * Negative durations are allowed, meaning the end is before the start.
55 *
56 * Internally the duration is stored as a int64_t in units of
57 * PR_TicksPerSecond() when building with NSPR interval timers, or a
58 * system-dependent unit when building with system clocks. The
59 * system-dependent unit must be constant, otherwise the semantics of
60 * this class would be broken.
61 *
62 * The ValueCalculator template parameter determines how arithmetic
63 * operations are performed on the integer count of ticks (mValue).
64 */
65template <typename ValueCalculator>
66class BaseTimeDuration {
67 public:
68 // The default duration is 0.
69 constexpr BaseTimeDuration() : mValue(0) {}
70 // Allow construction using '0' as the initial value, for readability,
71 // but no other numbers (so we don't have any implicit unit conversions).
72 struct _SomethingVeryRandomHere;
73 MOZ_IMPLICIT BaseTimeDuration(_SomethingVeryRandomHere* aZero) : mValue(0) {
74 MOZ_ASSERT(!aZero, "Who's playing funny games here?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aZero)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(!aZero))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!aZero" " (" "Who's playing funny games here?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/TimeStamp.h"
, 74); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aZero" ") ("
"Who's playing funny games here?" ")"); do { *((volatile int
*)__null) = 74; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
75 }
76 // Default copy-constructor and assignment are OK
77
78 // Converting copy-constructor and assignment operator
79 template <typename E>
80 explicit BaseTimeDuration(const BaseTimeDuration<E>& aOther)
81 : mValue(aOther.mValue) {}
82
83 template <typename E>
84 BaseTimeDuration& operator=(const BaseTimeDuration<E>& aOther) {
85 mValue = aOther.mValue;
86 return *this;
87 }
88
89 double ToSeconds() const {
90 if (mValue == INT64_MAX(9223372036854775807L)) {
91 return PositiveInfinity<double>();
92 }
93 if (mValue == INT64_MIN(-9223372036854775807L -1)) {
94 return NegativeInfinity<double>();
95 }
96 return BaseTimeDurationPlatformUtils::ToSeconds(mValue);
97 }
98 // Return a duration value that includes digits of time we think to
99 // be significant. This method should be used when displaying a
100 // time to humans.
101 double ToSecondsSigDigits() const {
102 if (mValue == INT64_MAX(9223372036854775807L)) {
103 return PositiveInfinity<double>();
104 }
105 if (mValue == INT64_MIN(-9223372036854775807L -1)) {
106 return NegativeInfinity<double>();
107 }
108 return BaseTimeDurationPlatformUtils::ToSecondsSigDigits(mValue);
109 }
110 double ToMilliseconds() const { return ToSeconds() * 1000.0; }
111 double ToMicroseconds() const { return ToMilliseconds() * 1000.0; }
112
113 // Using a double here is safe enough; with 53 bits we can represent
114 // durations up to over 280,000 years exactly. If the units of
115 // mValue do not allow us to represent durations of that length,
116 // long durations are clamped to the max/min representable value
117 // instead of overflowing.
118 static inline BaseTimeDuration FromSeconds(double aSeconds) {
119 return FromMilliseconds(aSeconds * 1000.0);
120 }
121 static BaseTimeDuration FromMilliseconds(double aMilliseconds) {
122 if (aMilliseconds == PositiveInfinity<double>()) {
123 return Forever();
124 }
125 if (aMilliseconds == NegativeInfinity<double>()) {
126 return FromTicks(INT64_MIN(-9223372036854775807L -1));
127 }
128 return FromTicks(
129 BaseTimeDurationPlatformUtils::TicksFromMilliseconds(aMilliseconds));
130 }
131 static inline BaseTimeDuration FromMicroseconds(double aMicroseconds) {
132 return FromMilliseconds(aMicroseconds / 1000.0);
133 }
134
135 static constexpr BaseTimeDuration Zero() { return BaseTimeDuration(); }
136 static constexpr BaseTimeDuration Forever() { return FromTicks(INT64_MAX(9223372036854775807L)); }
137
138 BaseTimeDuration operator+(const BaseTimeDuration& aOther) const {
139 return FromTicks(ValueCalculator::Add(mValue, aOther.mValue));
140 }
141 BaseTimeDuration operator-(const BaseTimeDuration& aOther) const {
142 return FromTicks(ValueCalculator::Subtract(mValue, aOther.mValue));
143 }
144 BaseTimeDuration& operator+=(const BaseTimeDuration& aOther) {
145 mValue = ValueCalculator::Add(mValue, aOther.mValue);
146 return *this;
147 }
148 BaseTimeDuration& operator-=(const BaseTimeDuration& aOther) {
149 mValue = ValueCalculator::Subtract(mValue, aOther.mValue);
150 return *this;
151 }
152 BaseTimeDuration operator-() const {
153 // We don't just use FromTicks(ValueCalculator::Subtract(0, mValue))
154 // since that won't give the correct result for -TimeDuration::Forever().
155 int64_t ticks;
156 if (mValue == INT64_MAX(9223372036854775807L)) {
157 ticks = INT64_MIN(-9223372036854775807L -1);
158 } else if (mValue == INT64_MIN(-9223372036854775807L -1)) {
159 ticks = INT64_MAX(9223372036854775807L);
160 } else {
161 ticks = -mValue;
162 }
163
164 return FromTicks(ticks);
165 }
166
167 static BaseTimeDuration Max(const BaseTimeDuration& aA,
168 const BaseTimeDuration& aB) {
169 return FromTicks(std::max(aA.mValue, aB.mValue));
170 }
171 static BaseTimeDuration Min(const BaseTimeDuration& aA,
172 const BaseTimeDuration& aB) {
173 return FromTicks(std::min(aA.mValue, aB.mValue));
174 }
175
176#if defined(DEBUG1)
177 int64_t GetValue() const { return mValue; }
178#endif
179
180 private:
181 // Block double multiplier (slower, imprecise if long duration) - Bug 853398.
182 // If required, use MultDouble explicitly and with care.
183 BaseTimeDuration operator*(const double aMultiplier) const = delete;
184
185 // Block double divisor (for the same reason, and because dividing by
186 // fractional values would otherwise invoke the int64_t variant, and rounding
187 // the passed argument can then cause divide-by-zero) - Bug 1147491.
188 BaseTimeDuration operator/(const double aDivisor) const = delete;
189
190 public:
191 BaseTimeDuration MultDouble(double aMultiplier) const {
192 return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier));
193 }
194 BaseTimeDuration operator*(const int32_t aMultiplier) const {
195 return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier));
196 }
197 BaseTimeDuration operator*(const uint32_t aMultiplier) const {
198 return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier));
199 }
200 BaseTimeDuration operator*(const int64_t aMultiplier) const {
201 return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier));
202 }
203 BaseTimeDuration operator*(const uint64_t aMultiplier) const {
204 if (aMultiplier > INT64_MAX(9223372036854775807L)) {
205 return Forever();
206 }
207 return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier));
208 }
209 BaseTimeDuration operator/(const int64_t aDivisor) const {
210 MOZ_ASSERT(aDivisor != 0, "Division by zero")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDivisor != 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDivisor != 0))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aDivisor != 0" " ("
"Division by zero" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/TimeStamp.h"
, 210); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDivisor != 0"
") (" "Division by zero" ")"); do { *((volatile int*)__null)
= 210; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
211 return FromTicks(ValueCalculator::Divide(mValue, aDivisor));
212 }
213 double operator/(const BaseTimeDuration& aOther) const {
214 MOZ_ASSERT(aOther.mValue != 0, "Division by zero")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOther.mValue != 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aOther.mValue != 0))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aOther.mValue != 0"
" (" "Division by zero" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/TimeStamp.h"
, 214); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOther.mValue != 0"
") (" "Division by zero" ")"); do { *((volatile int*)__null)
= 214; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
215 return ValueCalculator::DivideDouble(mValue, aOther.mValue);
216 }
217 BaseTimeDuration operator%(const BaseTimeDuration& aOther) const {
218 MOZ_ASSERT(aOther.mValue != 0, "Division by zero")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOther.mValue != 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aOther.mValue != 0))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aOther.mValue != 0"
" (" "Division by zero" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/TimeStamp.h"
, 218); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOther.mValue != 0"
") (" "Division by zero" ")"); do { *((volatile int*)__null)
= 218; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
219 return FromTicks(ValueCalculator::Modulo(mValue, aOther.mValue));
220 }
221
222 template <typename E>
223 bool operator<(const BaseTimeDuration<E>& aOther) const {
224 return mValue < aOther.mValue;
225 }
226 template <typename E>
227 bool operator<=(const BaseTimeDuration<E>& aOther) const {
228 return mValue <= aOther.mValue;
229 }
230 template <typename E>
231 bool operator>=(const BaseTimeDuration<E>& aOther) const {
232 return mValue >= aOther.mValue;
233 }
234 template <typename E>
235 bool operator>(const BaseTimeDuration<E>& aOther) const {
236 return mValue > aOther.mValue;
237 }
238 template <typename E>
239 bool operator==(const BaseTimeDuration<E>& aOther) const {
240 return mValue == aOther.mValue;
241 }
242 template <typename E>
243 bool operator!=(const BaseTimeDuration<E>& aOther) const {
244 return mValue != aOther.mValue;
245 }
246 bool IsZero() const { return mValue == 0; }
247 explicit operator bool() const { return mValue != 0; }
248
249 friend std::ostream& operator<<(std::ostream& aStream,
250 const BaseTimeDuration& aDuration) {
251 return aStream << aDuration.ToMilliseconds() << " ms";
252 }
253
254 // Return a best guess at the system's current timing resolution,
255 // which might be variable. BaseTimeDurations below this order of
256 // magnitude are meaningless, and those at the same order of
257 // magnitude or just above are suspect.
258 static BaseTimeDuration Resolution() {
259 return FromTicks(BaseTimeDurationPlatformUtils::ResolutionInTicks());
260 }
261
262 // We could define additional operators here:
263 // -- convert to/from other time units
264 // -- scale duration by a float
265 // but let's do that on demand.
266 // Comparing durations for equality will only lead to bugs on
267 // platforms with high-resolution timers.
268
269 private:
270 friend class TimeStamp;
271 friend struct IPC::ParamTraits<mozilla::BaseTimeDuration<ValueCalculator>>;
272 template <typename>
273 friend class BaseTimeDuration;
274
275 static constexpr BaseTimeDuration FromTicks(int64_t aTicks) {
276 BaseTimeDuration t;
277 t.mValue = aTicks;
278 return t;
279 }
280
281 static BaseTimeDuration FromTicks(double aTicks) {
282 // NOTE: this MUST be a >= test, because int64_t(double(INT64_MAX))
283 // overflows and gives INT64_MIN.
284 if (aTicks >= double(INT64_MAX(9223372036854775807L))) {
285 return FromTicks(INT64_MAX(9223372036854775807L));
286 }
287
288 // This MUST be a <= test.
289 if (aTicks <= double(INT64_MIN(-9223372036854775807L -1))) {
290 return FromTicks(INT64_MIN(-9223372036854775807L -1));
291 }
292
293 return FromTicks(int64_t(aTicks));
294 }
295
296 // Duration, result is implementation-specific difference of two TimeStamps
297 int64_t mValue;
298};
299
300/**
301 * Perform arithmetic operations on the value of a BaseTimeDuration without
302 * doing strict checks on the range of values.
303 */
304class TimeDurationValueCalculator {
305 public:
306 static int64_t Add(int64_t aA, int64_t aB) { return aA + aB; }
307 static int64_t Subtract(int64_t aA, int64_t aB) { return aA - aB; }
308
309 template <typename T>
310 static int64_t Multiply(int64_t aA, T aB) {
311 static_assert(std::is_integral_v<T>,
312 "Using integer multiplication routine with non-integer type."
313 " Further specialization required");
314 return aA * static_cast<int64_t>(aB);
315 }
316
317 static int64_t Divide(int64_t aA, int64_t aB) { return aA / aB; }
318 static double DivideDouble(int64_t aA, int64_t aB) {
319 return static_cast<double>(aA) / aB;
320 }
321 static int64_t Modulo(int64_t aA, int64_t aB) { return aA % aB; }
322};
323
324template <>
325inline int64_t TimeDurationValueCalculator::Multiply<double>(int64_t aA,
326 double aB) {
327 return static_cast<int64_t>(aA * aB);
328}
329
330/**
331 * Specialization of BaseTimeDuration that uses TimeDurationValueCalculator for
332 * arithmetic on the mValue member.
333 *
334 * Use this class for time durations that are *not* expected to hold values of
335 * Forever (or the negative equivalent) or when such time duration are *not*
336 * expected to be used in arithmetic operations.
337 */
338typedef BaseTimeDuration<TimeDurationValueCalculator> TimeDuration;
339
340/**
341 * Instances of this class represent moments in time, or a special
342 * "null" moment. We do not use the non-monotonic system clock or
343 * local time, since they can be reset, causing apparent backward
344 * travel in time, which can confuse algorithms. Instead we measure
345 * elapsed time according to the system. This time can never go
346 * backwards (i.e. it never wraps around, at least not in less than
347 * five million years of system elapsed time). It might not advance
348 * while the system is sleeping. If TimeStamp::SetNow() is not called
349 * at all for hours or days, we might not notice the passage of some
350 * of that time.
351 *
352 * We deliberately do not expose a way to convert TimeStamps to some
353 * particular unit. All you can do is compute a difference between two
354 * TimeStamps to get a TimeDuration. You can also add a TimeDuration
355 * to a TimeStamp to get a new TimeStamp. You can't do something
356 * meaningless like add two TimeStamps.
357 *
358 * Internally this is implemented as either a wrapper around
359 * - high-resolution, monotonic, system clocks if they exist on this
360 * platform
361 * - PRIntervalTime otherwise. We detect wraparounds of
362 * PRIntervalTime and work around them.
363 *
364 * This class is similar to C++11's time_point, however it is
365 * explicitly nullable and provides an IsNull() method. time_point
366 * is initialized to the clock's epoch and provides a
367 * time_since_epoch() method that functions similiarly. i.e.
368 * t.IsNull() is equivalent to t.time_since_epoch() ==
369 * decltype(t)::duration::zero();
370 *
371 * Note that, since TimeStamp objects are small, prefer to pass them by value
372 * unless there is a specific reason not to do so.
373 */
374#if defined(XP_WIN)
375// If this static_assert fails then possibly the warning comment below is no
376// longer valid and should be removed.
377static_assert(sizeof(TimeStampValue) > 8);
378#endif
379/*
380 * WARNING: On Windows, each TimeStamp is represented internally by two
381 * different raw values (one from GTC and one from QPC) and which value gets
382 * used for a given operation depends on whether both operands have QPC values
383 * or not. This duality of values can lead to some surprising results when
384 * mixing TimeStamps with and without QPC values, such as comparisons being
385 * non-transitive (ie, a > b > c might not imply a > c). See bug 1829983 for
386 * more details/an example.
387 */
388class TimeStamp {
389 public:
390 /**
391 * Initialize to the "null" moment
392 */
393 constexpr TimeStamp() : mValue(0) {}
394 // Default copy-constructor and assignment are OK
395
396 /**
397 * The system timestamps are the same as the TimeStamp
398 * retrieved by mozilla::TimeStamp. Since we need this for
399 * vsync timestamps, we enable the creation of mozilla::TimeStamps
400 * on platforms that support vsync aligned refresh drivers / compositors
401 * Verified true as of Jan 31, 2015: B2G and OS X
402 * False on Windows 7
403 * Android's event time uses CLOCK_MONOTONIC via SystemClock.uptimeMilles.
404 * So it is same value of TimeStamp posix implementation.
405 * Wayland/GTK event time also uses CLOCK_MONOTONIC on Weston/Mutter
406 * compositors.
407 * UNTESTED ON OTHER PLATFORMS
408 */
409#if defined(XP_DARWIN) || defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK1)
410 static TimeStamp FromSystemTime(int64_t aSystemTime) {
411 static_assert(sizeof(aSystemTime) == sizeof(TimeStampValue),
412 "System timestamp should be same units as TimeStampValue");
413 return TimeStamp(aSystemTime);
414 }
415#endif
416
417 /**
418 * Return true if this is the "null" moment
419 */
420 constexpr bool IsNull() const { return mValue == 0; }
31
The left operand of '==' is a garbage value
421
422 /**
423 * Return true if this is not the "null" moment, may be used in tests, e.g.:
424 * |if (timestamp) { ... }|
425 */
426 explicit operator bool() const { return mValue != 0; }
427
428 /**
429 * Return a timestamp reflecting the current elapsed system time. This
430 * is monotonically increasing (i.e., does not decrease) over the
431 * lifetime of this process' XPCOM session.
432 *
433 * Now() is trying to ensure the best possible precision on each platform,
434 * at least one millisecond.
435 *
436 * NowLoRes() has been introduced to workaround performance problems of
437 * QueryPerformanceCounter on the Windows platform. NowLoRes() is giving
438 * lower precision, usually 15.6 ms, but with very good performance benefit.
439 * Use it for measurements of longer times, like >200ms timeouts.
440 */
441 static TimeStamp Now() { return Now(true); }
442 static TimeStamp NowLoRes() { return Now(false); }
443
444 /**
445 * Return a timestamp representing the time when the current process was
446 * created which will be comparable with other timestamps taken with this
447 * class.
448 *
449 * @returns A timestamp representing the time when the process was created
450 */
451 static MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) TimeStamp ProcessCreation();
452
453 /**
454 * Return the very first timestamp that was taken. This can be used instead
455 * of TimeStamp::ProcessCreation() by code that might not allow running the
456 * complex logic required to compute the real process creation. This will
457 * necessarily have been recorded sometimes after TimeStamp::ProcessCreation()
458 * or at best should be equal to it.
459 *
460 * @returns The first tiemstamp that was taken by this process
461 */
462 static MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) TimeStamp FirstTimeStamp();
463
464 /**
465 * Records a process restart. After this call ProcessCreation() will return
466 * the time when the browser was restarted instead of the actual time when
467 * the process was created.
468 */
469 static MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) void RecordProcessRestart();
470
471#ifdef XP_LINUX1
472 uint64_t RawClockMonotonicNanosecondsSinceBoot() const {
473 return static_cast<uint64_t>(mValue);
474 }
475#endif
476
477#ifdef XP_DARWIN
478 // Returns the number of nanoseconds since the mach_absolute_time origin.
479 MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) uint64_t RawMachAbsoluteTimeNanoseconds() const;
480#endif
481
482#ifdef XP_WIN
483 Maybe<uint64_t> RawQueryPerformanceCounterValue() const {
484 // mQPC is stored in `mt` i.e. QueryPerformanceCounter * 1000
485 // so divide out the 1000
486 return mValue.mHasQPC ? Some(mValue.mQPC / 1000ULL) : Nothing();
487 }
488#endif
489
490 /**
491 * Compute the difference between two timestamps. Both must be non-null.
492 */
493 TimeDuration operator-(const TimeStamp& aOther) const {
494 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsNull()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsNull()" " (" "Cannot compute with a null value"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/TimeStamp.h"
, 494); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsNull()" ") ("
"Cannot compute with a null value" ")"); do { *((volatile int
*)__null) = 494; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
495 MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aOther.IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aOther.IsNull()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!aOther.IsNull()"
" (" "Cannot compute with aOther null value" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/TimeStamp.h"
, 495); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aOther.IsNull()"
") (" "Cannot compute with aOther null value" ")"); do { *((
volatile int*)__null) = 495; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
496 static_assert(-INT64_MAX(9223372036854775807L) > INT64_MIN(-9223372036854775807L -1), "int64_t sanity check");
497 int64_t ticks = int64_t(mValue - aOther.mValue);
498 // Check for overflow.
499 if (mValue > aOther.mValue) {
500 if (ticks < 0) {
501 ticks = INT64_MAX(9223372036854775807L);
502 }
503 } else {
504 if (ticks > 0) {
505 ticks = INT64_MIN(-9223372036854775807L -1);
506 }
507 }
508 return TimeDuration::FromTicks(ticks);
509 }
510
511 TimeStamp operator+(const TimeDuration& aOther) const {
512 TimeStamp result = *this;
513 result += aOther;
514 return result;
515 }
516 TimeStamp operator-(const TimeDuration& aOther) const {
517 TimeStamp result = *this;
518 result -= aOther;
519 return result;
520 }
521 TimeStamp& operator+=(const TimeDuration& aOther) {
522 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsNull()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsNull()" " (" "Cannot compute with a null value"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/TimeStamp.h"
, 522); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsNull()" ") ("
"Cannot compute with a null value" ")"); do { *((volatile int
*)__null) = 522; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
523 TimeStampValue value = mValue + aOther.mValue;
524 // Check for underflow.
525 // (We don't check for overflow because it's not obvious what the error
526 // behavior should be in that case.)
527 if (aOther.mValue < 0 && value > mValue) {
528 value = 0;
529 }
530 mValue = value;
531 return *this;
532 }
533 TimeStamp& operator-=(const TimeDuration& aOther) {
534 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsNull()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsNull()" " (" "Cannot compute with a null value"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/TimeStamp.h"
, 534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsNull()" ") ("
"Cannot compute with a null value" ")"); do { *((volatile int
*)__null) = 534; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
535 TimeStampValue value = mValue - aOther.mValue;
536 // Check for underflow.
537 // (We don't check for overflow because it's not obvious what the error
538 // behavior should be in that case.)
539 if (aOther.mValue > 0 && value > mValue) {
540 value = 0;
541 }
542 mValue = value;
543 return *this;
544 }
545
546 constexpr bool operator<(const TimeStamp& aOther) const {
547 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsNull()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsNull()" " (" "Cannot compute with a null value"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/TimeStamp.h"
, 547); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsNull()" ") ("
"Cannot compute with a null value" ")"); do { *((volatile int
*)__null) = 547; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
548 MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aOther.IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aOther.IsNull()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!aOther.IsNull()"
" (" "Cannot compute with aOther null value" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/TimeStamp.h"
, 548); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aOther.IsNull()"
") (" "Cannot compute with aOther null value" ")"); do { *((
volatile int*)__null) = 548; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
549 return mValue < aOther.mValue;
550 }
551 constexpr bool operator<=(const TimeStamp& aOther) const {
552 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsNull()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsNull()" " (" "Cannot compute with a null value"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/TimeStamp.h"
, 552); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsNull()" ") ("
"Cannot compute with a null value" ")"); do { *((volatile int
*)__null) = 552; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
553 MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aOther.IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aOther.IsNull()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!aOther.IsNull()"
" (" "Cannot compute with aOther null value" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/TimeStamp.h"
, 553); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aOther.IsNull()"
") (" "Cannot compute with aOther null value" ")"); do { *((
volatile int*)__null) = 553; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
554 return mValue <= aOther.mValue;
555 }
556 constexpr bool operator>=(const TimeStamp& aOther) const {
557 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsNull()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsNull()" " (" "Cannot compute with a null value"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/TimeStamp.h"
, 557); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsNull()" ") ("
"Cannot compute with a null value" ")"); do { *((volatile int
*)__null) = 557; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
558 MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aOther.IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aOther.IsNull()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!aOther.IsNull()"
" (" "Cannot compute with aOther null value" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/TimeStamp.h"
, 558); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aOther.IsNull()"
") (" "Cannot compute with aOther null value" ")"); do { *((
volatile int*)__null) = 558; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
559 return mValue >= aOther.mValue;
560 }
561 constexpr bool operator>(const TimeStamp& aOther) const {
562 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsNull()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsNull()" " (" "Cannot compute with a null value"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/TimeStamp.h"
, 562); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsNull()" ") ("
"Cannot compute with a null value" ")"); do { *((volatile int
*)__null) = 562; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
563 MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aOther.IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aOther.IsNull()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!aOther.IsNull()"
" (" "Cannot compute with aOther null value" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/TimeStamp.h"
, 563); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aOther.IsNull()"
") (" "Cannot compute with aOther null value" ")"); do { *((
volatile int*)__null) = 563; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
564 return mValue > aOther.mValue;
565 }
566 bool operator==(const TimeStamp& aOther) const {
567 return IsNull() ? aOther.IsNull()
568 : !aOther.IsNull() && mValue == aOther.mValue;
569 }
570 bool operator!=(const TimeStamp& aOther) const { return !(*this == aOther); }
571
572 // Comparing TimeStamps for equality should be discouraged. Adding
573 // two TimeStamps, or scaling TimeStamps, is nonsense and must never
574 // be allowed.
575
576 static MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) void Startup();
577 static MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) void Shutdown();
578
579#if defined(DEBUG1)
580 TimeStampValue GetValue() const { return mValue; }
581#endif
582
583 private:
584 friend struct IPC::ParamTraits<mozilla::TimeStamp>;
585 friend struct TimeStampInitialization;
586 friend class TimeStampTests;
587
588 constexpr MOZ_IMPLICIT TimeStamp(TimeStampValue aValue) : mValue(aValue) {}
589
590 static MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) TimeStamp Now(bool aHighResolution);
591
592 /**
593 * Computes the uptime of the current process in microseconds. The result
594 * is platform-dependent and needs to be checked against existing timestamps
595 * for consistency.
596 *
597 * @returns The number of microseconds since the calling process was started
598 * or 0 if an error was encountered while computing the uptime
599 */
600 static MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) uint64_t ComputeProcessUptime();
601
602 /**
603 * When built with PRIntervalTime, a value of 0 means this instance
604 * is "null". Otherwise, the low 32 bits represent a PRIntervalTime,
605 * and the high 32 bits represent a counter of the number of
606 * rollovers of PRIntervalTime that we've seen. This counter starts
607 * at 1 to avoid a real time colliding with the "null" value.
608 *
609 * PR_INTERVAL_MAX is set at 100,000 ticks per second. So the minimum
610 * time to wrap around is about 2^64/100000 seconds, i.e. about
611 * 5,849,424 years.
612 *
613 * When using a system clock, a value is system dependent.
614 */
615 TimeStampValue mValue;
616};
617
618} // namespace mozilla
619
620#endif /* mozilla_TimeStamp_h */