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 |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
412 | extern "C" int MOZ_XMLTranslateEntity(const char* ptr, const char* end, | |||
413 | const char** next, char16_t* result); | |||
414 | extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end, int ns_aware, | |||
415 | const char** colon); | |||
416 | ||||
417 | using namespace mozilla::dom; | |||
418 | using namespace mozilla::ipc; | |||
419 | using namespace mozilla::gfx; | |||
420 | using namespace mozilla::layers; | |||
421 | using namespace mozilla::widget; | |||
422 | using namespace mozilla; | |||
423 | ||||
424 | const char kLoadAsData[] = "loadAsData"; | |||
425 | ||||
426 | nsIXPConnect* nsContentUtils::sXPConnect; | |||
427 | nsIScriptSecurityManager* nsContentUtils::sSecurityManager; | |||
428 | nsIPrincipal* nsContentUtils::sSystemPrincipal; | |||
429 | nsIPrincipal* nsContentUtils::sNullSubjectPrincipal; | |||
430 | nsIPrincipal* nsContentUtils::sFingerprintingProtectionPrincipal; | |||
431 | nsIConsoleService* nsContentUtils::sConsoleService; | |||
432 | ||||
433 | static nsTHashMap<RefPtr<nsAtom>, EventNameMapping>* sAtomEventTable; | |||
434 | static nsTHashMap<nsStringHashKey, EventNameMapping>* sStringEventTable; | |||
435 | static nsTArray<RefPtr<nsAtom>>* sUserDefinedEvents; | |||
436 | nsIStringBundleService* nsContentUtils::sStringBundleService; | |||
437 | ||||
438 | static StaticRefPtr<nsIStringBundle> | |||
439 | sStringBundles[nsContentUtils::PropertiesFile_COUNT]; | |||
440 | ||||
441 | nsIContentPolicy* nsContentUtils::sContentPolicyService; | |||
442 | bool nsContentUtils::sTriedToGetContentPolicy = false; | |||
443 | StaticRefPtr<nsIBidiKeyboard> nsContentUtils::sBidiKeyboard; | |||
444 | uint32_t nsContentUtils::sScriptBlockerCount = 0; | |||
445 | uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0; | |||
446 | AutoTArray<nsCOMPtr<nsIRunnable>, 8>* nsContentUtils::sBlockedScriptRunners = | |||
447 | nullptr; | |||
448 | uint32_t nsContentUtils::sRunnersCountAtFirstBlocker = 0; | |||
449 | nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nullptr; | |||
450 | ||||
451 | bool nsContentUtils::sIsHandlingKeyBoardEvent = false; | |||
452 | ||||
453 | nsString* nsContentUtils::sShiftText = nullptr; | |||
454 | nsString* nsContentUtils::sControlText = nullptr; | |||
455 | nsString* nsContentUtils::sCommandOrWinText = nullptr; | |||
456 | nsString* nsContentUtils::sAltText = nullptr; | |||
457 | nsString* nsContentUtils::sModifierSeparator = nullptr; | |||
458 | ||||
459 | bool nsContentUtils::sInitialized = false; | |||
460 | #ifndef RELEASE_OR_BETA | |||
461 | bool nsContentUtils::sBypassCSSOMOriginCheck = false; | |||
462 | #endif | |||
463 | ||||
464 | nsCString* nsContentUtils::sJSScriptBytecodeMimeType = nullptr; | |||
465 | nsCString* nsContentUtils::sJSModuleBytecodeMimeType = nullptr; | |||
466 | ||||
467 | nsContentUtils::UserInteractionObserver* | |||
468 | nsContentUtils::sUserInteractionObserver = nullptr; | |||
469 | ||||
470 | nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr; | |||
471 | nsParser* nsContentUtils::sXMLFragmentParser = nullptr; | |||
472 | nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr; | |||
473 | bool nsContentUtils::sFragmentParsingActive = false; | |||
474 | ||||
475 | bool nsContentUtils::sMayHaveFormCheckboxStateChangeListeners = false; | |||
476 | bool nsContentUtils::sMayHaveFormRadioStateChangeListeners = false; | |||
477 | ||||
478 | mozilla::LazyLogModule nsContentUtils::gResistFingerprintingLog( | |||
479 | "nsResistFingerprinting"); | |||
480 | mozilla::LazyLogModule nsContentUtils::sDOMDumpLog("Dump"); | |||
481 | ||||
482 | int32_t nsContentUtils::sInnerOrOuterWindowCount = 0; | |||
483 | uint32_t nsContentUtils::sInnerOrOuterWindowSerialCounter = 0; | |||
484 | ||||
485 | template Maybe<int32_t> nsContentUtils::ComparePoints( | |||
486 | const RangeBoundary& aFirstBoundary, const RangeBoundary& aSecondBoundary); | |||
487 | template Maybe<int32_t> nsContentUtils::ComparePoints( | |||
488 | const RangeBoundary& aFirstBoundary, | |||
489 | const RawRangeBoundary& aSecondBoundary); | |||
490 | template Maybe<int32_t> nsContentUtils::ComparePoints( | |||
491 | const RawRangeBoundary& aFirstBoundary, | |||
492 | const RangeBoundary& aSecondBoundary); | |||
493 | template Maybe<int32_t> nsContentUtils::ComparePoints( | |||
494 | const RawRangeBoundary& aFirstBoundary, | |||
495 | const RawRangeBoundary& aSecondBoundary); | |||
496 | ||||
497 | template int32_t nsContentUtils::ComparePoints_Deprecated( | |||
498 | const RangeBoundary& aFirstBoundary, const RangeBoundary& aSecondBoundary, | |||
499 | bool* aDisconnected); | |||
500 | template int32_t nsContentUtils::ComparePoints_Deprecated( | |||
501 | const RangeBoundary& aFirstBoundary, | |||
502 | const RawRangeBoundary& aSecondBoundary, bool* aDisconnected); | |||
503 | template int32_t nsContentUtils::ComparePoints_Deprecated( | |||
504 | const RawRangeBoundary& aFirstBoundary, | |||
505 | const RangeBoundary& aSecondBoundary, bool* aDisconnected); | |||
506 | template 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 | |||
512 | enum 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 | ||||
519 | enum 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 | ||||
526 | enum 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 | ||||
533 | enum 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 | ||||
542 | enum AutocompleteFieldHint : uint8_t { | |||
543 | #define AUTOCOMPLETE_FIELD_HINT(name_, value_) eAutocompleteFieldHint_##name_, | |||
544 | #include "AutocompleteFieldList.h" | |||
545 | #undef AUTOCOMPLETE_FIELD_HINT | |||
546 | }; | |||
547 | ||||
548 | enum 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 | ||||
555 | enum AutocompleteCredentialType : uint8_t { | |||
556 | #define AUTOCOMPLETE_CREDENTIAL_TYPE(name_, value_) \ | |||
557 | eAutocompleteCredentialType_##name_, | |||
558 | #include "AutocompleteFieldList.h" | |||
559 | #undef AUTOCOMPLETE_CREDENTIAL_TYPE | |||
560 | }; | |||
561 | ||||
562 | enum AutocompleteCategory { | |||
563 | #define AUTOCOMPLETE_CATEGORY(name_, value_) eAutocompleteCategory_##name_, | |||
564 | #include "AutocompleteFieldList.h" | |||
565 | #undef AUTOCOMPLETE_CATEGORY | |||
566 | }; | |||
567 | ||||
568 | static 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 | ||||
575 | static 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 | ||||
582 | static 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 | ||||
590 | static 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 | ||||
597 | static 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 | ||||
604 | static 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 | ||||
611 | static 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 | ||||
618 | static 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 | ||||
625 | namespace { | |||
626 | ||||
627 | static PLDHashTable* sEventListenerManagersHash; | |||
628 | ||||
629 | // A global hashtable to for keeping the arena alive for cross docGroup node | |||
630 | // adoption. | |||
631 | static nsRefPtrHashtable<nsPtrHashKey<const nsINode>, mozilla::dom::DOMArena>* | |||
632 | sDOMArenaHashtable; | |||
633 | ||||
634 | class 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 | ||||
660 | NS_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 | ||||
662 | class 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 | ||||
677 | static void EventListenerManagerHashInitEntry(PLDHashEntryHdr* entry, | |||
678 | const void* key) { | |||
679 | // Initialize the entry with placement new | |||
680 | new (entry) EventListenerManagerMapEntry(key); | |||
681 | } | |||
682 | ||||
683 | static 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 | ||||
692 | class 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 | ||||
703 | void 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 | ||||
714 | void AutoSuppressEventHandling::UnsuppressDocument(Document* aDoc) { | |||
715 | aDoc->UnsuppressEventHandlingAndFireEvents(true); | |||
716 | } | |||
717 | ||||
718 | AutoSuppressEventHandling::~AutoSuppressEventHandling() { | |||
719 | UnsuppressDocuments(); | |||
720 | } | |||
721 | ||||
722 | void 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 | ||||
730 | AutoSuppressEventHandlingAndSuspend::~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 | */ | |||
745 | class 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 | ||||
762 | static 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 | ||||
770 | static 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 | |||
791 | nsresult 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 | ||||
892 | bool 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 | ||||
910 | void nsContentUtils::GetShiftText(nsAString& text) { | |||
911 | if (!sShiftText) InitializeModifierStrings(); | |||
912 | text.Assign(*sShiftText); | |||
913 | } | |||
914 | ||||
915 | void nsContentUtils::GetControlText(nsAString& text) { | |||
916 | if (!sControlText) InitializeModifierStrings(); | |||
917 | text.Assign(*sControlText); | |||
918 | } | |||
919 | ||||
920 | void nsContentUtils::GetCommandOrWinText(nsAString& text) { | |||
921 | if (!sCommandOrWinText) { | |||
922 | InitializeModifierStrings(); | |||
923 | } | |||
924 | text.Assign(*sCommandOrWinText); | |||
925 | } | |||
926 | ||||
927 | void nsContentUtils::GetAltText(nsAString& text) { | |||
928 | if (!sAltText) InitializeModifierStrings(); | |||
929 | text.Assign(*sAltText); | |||
930 | } | |||
931 | ||||
932 | void nsContentUtils::GetModifierSeparatorText(nsAString& text) { | |||
933 | if (!sModifierSeparator) InitializeModifierStrings(); | |||
934 | text.Assign(*sModifierSeparator); | |||
935 | } | |||
936 | ||||
937 | void 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 | ||||
974 | mozilla::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 | ||||
988 | bool 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 */ | |||
996 | nsAtom* 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 | ||||
1008 | bool 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 | ||||
1043 | void 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 | ||||
1066 | static 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 | ||||
1080 | nsresult 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 | ||||
1090 | nsresult 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 | ||||
1138 | bool 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 | ||||
1157 | nsContentUtils::AutocompleteAttrState | |||
1158 | nsContentUtils::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 | ||||
1224 | nsContentUtils::AutocompleteAttrState | |||
1225 | nsContentUtils::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 | */ | |||
1242 | nsContentUtils::AutocompleteAttrState | |||
1243 | nsContentUtils::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 | |||
1436 | template <class CharT> | |||
1437 | int32_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 | |||
1513 | int32_t nsContentUtils::ParseHTMLInteger(const char16_t* aStart, | |||
1514 | const char16_t* aEnd, | |||
1515 | ParseHTMLIntegerResultFlags* aResult) { | |||
1516 | return ParseHTMLIntegerImpl(aStart, aEnd, aResult); | |||
1517 | } | |||
1518 | ||||
1519 | int32_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 | ||||
1538 | bool 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 | ||||
1641 | bool 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 | ||||
1649 | void 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 | */ | |||
1673 | uint32_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 | */ | |||
1697 | bool 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 | */ | |||
1715 | void 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 | ||||
1734 | nsIBidiKeyboard* 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 | |||
1753 | bool 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 | |||
1769 | bool 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 | |||
1776 | bool 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 | |||
1784 | bool 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 */ | |||
1795 | bool 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 */ | |||
1802 | bool nsContentUtils::IsHTMLWhitespaceOrNBSP(char16_t aChar) { | |||
1803 | return IsHTMLWhitespace(aChar) || aChar == char16_t(0xA0); | |||
1804 | } | |||
1805 | ||||
1806 | /* static */ | |||
1807 | bool 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 */ | |||
1823 | bool 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 | |||
1867 | int32_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 */ | |||
1918 | void 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 */ | |||
1945 | bool nsContentUtils::OfflineAppAllowed(nsIURI* aURI) { return false; } | |||
1946 | ||||
1947 | /* static */ | |||
1948 | bool nsContentUtils::OfflineAppAllowed(nsIPrincipal* aPrincipal) { | |||
1949 | return false; | |||
1950 | } | |||
1951 | // Static | |||
1952 | bool 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 | |||
1970 | void 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 | |||
2065 | nsresult 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 | |||
2093 | bool 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 | |||
2109 | bool 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 | |||
2123 | bool 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 | |||
2131 | bool 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 | |||
2143 | bool nsContentUtils::CallerHasPermission(JSContext* aCx, const nsAtom* aPerm) { | |||
2144 | return PrincipalHasPermission(*SubjectPrincipal(aCx), aPerm); | |||
2145 | } | |||
2146 | ||||
2147 | // static | |||
2148 | nsIPrincipal* 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 | |||
2178 | bool 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 | |||
2207 | bool 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 | ||||
2229 | bool 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 | |||
2235 | bool nsContentUtils::IsFuzzingEnabled() { | |||
2236 | return StaticPrefs::fuzzing_enabled(); | |||
2237 | } | |||
2238 | #endif | |||
2239 | ||||
2240 | /* static */ | |||
2241 | bool 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 */ | |||
2250 | bool nsContentUtils::ShouldResistFingerprinting(bool aIsPrivateMode, | |||
2251 | RFPTarget aTarget) { | |||
2252 | return nsRFPService::IsRFPEnabledFor(aIsPrivateMode, aTarget, Nothing()); | |||
2253 | } | |||
2254 | ||||
2255 | /* static */ | |||
2256 | bool 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 | ||||
2267 | inline 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 | ||||
2278 | inline 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 | ||||
2300 | bool 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 | ||||
2339 | inline 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 | ||||
2352 | inline 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 | ||||
2358 | inline 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 | ||||
2375 | const char* kExemptedDomainsPrefName = | |||
2376 | "privacy.resistFingerprinting.exemptedDomains"; | |||
2377 | ||||
2378 | inline 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 */ | |||
2417 | bool 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 | ||||
2424 | namespace { | |||
2425 | ||||
2426 | // This function is only called within this file for Positive Return Checks | |||
2427 | bool 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 */ | |||
2436 | bool 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 | ||||
2445 | bool 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 */ | |||
2464 | bool 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 */ | |||
2566 | bool 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 */ | |||
2627 | bool 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 */ | |||
2693 | void 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 | ||||
2759 | bool nsContentUtils::ThreadsafeIsCallerChrome() { | |||
2760 | return NS_IsMainThread() ? IsCallerChrome() | |||
2761 | : IsCurrentThreadRunningChromeWorker(); | |||
2762 | } | |||
2763 | ||||
2764 | bool 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 | ||||
2778 | bool nsContentUtils::IsSystemCaller(JSContext* aCx) { | |||
2779 | // Note that SubjectPrincipal() assumes we are in a compartment here. | |||
2780 | return SubjectPrincipal(aCx) == sSystemPrincipal; | |||
2781 | } | |||
2782 | ||||
2783 | bool 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 | |||
2791 | bool nsContentUtils::LookupBindingMember( | |||
2792 | JSContext* aCx, nsIContent* aContent, JS::Handle<jsid> aId, | |||
2793 | JS::MutableHandle<JS::PropertyDescriptor> aDesc) { | |||
2794 | return true; | |||
2795 | } | |||
2796 | ||||
2797 | nsINode* 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 | ||||
2817 | bool 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 | |||
2836 | bool 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 | |||
2854 | bool 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 | |||
2870 | bool 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 | |||
2887 | nsINode* 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 | |||
2909 | Element* 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 | |||
2935 | nsresult 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 | |||
2945 | template <typename GetParentFunc> | |||
2946 | nsresult 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 | ||||
2983 | nsresult 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 | ||||
2991 | nsresult 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 | ||||
3002 | template <typename Node, typename GetParentFunc> | |||
3003 | static 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 */ | |||
3038 | nsINode* nsContentUtils::GetCommonAncestorHelper(nsINode* aNode1, | |||
3039 | nsINode* aNode2) { | |||
3040 | return GetCommonAncestorInternal( | |||
3041 | aNode1, aNode2, [](nsINode* aNode) { return aNode->GetParentNode(); }); | |||
3042 | } | |||
3043 | ||||
3044 | /* static */ | |||
3045 | nsINode* 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 */ | |||
3057 | nsIContent* nsContentUtils::GetCommonFlattenedTreeAncestorHelper( | |||
3058 | nsIContent* aContent1, nsIContent* aContent2) { | |||
3059 | return GetCommonAncestorInternal( | |||
3060 | aContent1, aContent2, | |||
3061 | [](nsIContent* aContent) { return aContent->GetFlattenedTreeParent(); }); | |||
3062 | } | |||
3063 | ||||
3064 | /* static */ | |||
3065 | nsIContent* 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 */ | |||
3078 | Element* nsContentUtils::GetCommonFlattenedTreeAncestorForStyle( | |||
3079 | Element* aElement1, Element* aElement2) { | |||
3080 | return GetCommonAncestorInternal(aElement1, aElement2, [](Element* aElement) { | |||
3081 | return aElement->GetFlattenedTreeParentElementForStyle(); | |||
3082 | }); | |||
3083 | } | |||
3084 | ||||
3085 | /* static */ | |||
3086 | bool 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 */ | |||
3097 | Maybe<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 */ | |||
3114 | int32_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 */ | |||
3207 | BrowserParent* 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 */ | |||
3218 | Element* 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 */ | |||
3271 | template <typename FPT, typename FRT, typename SPT, typename SRT> | |||
3272 | Maybe<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 */ | |||
3291 | template <typename FPT, typename FRT, typename SPT, typename SRT> | |||
3292 | int32_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 | ||||
3311 | inline 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 | |||
3327 | const 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 | |||
3361 | template <bool IsWhitespace(char16_t)> | |||
3362 | const 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. | |||
3397 | template const nsDependentSubstring | |||
3398 | nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(const nsAString&, bool); | |||
3399 | template const nsDependentSubstring nsContentUtils::TrimWhitespace< | |||
3400 | nsContentUtils::IsHTMLWhitespace>(const nsAString&, bool); | |||
3401 | template const nsDependentSubstring nsContentUtils::TrimWhitespace< | |||
3402 | nsContentUtils::IsHTMLWhitespaceOrNBSP>(const nsAString&, bool); | |||
3403 | ||||
3404 | static inline void KeyAppendSep(nsACString& aKey) { | |||
3405 | if (!aKey.IsEmpty()) { | |||
3406 | aKey.Append('>'); | |||
3407 | } | |||
3408 | } | |||
3409 | ||||
3410 | static 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 | ||||
3420 | static 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 | ||||
3431 | static inline void KeyAppendInt(int32_t aInt, nsACString& aKey) { | |||
3432 | KeyAppendSep(aKey); | |||
3433 | ||||
3434 | aKey.AppendInt(aInt); | |||
3435 | } | |||
3436 | ||||
3437 | static 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*/ | |||
3445 | void 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 | |||
3617 | nsIPrincipal* 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 | |||
3631 | nsIPrincipal* 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 | |||
3671 | nsIPrincipal* 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 | |||
3684 | nsresult 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 | |||
3696 | bool 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 | |||
3713 | bool 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 | |||
3765 | bool 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 | |||
3794 | nsresult 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 | |||
3817 | nsresult 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 | |||
3846 | nsresult 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 | |||
3879 | void 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 | |||
3928 | PresShell* 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 | |||
3937 | nsPresContext* 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 | |||
3947 | bool 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 | |||
3971 | bool 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? | |||
3987 | bool 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 | ||||
4000 | imgLoader* 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 | |||
4012 | imgLoader* 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 | |||
4024 | int32_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 | |||
4036 | nsresult 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 | |||
4085 | already_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 | ||||
4121 | static 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 | ||||
4130 | static 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 | ||||
4145 | static 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 | |||
4163 | bool 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 | |||
4175 | bool 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 | |||
4182 | bool 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 | |||
4188 | nsresult 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 | ||||
4200 | static 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 | ||||
4224 | bool nsContentUtils::IsSitePermAllow(nsIPrincipal* aPrincipal, | |||
4225 | const nsACString& aType) { | |||
4226 | return TestSitePerm(aPrincipal, aType, nsIPermissionManager::ALLOW_ACTION, | |||
4227 | false); | |||
4228 | } | |||
4229 | ||||
4230 | bool nsContentUtils::IsSitePermDeny(nsIPrincipal* aPrincipal, | |||
4231 | const nsACString& aType) { | |||
4232 | return TestSitePerm(aPrincipal, aType, nsIPermissionManager::DENY_ACTION, | |||
4233 | false); | |||
4234 | } | |||
4235 | ||||
4236 | bool nsContentUtils::IsExactSitePermAllow(nsIPrincipal* aPrincipal, | |||
4237 | const nsACString& aType) { | |||
4238 | return TestSitePerm(aPrincipal, aType, nsIPermissionManager::ALLOW_ACTION, | |||
4239 | true); | |||
4240 | } | |||
4241 | ||||
4242 | bool nsContentUtils::IsExactSitePermDeny(nsIPrincipal* aPrincipal, | |||
4243 | const nsACString& aType) { | |||
4244 | return TestSitePerm(aPrincipal, aType, nsIPermissionManager::DENY_ACTION, | |||
4245 | true); | |||
4246 | } | |||
4247 | ||||
4248 | bool 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 | ||||
4265 | static const char* gEventNames[] = {"event"}; | |||
4266 | static 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 | |||
4269 | static const char* gOnErrorNames[] = {"event", "source", "lineno", "colno", | |||
4270 | "error"}; | |||
4271 | ||||
4272 | // static | |||
4273 | void 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. | |||
4294 | static 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 */ | |||
4313 | nsresult 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 */ | |||
4331 | void 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 */ | |||
4361 | bool nsContentUtils::SpoofLocaleEnglish() { | |||
4362 | // 0 - will prompt | |||
4363 | // 1 - don't spoof | |||
4364 | // 2 - spoof | |||
4365 | return StaticPrefs::privacy_spoof_english() == 2; | |||
4366 | } | |||
4367 | ||||
4368 | static 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 */ | |||
4389 | nsresult 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 */ | |||
4398 | nsresult nsContentUtils::GetLocalizedString(PropertiesFile aFile, | |||
4399 | const char* aKey, | |||
4400 | nsAString& aResult) { | |||
4401 | return FormatLocalizedString(aFile, aKey, {}, aResult); | |||
4402 | } | |||
4403 | ||||
4404 | /* static */ | |||
4405 | nsresult 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 | ||||
4413 | class 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 */ | |||
4450 | nsresult 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 */ | |||
4482 | void 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 */ | |||
4501 | nsresult 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 */ | |||
4518 | void nsContentUtils::ReportEmptyGetElementByIdArg(const Document* aDoc) { | |||
4519 | ReportToConsole(nsIScriptError::warningFlag, "DOM"_ns, aDoc, | |||
4520 | nsContentUtils::eDOM_PROPERTIES, "EmptyGetElementByIdParam"); | |||
4521 | } | |||
4522 | ||||
4523 | /* static */ | |||
4524 | nsresult 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 */ | |||
4539 | nsresult 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 | ||||
4568 | void 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 | ||||
4578 | bool nsContentUtils::IsChromeDoc(const Document* aDocument) { | |||
4579 | return aDocument && aDocument->NodePrincipal() == sSystemPrincipal; | |||
4580 | } | |||
4581 | ||||
4582 | bool nsContentUtils::IsAddonDoc(const Document* aDocument) { | |||
4583 | return aDocument && | |||
4584 | aDocument->NodePrincipal()->GetIsAddonOrExpandedAddonPrincipal(); | |||
4585 | } | |||
4586 | ||||
4587 | bool nsContentUtils::IsChildOfSameType(Document* aDoc) { | |||
4588 | if (BrowsingContext* bc = aDoc->GetBrowsingContext()) { | |||
4589 | return bc->GetParent(); | |||
4590 | } | |||
4591 | return false; | |||
4592 | } | |||
4593 | ||||
4594 | static bool IsJSONType(const nsACString& aContentType) { | |||
4595 | return aContentType.EqualsLiteral(TEXT_JSON"text/json") || | |||
4596 | aContentType.EqualsLiteral(APPLICATION_JSON"application/json"); | |||
4597 | } | |||
4598 | ||||
4599 | static 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 | ||||
4642 | bool 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 | ||||
4650 | bool 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 | ||||
4657 | bool nsContentUtils::IsInChromeDocshell(const Document* aDocument) { | |||
4658 | return aDocument && aDocument->IsInChromeDocShell(); | |||
4659 | } | |||
4660 | ||||
4661 | // static | |||
4662 | nsIContentPolicy* 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 | |||
4673 | bool 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 | |||
4684 | EventMessage 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 | |||
4697 | mozilla::EventClassID nsContentUtils::GetEventClassID(const nsAString& aName) { | |||
4698 | EventNameMapping mapping; | |||
4699 | if (sStringEventTable->Get(aName, &mapping)) return mapping.mEventClassID; | |||
4700 | ||||
4701 | return eBasicEventClass; | |||
4702 | } | |||
4703 | ||||
4704 | nsAtom* 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 | |||
4737 | EventMessage 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 | ||||
4759 | static 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 | |||
4778 | nsresult 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 | |||
4790 | nsresult 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 | |||
4798 | nsresult 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 | |||
4827 | nsresult 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 | |||
4858 | nsresult nsContentUtils::DispatchInputEvent(Element* aEventTarget) { | |||
4859 | return DispatchInputEvent(aEventTarget, mozilla::eEditorInput, | |||
4860 | mozilla::EditorInputType::eUnknown, nullptr, | |||
4861 | InputEventOptions()); | |||
4862 | } | |||
4863 | ||||
4864 | // static | |||
4865 | nsresult 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 | ||||
5024 | nsresult 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 | ||||
5056 | void 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 | ||||
5086 | nsresult 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 */ | |||
5096 | Element* 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 */ | |||
5108 | Element* 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 */ | |||
5123 | void 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 */ | |||
5133 | void 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 */ | |||
5142 | bool 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 */ | |||
5152 | bool 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 */ | |||
5204 | bool 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 | ||||
5213 | void 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 | ||||
5260 | void 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 */ | |||
5277 | void 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 | ||||
5292 | EventListenerManager* 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 | ||||
5317 | EventListenerManager* 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 | ||||
5339 | void 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 | ||||
5352 | already_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 */ | |||
5362 | void 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 */ | |||
5380 | bool 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 | ||||
5412 | already_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 */ | |||
5516 | void 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 */ | |||
5523 | void nsContentUtils::XPCOMShutdown() { nsContentUtils::DropFragmentParsers(); } | |||
5524 | ||||
5525 | /* Helper function to compuate Sanitization Flags for ParseFramentHTML/XML */ | |||
5526 | uint32_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 */ | |||
5552 | void 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 */ | |||
5585 | nsresult 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 */ | |||
5658 | nsresult 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 */ | |||
5677 | nsresult 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 */ | |||
5758 | nsresult 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 | ||||
5782 | static 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 */ | |||
5822 | already_AddRefed<Document> nsContentUtils::CreateInertXMLDocument( | |||
5823 | const Document* aTemplate) { | |||
5824 | return CreateInertDocument(aTemplate, DocumentFlavorXML); | |||
5825 | } | |||
5826 | ||||
5827 | /* static */ | |||
5828 | already_AddRefed<Document> nsContentUtils::CreateInertHTMLDocument( | |||
5829 | const Document* aTemplate) { | |||
5830 | return CreateInertDocument(aTemplate, DocumentFlavorHTML); | |||
5831 | } | |||
5832 | ||||
5833 | /* static */ | |||
5834 | nsresult 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 | ||||
5921 | static 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 */ | |||
5943 | bool 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 | ||||
5965 | bool 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 */ | |||
5983 | bool 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 */ | |||
6004 | bool 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 */ | |||
6017 | void nsContentUtils::NotifyInstalledMenuKeyboardListener(bool aInstalling) { | |||
6018 | IMEStateManager::OnInstalledMenuKeyboardListener(aInstalling); | |||
6019 | } | |||
6020 | ||||
6021 | /* static */ | |||
6022 | bool 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 | ||||
6028 | bool nsContentUtils::IsExpandedPrincipal(nsIPrincipal* aPrincipal) { | |||
6029 | return aPrincipal && aPrincipal->GetIsExpandedPrincipal(); | |||
6030 | } | |||
6031 | ||||
6032 | bool nsContentUtils::IsSystemOrExpandedPrincipal(nsIPrincipal* aPrincipal) { | |||
6033 | return (aPrincipal && aPrincipal->IsSystemPrincipal()) || | |||
6034 | IsExpandedPrincipal(aPrincipal); | |||
6035 | } | |||
6036 | ||||
6037 | nsIPrincipal* 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 | ||||
6042 | bool 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 */ | |||
6065 | void 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 */ | |||
6127 | void 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 */ | |||
6138 | nsIWidget* nsContentUtils::GetTopLevelWidget(nsIWidget* aWidget) { | |||
6139 | if (!aWidget) return nullptr; | |||
6140 | ||||
6141 | return aWidget->GetTopLevelWidget(); | |||
6142 | } | |||
6143 | ||||
6144 | /* static */ | |||
6145 | const 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 */ | |||
6161 | void 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 | |||
6173 | static bool sRemovingScriptBlockers = false; | |||
6174 | #endif | |||
6175 | ||||
6176 | /* static */ | |||
6177 | void 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 */ | |||
6221 | already_AddRefed<nsPIDOMWindowOuter> | |||
6222 | nsContentUtils::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 */ | |||
6234 | void 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 */ | |||
6256 | void nsContentUtils::AddScriptRunner(already_AddRefed<nsIRunnable> aRunnable) { | |||
6257 | nsCOMPtr<nsIRunnable> runnable = aRunnable; | |||
6258 | if (!runnable) { | |||
6259 | return; | |||
6260 | } | |||
6261 | ||||
6262 | if (sScriptBlockerCount) { | |||
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); }; | |||
6268 | runnable->Run(); | |||
6269 | } | |||
6270 | ||||
6271 | /* static */ | |||
6272 | void nsContentUtils::AddScriptRunner(nsIRunnable* aRunnable) { | |||
6273 | nsCOMPtr<nsIRunnable> runnable = aRunnable; | |||
6274 | AddScriptRunner(runnable.forget()); | |||
| ||||
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 */ | |||
6284 | void 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 */ | |||
6290 | void 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 */ | |||
6298 | bool 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 */ | |||
6304 | void 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 */ | |||
6316 | already_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 */ | |||
6328 | already_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 */ | |||
6339 | nsresult 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 */ | |||
6402 | uint32_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 */ | |||
6434 | bool 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 */ | |||
6472 | bool 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 */ | |||
6484 | JSContext* 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 | ||||
6492 | template <typename StringType, typename CharType> | |||
6493 | void _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 */ | |||
6508 | void nsContentUtils::ASCIIToLower(nsAString& aStr) { | |||
6509 | return _ASCIIToLowerInSitu<nsAString, char16_t>(aStr); | |||
6510 | } | |||
6511 | ||||
6512 | /* static */ | |||
6513 | void nsContentUtils::ASCIIToLower(nsACString& aStr) { | |||
6514 | return _ASCIIToLowerInSitu<nsACString, char>(aStr); | |||
6515 | } | |||
6516 | ||||
6517 | template <typename StringType, typename CharType> | |||
6518 | void _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 */ | |||
6537 | void nsContentUtils::ASCIIToLower(const nsAString& aSource, nsAString& aDest) { | |||
6538 | return _ASCIIToLowerCopy<nsAString, char16_t>(aSource, aDest); | |||
6539 | } | |||
6540 | ||||
6541 | /* static */ | |||
6542 | void nsContentUtils::ASCIIToLower(const nsACString& aSource, | |||
6543 | nsACString& aDest) { | |||
6544 | return _ASCIIToLowerCopy<nsACString, char>(aSource, aDest); | |||
6545 | } | |||
6546 | ||||
6547 | template <typename StringType, typename CharType> | |||
6548 | void _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 */ | |||
6563 | void nsContentUtils::ASCIIToUpper(nsAString& aStr) { | |||
6564 | return _ASCIIToUpperInSitu<nsAString, char16_t>(aStr); | |||
6565 | } | |||
6566 | ||||
6567 | /* static */ | |||
6568 | void nsContentUtils::ASCIIToUpper(nsACString& aStr) { | |||
6569 | return _ASCIIToUpperInSitu<nsACString, char>(aStr); | |||
6570 | } | |||
6571 | ||||
6572 | template <typename StringType, typename CharType> | |||
6573 | void _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 */ | |||
6592 | void nsContentUtils::ASCIIToUpper(const nsAString& aSource, nsAString& aDest) { | |||
6593 | return _ASCIIToUpperCopy<nsAString, char16_t>(aSource, aDest); | |||
6594 | } | |||
6595 | ||||
6596 | /* static */ | |||
6597 | void nsContentUtils::ASCIIToUpper(const nsACString& aSource, | |||
6598 | nsACString& aDest) { | |||
6599 | return _ASCIIToUpperCopy<nsACString, char>(aSource, aDest); | |||
6600 | } | |||
6601 | ||||
6602 | /* static */ | |||
6603 | bool 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 */ | |||
6619 | bool 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 */ | |||
6655 | bool 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 */ | |||
6670 | nsIInterfaceRequestor* nsContentUtils::SameOriginChecker() { | |||
6671 | if (!sSameOriginChecker) { | |||
6672 | sSameOriginChecker = new SameOriginCheckerImpl(); | |||
6673 | NS_ADDREF(sSameOriginChecker)(sSameOriginChecker)->AddRef(); | |||
6674 | } | |||
6675 | return sSameOriginChecker; | |||
6676 | } | |||
6677 | ||||
6678 | /* static */ | |||
6679 | nsresult 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 | ||||
6702 | NS_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 | ||||
6705 | NS_IMETHODIMPnsresult | |||
6706 | SameOriginCheckerImpl::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 | ||||
6719 | NS_IMETHODIMPnsresult | |||
6720 | SameOriginCheckerImpl::GetInterface(const nsIID& aIID, void** aResult) { | |||
6721 | return QueryInterface(aIID, aResult); | |||
6722 | } | |||
6723 | ||||
6724 | /* static */ | |||
6725 | nsresult 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 */ | |||
6803 | nsresult 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 */ | |||
6821 | nsresult 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 */ | |||
6848 | bool 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 */ | |||
6860 | bool nsContentUtils::CanAccessNativeAnon() { | |||
6861 | return LegacyIsCallerChromeOrNativeCode(); | |||
6862 | } | |||
6863 | ||||
6864 | /* static */ | |||
6865 | nsresult 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 | |||
6893 | nsresult 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 | ||||
6922 | void 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 | ||||
6942 | struct ClassMatchingInfo { | |||
6943 | AtomArray mClasses; | |||
6944 | nsCaseTreatment mCaseTreatment; | |||
6945 | }; | |||
6946 | ||||
6947 | // static | |||
6948 | bool 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 | |||
6974 | void nsContentUtils::DestroyClassNameArray(void* aData) { | |||
6975 | ClassMatchingInfo* info = static_cast<ClassMatchingInfo*>(aData); | |||
6976 | delete info; | |||
6977 | } | |||
6978 | ||||
6979 | // static | |||
6980 | void* 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 | ||||
6999 | bool 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 | ||||
7006 | void 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 | ||||
7034 | void nsContentUtils::RemoveNewlines(nsString& aString) { aString.StripCRLF(); } | |||
7035 | ||||
7036 | void nsContentUtils::PlatformToDOMLineBreaks(nsString& aString) { | |||
7037 | if (!PlatformToDOMLineBreaks(aString, fallible)) { | |||
7038 | aString.AllocFailed(aString.Length()); | |||
7039 | } | |||
7040 | } | |||
7041 | ||||
7042 | bool 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 | ||||
7059 | already_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 | ||||
7068 | PresShell* 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 */ | |||
7099 | nsPresContext* nsContentUtils::FindPresContextForDocument( | |||
7100 | const Document* aDocument) { | |||
7101 | if (PresShell* presShell = FindPresShellForDocument(aDocument)) { | |||
7102 | return presShell->GetPresContext(); | |||
7103 | } | |||
7104 | return nullptr; | |||
7105 | } | |||
7106 | ||||
7107 | nsIWidget* 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 | ||||
7127 | nsIWidget* 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 | ||||
7141 | WindowRenderer* 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 | ||||
7151 | WindowRenderer* 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 | ||||
7161 | bool 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 | ||||
7173 | bool nsContentUtils::IsPDFJSEnabled() { | |||
7174 | nsCOMPtr<nsIStreamConverter> conv = do_CreateInstance( | |||
7175 | "@mozilla.org/streamconv;1?from=application/pdf&to=text/html"); | |||
7176 | return conv; | |||
7177 | } | |||
7178 | ||||
7179 | bool 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 | ||||
7189 | bool nsContentUtils::IsSystemOrPDFJS(JSContext* aCx, JSObject*) { | |||
7190 | nsIPrincipal* principal = SubjectPrincipal(aCx); | |||
7191 | return principal && (principal->IsSystemPrincipal() || IsPDFJS(principal)); | |||
7192 | } | |||
7193 | ||||
7194 | bool 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 | ||||
7202 | already_AddRefed<nsIDocumentLoaderFactory> | |||
7203 | nsContentUtils::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 | ||||
7247 | static 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 | |||
7280 | Maybe<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 | |||
7350 | nsresult 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 | |||
7359 | bool 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 */ | |||
7406 | bool 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 */ | |||
7417 | bool 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 */ | |||
7427 | void 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 */ | |||
7446 | const 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 | |||
7459 | int32_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 | |||
7493 | bool 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 | |||
7524 | void 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 | |||
7586 | HTMLEditor* nsContentUtils::GetHTMLEditor(nsPresContext* aPresContext) { | |||
7587 | if (!aPresContext) { | |||
7588 | return nullptr; | |||
7589 | } | |||
7590 | return GetHTMLEditor(aPresContext->GetDocShell()); | |||
7591 | } | |||
7592 | ||||
7593 | // static | |||
7594 | HTMLEditor* 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 | |||
7604 | EditorBase* nsContentUtils::GetActiveEditor(nsPresContext* aPresContext) { | |||
7605 | if (!aPresContext) { | |||
7606 | return nullptr; | |||
7607 | } | |||
7608 | ||||
7609 | return GetActiveEditor(aPresContext->Document()->GetWindow()); | |||
7610 | } | |||
7611 | ||||
7612 | // static | |||
7613 | EditorBase* 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 | |||
7642 | TextEditor* 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 | |||
7663 | bool 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 | |||
7674 | bool 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 | |||
7696 | bool 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 | |||
7727 | bool nsContentUtils::IsForbiddenResponseHeader(const nsACString& aHeader) { | |||
7728 | return (aHeader.LowerCaseEqualsASCII("set-cookie") || | |||
7729 | aHeader.LowerCaseEqualsASCII("set-cookie2")); | |||
7730 | } | |||
7731 | ||||
7732 | // static | |||
7733 | bool 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 | |||
7740 | bool 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 | ||||
7757 | Maybe<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 | |||
7829 | bool 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 | |||
7851 | bool nsContentUtils::IsAllowedNonCorsAccept(const nsACString& aHeaderValue) { | |||
7852 | if (IsCorsUnsafeRequestHeaderValue(aHeaderValue)) { | |||
7853 | return false; | |||
7854 | } | |||
7855 | return true; | |||
7856 | } | |||
7857 | ||||
7858 | // static | |||
7859 | bool 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 | |||
7880 | bool 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 | ||||
7897 | bool 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 | |||
7911 | bool 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 | ||||
7929 | mozilla::LogModule* nsContentUtils::ResistFingerprintingLog() { | |||
7930 | return gResistFingerprintingLog; | |||
7931 | } | |||
7932 | mozilla::LogModule* nsContentUtils::DOMDumpLog() { return sDOMDumpLog; } | |||
7933 | ||||
7934 | bool 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 | ||||
7941 | void 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 | ||||
7948 | void 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. | |||
7956 | static 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 | ||||
7974 | bool 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 | ||||
7983 | bool 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 | ||||
7992 | bool 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 | ||||
8006 | bool 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 | ||||
8040 | uint64_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 | ||||
8056 | uint64_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 | |||
8088 | void 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 | ||||
8097 | nsresult 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 | ||||
8110 | nsresult 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 | ||||
8121 | nsresult 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 | ||||
8132 | CallState 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 | ||||
8165 | void 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 | ||||
8177 | bool 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 | ||||
8193 | nsresult 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 | ||||
8271 | nsresult 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 | ||||
8297 | nsresult 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 | ||||
8344 | void 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 | ||||
8361 | nsresult 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 | ||||
8381 | static 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 | ||||
8402 | nsresult 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 | ||||
8419 | bool 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. | |||
8429 | static 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. | |||
8436 | static IPCTransferableDataCString AsIPCTransferableDataCString( | |||
8437 | Span<const char> aInput) { | |||
8438 | return IPCTransferableDataCString{BigBuffer(AsBytes(aInput))}; | |||
8439 | } | |||
8440 | ||||
8441 | void 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 | ||||
8616 | void 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 | ||||
8639 | Maybe<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 | ||||
8668 | Maybe<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 | ||||
8679 | already_AddRefed<DataSourceSurface> nsContentUtils::IPCImageToSurface( | |||
8680 | const IPCImage& aImage) { | |||
8681 | return BigBufferToDataSurface(aImage.data(), aImage.stride(), | |||
8682 | aImage.size().ToUnknownSize(), aImage.format()); | |||
8683 | } | |||
8684 | ||||
8685 | Modifiers 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 | ||||
8726 | nsIWidget* 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 | ||||
8737 | int16_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 | ||||
8759 | LayoutDeviceIntPoint 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 | ||||
8769 | nsView* 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 | ||||
8788 | nsresult 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 */ | |||
8911 | void 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 */ | |||
8942 | void 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 */ | |||
8967 | already_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 */ | |||
8977 | bool 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 */ | |||
9015 | bool 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 | |||
9025 | ReferrerPolicy 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 | |||
9044 | bool 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 | |||
9057 | bool 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 | |||
9067 | bool 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 | |||
9086 | bool 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 | ||||
9108 | namespace { | |||
9109 | ||||
9110 | // We put StringBuilder in the anonymous namespace to prevent anything outside | |||
9111 | // this file from accidentally being linked against it. | |||
9112 | class 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 | ||||
9154 | class 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"""); | |||
9343 | flushedUntil = currentPosition + 1; | |||
9344 | break; | |||
9345 | case '&': | |||
9346 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); | |||
9347 | aAppender.AppendLiteral(u"&"); | |||
9348 | flushedUntil = currentPosition + 1; | |||
9349 | break; | |||
9350 | case 0x00A0: | |||
9351 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); | |||
9352 | aAppender.AppendLiteral(u" "); | |||
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"<"); | |||
9374 | flushedUntil = currentPosition + 1; | |||
9375 | break; | |||
9376 | case '>': | |||
9377 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); | |||
9378 | aAppender.AppendLiteral(u">"); | |||
9379 | flushedUntil = currentPosition + 1; | |||
9380 | break; | |||
9381 | case '&': | |||
9382 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); | |||
9383 | aAppender.AppendLiteral(u"&"); | |||
9384 | flushedUntil = currentPosition + 1; | |||
9385 | break; | |||
9386 | case T(0xA0): | |||
9387 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); | |||
9388 | aAppender.AppendLiteral(u" "); | |||
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 | ||||
9408 | static_assert(sizeof(StringBuilder) <= StringBuilder::TARGET_SIZE, | |||
9409 | "StringBuilder should fit in the target bucket"); | |||
9410 | ||||
9411 | } // namespace | |||
9412 | ||||
9413 | static 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("<"), ArrayLength(">"), | |||
9457 | ArrayLength("&"), ArrayLength(" ")}) - | |||
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 | ||||
9468 | static 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("""), ArrayLength("&"), | |||
9498 | ArrayLength(" ")}) - | |||
9499 | 2; | |||
9500 | static_assert(maxCharExtraSpace < 100, "Possible underflow"); | |||
9501 | return CheckedInt<uint32_t>(numEncodedChars) * maxCharExtraSpace; | |||
9502 | } | |||
9503 | ||||
9504 | static 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 | ||||
9529 | static 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 | ||||
9610 | static 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 | ||||
9643 | static inline bool IsVoidTag(Element* aElement) { | |||
9644 | if (!aElement->IsHTMLElement()) { | |||
9645 | return false; | |||
9646 | } | |||
9647 | return FragmentOrElement::IsHTMLVoid(aElement->NodeInfo()->NameAtom()); | |||
9648 | } | |||
9649 | ||||
9650 | static 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 | ||||
9685 | template <SerializeShadowRoots ShouldSerializeShadowRoots> | |||
9686 | static 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 = ¤t->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 | ||||
9816 | template <SerializeShadowRoots ShouldSerializeShadowRoots> | |||
9817 | bool 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 | ||||
9843 | template bool nsContentUtils::SerializeNodeToMarkup<SerializeShadowRoots::No>( | |||
9844 | nsINode* aRoot, bool aDescendantsOnly, nsAString& aOut, | |||
9845 | bool aSerializableShadowRoots, | |||
9846 | const Sequence<OwningNonNull<ShadowRoot>>& aShadowRoots); | |||
9847 | template bool nsContentUtils::SerializeNodeToMarkup<SerializeShadowRoots::Yes>( | |||
9848 | nsINode* aRoot, bool aDescendantsOnly, nsAString& aOut, | |||
9849 | bool aSerializableShadowRoots, | |||
9850 | const Sequence<OwningNonNull<ShadowRoot>>& aShadowRoots); | |||
9851 | ||||
9852 | bool 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 */ | |||
9878 | void 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 */ | |||
9888 | nsIDocShell* 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 */ | |||
9948 | bool 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 */ | |||
9997 | bool 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 */ | |||
10031 | void 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 | ||||
10050 | MOZ_CAN_RUN_SCRIPT | |||
10051 | static 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 */ | |||
10098 | nsresult 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 | ||||
10284 | CustomElementRegistry* 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 */ | |||
10301 | CustomElementDefinition* 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 */ | |||
10318 | void 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 */ | |||
10330 | void 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 */ | |||
10342 | void 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 */ | |||
10354 | void 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 */ | |||
10371 | void 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 */ | |||
10384 | CustomElementFormValue 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 */ | |||
10401 | Nullable<OwningFileOrUSVStringOrFormData> | |||
10402 | nsContentUtils::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 */ | |||
10456 | void 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 | ||||
10482 | static 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 */ | |||
10491 | void 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 | ||||
10524 | bool 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 | ||||
10536 | bool 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 */ | |||
10545 | bool 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 */ | |||
10592 | void 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 */ | |||
10617 | nsresult 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 */ | |||
10646 | void 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 */ | |||
10683 | bool 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 | */ | |||
10723 | static 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 */ | |||
10756 | uint32_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 */ | |||
10780 | bool 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. | |||
10787 | static constexpr uint64_t kIdTotalBits = 53; | |||
10788 | static constexpr uint64_t kIdProcessBits = 22; | |||
10789 | static constexpr uint64_t kIdBits = kIdTotalBits - kIdProcessBits; | |||
10790 | ||||
10791 | /* static */ | |||
10792 | uint64_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 */ | |||
10810 | std::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. | |||
10816 | static uint64_t gNextTabId = 0; | |||
10817 | ||||
10818 | /* static */ | |||
10819 | uint64_t nsContentUtils::GenerateTabId() { | |||
10820 | return GenerateProcessSpecificId(++gNextTabId); | |||
10821 | } | |||
10822 | ||||
10823 | // Next process-local Browser ID. | |||
10824 | static uint64_t gNextBrowserId = 0; | |||
10825 | ||||
10826 | /* static */ | |||
10827 | uint64_t nsContentUtils::GenerateBrowserId() { | |||
10828 | return GenerateProcessSpecificId(++gNextBrowserId); | |||
10829 | } | |||
10830 | ||||
10831 | // Next process-local Browsing Context ID. | |||
10832 | static uint64_t gNextBrowsingContextId = 0; | |||
10833 | ||||
10834 | /* static */ | |||
10835 | uint64_t nsContentUtils::GenerateBrowsingContextId() { | |||
10836 | return GenerateProcessSpecificId(++gNextBrowsingContextId); | |||
10837 | } | |||
10838 | ||||
10839 | // Next process-local Window ID. | |||
10840 | static uint64_t gNextWindowId = 0; | |||
10841 | ||||
10842 | /* static */ | |||
10843 | uint64_t nsContentUtils::GenerateWindowId() { | |||
10844 | return GenerateProcessSpecificId(++gNextWindowId); | |||
10845 | } | |||
10846 | ||||
10847 | // Next process-local load. | |||
10848 | static Atomic<uint64_t> gNextLoadIdentifier(0); | |||
10849 | ||||
10850 | /* static */ | |||
10851 | uint64_t nsContentUtils::GenerateLoadIdentifier() { | |||
10852 | return GenerateProcessSpecificId(++gNextLoadIdentifier); | |||
10853 | } | |||
10854 | ||||
10855 | /* static */ | |||
10856 | bool nsContentUtils::GetUserIsInteracting() { | |||
10857 | return UserInteractionObserver::sUserActive; | |||
10858 | } | |||
10859 | ||||
10860 | /* static */ | |||
10861 | bool 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 */ | |||
10871 | bool 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 */ | |||
10891 | bool 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 | ||||
10906 | static const char* kUserInteractionInactive = "user-interaction-inactive"; | |||
10907 | static const char* kUserInteractionActive = "user-interaction-active"; | |||
10908 | ||||
10909 | void 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 | ||||
10925 | void 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 | */ | |||
10939 | void 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 | ||||
10947 | NS_IMETHODIMPnsresult | |||
10948 | nsContentUtils::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 | ||||
10974 | Atomic<bool> nsContentUtils::UserInteractionObserver::sUserActive(false); | |||
10975 | NS_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 */ | |||
10978 | bool 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 */ | |||
10986 | bool 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 | ||||
10998 | template <prototypes::ID PrototypeID, class NativeType, typename T> | |||
10999 | static 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 */ | |||
11022 | void 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 */ | |||
11081 | bool 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 */ | |||
11095 | already_AddRefed<ContentFrameMessageManager> | |||
11096 | nsContentUtils::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 */ | |||
11113 | uint32_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 */ | |||
11120 | void 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 */ | |||
11127 | nsresult 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 | ||||
11141 | static 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 */ | |||
11147 | bool 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 */ | |||
11169 | bool 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 | ||||
11188 | static 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 */ | |||
11219 | nsGlobalWindowInner* nsContentUtils::IncumbentInnerWindow() { | |||
11220 | return GetInnerWindowForGlobal(GetIncumbentGlobal()); | |||
11221 | } | |||
11222 | ||||
11223 | /* static */ | |||
11224 | nsGlobalWindowInner* nsContentUtils::EntryInnerWindow() { | |||
11225 | return GetInnerWindowForGlobal(GetEntryGlobal()); | |||
11226 | } | |||
11227 | ||||
11228 | /* static */ | |||
11229 | bool 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 */ | |||
11239 | bool 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 */ | |||
11317 | ScreenIntMargin 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 */ | |||
11381 | nsContentUtils::SubresourceCacheValidationInfo | |||
11382 | nsContentUtils::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 | ||||
11433 | CacheExpirationTime 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 */ | |||
11446 | bool 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 | ||||
11459 | nsCString 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 */ | |||
11469 | nsresult 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 | ||||
11508 | void 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 | ||||
11515 | nsIContent* 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 | ||||
11525 | template <TreeKind aKind> | |||
11526 | MOZ_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 | ||||
11534 | template <TreeKind aKind> | |||
11535 | MOZ_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 | ||||
11544 | template <TreeKind aTreeKind> | |||
11545 | int32_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 | ||||
11644 | nsIContent* 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 | ||||
11672 | template int32_t nsContentUtils::CompareTreePosition<TreeKind::DOM>( | |||
11673 | const nsINode*, const nsINode*, const nsINode*); | |||
11674 | template int32_t nsContentUtils::CompareTreePosition<TreeKind::Flat>( | |||
11675 | const nsINode*, const nsINode*, const nsINode*); | |||
11676 | ||||
11677 | namespace mozilla { | |||
11678 | std::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 |
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 | |||||||||||||||
27 | class nsCycleCollectionTraversalCallback; | ||||||||||||||
28 | |||||||||||||||
29 | template <typename T> | ||||||||||||||
30 | inline void CycleCollectionNoteChild( | ||||||||||||||
31 | nsCycleCollectionTraversalCallback& aCallback, T* aChild, const char* aName, | ||||||||||||||
32 | uint32_t aFlags); | ||||||||||||||
33 | |||||||||||||||
34 | namespace mozilla { | ||||||||||||||
35 | |||||||||||||||
36 | struct Nothing {}; | ||||||||||||||
37 | |||||||||||||||
38 | inline constexpr bool operator==(const Nothing&, const Nothing&) { | ||||||||||||||
39 | return true; | ||||||||||||||
40 | } | ||||||||||||||
41 | |||||||||||||||
42 | template <class T> | ||||||||||||||
43 | class Maybe; | ||||||||||||||
44 | |||||||||||||||
45 | namespace 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). | ||||||||||||||
56 | template <size_t offset> | ||||||||||||||
57 | inline void WritePoisonAtOffset(void* p, const uintptr_t poisonValue) { | ||||||||||||||
58 | memcpy(static_cast<char*>(p) + offset * sizeof(poisonValue), &poisonValue, | ||||||||||||||
59 | sizeof(poisonValue)); | ||||||||||||||
60 | } | ||||||||||||||
61 | |||||||||||||||
62 | template <size_t Offset, size_t NOffsets> | ||||||||||||||
63 | struct 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 | |||||||||||||||
70 | template <size_t N> | ||||||||||||||
71 | struct 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. | ||||||||||||||
80 | template <size_t ObjectSize> | ||||||||||||||
81 | struct OutOfLinePoisoner { | ||||||||||||||
82 | static MOZ_NEVER_INLINE__attribute__((noinline)) void poison(void* p, const uintptr_t) { | ||||||||||||||
83 | mozWritePoison(p, ObjectSize); | ||||||||||||||
84 | } | ||||||||||||||
85 | }; | ||||||||||||||
86 | |||||||||||||||
87 | template <typename T> | ||||||||||||||
88 | inline 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 | |||||||||||||||
95 | template <typename T> | ||||||||||||||
96 | struct 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 | |||||||||||||||
109 | template <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>> | ||||||||||||||
114 | class 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 | |||||||||||||||
151 | template <typename T> | ||||||||||||||
152 | class 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 | |||||||||||||||
170 | template <typename T> | ||||||||||||||
171 | class 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 | |||||||||||||||
189 | template <typename T> | ||||||||||||||
190 | class 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 | |||||||||||||||
201 | template <typename T> | ||||||||||||||
202 | class 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 | |||||||||||||||
214 | template <typename T> | ||||||||||||||
215 | class 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 | |||||||||||||||
227 | template <typename T, bool TriviallyDestructibleAndCopyable> | ||||||||||||||
228 | class 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 | |||||||||||||||
243 | template <typename T, bool TriviallyDestructibleAndCopyable = | ||||||||||||||
244 | IsTriviallyDestructibleAndCopyable<T>> | ||||||||||||||
245 | struct MaybeStorage; | ||||||||||||||
246 | |||||||||||||||
247 | template <typename T> | ||||||||||||||
248 | struct MaybeStorage<T, false> : MaybeStorageBase<T> { | ||||||||||||||
249 | protected: | ||||||||||||||
250 | char mIsSome = false; // not bool -- guarantees minimal space consumption | ||||||||||||||
251 | |||||||||||||||
252 | MaybeStorage() = default; | ||||||||||||||
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
| ||||||||||||||
274 | this->addr()->T::~T(); | ||||||||||||||
275 | } | ||||||||||||||
276 | } | ||||||||||||||
277 | }; | ||||||||||||||
278 | |||||||||||||||
279 | template <typename T> | ||||||||||||||
280 | struct 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 | |||||||||||||||
296 | template <typename T> | ||||||||||||||
297 | struct IsMaybeImpl : std::false_type {}; | ||||||||||||||
298 | |||||||||||||||
299 | template <typename T> | ||||||||||||||
300 | struct IsMaybeImpl<Maybe<T>> : std::true_type {}; | ||||||||||||||
301 | |||||||||||||||
302 | template <typename T> | ||||||||||||||
303 | using IsMaybe = IsMaybeImpl<std::decay_t<T>>; | ||||||||||||||
304 | |||||||||||||||
305 | } // namespace detail | ||||||||||||||
306 | |||||||||||||||
307 | template <typename T, typename U = typename std::remove_cv< | ||||||||||||||
308 | typename std::remove_reference<T>::type>::type> | ||||||||||||||
309 | constexpr 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 | */ | ||||||||||||||
362 | template <class T> | ||||||||||||||
363 | class 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; | ||||||||||||||
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 | |||||||||||||||
843 | template <typename T> | ||||||||||||||
844 | class 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 | |||||||||||||||
921 | template <typename T> | ||||||||||||||
922 | constexpr 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 | |||||||||||||||
927 | template <typename T> | ||||||||||||||
928 | constexpr 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 | |||||||||||||||
933 | template <typename T> | ||||||||||||||
934 | constexpr 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 | |||||||||||||||
939 | template <typename T> | ||||||||||||||
940 | T* 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 | |||||||||||||||
945 | template <typename T> | ||||||||||||||
946 | constexpr 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 | |||||||||||||||
951 | template <typename T> | ||||||||||||||
952 | constexpr 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 | |||||||||||||||
957 | template <typename T> | ||||||||||||||
958 | constexpr 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 | |||||||||||||||
963 | template <typename T> | ||||||||||||||
964 | constexpr 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 | |||||||||||||||
969 | template <typename T> | ||||||||||||||
970 | constexpr 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 | |||||||||||||||
975 | template <typename T> | ||||||||||||||
976 | constexpr 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 | |||||||||||||||
981 | template <typename T> | ||||||||||||||
982 | constexpr 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 | |||||||||||||||
987 | template <typename T> | ||||||||||||||
988 | constexpr 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 | |||||||||||||||
993 | template <typename T> | ||||||||||||||
994 | constexpr 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 | |||||||||||||||
999 | template <typename T> | ||||||||||||||
1000 | constexpr 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 | |||||||||||||||
1005 | template <typename T> | ||||||||||||||
1006 | constexpr 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 | |||||||||||||||
1011 | template <typename T> | ||||||||||||||
1012 | template <typename... Args> | ||||||||||||||
1013 | constexpr 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 | */ | ||||||||||||||
1029 | template <typename T, typename U> | ||||||||||||||
1030 | constexpr Maybe<U> Some(T&& aValue) { | ||||||||||||||
1031 | return {std::forward<T>(aValue), typename Maybe<U>::SomeGuard{}}; | ||||||||||||||
1032 | } | ||||||||||||||
1033 | |||||||||||||||
1034 | template <typename T> | ||||||||||||||
1035 | constexpr Maybe<T&> SomeRef(T& aValue) { | ||||||||||||||
1036 | Maybe<T&> value; | ||||||||||||||
1037 | value.emplace(aValue); | ||||||||||||||
1038 | return value; | ||||||||||||||
1039 | } | ||||||||||||||
1040 | |||||||||||||||
1041 | template <typename T> | ||||||||||||||
1042 | constexpr Maybe<T&> ToMaybeRef(T* const aPtr) { | ||||||||||||||
1043 | return aPtr ? SomeRef(*aPtr) : Nothing{}; | ||||||||||||||
1044 | } | ||||||||||||||
1045 | |||||||||||||||
1046 | template <typename T> | ||||||||||||||
1047 | Maybe<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 | */ | ||||||||||||||
1059 | template <typename T> | ||||||||||||||
1060 | constexpr 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 | |||||||||||||||
1070 | template <typename T> | ||||||||||||||
1071 | constexpr 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 | */ | ||||||||||||||
1079 | template <typename T> | ||||||||||||||
1080 | constexpr bool operator==(const Maybe<T>& aLHS, const Nothing& aRHS) { | ||||||||||||||
1081 | return aLHS.isNothing(); | ||||||||||||||
1082 | } | ||||||||||||||
1083 | |||||||||||||||
1084 | template <typename T> | ||||||||||||||
1085 | constexpr bool operator!=(const Maybe<T>& aLHS, const Nothing& aRHS) { | ||||||||||||||
1086 | return !(aLHS == aRHS); | ||||||||||||||
1087 | } | ||||||||||||||
1088 | |||||||||||||||
1089 | template <typename T> | ||||||||||||||
1090 | constexpr bool operator==(const Nothing& aLHS, const Maybe<T>& aRHS) { | ||||||||||||||
1091 | return aRHS.isNothing(); | ||||||||||||||
1092 | } | ||||||||||||||
1093 | |||||||||||||||
1094 | template <typename T> | ||||||||||||||
1095 | constexpr 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 | */ | ||||||||||||||
1103 | template <typename T> | ||||||||||||||
1104 | constexpr 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 | |||||||||||||||
1114 | template <typename T> | ||||||||||||||
1115 | constexpr bool operator>(const Maybe<T>& aLHS, const Maybe<T>& aRHS) { | ||||||||||||||
1116 | return !(aLHS < aRHS || aLHS == aRHS); | ||||||||||||||
1117 | } | ||||||||||||||
1118 | |||||||||||||||
1119 | template <typename T> | ||||||||||||||
1120 | constexpr bool operator<=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) { | ||||||||||||||
1121 | return aLHS < aRHS || aLHS == aRHS; | ||||||||||||||
1122 | } | ||||||||||||||
1123 | |||||||||||||||
1124 | template <typename T> | ||||||||||||||
1125 | constexpr bool operator>=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) { | ||||||||||||||
1126 | return !(aLHS < aRHS); | ||||||||||||||
1127 | } | ||||||||||||||
1128 | |||||||||||||||
1129 | template <typename T> | ||||||||||||||
1130 | inline 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 | |||||||||||||||
1138 | template <typename T> | ||||||||||||||
1139 | inline 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 */ |
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 | |
16 | namespace mozilla::detail { |
17 | |
18 | template <typename T> |
19 | constexpr 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 | |
24 | template <typename T, bool TriviallyDestructibleAndCopyable = |
25 | IsTriviallyDestructibleAndCopyable<T>> |
26 | struct MaybeStorageBase; |
27 | |
28 | template <typename T> |
29 | struct MaybeStorageBase<T, false> { |
30 | protected: |
31 | using NonConstT = std::remove_const_t<T>; |
32 | |
33 | union Union { |
34 | Union() {} |
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() {} |
44 | |
45 | NonConstT val; |
46 | } mStorage; |
47 | |
48 | public: |
49 | MaybeStorageBase() = default; |
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 | |
60 | template <typename T> |
61 | struct 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 |
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 | |
20 | class nsIPrincipal; |
21 | |
22 | namespace mozilla { |
23 | class BlobURLsReporter; |
24 | class OriginAttributes; |
25 | template <class T> |
26 | class Maybe; |
27 | |
28 | namespace dom { |
29 | |
30 | class BlobImpl; |
31 | class BlobURLRegistrationData; |
32 | class ContentParent; |
33 | class MediaSource; |
34 | |
35 | class 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 | |
120 | bool IsBlobURI(nsIURI* aUri); |
121 | bool IsMediaSourceURI(nsIURI* aUri); |
122 | |
123 | // Return true if inner scheme of blobURL is http or https, false otherwise. |
124 | bool BlobURLSchemeIsHTTPOrHTTPS(const nsACString& aUri); |
125 | |
126 | } // namespace dom |
127 | } // namespace mozilla |
128 | |
129 | extern nsresult NS_GetBlobForBlobURI(nsIURI* aURI, |
130 | mozilla::dom::BlobImpl** aBlob); |
131 | |
132 | extern nsresult NS_GetBlobForBlobURISpec(const nsACString& aSpec, |
133 | mozilla::dom::BlobImpl** aBlob, |
134 | bool aAlsoIfRevoked = false); |
135 | |
136 | extern nsresult NS_SetChannelContentRangeForBlobURI(nsIChannel* aChannel, |
137 | nsIURI* aURI, |
138 | nsACString& aRangeHeader); |
139 | |
140 | extern nsresult NS_GetSourceForMediaSourceURI( |
141 | nsIURI* aURI, mozilla::dom::MediaSource** aSource); |
142 | |
143 | #endif /* mozilla_dom_BlobURLProtocolHandler_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 | |
22 | namespace mozilla { |
23 | |
24 | class 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()) { |
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) |
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 |
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 | |
16 | namespace mozilla { |
17 | |
18 | enum 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 | |
43 | namespace mozilla { |
44 | |
45 | // Return a NotNull<const CHAR*> pointing at the literal empty string `""`. |
46 | template <typename CHAR> |
47 | constexpr 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. |
59 | template <typename CHAR> |
60 | constexpr 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. |
75 | template <typename CHAR> |
76 | class 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 | |
215 | using ProfilerString8View = ProfilerStringView<char>; |
216 | using ProfilerString16View = ProfilerStringView<char16_t>; |
217 | |
218 | // This compulsory marker parameter contains the required category information. |
219 | class 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 | |
241 | namespace 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 |
251 | MOZ_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(...))` |
262 | using MarkerCategory = ::mozilla::MarkerCategory; |
263 | |
264 | } // namespace baseprofiler::category |
265 | |
266 | // The classes below are all embedded in a `MarkerOptions` object. |
267 | class 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. |
272 | class 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. |
310 | class 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) |
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()); |
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. |
441 | class 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. |
588 | class 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. |
613 | class 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 | |
677 | namespace 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. |
681 | struct NoPayload final {}; |
682 | |
683 | } // namespace mozilla::baseprofiler::markers |
684 | |
685 | namespace mozilla { |
686 | |
687 | class 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. |
693 | class 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 | |
978 | namespace detail { |
979 | // GCC doesn't allow this to live inside the class. |
980 | template <typename PayloadType> |
981 | static void StreamPayload(baseprofiler::SpliceableJSONWriter& aWriter, |
982 | const Span<const char> aKey, |
983 | const PayloadType& aPayload) { |
984 | aWriter.StringProperty(aKey, aPayload); |
985 | } |
986 | |
987 | template <typename PayloadType> |
988 | inline 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 | |
998 | template <> |
999 | inline void StreamPayload<bool>(baseprofiler::SpliceableJSONWriter& aWriter, |
1000 | const Span<const char> aKey, |
1001 | const bool& aPayload) { |
1002 | aWriter.BoolProperty(aKey, aPayload); |
1003 | } |
1004 | |
1005 | template <> |
1006 | inline 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. |
1018 | template <typename T> |
1019 | struct 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 |
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 | ||||
19 | namespace IPC { | |||
20 | template <typename T> | |||
21 | struct 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 | ||||
32 | namespace mozilla { | |||
33 | ||||
34 | #ifndef XP_WIN | |||
35 | typedef uint64_t TimeStampValue; | |||
36 | #endif | |||
37 | ||||
38 | class TimeStamp; | |||
39 | class TimeStampTests; | |||
40 | ||||
41 | /** | |||
42 | * Platform-specific implementation details of BaseTimeDuration. | |||
43 | */ | |||
44 | class 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 | */ | |||
65 | template <typename ValueCalculator> | |||
66 | class 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 | */ | |||
304 | class 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 | ||||
324 | template <> | |||
325 | inline 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 | */ | |||
338 | typedef 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. | |||
377 | static_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 | */ | |||
388 | class 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; } | |||
| ||||
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 */ |