| 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 */ |