| File: | var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp |
| Warning: | line 10155, column 7 Called C++ object pointer is null |
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/TrustedHTML.h" | |||
| 203 | #include "mozilla/dom/TrustedTypesConstants.h" | |||
| 204 | #include "mozilla/dom/TrustedTypeUtils.h" | |||
| 205 | #include "mozilla/dom/UserActivation.h" | |||
| 206 | #include "mozilla/dom/ViewTransition.h" | |||
| 207 | #include "mozilla/dom/WindowContext.h" | |||
| 208 | #include "mozilla/dom/WorkerCommon.h" | |||
| 209 | #include "mozilla/dom/WorkerPrivate.h" | |||
| 210 | #include "mozilla/dom/WorkerRunnable.h" | |||
| 211 | #include "mozilla/dom/XULCommandEvent.h" | |||
| 212 | #include "mozilla/glean/GleanPings.h" | |||
| 213 | #include "mozilla/fallible.h" | |||
| 214 | #include "mozilla/gfx/2D.h" | |||
| 215 | #include "mozilla/gfx/BaseMargin.h" | |||
| 216 | #include "mozilla/gfx/BasePoint.h" | |||
| 217 | #include "mozilla/gfx/BaseSize.h" | |||
| 218 | #include "mozilla/gfx/DataSurfaceHelpers.h" | |||
| 219 | #include "mozilla/gfx/Point.h" | |||
| 220 | #include "mozilla/gfx/Rect.h" | |||
| 221 | #include "mozilla/gfx/Types.h" | |||
| 222 | #include "mozilla/ipc/ProtocolUtils.h" | |||
| 223 | #include "mozilla/ipc/SharedMemory.h" | |||
| 224 | #include "mozilla/net/UrlClassifierCommon.h" | |||
| 225 | #include "mozilla/Tokenizer.h" | |||
| 226 | #include "mozilla/widget/IMEData.h" | |||
| 227 | #include "nsAboutProtocolUtils.h" | |||
| 228 | #include "nsArrayUtils.h" | |||
| 229 | #include "nsAtomHashKeys.h" | |||
| 230 | #include "nsAttrName.h" | |||
| 231 | #include "nsAttrValue.h" | |||
| 232 | #include "nsAttrValueInlines.h" | |||
| 233 | #include "nsBaseHashtable.h" | |||
| 234 | #include "nsCCUncollectableMarker.h" | |||
| 235 | #include "nsCOMPtr.h" | |||
| 236 | #include "nsCRT.h" | |||
| 237 | #include "nsCRTGlue.h" | |||
| 238 | #include "nsCanvasFrame.h" | |||
| 239 | #include "nsCaseTreatment.h" | |||
| 240 | #include "nsCharSeparatedTokenizer.h" | |||
| 241 | #include "nsCharTraits.h" | |||
| 242 | #include "nsCompatibility.h" | |||
| 243 | #include "nsComponentManagerUtils.h" | |||
| 244 | #include "nsContainerFrame.h" | |||
| 245 | #include "nsContentCreatorFunctions.h" | |||
| 246 | #include "nsContentDLF.h" | |||
| 247 | #include "nsContentList.h" | |||
| 248 | #include "nsContentListDeclarations.h" | |||
| 249 | #include "nsContentPolicyUtils.h" | |||
| 250 | #include "nsCoord.h" | |||
| 251 | #include "nsCycleCollectionNoteChild.h" | |||
| 252 | #include "nsDOMMutationObserver.h" | |||
| 253 | #include "nsDOMString.h" | |||
| 254 | #include "nsTHashMap.h" | |||
| 255 | #include "nsDebug.h" | |||
| 256 | #include "nsDocShell.h" | |||
| 257 | #include "nsDocShellCID.h" | |||
| 258 | #include "nsError.h" | |||
| 259 | #include "nsFocusManager.h" | |||
| 260 | #include "nsFrameList.h" | |||
| 261 | #include "nsFrameLoader.h" | |||
| 262 | #include "nsFrameLoaderOwner.h" | |||
| 263 | #include "nsGenericHTMLElement.h" | |||
| 264 | #include "nsGkAtoms.h" | |||
| 265 | #include "nsGlobalWindowInner.h" | |||
| 266 | #include "nsGlobalWindowOuter.h" | |||
| 267 | #include "nsHTMLDocument.h" | |||
| 268 | #include "nsHTMLTags.h" | |||
| 269 | #include "nsHashKeys.h" | |||
| 270 | #include "nsHtml5StringParser.h" | |||
| 271 | #include "nsIAboutModule.h" | |||
| 272 | #include "nsIAnonymousContentCreator.h" | |||
| 273 | #include "nsIAppShell.h" | |||
| 274 | #include "nsIArray.h" | |||
| 275 | #include "nsIAsyncVerifyRedirectCallback.h" | |||
| 276 | #include "nsIBidiKeyboard.h" | |||
| 277 | #include "nsIBrowser.h" | |||
| 278 | #include "nsICacheInfoChannel.h" | |||
| 279 | #include "nsICachingChannel.h" | |||
| 280 | #include "nsICategoryManager.h" | |||
| 281 | #include "nsIChannel.h" | |||
| 282 | #include "nsIChannelEventSink.h" | |||
| 283 | #include "nsIClassifiedChannel.h" | |||
| 284 | #include "nsIConsoleService.h" | |||
| 285 | #include "nsIContent.h" | |||
| 286 | #include "nsIContentInlines.h" | |||
| 287 | #include "nsIContentPolicy.h" | |||
| 288 | #include "nsIContentSecurityPolicy.h" | |||
| 289 | #include "nsIContentSink.h" | |||
| 290 | #include "nsIDOMWindowUtils.h" | |||
| 291 | #include "nsIDocShell.h" | |||
| 292 | #include "nsIDocShellTreeItem.h" | |||
| 293 | #include "nsIDocumentEncoder.h" | |||
| 294 | #include "nsIDocumentLoaderFactory.h" | |||
| 295 | #include "nsIDocumentViewer.h" | |||
| 296 | #include "nsIDragService.h" | |||
| 297 | #include "nsIDragSession.h" | |||
| 298 | #include "nsIFile.h" | |||
| 299 | #include "nsIFocusManager.h" | |||
| 300 | #include "nsIFormControl.h" | |||
| 301 | #include "nsIFragmentContentSink.h" | |||
| 302 | #include "nsIFrame.h" | |||
| 303 | #include "nsIGlobalObject.h" | |||
| 304 | #include "nsIHttpChannel.h" | |||
| 305 | #include "nsIHttpChannelInternal.h" | |||
| 306 | #include "nsIIOService.h" | |||
| 307 | #include "nsIImageLoadingContent.h" | |||
| 308 | #include "nsIInputStream.h" | |||
| 309 | #include "nsIInterfaceRequestor.h" | |||
| 310 | #include "nsIInterfaceRequestorUtils.h" | |||
| 311 | #include "nsILoadContext.h" | |||
| 312 | #include "nsILoadGroup.h" | |||
| 313 | #include "nsILoadInfo.h" | |||
| 314 | #include "nsIMIMEService.h" | |||
| 315 | #include "nsIMemoryReporter.h" | |||
| 316 | #include "nsINetUtil.h" | |||
| 317 | #include "nsINode.h" | |||
| 318 | #include "nsIObjectLoadingContent.h" | |||
| 319 | #include "nsIObserver.h" | |||
| 320 | #include "nsIObserverService.h" | |||
| 321 | #include "nsIParserUtils.h" | |||
| 322 | #include "nsIPermissionManager.h" | |||
| 323 | #include "nsIPrincipal.h" | |||
| 324 | #include "nsIProperties.h" | |||
| 325 | #include "nsIProtocolHandler.h" | |||
| 326 | #include "nsIRequest.h" | |||
| 327 | #include "nsIRunnable.h" | |||
| 328 | #include "nsIScreen.h" | |||
| 329 | #include "nsIScriptError.h" | |||
| 330 | #include "nsIScriptGlobalObject.h" | |||
| 331 | #include "nsIScriptObjectPrincipal.h" | |||
| 332 | #include "nsIScriptSecurityManager.h" | |||
| 333 | #include "nsISerialEventTarget.h" | |||
| 334 | #include "nsIStreamConverter.h" | |||
| 335 | #include "nsIStreamConverterService.h" | |||
| 336 | #include "nsIStringBundle.h" | |||
| 337 | #include "nsISupports.h" | |||
| 338 | #include "nsISupportsPrimitives.h" | |||
| 339 | #include "nsISupportsUtils.h" | |||
| 340 | #include "nsITransferable.h" | |||
| 341 | #include "nsIURI.h" | |||
| 342 | #include "nsIURIMutator.h" | |||
| 343 | #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE) | |||
| 344 | # include "nsIURIWithSpecialOrigin.h" | |||
| 345 | #endif | |||
| 346 | #include "nsIUserIdleServiceInternal.h" | |||
| 347 | #include "nsIWeakReferenceUtils.h" | |||
| 348 | #include "nsIWebNavigation.h" | |||
| 349 | #include "nsIWebNavigationInfo.h" | |||
| 350 | #include "nsIWidget.h" | |||
| 351 | #include "nsIWindowMediator.h" | |||
| 352 | #include "nsIXPConnect.h" | |||
| 353 | #include "nsJSPrincipals.h" | |||
| 354 | #include "nsJSUtils.h" | |||
| 355 | #include "nsLayoutUtils.h" | |||
| 356 | #include "nsLiteralString.h" | |||
| 357 | #include "nsMargin.h" | |||
| 358 | #include "nsMimeTypes.h" | |||
| 359 | #include "nsNameSpaceManager.h" | |||
| 360 | #include "nsNetCID.h" | |||
| 361 | #include "nsNetUtil.h" | |||
| 362 | #include "nsNodeInfoManager.h" | |||
| 363 | #include "nsPIDOMWindow.h" | |||
| 364 | #include "nsPIDOMWindowInlines.h" | |||
| 365 | #include "nsParser.h" | |||
| 366 | #include "nsParserConstants.h" | |||
| 367 | #include "nsPoint.h" | |||
| 368 | #include "nsPointerHashKeys.h" | |||
| 369 | #include "nsPresContext.h" | |||
| 370 | #include "nsQueryFrame.h" | |||
| 371 | #include "nsQueryObject.h" | |||
| 372 | #include "nsRange.h" | |||
| 373 | #include "nsRefPtrHashtable.h" | |||
| 374 | #include "nsSandboxFlags.h" | |||
| 375 | #include "nsScriptSecurityManager.h" | |||
| 376 | #include "nsServiceManagerUtils.h" | |||
| 377 | #include "nsStreamUtils.h" | |||
| 378 | #include "nsString.h" | |||
| 379 | #include "nsStringBundle.h" | |||
| 380 | #include "nsStringFlags.h" | |||
| 381 | #include "nsStringFwd.h" | |||
| 382 | #include "nsStringIterator.h" | |||
| 383 | #include "nsStringStream.h" | |||
| 384 | #include "nsTArray.h" | |||
| 385 | #include "nsTLiteralString.h" | |||
| 386 | #include "nsTPromiseFlatString.h" | |||
| 387 | #include "nsTStringRepr.h" | |||
| 388 | #include "nsTextFragment.h" | |||
| 389 | #include "nsTextNode.h" | |||
| 390 | #include "nsThreadManager.h" | |||
| 391 | #include "nsThreadUtils.h" | |||
| 392 | #include "nsTreeSanitizer.h" | |||
| 393 | #include "nsUGenCategory.h" | |||
| 394 | #include "nsURLHelper.h" | |||
| 395 | #include "nsUnicodeProperties.h" | |||
| 396 | #include "nsVariant.h" | |||
| 397 | #include "nsWidgetsCID.h" | |||
| 398 | #include "nsView.h" | |||
| 399 | #include "nsViewManager.h" | |||
| 400 | #include "nsXPCOM.h" | |||
| 401 | #include "nsXPCOMCID.h" | |||
| 402 | #include "nsXULAppAPI.h" | |||
| 403 | #include "nsXULElement.h" | |||
| 404 | #include "nsXULPopupManager.h" | |||
| 405 | #include "nscore.h" | |||
| 406 | #include "prinrval.h" | |||
| 407 | #include "xpcprivate.h" | |||
| 408 | #include "xpcpublic.h" | |||
| 409 | ||||
| 410 | #if defined(XP_WIN) | |||
| 411 | // Undefine LoadImage to prevent naming conflict with Windows. | |||
| 412 | # undef LoadImage | |||
| 413 | #endif | |||
| 414 | ||||
| 415 | extern "C" int MOZ_XMLTranslateEntity(const char* ptr, const char* end, | |||
| 416 | const char** next, char16_t* result); | |||
| 417 | extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end, int ns_aware, | |||
| 418 | const char** colon); | |||
| 419 | ||||
| 420 | using namespace mozilla::dom; | |||
| 421 | using namespace mozilla::ipc; | |||
| 422 | using namespace mozilla::gfx; | |||
| 423 | using namespace mozilla::layers; | |||
| 424 | using namespace mozilla::widget; | |||
| 425 | using namespace mozilla; | |||
| 426 | ||||
| 427 | const char kLoadAsData[] = "loadAsData"; | |||
| 428 | ||||
| 429 | nsIXPConnect* nsContentUtils::sXPConnect; | |||
| 430 | nsIScriptSecurityManager* nsContentUtils::sSecurityManager; | |||
| 431 | nsIPrincipal* nsContentUtils::sSystemPrincipal; | |||
| 432 | nsIPrincipal* nsContentUtils::sNullSubjectPrincipal; | |||
| 433 | nsIPrincipal* nsContentUtils::sFingerprintingProtectionPrincipal; | |||
| 434 | nsIConsoleService* nsContentUtils::sConsoleService; | |||
| 435 | ||||
| 436 | static nsTHashMap<RefPtr<nsAtom>, EventNameMapping>* sAtomEventTable; | |||
| 437 | static nsTHashMap<nsStringHashKey, EventNameMapping>* sStringEventTable; | |||
| 438 | static nsTArray<RefPtr<nsAtom>>* sUserDefinedEvents; | |||
| 439 | nsIStringBundleService* nsContentUtils::sStringBundleService; | |||
| 440 | ||||
| 441 | static StaticRefPtr<nsIStringBundle> | |||
| 442 | sStringBundles[nsContentUtils::PropertiesFile_COUNT]; | |||
| 443 | ||||
| 444 | nsIContentPolicy* nsContentUtils::sContentPolicyService; | |||
| 445 | bool nsContentUtils::sTriedToGetContentPolicy = false; | |||
| 446 | StaticRefPtr<nsIBidiKeyboard> nsContentUtils::sBidiKeyboard; | |||
| 447 | uint32_t nsContentUtils::sScriptBlockerCount = 0; | |||
| 448 | uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0; | |||
| 449 | AutoTArray<nsCOMPtr<nsIRunnable>, 8>* nsContentUtils::sBlockedScriptRunners = | |||
| 450 | nullptr; | |||
| 451 | uint32_t nsContentUtils::sRunnersCountAtFirstBlocker = 0; | |||
| 452 | nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nullptr; | |||
| 453 | ||||
| 454 | bool nsContentUtils::sIsHandlingKeyBoardEvent = false; | |||
| 455 | ||||
| 456 | nsString* nsContentUtils::sShiftText = nullptr; | |||
| 457 | nsString* nsContentUtils::sControlText = nullptr; | |||
| 458 | nsString* nsContentUtils::sCommandOrWinText = nullptr; | |||
| 459 | nsString* nsContentUtils::sAltText = nullptr; | |||
| 460 | nsString* nsContentUtils::sModifierSeparator = nullptr; | |||
| 461 | ||||
| 462 | bool nsContentUtils::sInitialized = false; | |||
| 463 | #ifndef RELEASE_OR_BETA | |||
| 464 | bool nsContentUtils::sBypassCSSOMOriginCheck = false; | |||
| 465 | #endif | |||
| 466 | ||||
| 467 | nsCString* nsContentUtils::sJSScriptBytecodeMimeType = nullptr; | |||
| 468 | nsCString* nsContentUtils::sJSModuleBytecodeMimeType = nullptr; | |||
| 469 | ||||
| 470 | nsContentUtils::UserInteractionObserver* | |||
| 471 | nsContentUtils::sUserInteractionObserver = nullptr; | |||
| 472 | ||||
| 473 | nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr; | |||
| 474 | nsParser* nsContentUtils::sXMLFragmentParser = nullptr; | |||
| 475 | nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr; | |||
| 476 | bool nsContentUtils::sFragmentParsingActive = false; | |||
| 477 | ||||
| 478 | bool nsContentUtils::sMayHaveFormCheckboxStateChangeListeners = false; | |||
| 479 | bool nsContentUtils::sMayHaveFormRadioStateChangeListeners = false; | |||
| 480 | ||||
| 481 | mozilla::LazyLogModule nsContentUtils::gResistFingerprintingLog( | |||
| 482 | "nsResistFingerprinting"); | |||
| 483 | mozilla::LazyLogModule nsContentUtils::sDOMDumpLog("Dump"); | |||
| 484 | ||||
| 485 | int32_t nsContentUtils::sInnerOrOuterWindowCount = 0; | |||
| 486 | uint32_t nsContentUtils::sInnerOrOuterWindowSerialCounter = 0; | |||
| 487 | ||||
| 488 | template Maybe<int32_t> nsContentUtils::ComparePoints( | |||
| 489 | const RangeBoundary& aFirstBoundary, const RangeBoundary& aSecondBoundary); | |||
| 490 | template Maybe<int32_t> nsContentUtils::ComparePoints( | |||
| 491 | const RangeBoundary& aFirstBoundary, | |||
| 492 | const RawRangeBoundary& aSecondBoundary); | |||
| 493 | template Maybe<int32_t> nsContentUtils::ComparePoints( | |||
| 494 | const RawRangeBoundary& aFirstBoundary, | |||
| 495 | const RangeBoundary& aSecondBoundary); | |||
| 496 | template Maybe<int32_t> nsContentUtils::ComparePoints( | |||
| 497 | const RawRangeBoundary& aFirstBoundary, | |||
| 498 | const RawRangeBoundary& aSecondBoundary); | |||
| 499 | ||||
| 500 | template int32_t nsContentUtils::ComparePoints_Deprecated( | |||
| 501 | const RangeBoundary& aFirstBoundary, const RangeBoundary& aSecondBoundary, | |||
| 502 | bool* aDisconnected); | |||
| 503 | template int32_t nsContentUtils::ComparePoints_Deprecated( | |||
| 504 | const RangeBoundary& aFirstBoundary, | |||
| 505 | const RawRangeBoundary& aSecondBoundary, bool* aDisconnected); | |||
| 506 | template int32_t nsContentUtils::ComparePoints_Deprecated( | |||
| 507 | const RawRangeBoundary& aFirstBoundary, | |||
| 508 | const RangeBoundary& aSecondBoundary, bool* aDisconnected); | |||
| 509 | template int32_t nsContentUtils::ComparePoints_Deprecated( | |||
| 510 | const RawRangeBoundary& aFirstBoundary, | |||
| 511 | const RawRangeBoundary& aSecondBoundary, bool* aDisconnected); | |||
| 512 | ||||
| 513 | // Subset of | |||
| 514 | // http://www.whatwg.org/specs/web-apps/current-work/#autofill-field-name | |||
| 515 | enum AutocompleteUnsupportedFieldName : uint8_t { | |||
| 516 | #define AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME(name_, value_) \ | |||
| 517 | eAutocompleteUnsupportedFieldName_##name_, | |||
| 518 | #include "AutocompleteFieldList.h" | |||
| 519 | #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME | |||
| 520 | }; | |||
| 521 | ||||
| 522 | enum AutocompleteNoPersistFieldName : uint8_t { | |||
| 523 | #define AUTOCOMPLETE_NO_PERSIST_FIELD_NAME(name_, value_) \ | |||
| 524 | eAutocompleteNoPersistFieldName_##name_, | |||
| 525 | #include "AutocompleteFieldList.h" | |||
| 526 | #undef AUTOCOMPLETE_NO_PERSIST_FIELD_NAME | |||
| 527 | }; | |||
| 528 | ||||
| 529 | enum AutocompleteUnsupportFieldContactHint : uint8_t { | |||
| 530 | #define AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT(name_, value_) \ | |||
| 531 | eAutocompleteUnsupportedFieldContactHint_##name_, | |||
| 532 | #include "AutocompleteFieldList.h" | |||
| 533 | #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT | |||
| 534 | }; | |||
| 535 | ||||
| 536 | enum AutocompleteFieldName : uint8_t { | |||
| 537 | #define AUTOCOMPLETE_FIELD_NAME(name_, value_) eAutocompleteFieldName_##name_, | |||
| 538 | #define AUTOCOMPLETE_CONTACT_FIELD_NAME(name_, value_) \ | |||
| 539 | AUTOCOMPLETE_FIELD_NAME(name_, value_) | |||
| 540 | #include "AutocompleteFieldList.h" | |||
| 541 | #undef AUTOCOMPLETE_FIELD_NAME | |||
| 542 | #undef AUTOCOMPLETE_CONTACT_FIELD_NAME | |||
| 543 | }; | |||
| 544 | ||||
| 545 | enum AutocompleteFieldHint : uint8_t { | |||
| 546 | #define AUTOCOMPLETE_FIELD_HINT(name_, value_) eAutocompleteFieldHint_##name_, | |||
| 547 | #include "AutocompleteFieldList.h" | |||
| 548 | #undef AUTOCOMPLETE_FIELD_HINT | |||
| 549 | }; | |||
| 550 | ||||
| 551 | enum AutocompleteFieldContactHint : uint8_t { | |||
| 552 | #define AUTOCOMPLETE_FIELD_CONTACT_HINT(name_, value_) \ | |||
| 553 | eAutocompleteFieldContactHint_##name_, | |||
| 554 | #include "AutocompleteFieldList.h" | |||
| 555 | #undef AUTOCOMPLETE_FIELD_CONTACT_HINT | |||
| 556 | }; | |||
| 557 | ||||
| 558 | enum AutocompleteCredentialType : uint8_t { | |||
| 559 | #define AUTOCOMPLETE_CREDENTIAL_TYPE(name_, value_) \ | |||
| 560 | eAutocompleteCredentialType_##name_, | |||
| 561 | #include "AutocompleteFieldList.h" | |||
| 562 | #undef AUTOCOMPLETE_CREDENTIAL_TYPE | |||
| 563 | }; | |||
| 564 | ||||
| 565 | enum AutocompleteCategory { | |||
| 566 | #define AUTOCOMPLETE_CATEGORY(name_, value_) eAutocompleteCategory_##name_, | |||
| 567 | #include "AutocompleteFieldList.h" | |||
| 568 | #undef AUTOCOMPLETE_CATEGORY | |||
| 569 | }; | |||
| 570 | ||||
| 571 | static const nsAttrValue::EnumTable kAutocompleteUnsupportedFieldNameTable[] = { | |||
| 572 | #define AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME(name_, value_) \ | |||
| 573 | {value_, eAutocompleteUnsupportedFieldName_##name_}, | |||
| 574 | #include "AutocompleteFieldList.h" | |||
| 575 | #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME | |||
| 576 | {nullptr, 0}}; | |||
| 577 | ||||
| 578 | static const nsAttrValue::EnumTable kAutocompleteNoPersistFieldNameTable[] = { | |||
| 579 | #define AUTOCOMPLETE_NO_PERSIST_FIELD_NAME(name_, value_) \ | |||
| 580 | {value_, eAutocompleteNoPersistFieldName_##name_}, | |||
| 581 | #include "AutocompleteFieldList.h" | |||
| 582 | #undef AUTOCOMPLETE_NO_PERSIST_FIELD_NAME | |||
| 583 | {nullptr, 0}}; | |||
| 584 | ||||
| 585 | static const nsAttrValue::EnumTable | |||
| 586 | kAutocompleteUnsupportedContactFieldHintTable[] = { | |||
| 587 | #define AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT(name_, value_) \ | |||
| 588 | {value_, eAutocompleteUnsupportedFieldContactHint_##name_}, | |||
| 589 | #include "AutocompleteFieldList.h" | |||
| 590 | #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT | |||
| 591 | {nullptr, 0}}; | |||
| 592 | ||||
| 593 | static const nsAttrValue::EnumTable kAutocompleteFieldNameTable[] = { | |||
| 594 | #define AUTOCOMPLETE_FIELD_NAME(name_, value_) \ | |||
| 595 | {value_, eAutocompleteFieldName_##name_}, | |||
| 596 | #include "AutocompleteFieldList.h" | |||
| 597 | #undef AUTOCOMPLETE_FIELD_NAME | |||
| 598 | {nullptr, 0}}; | |||
| 599 | ||||
| 600 | static const nsAttrValue::EnumTable kAutocompleteContactFieldNameTable[] = { | |||
| 601 | #define AUTOCOMPLETE_CONTACT_FIELD_NAME(name_, value_) \ | |||
| 602 | {value_, eAutocompleteFieldName_##name_}, | |||
| 603 | #include "AutocompleteFieldList.h" | |||
| 604 | #undef AUTOCOMPLETE_CONTACT_FIELD_NAME | |||
| 605 | {nullptr, 0}}; | |||
| 606 | ||||
| 607 | static const nsAttrValue::EnumTable kAutocompleteFieldHintTable[] = { | |||
| 608 | #define AUTOCOMPLETE_FIELD_HINT(name_, value_) \ | |||
| 609 | {value_, eAutocompleteFieldHint_##name_}, | |||
| 610 | #include "AutocompleteFieldList.h" | |||
| 611 | #undef AUTOCOMPLETE_FIELD_HINT | |||
| 612 | {nullptr, 0}}; | |||
| 613 | ||||
| 614 | static const nsAttrValue::EnumTable kAutocompleteContactFieldHintTable[] = { | |||
| 615 | #define AUTOCOMPLETE_FIELD_CONTACT_HINT(name_, value_) \ | |||
| 616 | {value_, eAutocompleteFieldContactHint_##name_}, | |||
| 617 | #include "AutocompleteFieldList.h" | |||
| 618 | #undef AUTOCOMPLETE_FIELD_CONTACT_HINT | |||
| 619 | {nullptr, 0}}; | |||
| 620 | ||||
| 621 | static const nsAttrValue::EnumTable kAutocompleteCredentialTypeTable[] = { | |||
| 622 | #define AUTOCOMPLETE_CREDENTIAL_TYPE(name_, value_) \ | |||
| 623 | {value_, eAutocompleteCredentialType_##name_}, | |||
| 624 | #include "AutocompleteFieldList.h" | |||
| 625 | #undef AUTOCOMPLETE_CREDENTIAL_TYPE | |||
| 626 | {nullptr, 0}}; | |||
| 627 | ||||
| 628 | namespace { | |||
| 629 | ||||
| 630 | static PLDHashTable* sEventListenerManagersHash; | |||
| 631 | ||||
| 632 | // A global hashtable to for keeping the arena alive for cross docGroup node | |||
| 633 | // adoption. | |||
| 634 | static nsRefPtrHashtable<nsPtrHashKey<const nsINode>, mozilla::dom::DOMArena>* | |||
| 635 | sDOMArenaHashtable; | |||
| 636 | ||||
| 637 | class DOMEventListenerManagersHashReporter final : public nsIMemoryReporter { | |||
| 638 | MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)static size_t MallocSizeOf(const void* aPtr) { mozilla::dmd:: Report(aPtr); return moz_malloc_size_of(aPtr); } | |||
| 639 | ||||
| 640 | ~DOMEventListenerManagersHashReporter() = default; | |||
| 641 | ||||
| 642 | public: | |||
| 643 | 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: | |||
| 644 | ||||
| 645 | NS_IMETHODvirtual nsresult CollectReports(nsIHandleReportCallback* aHandleReport, | |||
| 646 | nsISupports* aData, bool aAnonymize) override { | |||
| 647 | // We don't measure the |EventListenerManager| objects pointed to by the | |||
| 648 | // entries because those references are non-owning. | |||
| 649 | int64_t amount = | |||
| 650 | sEventListenerManagersHash | |||
| 651 | ? sEventListenerManagersHash->ShallowSizeOfIncludingThis( | |||
| 652 | MallocSizeOf) | |||
| 653 | : 0; | |||
| 654 | ||||
| 655 | 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) | |||
| 656 | "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) | |||
| 657 | 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); | |||
| 658 | ||||
| 659 | return NS_OK; | |||
| 660 | } | |||
| 661 | }; | |||
| 662 | ||||
| 663 | 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" , 663); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 663; __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" , 663); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"DOMEventListenerManagersHashReporter\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 663; __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" , 663); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 663 ; __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" , 663); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"DOMEventListenerManagersHashReporter\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 663; __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" , 663); 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(std::size(table) > 1, "need at least 1 interface" ); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID , aInstancePtr, table); return rv; } | |||
| 664 | ||||
| 665 | class EventListenerManagerMapEntry : public PLDHashEntryHdr { | |||
| 666 | public: | |||
| 667 | explicit EventListenerManagerMapEntry(const void* aKey) : mKey(aKey) {} | |||
| 668 | ||||
| 669 | ~EventListenerManagerMapEntry() { | |||
| 670 | 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" , 670); MOZ_PretendNoReturn(); } } while (0); | |||
| 671 | } | |||
| 672 | ||||
| 673 | protected: // declared protected to silence clang warnings | |||
| 674 | const void* mKey; // must be first, to look like PLDHashEntryStub | |||
| 675 | ||||
| 676 | public: | |||
| 677 | RefPtr<EventListenerManager> mListenerManager; | |||
| 678 | }; | |||
| 679 | ||||
| 680 | static void EventListenerManagerHashInitEntry(PLDHashEntryHdr* entry, | |||
| 681 | const void* key) { | |||
| 682 | // Initialize the entry with placement new | |||
| 683 | new (entry) EventListenerManagerMapEntry(key); | |||
| 684 | } | |||
| 685 | ||||
| 686 | static void EventListenerManagerHashClearEntry(PLDHashTable* table, | |||
| 687 | PLDHashEntryHdr* entry) { | |||
| 688 | EventListenerManagerMapEntry* lm = | |||
| 689 | static_cast<EventListenerManagerMapEntry*>(entry); | |||
| 690 | ||||
| 691 | // Let the EventListenerManagerMapEntry clean itself up... | |||
| 692 | lm->~EventListenerManagerMapEntry(); | |||
| 693 | } | |||
| 694 | ||||
| 695 | class SameOriginCheckerImpl final : public nsIChannelEventSink, | |||
| 696 | public nsIInterfaceRequestor { | |||
| 697 | ~SameOriginCheckerImpl() = default; | |||
| 698 | ||||
| 699 | 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: | |||
| 700 | NS_DECL_NSICHANNELEVENTSINKvirtual nsresult AsyncOnChannelRedirect(nsIChannel *oldChannel , nsIChannel *newChannel, uint32_t flags, nsIAsyncVerifyRedirectCallback *callback) override; | |||
| 701 | NS_DECL_NSIINTERFACEREQUESTORvirtual nsresult GetInterface(const nsIID & uuid, void * * result) override; | |||
| 702 | }; | |||
| 703 | ||||
| 704 | } // namespace | |||
| 705 | ||||
| 706 | void AutoSuppressEventHandling::SuppressDocument(Document* aDoc) { | |||
| 707 | // Note: Document::SuppressEventHandling will also automatically suppress | |||
| 708 | // event handling for any in-process sub-documents. However, since we need | |||
| 709 | // to deal with cases where remote BrowsingContexts may be interleaved | |||
| 710 | // with in-process ones, we still need to walk the entire tree ourselves. | |||
| 711 | // This may be slightly redundant in some cases, but since event handling | |||
| 712 | // suppressions maintain a count of current blockers, it does not cause | |||
| 713 | // any problems. | |||
| 714 | aDoc->SuppressEventHandling(); | |||
| 715 | } | |||
| 716 | ||||
| 717 | void AutoSuppressEventHandling::UnsuppressDocument(Document* aDoc) { | |||
| 718 | aDoc->UnsuppressEventHandlingAndFireEvents(true); | |||
| 719 | } | |||
| 720 | ||||
| 721 | AutoSuppressEventHandling::~AutoSuppressEventHandling() { | |||
| 722 | UnsuppressDocuments(); | |||
| 723 | } | |||
| 724 | ||||
| 725 | void AutoSuppressEventHandlingAndSuspend::SuppressDocument(Document* aDoc) { | |||
| 726 | AutoSuppressEventHandling::SuppressDocument(aDoc); | |||
| 727 | if (nsCOMPtr<nsPIDOMWindowInner> win = aDoc->GetInnerWindow()) { | |||
| 728 | win->Suspend(); | |||
| 729 | mWindows.AppendElement(win); | |||
| 730 | } | |||
| 731 | } | |||
| 732 | ||||
| 733 | AutoSuppressEventHandlingAndSuspend::~AutoSuppressEventHandlingAndSuspend() { | |||
| 734 | for (const auto& win : mWindows) { | |||
| 735 | win->Resume(); | |||
| 736 | } | |||
| 737 | } | |||
| 738 | ||||
| 739 | /** | |||
| 740 | * This class is used to determine whether or not the user is currently | |||
| 741 | * interacting with the browser. It listens to observer events to toggle the | |||
| 742 | * value of the sUserActive static. | |||
| 743 | * | |||
| 744 | * This class is an internal implementation detail. | |||
| 745 | * nsContentUtils::GetUserIsInteracting() should be used to access current | |||
| 746 | * user interaction status. | |||
| 747 | */ | |||
| 748 | class nsContentUtils::UserInteractionObserver final | |||
| 749 | : public nsIObserver, | |||
| 750 | public BackgroundHangAnnotator { | |||
| 751 | public: | |||
| 752 | 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: | |||
| 753 | NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic , const char16_t * aData) override; | |||
| 754 | ||||
| 755 | void Init(); | |||
| 756 | void Shutdown(); | |||
| 757 | void AnnotateHang(BackgroundHangAnnotations& aAnnotations) override; | |||
| 758 | ||||
| 759 | static Atomic<bool> sUserActive; | |||
| 760 | ||||
| 761 | private: | |||
| 762 | ~UserInteractionObserver() = default; | |||
| 763 | }; | |||
| 764 | ||||
| 765 | static constexpr nsLiteralCString kRfpPrefs[] = { | |||
| 766 | "privacy.resistFingerprinting"_ns, | |||
| 767 | "privacy.resistFingerprinting.pbmode"_ns, | |||
| 768 | "privacy.fingerprintingProtection"_ns, | |||
| 769 | "privacy.fingerprintingProtection.pbmode"_ns, | |||
| 770 | "privacy.fingerprintingProtection.overrides"_ns, | |||
| 771 | }; | |||
| 772 | ||||
| 773 | static void RecomputeResistFingerprintingAllDocs(const char*, void*) { | |||
| 774 | AutoTArray<RefPtr<BrowsingContextGroup>, 5> bcGroups; | |||
| 775 | BrowsingContextGroup::GetAllGroups(bcGroups); | |||
| 776 | for (auto& bcGroup : bcGroups) { | |||
| 777 | AutoTArray<DocGroup*, 5> docGroups; | |||
| 778 | bcGroup->GetDocGroups(docGroups); | |||
| 779 | for (auto* docGroup : docGroups) { | |||
| 780 | for (Document* doc : *docGroup) { | |||
| 781 | if (doc->RecomputeResistFingerprinting()) { | |||
| 782 | if (auto* pc = doc->GetPresContext()) { | |||
| 783 | pc->MediaFeatureValuesChanged( | |||
| 784 | {MediaFeatureChangeReason::PreferenceChange}, | |||
| 785 | MediaFeatureChangePropagation::JustThisDocument); | |||
| 786 | } | |||
| 787 | } | |||
| 788 | } | |||
| 789 | } | |||
| 790 | } | |||
| 791 | } | |||
| 792 | ||||
| 793 | // static | |||
| 794 | nsresult nsContentUtils::Init() { | |||
| 795 | if (sInitialized) { | |||
| 796 | 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" , 796); | |||
| 797 | ||||
| 798 | return NS_OK; | |||
| 799 | } | |||
| 800 | ||||
| 801 | nsHTMLTags::AddRefTable(); | |||
| 802 | ||||
| 803 | sXPConnect = nsXPConnect::XPConnect(); | |||
| 804 | // We hold a strong ref to sXPConnect to ensure that it does not go away until | |||
| 805 | // nsLayoutStatics::Shutdown is happening. Otherwise ~nsXPConnect can be | |||
| 806 | // triggered by xpcModuleDtor late in shutdown and cause crashes due to | |||
| 807 | // various stuff already being torn down by then. Note that this means that | |||
| 808 | // we are effectively making sure that if we leak nsLayoutStatics then we also | |||
| 809 | // leak nsXPConnect. | |||
| 810 | NS_ADDREF(sXPConnect)(sXPConnect)->AddRef(); | |||
| 811 | ||||
| 812 | sSecurityManager = nsScriptSecurityManager::GetScriptSecurityManager(); | |||
| 813 | if (!sSecurityManager) return NS_ERROR_FAILURE; | |||
| 814 | NS_ADDREF(sSecurityManager)(sSecurityManager)->AddRef(); | |||
| 815 | ||||
| 816 | sSecurityManager->GetSystemPrincipal(&sSystemPrincipal); | |||
| 817 | 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" , 817); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sSystemPrincipal" ")"); do { *((volatile int*)__null) = 817; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 818 | ||||
| 819 | RefPtr<NullPrincipal> nullPrincipal = | |||
| 820 | NullPrincipal::CreateWithoutOriginAttributes(); | |||
| 821 | if (!nullPrincipal) { | |||
| 822 | return NS_ERROR_FAILURE; | |||
| 823 | } | |||
| 824 | ||||
| 825 | nullPrincipal.forget(&sNullSubjectPrincipal); | |||
| 826 | ||||
| 827 | RefPtr<nsIPrincipal> fingerprintingProtectionPrincipal = | |||
| 828 | BasePrincipal::CreateContentPrincipal( | |||
| 829 | "about:fingerprintingprotection"_ns); | |||
| 830 | if (!fingerprintingProtectionPrincipal) { | |||
| 831 | return NS_ERROR_FAILURE; | |||
| 832 | } | |||
| 833 | ||||
| 834 | fingerprintingProtectionPrincipal.forget(&sFingerprintingProtectionPrincipal); | |||
| 835 | ||||
| 836 | if (!InitializeEventTable()) return NS_ERROR_FAILURE; | |||
| 837 | ||||
| 838 | if (!sEventListenerManagersHash) { | |||
| 839 | static const PLDHashTableOps hash_table_ops = { | |||
| 840 | PLDHashTable::HashVoidPtrKeyStub, PLDHashTable::MatchEntryStub, | |||
| 841 | PLDHashTable::MoveEntryStub, EventListenerManagerHashClearEntry, | |||
| 842 | EventListenerManagerHashInitEntry}; | |||
| 843 | ||||
| 844 | sEventListenerManagersHash = | |||
| 845 | new PLDHashTable(&hash_table_ops, sizeof(EventListenerManagerMapEntry)); | |||
| 846 | ||||
| 847 | RegisterStrongMemoryReporter(new DOMEventListenerManagersHashReporter()); | |||
| 848 | } | |||
| 849 | ||||
| 850 | sBlockedScriptRunners = new AutoTArray<nsCOMPtr<nsIRunnable>, 8>; | |||
| 851 | ||||
| 852 | #ifndef RELEASE_OR_BETA | |||
| 853 | sBypassCSSOMOriginCheck = getenv("MOZ_BYPASS_CSSOM_ORIGIN_CHECK"); | |||
| 854 | #endif | |||
| 855 | ||||
| 856 | Element::InitCCCallbacks(); | |||
| 857 | ||||
| 858 | RefPtr<nsRFPService> rfpService = nsRFPService::GetOrCreate(); | |||
| 859 | 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" , 859); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rfpService" ")" ); do { *((volatile int*)__null) = 859; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 860 | ||||
| 861 | if (XRE_IsParentProcess()) { | |||
| 862 | AsyncPrecreateStringBundles(); | |||
| 863 | ||||
| 864 | #if defined(MOZ_WIDGET_ANDROID) | |||
| 865 | // On Android, at-shutdown ping submission isn't reliable | |||
| 866 | // (( because, on Android, we usually get killed, not shut down )). | |||
| 867 | // To have a chance at submitting the ping, aim for idle after startup. | |||
| 868 | nsresult rv = NS_DispatchToCurrentThreadQueue( | |||
| 869 | NS_NewRunnableFunction( | |||
| 870 | "AndroidUseCounterPingSubmitter", | |||
| 871 | []() { glean_pings::UseCounters.Submit("idle_startup"_ns); }), | |||
| 872 | EventQueuePriority::Idle); | |||
| 873 | // This is mostly best-effort, so if it goes awry, just log. | |||
| 874 | 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" , 874); | |||
| 875 | #endif // defined(MOZ_WIDGET_ANDROID) | |||
| 876 | ||||
| 877 | RunOnShutdown( | |||
| 878 | [&] { glean_pings::UseCounters.Submit("app_shutdown_confirmed"_ns); }, | |||
| 879 | ShutdownPhase::AppShutdownConfirmed); | |||
| 880 | } | |||
| 881 | ||||
| 882 | RefPtr<UserInteractionObserver> uio = new UserInteractionObserver(); | |||
| 883 | uio->Init(); | |||
| 884 | uio.forget(&sUserInteractionObserver); | |||
| 885 | ||||
| 886 | for (const auto& pref : kRfpPrefs) { | |||
| 887 | Preferences::RegisterCallback(RecomputeResistFingerprintingAllDocs, pref); | |||
| 888 | } | |||
| 889 | ||||
| 890 | sInitialized = true; | |||
| 891 | ||||
| 892 | return NS_OK; | |||
| 893 | } | |||
| 894 | ||||
| 895 | bool nsContentUtils::InitJSBytecodeMimeType() { | |||
| 896 | 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" , 896); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 896; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 897 | 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" , 897); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sJSScriptBytecodeMimeType" ")"); do { *((volatile int*)__null) = 897; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 898 | 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" , 898); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sJSModuleBytecodeMimeType" ")"); do { *((volatile int*)__null) = 898; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 899 | ||||
| 900 | JS::BuildIdCharVector jsBuildId; | |||
| 901 | if (!JS::GetScriptTranscodingBuildId(&jsBuildId)) { | |||
| 902 | return false; | |||
| 903 | } | |||
| 904 | ||||
| 905 | nsDependentCSubstring jsBuildIdStr(jsBuildId.begin(), jsBuildId.length()); | |||
| 906 | sJSScriptBytecodeMimeType = | |||
| 907 | new nsCString("javascript/moz-script-bytecode-"_ns + jsBuildIdStr); | |||
| 908 | sJSModuleBytecodeMimeType = | |||
| 909 | new nsCString("javascript/moz-module-bytecode-"_ns + jsBuildIdStr); | |||
| 910 | return true; | |||
| 911 | } | |||
| 912 | ||||
| 913 | void nsContentUtils::GetShiftText(nsAString& text) { | |||
| 914 | if (!sShiftText) InitializeModifierStrings(); | |||
| 915 | text.Assign(*sShiftText); | |||
| 916 | } | |||
| 917 | ||||
| 918 | void nsContentUtils::GetControlText(nsAString& text) { | |||
| 919 | if (!sControlText) InitializeModifierStrings(); | |||
| 920 | text.Assign(*sControlText); | |||
| 921 | } | |||
| 922 | ||||
| 923 | void nsContentUtils::GetCommandOrWinText(nsAString& text) { | |||
| 924 | if (!sCommandOrWinText) { | |||
| 925 | InitializeModifierStrings(); | |||
| 926 | } | |||
| 927 | text.Assign(*sCommandOrWinText); | |||
| 928 | } | |||
| 929 | ||||
| 930 | void nsContentUtils::GetAltText(nsAString& text) { | |||
| 931 | if (!sAltText) InitializeModifierStrings(); | |||
| 932 | text.Assign(*sAltText); | |||
| 933 | } | |||
| 934 | ||||
| 935 | void nsContentUtils::GetModifierSeparatorText(nsAString& text) { | |||
| 936 | if (!sModifierSeparator) InitializeModifierStrings(); | |||
| 937 | text.Assign(*sModifierSeparator); | |||
| 938 | } | |||
| 939 | ||||
| 940 | void nsContentUtils::InitializeModifierStrings() { | |||
| 941 | // load the display strings for the keyboard accelerators | |||
| 942 | nsCOMPtr<nsIStringBundleService> bundleService = | |||
| 943 | mozilla::components::StringBundle::Service(); | |||
| 944 | nsCOMPtr<nsIStringBundle> bundle; | |||
| 945 | DebugOnly<nsresult> rv = NS_OK; | |||
| 946 | if (bundleService) { | |||
| 947 | rv = bundleService->CreateBundle( | |||
| 948 | "chrome://global-platform/locale/platformKeys.properties", | |||
| 949 | getter_AddRefs(bundle)); | |||
| 950 | } | |||
| 951 | ||||
| 952 | 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" , 954); MOZ_PretendNoReturn(); } } while (0) | |||
| 953 | 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" , 954); MOZ_PretendNoReturn(); } } while (0) | |||
| 954 | "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" , 954); MOZ_PretendNoReturn(); } } while (0); | |||
| 955 | nsAutoString shiftModifier; | |||
| 956 | nsAutoString commandOrWinModifier; | |||
| 957 | nsAutoString altModifier; | |||
| 958 | nsAutoString controlModifier; | |||
| 959 | nsAutoString modifierSeparator; | |||
| 960 | if (bundle) { | |||
| 961 | // macs use symbols for each modifier key, so fetch each from the bundle, | |||
| 962 | // which also covers i18n | |||
| 963 | bundle->GetStringFromName("VK_SHIFT", shiftModifier); | |||
| 964 | bundle->GetStringFromName("VK_COMMAND_OR_WIN", commandOrWinModifier); | |||
| 965 | bundle->GetStringFromName("VK_ALT", altModifier); | |||
| 966 | bundle->GetStringFromName("VK_CONTROL", controlModifier); | |||
| 967 | bundle->GetStringFromName("MODIFIER_SEPARATOR", modifierSeparator); | |||
| 968 | } | |||
| 969 | // if any of these don't exist, we get an empty string | |||
| 970 | sShiftText = new nsString(shiftModifier); | |||
| 971 | sCommandOrWinText = new nsString(commandOrWinModifier); | |||
| 972 | sAltText = new nsString(altModifier); | |||
| 973 | sControlText = new nsString(controlModifier); | |||
| 974 | sModifierSeparator = new nsString(modifierSeparator); | |||
| 975 | } | |||
| 976 | ||||
| 977 | mozilla::EventClassID nsContentUtils::GetEventClassIDFromMessage( | |||
| 978 | EventMessage aEventMessage) { | |||
| 979 | switch (aEventMessage) { | |||
| 980 | #define MESSAGE_TO_EVENT(name_, message_, type_, struct_) \ | |||
| 981 | case message_: \ | |||
| 982 | return struct_; | |||
| 983 | #include "mozilla/EventNameList.h" | |||
| 984 | #undef MESSAGE_TO_EVENT | |||
| 985 | default: | |||
| 986 | 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" , 986); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "Invalid event message?" ")"); do { *((volatile int*)__null) = 986; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); | |||
| 987 | return eBasicEventClass; | |||
| 988 | } | |||
| 989 | } | |||
| 990 | ||||
| 991 | bool nsContentUtils::IsExternalProtocol(nsIURI* aURI) { | |||
| 992 | bool doesNotReturnData = false; | |||
| 993 | nsresult rv = NS_URIChainHasFlags( | |||
| 994 | aURI, nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA, &doesNotReturnData); | |||
| 995 | return NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && doesNotReturnData; | |||
| 996 | } | |||
| 997 | ||||
| 998 | /* static */ | |||
| 999 | nsAtom* nsContentUtils::GetEventTypeFromMessage(EventMessage aEventMessage) { | |||
| 1000 | switch (aEventMessage) { | |||
| 1001 | #define MESSAGE_TO_EVENT(name_, message_, type_, struct_) \ | |||
| 1002 | case message_: \ | |||
| 1003 | return nsGkAtoms::on##name_; | |||
| 1004 | #include "mozilla/EventNameList.h" | |||
| 1005 | #undef MESSAGE_TO_EVENT | |||
| 1006 | default: | |||
| 1007 | return nullptr; | |||
| 1008 | } | |||
| 1009 | } | |||
| 1010 | ||||
| 1011 | bool nsContentUtils::InitializeEventTable() { | |||
| 1012 | 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" , 1012); MOZ_PretendNoReturn(); } } while (0); | |||
| 1013 | 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" , 1013); MOZ_PretendNoReturn(); } } while (0); | |||
| 1014 | ||||
| 1015 | static const EventNameMapping eventArray[] = { | |||
| 1016 | #define EVENT(name_, _message, _type, _class) \ | |||
| 1017 | {nsGkAtoms::on##name_, _type, _message, _class}, | |||
| 1018 | #define WINDOW_ONLY_EVENT EVENT | |||
| 1019 | #define DOCUMENT_ONLY_EVENTEVENT EVENT | |||
| 1020 | #define NON_IDL_EVENT EVENT | |||
| 1021 | #include "mozilla/EventNameList.h" | |||
| 1022 | #undef WINDOW_ONLY_EVENT | |||
| 1023 | #undef NON_IDL_EVENT | |||
| 1024 | #undef EVENT | |||
| 1025 | {nullptr}}; | |||
| 1026 | ||||
| 1027 | sAtomEventTable = | |||
| 1028 | new nsTHashMap<RefPtr<nsAtom>, EventNameMapping>(std::size(eventArray)); | |||
| 1029 | sStringEventTable = | |||
| 1030 | new nsTHashMap<nsStringHashKey, EventNameMapping>(std::size(eventArray)); | |||
| 1031 | sUserDefinedEvents = new nsTArray<RefPtr<nsAtom>>(64); | |||
| 1032 | ||||
| 1033 | // Subtract one from the length because of the trailing null | |||
| 1034 | for (uint32_t i = 0; i < std::size(eventArray) - 1; ++i) { | |||
| 1035 | 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" , 1036); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sAtomEventTable->Contains(eventArray[i].mAtom)" ") (" "Double-defining event name; fix your EventNameList.h" ")"); do { *((volatile int*)__null) = 1036; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) | |||
| 1036 | "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" , 1036); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sAtomEventTable->Contains(eventArray[i].mAtom)" ") (" "Double-defining event name; fix your EventNameList.h" ")"); do { *((volatile int*)__null) = 1036; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 1037 | sAtomEventTable->InsertOrUpdate(eventArray[i].mAtom, eventArray[i]); | |||
| 1038 | sStringEventTable->InsertOrUpdate( | |||
| 1039 | Substring(nsDependentAtomString(eventArray[i].mAtom), 2), | |||
| 1040 | eventArray[i]); | |||
| 1041 | } | |||
| 1042 | ||||
| 1043 | return true; | |||
| 1044 | } | |||
| 1045 | ||||
| 1046 | void nsContentUtils::InitializeTouchEventTable() { | |||
| 1047 | static bool sEventTableInitialized = false; | |||
| 1048 | if (!sEventTableInitialized && sAtomEventTable && sStringEventTable) { | |||
| 1049 | sEventTableInitialized = true; | |||
| 1050 | static const EventNameMapping touchEventArray[] = { | |||
| 1051 | #define EVENT(name_, _message, _type, _class) | |||
| 1052 | #define TOUCH_EVENT(name_, _message, _type, _class) \ | |||
| 1053 | {nsGkAtoms::on##name_, _type, _message, _class}, | |||
| 1054 | #include "mozilla/EventNameList.h" | |||
| 1055 | #undef TOUCH_EVENT | |||
| 1056 | #undef EVENT | |||
| 1057 | {nullptr}}; | |||
| 1058 | // Subtract one from the length because of the trailing null | |||
| 1059 | for (uint32_t i = 0; i < std::size(touchEventArray) - 1; ++i) { | |||
| 1060 | sAtomEventTable->InsertOrUpdate(touchEventArray[i].mAtom, | |||
| 1061 | touchEventArray[i]); | |||
| 1062 | sStringEventTable->InsertOrUpdate( | |||
| 1063 | Substring(nsDependentAtomString(touchEventArray[i].mAtom), 2), | |||
| 1064 | touchEventArray[i]); | |||
| 1065 | } | |||
| 1066 | } | |||
| 1067 | } | |||
| 1068 | ||||
| 1069 | static bool Is8bit(const nsAString& aString) { | |||
| 1070 | static const char16_t EIGHT_BIT = char16_t(~0x00FF); | |||
| 1071 | ||||
| 1072 | for (nsAString::const_char_iterator start = aString.BeginReading(), | |||
| 1073 | end = aString.EndReading(); | |||
| 1074 | start != end; ++start) { | |||
| 1075 | if (*start & EIGHT_BIT) { | |||
| 1076 | return false; | |||
| 1077 | } | |||
| 1078 | } | |||
| 1079 | ||||
| 1080 | return true; | |||
| 1081 | } | |||
| 1082 | ||||
| 1083 | nsresult nsContentUtils::Btoa(const nsAString& aBinaryData, | |||
| 1084 | nsAString& aAsciiBase64String) { | |||
| 1085 | if (!Is8bit(aBinaryData)) { | |||
| 1086 | aAsciiBase64String.Truncate(); | |||
| 1087 | return NS_ERROR_DOM_INVALID_CHARACTER_ERR; | |||
| 1088 | } | |||
| 1089 | ||||
| 1090 | return Base64Encode(aBinaryData, aAsciiBase64String); | |||
| 1091 | } | |||
| 1092 | ||||
| 1093 | nsresult nsContentUtils::Atob(const nsAString& aAsciiBase64String, | |||
| 1094 | nsAString& aBinaryData) { | |||
| 1095 | if (!Is8bit(aAsciiBase64String)) { | |||
| 1096 | aBinaryData.Truncate(); | |||
| 1097 | return NS_ERROR_DOM_INVALID_CHARACTER_ERR; | |||
| 1098 | } | |||
| 1099 | ||||
| 1100 | const char16_t* start = aAsciiBase64String.BeginReading(); | |||
| 1101 | const char16_t* cur = start; | |||
| 1102 | const char16_t* end = aAsciiBase64String.EndReading(); | |||
| 1103 | bool hasWhitespace = false; | |||
| 1104 | ||||
| 1105 | while (cur < end) { | |||
| 1106 | if (nsContentUtils::IsHTMLWhitespace(*cur)) { | |||
| 1107 | hasWhitespace = true; | |||
| 1108 | break; | |||
| 1109 | } | |||
| 1110 | cur++; | |||
| 1111 | } | |||
| 1112 | ||||
| 1113 | nsresult rv; | |||
| 1114 | ||||
| 1115 | if (hasWhitespace) { | |||
| 1116 | nsString trimmedString; | |||
| 1117 | ||||
| 1118 | if (!trimmedString.SetCapacity(aAsciiBase64String.Length(), fallible)) { | |||
| 1119 | return NS_ERROR_DOM_INVALID_CHARACTER_ERR; | |||
| 1120 | } | |||
| 1121 | ||||
| 1122 | trimmedString.Append(start, cur - start); | |||
| 1123 | ||||
| 1124 | while (cur < end) { | |||
| 1125 | if (!nsContentUtils::IsHTMLWhitespace(*cur)) { | |||
| 1126 | trimmedString.Append(*cur); | |||
| 1127 | } | |||
| 1128 | cur++; | |||
| 1129 | } | |||
| 1130 | rv = Base64Decode(trimmedString, aBinaryData); | |||
| 1131 | } else { | |||
| 1132 | rv = Base64Decode(aAsciiBase64String, aBinaryData); | |||
| 1133 | } | |||
| 1134 | ||||
| 1135 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && rv == NS_ERROR_INVALID_ARG) { | |||
| 1136 | return NS_ERROR_DOM_INVALID_CHARACTER_ERR; | |||
| 1137 | } | |||
| 1138 | return rv; | |||
| 1139 | } | |||
| 1140 | ||||
| 1141 | bool nsContentUtils::IsAutocompleteEnabled( | |||
| 1142 | mozilla::dom::HTMLInputElement* aInput) { | |||
| 1143 | 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" , 1143); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aInput" ") (" "aInput should not be null!" ")"); do { *((volatile int*)__null ) = 1143; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); | |||
| 1144 | ||||
| 1145 | nsAutoString autocomplete; | |||
| 1146 | aInput->GetAutocomplete(autocomplete); | |||
| 1147 | ||||
| 1148 | if (autocomplete.IsEmpty()) { | |||
| 1149 | auto* form = aInput->GetForm(); | |||
| 1150 | if (!form) { | |||
| 1151 | return true; | |||
| 1152 | } | |||
| 1153 | ||||
| 1154 | form->GetAutocomplete(autocomplete); | |||
| 1155 | } | |||
| 1156 | ||||
| 1157 | return !autocomplete.EqualsLiteral("off"); | |||
| 1158 | } | |||
| 1159 | ||||
| 1160 | nsContentUtils::AutocompleteAttrState | |||
| 1161 | nsContentUtils::SerializeAutocompleteAttribute( | |||
| 1162 | const nsAttrValue* aAttr, nsAString& aResult, | |||
| 1163 | AutocompleteAttrState aCachedState) { | |||
| 1164 | if (!aAttr || | |||
| 1165 | aCachedState == nsContentUtils::eAutocompleteAttrState_Invalid) { | |||
| 1166 | return aCachedState; | |||
| 1167 | } | |||
| 1168 | ||||
| 1169 | if (aCachedState == nsContentUtils::eAutocompleteAttrState_Valid) { | |||
| 1170 | uint32_t atomCount = aAttr->GetAtomCount(); | |||
| 1171 | for (uint32_t i = 0; i < atomCount; i++) { | |||
| 1172 | if (i != 0) { | |||
| 1173 | aResult.Append(' '); | |||
| 1174 | } | |||
| 1175 | aResult.Append(nsDependentAtomString(aAttr->AtomAt(i))); | |||
| 1176 | } | |||
| 1177 | nsContentUtils::ASCIIToLower(aResult); | |||
| 1178 | return aCachedState; | |||
| 1179 | } | |||
| 1180 | ||||
| 1181 | aResult.Truncate(); | |||
| 1182 | ||||
| 1183 | mozilla::dom::AutocompleteInfo info; | |||
| 1184 | AutocompleteAttrState state = | |||
| 1185 | InternalSerializeAutocompleteAttribute(aAttr, info); | |||
| 1186 | if (state == eAutocompleteAttrState_Valid) { | |||
| 1187 | // Concatenate the info fields. | |||
| 1188 | aResult = info.mSection; | |||
| 1189 | ||||
| 1190 | if (!info.mAddressType.IsEmpty()) { | |||
| 1191 | if (!aResult.IsEmpty()) { | |||
| 1192 | aResult += ' '; | |||
| 1193 | } | |||
| 1194 | aResult += info.mAddressType; | |||
| 1195 | } | |||
| 1196 | ||||
| 1197 | if (!info.mContactType.IsEmpty()) { | |||
| 1198 | if (!aResult.IsEmpty()) { | |||
| 1199 | aResult += ' '; | |||
| 1200 | } | |||
| 1201 | aResult += info.mContactType; | |||
| 1202 | } | |||
| 1203 | ||||
| 1204 | if (!info.mFieldName.IsEmpty()) { | |||
| 1205 | if (!aResult.IsEmpty()) { | |||
| 1206 | aResult += ' '; | |||
| 1207 | } | |||
| 1208 | aResult += info.mFieldName; | |||
| 1209 | } | |||
| 1210 | ||||
| 1211 | // The autocomplete attribute value "webauthn" is interpreted as both a | |||
| 1212 | // field name and a credential type. The corresponding IDL-exposed autofill | |||
| 1213 | // value is "webauthn", not "webauthn webauthn". | |||
| 1214 | if (!info.mCredentialType.IsEmpty() && | |||
| 1215 | !(info.mCredentialType.Equals(u"webauthn"_ns) && | |||
| 1216 | info.mCredentialType.Equals(aResult))) { | |||
| 1217 | if (!aResult.IsEmpty()) { | |||
| 1218 | aResult += ' '; | |||
| 1219 | } | |||
| 1220 | aResult += info.mCredentialType; | |||
| 1221 | } | |||
| 1222 | } | |||
| 1223 | ||||
| 1224 | return state; | |||
| 1225 | } | |||
| 1226 | ||||
| 1227 | nsContentUtils::AutocompleteAttrState | |||
| 1228 | nsContentUtils::SerializeAutocompleteAttribute( | |||
| 1229 | const nsAttrValue* aAttr, mozilla::dom::AutocompleteInfo& aInfo, | |||
| 1230 | AutocompleteAttrState aCachedState, bool aGrantAllValidValue) { | |||
| 1231 | if (!aAttr || | |||
| 1232 | aCachedState == nsContentUtils::eAutocompleteAttrState_Invalid) { | |||
| 1233 | return aCachedState; | |||
| 1234 | } | |||
| 1235 | ||||
| 1236 | return InternalSerializeAutocompleteAttribute(aAttr, aInfo, | |||
| 1237 | aGrantAllValidValue); | |||
| 1238 | } | |||
| 1239 | ||||
| 1240 | /** | |||
| 1241 | * Helper to validate the @autocomplete tokens. | |||
| 1242 | * | |||
| 1243 | * @return {AutocompleteAttrState} The state of the attribute (invalid/valid). | |||
| 1244 | */ | |||
| 1245 | nsContentUtils::AutocompleteAttrState | |||
| 1246 | nsContentUtils::InternalSerializeAutocompleteAttribute( | |||
| 1247 | const nsAttrValue* aAttrVal, mozilla::dom::AutocompleteInfo& aInfo, | |||
| 1248 | bool aGrantAllValidValue) { | |||
| 1249 | // No autocomplete attribute so we are done | |||
| 1250 | if (!aAttrVal) { | |||
| 1251 | return eAutocompleteAttrState_Invalid; | |||
| 1252 | } | |||
| 1253 | ||||
| 1254 | uint32_t numTokens = aAttrVal->GetAtomCount(); | |||
| 1255 | if (!numTokens || numTokens > INT32_MAX(2147483647)) { | |||
| 1256 | return eAutocompleteAttrState_Invalid; | |||
| 1257 | } | |||
| 1258 | ||||
| 1259 | uint32_t index = numTokens - 1; | |||
| 1260 | nsString tokenString = nsDependentAtomString(aAttrVal->AtomAt(index)); | |||
| 1261 | AutocompleteCategory category; | |||
| 1262 | nsAttrValue enumValue; | |||
| 1263 | nsAutoString credentialTypeStr; | |||
| 1264 | ||||
| 1265 | bool result = enumValue.ParseEnumValue( | |||
| 1266 | tokenString, kAutocompleteCredentialTypeTable, false); | |||
| 1267 | if (result) { | |||
| 1268 | if (!enumValue.Equals(u"webauthn"_ns, eIgnoreCase) || numTokens > 5) { | |||
| 1269 | return eAutocompleteAttrState_Invalid; | |||
| 1270 | } | |||
| 1271 | enumValue.ToString(credentialTypeStr); | |||
| 1272 | ASCIIToLower(credentialTypeStr); | |||
| 1273 | // category is Credential and the indexth token is "webauthn" | |||
| 1274 | if (index == 0) { | |||
| 1275 | aInfo.mFieldName.Assign(credentialTypeStr); | |||
| 1276 | aInfo.mCredentialType.Assign(credentialTypeStr); | |||
| 1277 | return eAutocompleteAttrState_Valid; | |||
| 1278 | } | |||
| 1279 | ||||
| 1280 | --index; | |||
| 1281 | tokenString = nsDependentAtomString(aAttrVal->AtomAt(index)); | |||
| 1282 | ||||
| 1283 | // Only the Normal and Contact categories are allowed with webauthn | |||
| 1284 | // - disallow Credential | |||
| 1285 | if (enumValue.ParseEnumValue(tokenString, kAutocompleteCredentialTypeTable, | |||
| 1286 | false)) { | |||
| 1287 | return eAutocompleteAttrState_Invalid; | |||
| 1288 | } | |||
| 1289 | // - disallow Off and Automatic | |||
| 1290 | if (enumValue.ParseEnumValue(tokenString, kAutocompleteFieldNameTable, | |||
| 1291 | false)) { | |||
| 1292 | if (enumValue.Equals(u"off"_ns, eIgnoreCase) || | |||
| 1293 | enumValue.Equals(u"on"_ns, eIgnoreCase)) { | |||
| 1294 | return eAutocompleteAttrState_Invalid; | |||
| 1295 | } | |||
| 1296 | } | |||
| 1297 | ||||
| 1298 | // Proceed to process the remaining tokens as if "webauthn" was not present. | |||
| 1299 | // We need to decrement numTokens to enforce the correct per-category limits | |||
| 1300 | // on the maximum number of tokens. | |||
| 1301 | --numTokens; | |||
| 1302 | } | |||
| 1303 | ||||
| 1304 | bool unsupported = false; | |||
| 1305 | if (!aGrantAllValidValue) { | |||
| 1306 | unsupported = enumValue.ParseEnumValue( | |||
| 1307 | tokenString, kAutocompleteUnsupportedFieldNameTable, false); | |||
| 1308 | if (unsupported) { | |||
| 1309 | return eAutocompleteAttrState_Invalid; | |||
| 1310 | } | |||
| 1311 | } | |||
| 1312 | ||||
| 1313 | nsAutoString fieldNameStr; | |||
| 1314 | result = | |||
| 1315 | enumValue.ParseEnumValue(tokenString, kAutocompleteFieldNameTable, false); | |||
| 1316 | ||||
| 1317 | if (result) { | |||
| 1318 | // Off/Automatic/Normal categories. | |||
| 1319 | if (enumValue.Equals(u"off"_ns, eIgnoreCase) || | |||
| 1320 | enumValue.Equals(u"on"_ns, eIgnoreCase)) { | |||
| 1321 | if (numTokens > 1) { | |||
| 1322 | return eAutocompleteAttrState_Invalid; | |||
| 1323 | } | |||
| 1324 | enumValue.ToString(fieldNameStr); | |||
| 1325 | ASCIIToLower(fieldNameStr); | |||
| 1326 | aInfo.mFieldName.Assign(fieldNameStr); | |||
| 1327 | aInfo.mCredentialType.Assign(credentialTypeStr); | |||
| 1328 | aInfo.mCanAutomaticallyPersist = | |||
| 1329 | !enumValue.Equals(u"off"_ns, eIgnoreCase); | |||
| 1330 | return eAutocompleteAttrState_Valid; | |||
| 1331 | } | |||
| 1332 | ||||
| 1333 | // Only allow on/off if form autofill @autocomplete values aren't enabled | |||
| 1334 | // and it doesn't grant all valid values. | |||
| 1335 | if (!StaticPrefs::dom_forms_autocomplete_formautofill() && | |||
| 1336 | !aGrantAllValidValue) { | |||
| 1337 | return eAutocompleteAttrState_Invalid; | |||
| 1338 | } | |||
| 1339 | ||||
| 1340 | // Normal category | |||
| 1341 | if (numTokens > 3) { | |||
| 1342 | return eAutocompleteAttrState_Invalid; | |||
| 1343 | } | |||
| 1344 | category = eAutocompleteCategory_NORMAL; | |||
| 1345 | } else { // Check if the last token is of the contact category instead. | |||
| 1346 | // Only allow on/off if form autofill @autocomplete values aren't enabled | |||
| 1347 | // and it doesn't grant all valid values. | |||
| 1348 | if (!StaticPrefs::dom_forms_autocomplete_formautofill() && | |||
| 1349 | !aGrantAllValidValue) { | |||
| 1350 | return eAutocompleteAttrState_Invalid; | |||
| 1351 | } | |||
| 1352 | ||||
| 1353 | result = enumValue.ParseEnumValue( | |||
| 1354 | tokenString, kAutocompleteContactFieldNameTable, false); | |||
| 1355 | if (!result || numTokens > 4) { | |||
| 1356 | return eAutocompleteAttrState_Invalid; | |||
| 1357 | } | |||
| 1358 | ||||
| 1359 | category = eAutocompleteCategory_CONTACT; | |||
| 1360 | } | |||
| 1361 | ||||
| 1362 | enumValue.ToString(fieldNameStr); | |||
| 1363 | ASCIIToLower(fieldNameStr); | |||
| 1364 | ||||
| 1365 | aInfo.mFieldName.Assign(fieldNameStr); | |||
| 1366 | aInfo.mCredentialType.Assign(credentialTypeStr); | |||
| 1367 | aInfo.mCanAutomaticallyPersist = !enumValue.ParseEnumValue( | |||
| 1368 | tokenString, kAutocompleteNoPersistFieldNameTable, false); | |||
| 1369 | ||||
| 1370 | // We are done if this was the only token. | |||
| 1371 | if (numTokens == 1) { | |||
| 1372 | return eAutocompleteAttrState_Valid; | |||
| 1373 | } | |||
| 1374 | ||||
| 1375 | --index; | |||
| 1376 | tokenString = nsDependentAtomString(aAttrVal->AtomAt(index)); | |||
| 1377 | ||||
| 1378 | if (category == eAutocompleteCategory_CONTACT) { | |||
| 1379 | if (!aGrantAllValidValue) { | |||
| 1380 | unsupported = enumValue.ParseEnumValue( | |||
| 1381 | tokenString, kAutocompleteUnsupportedContactFieldHintTable, false); | |||
| 1382 | if (unsupported) { | |||
| 1383 | return eAutocompleteAttrState_Invalid; | |||
| 1384 | } | |||
| 1385 | } | |||
| 1386 | ||||
| 1387 | nsAttrValue contactFieldHint; | |||
| 1388 | result = contactFieldHint.ParseEnumValue( | |||
| 1389 | tokenString, kAutocompleteContactFieldHintTable, false); | |||
| 1390 | if (result) { | |||
| 1391 | nsAutoString contactFieldHintString; | |||
| 1392 | contactFieldHint.ToString(contactFieldHintString); | |||
| 1393 | ASCIIToLower(contactFieldHintString); | |||
| 1394 | aInfo.mContactType.Assign(contactFieldHintString); | |||
| 1395 | if (index == 0) { | |||
| 1396 | return eAutocompleteAttrState_Valid; | |||
| 1397 | } | |||
| 1398 | --index; | |||
| 1399 | tokenString = nsDependentAtomString(aAttrVal->AtomAt(index)); | |||
| 1400 | } | |||
| 1401 | } | |||
| 1402 | ||||
| 1403 | // Check for billing/shipping tokens | |||
| 1404 | nsAttrValue fieldHint; | |||
| 1405 | if (fieldHint.ParseEnumValue(tokenString, kAutocompleteFieldHintTable, | |||
| 1406 | false)) { | |||
| 1407 | nsString fieldHintString; | |||
| 1408 | fieldHint.ToString(fieldHintString); | |||
| 1409 | ASCIIToLower(fieldHintString); | |||
| 1410 | aInfo.mAddressType.Assign(fieldHintString); | |||
| 1411 | if (index == 0) { | |||
| 1412 | return eAutocompleteAttrState_Valid; | |||
| 1413 | } | |||
| 1414 | --index; | |||
| 1415 | tokenString = nsDependentAtomString(aAttrVal->AtomAt(index)); | |||
| 1416 | } | |||
| 1417 | ||||
| 1418 | // Check for section-* token | |||
| 1419 | const nsDependentSubstring& section = Substring(tokenString, 0, 8); | |||
| 1420 | if (section.LowerCaseEqualsASCII("section-")) { | |||
| 1421 | ASCIIToLower(tokenString); | |||
| 1422 | aInfo.mSection.Assign(tokenString); | |||
| 1423 | if (index == 0) { | |||
| 1424 | return eAutocompleteAttrState_Valid; | |||
| 1425 | } | |||
| 1426 | } | |||
| 1427 | ||||
| 1428 | // Clear the fields as the autocomplete attribute is invalid. | |||
| 1429 | aInfo.mSection.Truncate(); | |||
| 1430 | aInfo.mAddressType.Truncate(); | |||
| 1431 | aInfo.mContactType.Truncate(); | |||
| 1432 | aInfo.mFieldName.Truncate(); | |||
| 1433 | aInfo.mCredentialType.Truncate(); | |||
| 1434 | ||||
| 1435 | return eAutocompleteAttrState_Invalid; | |||
| 1436 | } | |||
| 1437 | ||||
| 1438 | // Parse an integer according to HTML spec | |||
| 1439 | template <class CharT> | |||
| 1440 | int32_t nsContentUtils::ParseHTMLIntegerImpl( | |||
| 1441 | const CharT* aStart, const CharT* aEnd, | |||
| 1442 | ParseHTMLIntegerResultFlags* aResult) { | |||
| 1443 | int result = eParseHTMLInteger_NoFlags; | |||
| 1444 | ||||
| 1445 | const CharT* iter = aStart; | |||
| 1446 | ||||
| 1447 | while (iter != aEnd && nsContentUtils::IsHTMLWhitespace(*iter)) { | |||
| 1448 | result |= eParseHTMLInteger_NonStandard; | |||
| 1449 | ++iter; | |||
| 1450 | } | |||
| 1451 | ||||
| 1452 | if (iter == aEnd) { | |||
| 1453 | result |= eParseHTMLInteger_Error | eParseHTMLInteger_ErrorNoValue; | |||
| 1454 | *aResult = (ParseHTMLIntegerResultFlags)result; | |||
| 1455 | return 0; | |||
| 1456 | } | |||
| 1457 | ||||
| 1458 | int sign = 1; | |||
| 1459 | if (*iter == CharT('-')) { | |||
| 1460 | sign = -1; | |||
| 1461 | result |= eParseHTMLInteger_Negative; | |||
| 1462 | ++iter; | |||
| 1463 | } else if (*iter == CharT('+')) { | |||
| 1464 | result |= eParseHTMLInteger_NonStandard; | |||
| 1465 | ++iter; | |||
| 1466 | } | |||
| 1467 | ||||
| 1468 | bool foundValue = false; | |||
| 1469 | CheckedInt32 value = 0; | |||
| 1470 | ||||
| 1471 | // Check for leading zeros first. | |||
| 1472 | uint64_t leadingZeros = 0; | |||
| 1473 | while (iter != aEnd) { | |||
| 1474 | if (*iter != CharT('0')) { | |||
| 1475 | break; | |||
| 1476 | } | |||
| 1477 | ||||
| 1478 | ++leadingZeros; | |||
| 1479 | foundValue = true; | |||
| 1480 | ++iter; | |||
| 1481 | } | |||
| 1482 | ||||
| 1483 | while (iter != aEnd) { | |||
| 1484 | if (*iter >= CharT('0') && *iter <= CharT('9')) { | |||
| 1485 | value = (value * 10) + (*iter - CharT('0')) * sign; | |||
| 1486 | ++iter; | |||
| 1487 | if (!value.isValid()) { | |||
| 1488 | result |= eParseHTMLInteger_Error | eParseHTMLInteger_ErrorOverflow; | |||
| 1489 | break; | |||
| 1490 | } | |||
| 1491 | foundValue = true; | |||
| 1492 | } else { | |||
| 1493 | break; | |||
| 1494 | } | |||
| 1495 | } | |||
| 1496 | ||||
| 1497 | if (!foundValue) { | |||
| 1498 | result |= eParseHTMLInteger_Error | eParseHTMLInteger_ErrorNoValue; | |||
| 1499 | } | |||
| 1500 | ||||
| 1501 | if (value.isValid() && | |||
| 1502 | ((leadingZeros > 1 || (leadingZeros == 1 && !(value == 0))) || | |||
| 1503 | (sign == -1 && value == 0))) { | |||
| 1504 | result |= eParseHTMLInteger_NonStandard; | |||
| 1505 | } | |||
| 1506 | ||||
| 1507 | if (iter != aEnd) { | |||
| 1508 | result |= eParseHTMLInteger_DidNotConsumeAllInput; | |||
| 1509 | } | |||
| 1510 | ||||
| 1511 | *aResult = (ParseHTMLIntegerResultFlags)result; | |||
| 1512 | return value.isValid() ? value.value() : 0; | |||
| 1513 | } | |||
| 1514 | ||||
| 1515 | // Parse an integer according to HTML spec | |||
| 1516 | int32_t nsContentUtils::ParseHTMLInteger(const char16_t* aStart, | |||
| 1517 | const char16_t* aEnd, | |||
| 1518 | ParseHTMLIntegerResultFlags* aResult) { | |||
| 1519 | return ParseHTMLIntegerImpl(aStart, aEnd, aResult); | |||
| 1520 | } | |||
| 1521 | ||||
| 1522 | int32_t nsContentUtils::ParseHTMLInteger(const char* aStart, const char* aEnd, | |||
| 1523 | ParseHTMLIntegerResultFlags* aResult) { | |||
| 1524 | return ParseHTMLIntegerImpl(aStart, aEnd, aResult); | |||
| 1525 | } | |||
| 1526 | ||||
| 1527 | #define SKIP_WHITESPACE(iter, end_iter, end_res)while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*( iter))) { ++(iter); } if ((iter) == (end_iter)) { return (end_res ); } \ | |||
| 1528 | while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*(iter))) { \ | |||
| 1529 | ++(iter); \ | |||
| 1530 | } \ | |||
| 1531 | if ((iter) == (end_iter)) { \ | |||
| 1532 | return (end_res); \ | |||
| 1533 | } | |||
| 1534 | ||||
| 1535 | #define SKIP_ATTR_NAME(iter, end_iter)while ((iter) != (end_iter) && !nsCRT::IsAsciiSpace(* (iter)) && *(iter) != '=') { ++(iter); } \ | |||
| 1536 | while ((iter) != (end_iter) && !nsCRT::IsAsciiSpace(*(iter)) && \ | |||
| 1537 | *(iter) != '=') { \ | |||
| 1538 | ++(iter); \ | |||
| 1539 | } | |||
| 1540 | ||||
| 1541 | bool nsContentUtils::GetPseudoAttributeValue(const nsString& aSource, | |||
| 1542 | nsAtom* aName, nsAString& aValue) { | |||
| 1543 | aValue.Truncate(); | |||
| 1544 | ||||
| 1545 | const char16_t* start = aSource.get(); | |||
| 1546 | const char16_t* end = start + aSource.Length(); | |||
| 1547 | const char16_t* iter; | |||
| 1548 | ||||
| 1549 | while (start != end) { | |||
| 1550 | SKIP_WHITESPACE(start, end, false)while ((start) != (end) && nsCRT::IsAsciiSpace(*(start ))) { ++(start); } if ((start) == (end)) { return (false); } | |||
| 1551 | iter = start; | |||
| 1552 | SKIP_ATTR_NAME(iter, end)while ((iter) != (end) && !nsCRT::IsAsciiSpace(*(iter )) && *(iter) != '=') { ++(iter); } | |||
| 1553 | ||||
| 1554 | if (start == iter) { | |||
| 1555 | return false; | |||
| 1556 | } | |||
| 1557 | ||||
| 1558 | // Remember the attr name. | |||
| 1559 | const nsDependentSubstring& attrName = Substring(start, iter); | |||
| 1560 | ||||
| 1561 | // Now check whether this is a valid name="value" pair. | |||
| 1562 | start = iter; | |||
| 1563 | SKIP_WHITESPACE(start, end, false)while ((start) != (end) && nsCRT::IsAsciiSpace(*(start ))) { ++(start); } if ((start) == (end)) { return (false); } | |||
| 1564 | if (*start != '=') { | |||
| 1565 | // No '=', so this is not a name="value" pair. We don't know | |||
| 1566 | // what it is, and we have no way to handle it. | |||
| 1567 | return false; | |||
| 1568 | } | |||
| 1569 | ||||
| 1570 | // Have to skip the value. | |||
| 1571 | ++start; | |||
| 1572 | SKIP_WHITESPACE(start, end, false)while ((start) != (end) && nsCRT::IsAsciiSpace(*(start ))) { ++(start); } if ((start) == (end)) { return (false); } | |||
| 1573 | char16_t q = *start; | |||
| 1574 | if (q != kQuote && q != kApostrophe) { | |||
| 1575 | // Not a valid quoted value, so bail. | |||
| 1576 | return false; | |||
| 1577 | } | |||
| 1578 | ||||
| 1579 | ++start; // Point to the first char of the value. | |||
| 1580 | iter = start; | |||
| 1581 | ||||
| 1582 | while (iter != end && *iter != q) { | |||
| 1583 | ++iter; | |||
| 1584 | } | |||
| 1585 | ||||
| 1586 | if (iter == end) { | |||
| 1587 | // Oops, unterminated quoted string. | |||
| 1588 | return false; | |||
| 1589 | } | |||
| 1590 | ||||
| 1591 | // At this point attrName holds the name of the "attribute" and | |||
| 1592 | // the value is between start and iter. | |||
| 1593 | ||||
| 1594 | if (aName->Equals(attrName)) { | |||
| 1595 | // We'll accumulate as many characters as possible (until we hit either | |||
| 1596 | // the end of the string or the beginning of an entity). Chunks will be | |||
| 1597 | // delimited by start and chunkEnd. | |||
| 1598 | const char16_t* chunkEnd = start; | |||
| 1599 | while (chunkEnd != iter) { | |||
| 1600 | if (*chunkEnd == kLessThan) { | |||
| 1601 | aValue.Truncate(); | |||
| 1602 | ||||
| 1603 | return false; | |||
| 1604 | } | |||
| 1605 | ||||
| 1606 | if (*chunkEnd == kAmpersand) { | |||
| 1607 | aValue.Append(start, chunkEnd - start); | |||
| 1608 | ||||
| 1609 | const char16_t* afterEntity = nullptr; | |||
| 1610 | char16_t result[2]; | |||
| 1611 | uint32_t count = MOZ_XMLTranslateEntity( | |||
| 1612 | reinterpret_cast<const char*>(chunkEnd), | |||
| 1613 | reinterpret_cast<const char*>(iter), | |||
| 1614 | reinterpret_cast<const char**>(&afterEntity), result); | |||
| 1615 | if (count == 0) { | |||
| 1616 | aValue.Truncate(); | |||
| 1617 | ||||
| 1618 | return false; | |||
| 1619 | } | |||
| 1620 | ||||
| 1621 | aValue.Append(result, count); | |||
| 1622 | ||||
| 1623 | // Advance to after the entity and begin a new chunk. | |||
| 1624 | start = chunkEnd = afterEntity; | |||
| 1625 | } else { | |||
| 1626 | ++chunkEnd; | |||
| 1627 | } | |||
| 1628 | } | |||
| 1629 | ||||
| 1630 | // Append remainder. | |||
| 1631 | aValue.Append(start, iter - start); | |||
| 1632 | ||||
| 1633 | return true; | |||
| 1634 | } | |||
| 1635 | ||||
| 1636 | // Resume scanning after the end of the attribute value (past the quote | |||
| 1637 | // char). | |||
| 1638 | start = iter + 1; | |||
| 1639 | } | |||
| 1640 | ||||
| 1641 | return false; | |||
| 1642 | } | |||
| 1643 | ||||
| 1644 | bool nsContentUtils::IsJavaScriptLanguage(const nsString& aName) { | |||
| 1645 | // Create MIME type as "text/" + given input | |||
| 1646 | nsAutoString mimeType(u"text/"); | |||
| 1647 | mimeType.Append(aName); | |||
| 1648 | ||||
| 1649 | return IsJavascriptMIMEType(mimeType); | |||
| 1650 | } | |||
| 1651 | ||||
| 1652 | void nsContentUtils::SplitMimeType(const nsAString& aValue, nsString& aType, | |||
| 1653 | nsString& aParams) { | |||
| 1654 | aType.Truncate(); | |||
| 1655 | aParams.Truncate(); | |||
| 1656 | int32_t semiIndex = aValue.FindChar(char16_t(';')); | |||
| 1657 | if (-1 != semiIndex) { | |||
| 1658 | aType = Substring(aValue, 0, semiIndex); | |||
| 1659 | aParams = | |||
| 1660 | Substring(aValue, semiIndex + 1, aValue.Length() - (semiIndex + 1)); | |||
| 1661 | aParams.StripWhitespace(); | |||
| 1662 | } else { | |||
| 1663 | aType = aValue; | |||
| 1664 | } | |||
| 1665 | aType.StripWhitespace(); | |||
| 1666 | } | |||
| 1667 | ||||
| 1668 | /** | |||
| 1669 | * A helper function that parses a sandbox attribute (of an <iframe> or a CSP | |||
| 1670 | * directive) and converts it to the set of flags used internally. | |||
| 1671 | * | |||
| 1672 | * @param aSandboxAttr the sandbox attribute | |||
| 1673 | * @return the set of flags (SANDBOXED_NONE if aSandboxAttr is | |||
| 1674 | * null) | |||
| 1675 | */ | |||
| 1676 | uint32_t nsContentUtils::ParseSandboxAttributeToFlags( | |||
| 1677 | const nsAttrValue* aSandboxAttr) { | |||
| 1678 | if (!aSandboxAttr) { | |||
| 1679 | return SANDBOXED_NONE; | |||
| 1680 | } | |||
| 1681 | ||||
| 1682 | uint32_t out = SANDBOX_ALL_FLAGS; | |||
| 1683 | ||||
| 1684 | #define SANDBOX_KEYWORD(string, atom, flags) \ | |||
| 1685 | if (aSandboxAttr->Contains(nsGkAtoms::atom, eIgnoreCase)) { \ | |||
| 1686 | out &= ~(flags); \ | |||
| 1687 | } | |||
| 1688 | #include "IframeSandboxKeywordList.h" | |||
| 1689 | #undef SANDBOX_KEYWORD | |||
| 1690 | ||||
| 1691 | return out; | |||
| 1692 | } | |||
| 1693 | ||||
| 1694 | /** | |||
| 1695 | * A helper function that checks if a string matches a valid sandbox flag. | |||
| 1696 | * | |||
| 1697 | * @param aFlag the potential sandbox flag. | |||
| 1698 | * @return true if the flag is a sandbox flag. | |||
| 1699 | */ | |||
| 1700 | bool nsContentUtils::IsValidSandboxFlag(const nsAString& aFlag) { | |||
| 1701 | #define SANDBOX_KEYWORD(string, atom, flags) \ | |||
| 1702 | if (EqualsIgnoreASCIICase(nsDependentAtomString(nsGkAtoms::atom), aFlag)) { \ | |||
| 1703 | return true; \ | |||
| 1704 | } | |||
| 1705 | #include "IframeSandboxKeywordList.h" | |||
| 1706 | #undef SANDBOX_KEYWORD | |||
| 1707 | return false; | |||
| 1708 | } | |||
| 1709 | ||||
| 1710 | /** | |||
| 1711 | * A helper function that returns a string attribute corresponding to the | |||
| 1712 | * sandbox flags. | |||
| 1713 | * | |||
| 1714 | * @param aFlags the sandbox flags | |||
| 1715 | * @param aString the attribute corresponding to the flags (null if aFlags | |||
| 1716 | * is zero) | |||
| 1717 | */ | |||
| 1718 | void nsContentUtils::SandboxFlagsToString(uint32_t aFlags, nsAString& aString) { | |||
| 1719 | if (!aFlags) { | |||
| 1720 | SetDOMStringToNull(aString); | |||
| 1721 | return; | |||
| 1722 | } | |||
| 1723 | ||||
| 1724 | aString.Truncate(); | |||
| 1725 | ||||
| 1726 | #define SANDBOX_KEYWORD(string, atom, flags) \ | |||
| 1727 | if (!(aFlags & (flags))) { \ | |||
| 1728 | if (!aString.IsEmpty()) { \ | |||
| 1729 | aString.AppendLiteral(u" "); \ | |||
| 1730 | } \ | |||
| 1731 | aString.Append(nsDependentAtomString(nsGkAtoms::atom)); \ | |||
| 1732 | } | |||
| 1733 | #include "IframeSandboxKeywordList.h" | |||
| 1734 | #undef SANDBOX_KEYWORD | |||
| 1735 | } | |||
| 1736 | ||||
| 1737 | nsIBidiKeyboard* nsContentUtils::GetBidiKeyboard() { | |||
| 1738 | if (!sBidiKeyboard) { | |||
| 1739 | sBidiKeyboard = nsIWidget::CreateBidiKeyboard(); | |||
| 1740 | } | |||
| 1741 | return sBidiKeyboard; | |||
| 1742 | } | |||
| 1743 | ||||
| 1744 | /** | |||
| 1745 | * This is used to determine whether a character is in one of the classes | |||
| 1746 | * which CSS says should be part of the first-letter. Currently, that is | |||
| 1747 | * all punctuation classes (P*). Note that this is a change from CSS2 | |||
| 1748 | * which excluded Pc and Pd. | |||
| 1749 | * | |||
| 1750 | * https://www.w3.org/TR/css-pseudo-4/#first-letter-pseudo | |||
| 1751 | * "Punctuation (i.e, characters that belong to the Punctuation (P*) Unicode | |||
| 1752 | * general category [UAX44]) [...]" | |||
| 1753 | */ | |||
| 1754 | ||||
| 1755 | // static | |||
| 1756 | bool nsContentUtils::IsFirstLetterPunctuation(uint32_t aChar) { | |||
| 1757 | switch (mozilla::unicode::GetGeneralCategory(aChar)) { | |||
| 1758 | case HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION: /* Pc */ | |||
| 1759 | case HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION: /* Pd */ | |||
| 1760 | case HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION: /* Pe */ | |||
| 1761 | case HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION: /* Pf */ | |||
| 1762 | case HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION: /* Pi */ | |||
| 1763 | case HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION: /* Po */ | |||
| 1764 | case HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION: /* Ps */ | |||
| 1765 | return true; | |||
| 1766 | default: | |||
| 1767 | return false; | |||
| 1768 | } | |||
| 1769 | } | |||
| 1770 | ||||
| 1771 | // static | |||
| 1772 | bool nsContentUtils::IsAlphanumeric(uint32_t aChar) { | |||
| 1773 | nsUGenCategory cat = mozilla::unicode::GetGenCategory(aChar); | |||
| 1774 | ||||
| 1775 | return (cat == nsUGenCategory::kLetter || cat == nsUGenCategory::kNumber); | |||
| 1776 | } | |||
| 1777 | ||||
| 1778 | // static | |||
| 1779 | bool nsContentUtils::IsAlphanumericOrSymbol(uint32_t aChar) { | |||
| 1780 | nsUGenCategory cat = mozilla::unicode::GetGenCategory(aChar); | |||
| 1781 | ||||
| 1782 | return cat == nsUGenCategory::kLetter || cat == nsUGenCategory::kNumber || | |||
| 1783 | cat == nsUGenCategory::kSymbol; | |||
| 1784 | } | |||
| 1785 | ||||
| 1786 | // static | |||
| 1787 | bool nsContentUtils::IsHyphen(uint32_t aChar) { | |||
| 1788 | // Characters treated as hyphens for the purpose of "emergency" breaking | |||
| 1789 | // when the content would otherwise overflow. | |||
| 1790 | return aChar == uint32_t('-') || // HYPHEN-MINUS | |||
| 1791 | aChar == 0x2010 || // HYPHEN | |||
| 1792 | aChar == 0x2012 || // FIGURE DASH | |||
| 1793 | aChar == 0x2013 || // EN DASH | |||
| 1794 | aChar == 0x058A; // ARMENIAN HYPHEN | |||
| 1795 | } | |||
| 1796 | ||||
| 1797 | /* static */ | |||
| 1798 | bool nsContentUtils::IsHTMLWhitespace(char16_t aChar) { | |||
| 1799 | return aChar == char16_t(0x0009) || aChar == char16_t(0x000A) || | |||
| 1800 | aChar == char16_t(0x000C) || aChar == char16_t(0x000D) || | |||
| 1801 | aChar == char16_t(0x0020); | |||
| 1802 | } | |||
| 1803 | ||||
| 1804 | /* static */ | |||
| 1805 | bool nsContentUtils::IsHTMLWhitespaceOrNBSP(char16_t aChar) { | |||
| 1806 | return IsHTMLWhitespace(aChar) || aChar == char16_t(0xA0); | |||
| 1807 | } | |||
| 1808 | ||||
| 1809 | /* static */ | |||
| 1810 | bool nsContentUtils::IsHTMLBlockLevelElement(nsIContent* aContent) { | |||
| 1811 | return aContent->IsAnyOfHTMLElements( | |||
| 1812 | nsGkAtoms::address, nsGkAtoms::article, nsGkAtoms::aside, | |||
| 1813 | nsGkAtoms::blockquote, nsGkAtoms::center, nsGkAtoms::dir, nsGkAtoms::div, | |||
| 1814 | nsGkAtoms::dl, // XXX why not dt and dd? | |||
| 1815 | nsGkAtoms::fieldset, | |||
| 1816 | nsGkAtoms::figure, // XXX shouldn't figcaption be on this list | |||
| 1817 | nsGkAtoms::footer, nsGkAtoms::form, nsGkAtoms::h1, nsGkAtoms::h2, | |||
| 1818 | nsGkAtoms::h3, nsGkAtoms::h4, nsGkAtoms::h5, nsGkAtoms::h6, | |||
| 1819 | nsGkAtoms::header, nsGkAtoms::hgroup, nsGkAtoms::hr, nsGkAtoms::li, | |||
| 1820 | nsGkAtoms::listing, nsGkAtoms::menu, nsGkAtoms::nav, nsGkAtoms::ol, | |||
| 1821 | nsGkAtoms::p, nsGkAtoms::pre, nsGkAtoms::section, nsGkAtoms::table, | |||
| 1822 | nsGkAtoms::ul, nsGkAtoms::xmp); | |||
| 1823 | } | |||
| 1824 | ||||
| 1825 | // static | |||
| 1826 | int32_t nsContentUtils::ParseLegacyFontSize(const nsAString& aValue) { | |||
| 1827 | nsAString::const_iterator iter, end; | |||
| 1828 | aValue.BeginReading(iter); | |||
| 1829 | aValue.EndReading(end); | |||
| 1830 | ||||
| 1831 | while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) { | |||
| 1832 | ++iter; | |||
| 1833 | } | |||
| 1834 | ||||
| 1835 | if (iter == end) { | |||
| 1836 | return 0; | |||
| 1837 | } | |||
| 1838 | ||||
| 1839 | bool relative = false; | |||
| 1840 | bool negate = false; | |||
| 1841 | if (*iter == char16_t('-')) { | |||
| 1842 | relative = true; | |||
| 1843 | negate = true; | |||
| 1844 | ++iter; | |||
| 1845 | } else if (*iter == char16_t('+')) { | |||
| 1846 | relative = true; | |||
| 1847 | ++iter; | |||
| 1848 | } | |||
| 1849 | ||||
| 1850 | if (iter == end || *iter < char16_t('0') || *iter > char16_t('9')) { | |||
| 1851 | return 0; | |||
| 1852 | } | |||
| 1853 | ||||
| 1854 | // We don't have to worry about overflow, since we can bail out as soon as | |||
| 1855 | // we're bigger than 7. | |||
| 1856 | int32_t value = 0; | |||
| 1857 | while (iter != end && *iter >= char16_t('0') && *iter <= char16_t('9')) { | |||
| 1858 | value = 10 * value + (*iter - char16_t('0')); | |||
| 1859 | if (value >= 7) { | |||
| 1860 | break; | |||
| 1861 | } | |||
| 1862 | ++iter; | |||
| 1863 | } | |||
| 1864 | ||||
| 1865 | if (relative) { | |||
| 1866 | if (negate) { | |||
| 1867 | value = 3 - value; | |||
| 1868 | } else { | |||
| 1869 | value = 3 + value; | |||
| 1870 | } | |||
| 1871 | } | |||
| 1872 | ||||
| 1873 | return std::clamp(value, 1, 7); | |||
| 1874 | } | |||
| 1875 | ||||
| 1876 | /* static */ | |||
| 1877 | void nsContentUtils::GetOfflineAppManifest(Document* aDocument, nsIURI** aURI) { | |||
| 1878 | 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" , 1878); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 1878; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 1879 | 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" , 1879); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocument" ")" ); do { *((volatile int*)__null) = 1879; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 1880 | *aURI = nullptr; | |||
| 1881 | ||||
| 1882 | if (aDocument->GetController().isSome()) { | |||
| 1883 | return; | |||
| 1884 | } | |||
| 1885 | ||||
| 1886 | Element* docElement = aDocument->GetRootElement(); | |||
| 1887 | if (!docElement) { | |||
| 1888 | return; | |||
| 1889 | } | |||
| 1890 | ||||
| 1891 | nsAutoString manifestSpec; | |||
| 1892 | docElement->GetAttr(nsGkAtoms::manifest, manifestSpec); | |||
| 1893 | ||||
| 1894 | // Manifest URIs can't have fragment identifiers. | |||
| 1895 | if (manifestSpec.IsEmpty() || manifestSpec.Contains('#')) { | |||
| 1896 | return; | |||
| 1897 | } | |||
| 1898 | ||||
| 1899 | nsContentUtils::NewURIWithDocumentCharset(aURI, manifestSpec, aDocument, | |||
| 1900 | aDocument->GetDocBaseURI()); | |||
| 1901 | } | |||
| 1902 | ||||
| 1903 | /* static */ | |||
| 1904 | bool nsContentUtils::OfflineAppAllowed(nsIURI* aURI) { return false; } | |||
| 1905 | ||||
| 1906 | /* static */ | |||
| 1907 | bool nsContentUtils::OfflineAppAllowed(nsIPrincipal* aPrincipal) { | |||
| 1908 | return false; | |||
| 1909 | } | |||
| 1910 | // Static | |||
| 1911 | bool nsContentUtils::IsErrorPage(nsIURI* aURI) { | |||
| 1912 | if (!aURI) { | |||
| 1913 | return false; | |||
| 1914 | } | |||
| 1915 | ||||
| 1916 | if (!aURI->SchemeIs("about")) { | |||
| 1917 | return false; | |||
| 1918 | } | |||
| 1919 | ||||
| 1920 | nsAutoCString name; | |||
| 1921 | nsresult rv = NS_GetAboutModuleName(aURI, name); | |||
| 1922 | 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" , 1922); return false; } } while (false); | |||
| 1923 | ||||
| 1924 | return name.EqualsLiteral("certerror") || name.EqualsLiteral("neterror") || | |||
| 1925 | name.EqualsLiteral("blocked"); | |||
| 1926 | } | |||
| 1927 | ||||
| 1928 | // static | |||
| 1929 | void nsContentUtils::Shutdown() { | |||
| 1930 | sInitialized = false; | |||
| 1931 | ||||
| 1932 | nsHTMLTags::ReleaseTable(); | |||
| 1933 | ||||
| 1934 | NS_IF_RELEASE(sContentPolicyService)do { if (sContentPolicyService) { (sContentPolicyService)-> Release(); (sContentPolicyService) = 0; } } while (0); | |||
| 1935 | sTriedToGetContentPolicy = false; | |||
| 1936 | for (StaticRefPtr<nsIStringBundle>& bundle : sStringBundles) { | |||
| 1937 | bundle = nullptr; | |||
| 1938 | } | |||
| 1939 | ||||
| 1940 | NS_IF_RELEASE(sStringBundleService)do { if (sStringBundleService) { (sStringBundleService)->Release (); (sStringBundleService) = 0; } } while (0); | |||
| 1941 | NS_IF_RELEASE(sConsoleService)do { if (sConsoleService) { (sConsoleService)->Release(); ( sConsoleService) = 0; } } while (0); | |||
| 1942 | NS_IF_RELEASE(sXPConnect)do { if (sXPConnect) { (sXPConnect)->Release(); (sXPConnect ) = 0; } } while (0); | |||
| 1943 | NS_IF_RELEASE(sSecurityManager)do { if (sSecurityManager) { (sSecurityManager)->Release() ; (sSecurityManager) = 0; } } while (0); | |||
| 1944 | NS_IF_RELEASE(sSystemPrincipal)do { if (sSystemPrincipal) { (sSystemPrincipal)->Release() ; (sSystemPrincipal) = 0; } } while (0); | |||
| 1945 | NS_IF_RELEASE(sNullSubjectPrincipal)do { if (sNullSubjectPrincipal) { (sNullSubjectPrincipal)-> Release(); (sNullSubjectPrincipal) = 0; } } while (0); | |||
| 1946 | NS_IF_RELEASE(sFingerprintingProtectionPrincipal)do { if (sFingerprintingProtectionPrincipal) { (sFingerprintingProtectionPrincipal )->Release(); (sFingerprintingProtectionPrincipal) = 0; } } while (0); | |||
| 1947 | ||||
| 1948 | sBidiKeyboard = nullptr; | |||
| 1949 | ||||
| 1950 | delete sAtomEventTable; | |||
| 1951 | sAtomEventTable = nullptr; | |||
| 1952 | delete sStringEventTable; | |||
| 1953 | sStringEventTable = nullptr; | |||
| 1954 | delete sUserDefinedEvents; | |||
| 1955 | sUserDefinedEvents = nullptr; | |||
| 1956 | ||||
| 1957 | if (sEventListenerManagersHash) { | |||
| 1958 | 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" , 1959); MOZ_PretendNoReturn(); } } while (0) | |||
| 1959 | "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" , 1959); MOZ_PretendNoReturn(); } } while (0); | |||
| 1960 | ||||
| 1961 | // See comment above. | |||
| 1962 | ||||
| 1963 | // However, we have to handle this table differently. If it still | |||
| 1964 | // has entries, we want to leak it too, so that we can keep it alive | |||
| 1965 | // in case any elements are destroyed. Because if they are, we need | |||
| 1966 | // their event listener managers to be destroyed too, or otherwise | |||
| 1967 | // it could leave dangling references in DOMClassInfo's preserved | |||
| 1968 | // wrapper table. | |||
| 1969 | ||||
| 1970 | if (sEventListenerManagersHash->EntryCount() == 0) { | |||
| 1971 | delete sEventListenerManagersHash; | |||
| 1972 | sEventListenerManagersHash = nullptr; | |||
| 1973 | } | |||
| 1974 | } | |||
| 1975 | ||||
| 1976 | if (sDOMArenaHashtable) { | |||
| 1977 | 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" , 1977); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sDOMArenaHashtable->Count() == 0" ")"); do { *((volatile int*)__null) = 1977; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 1978 | 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" , 1978); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::dom_arena_allocator_enabled_AtStartup()" ")"); do { *((volatile int*)__null) = 1978; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 1979 | delete sDOMArenaHashtable; | |||
| 1980 | sDOMArenaHashtable = nullptr; | |||
| 1981 | } | |||
| 1982 | ||||
| 1983 | 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" , 1984); MOZ_PretendNoReturn(); } } while (0) | |||
| 1984 | "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" , 1984); MOZ_PretendNoReturn(); } } while (0); | |||
| 1985 | delete sBlockedScriptRunners; | |||
| 1986 | sBlockedScriptRunners = nullptr; | |||
| 1987 | ||||
| 1988 | delete sShiftText; | |||
| 1989 | sShiftText = nullptr; | |||
| 1990 | delete sControlText; | |||
| 1991 | sControlText = nullptr; | |||
| 1992 | delete sCommandOrWinText; | |||
| 1993 | sCommandOrWinText = nullptr; | |||
| 1994 | delete sAltText; | |||
| 1995 | sAltText = nullptr; | |||
| 1996 | delete sModifierSeparator; | |||
| 1997 | sModifierSeparator = nullptr; | |||
| 1998 | ||||
| 1999 | delete sJSScriptBytecodeMimeType; | |||
| 2000 | sJSScriptBytecodeMimeType = nullptr; | |||
| 2001 | ||||
| 2002 | delete sJSModuleBytecodeMimeType; | |||
| 2003 | sJSModuleBytecodeMimeType = nullptr; | |||
| 2004 | ||||
| 2005 | NS_IF_RELEASE(sSameOriginChecker)do { if (sSameOriginChecker) { (sSameOriginChecker)->Release (); (sSameOriginChecker) = 0; } } while (0); | |||
| 2006 | ||||
| 2007 | if (sUserInteractionObserver) { | |||
| 2008 | sUserInteractionObserver->Shutdown(); | |||
| 2009 | NS_RELEASE(sUserInteractionObserver)do { (sUserInteractionObserver)->Release(); (sUserInteractionObserver ) = 0; } while (0); | |||
| 2010 | } | |||
| 2011 | ||||
| 2012 | for (const auto& pref : kRfpPrefs) { | |||
| 2013 | Preferences::UnregisterCallback(RecomputeResistFingerprintingAllDocs, pref); | |||
| 2014 | } | |||
| 2015 | ||||
| 2016 | TextControlState::Shutdown(); | |||
| 2017 | } | |||
| 2018 | ||||
| 2019 | /** | |||
| 2020 | * Checks whether two nodes come from the same origin. aTrustedNode is | |||
| 2021 | * considered 'safe' in that a user can operate on it. | |||
| 2022 | */ | |||
| 2023 | // static | |||
| 2024 | nsresult nsContentUtils::CheckSameOrigin(const nsINode* aTrustedNode, | |||
| 2025 | const nsINode* unTrustedNode) { | |||
| 2026 | 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" , 2026); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTrustedNode" ")"); do { *((volatile int*)__null) = 2026; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 2027 | 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" , 2027); AnnotateMozCrashReason("MOZ_ASSERT" "(" "unTrustedNode" ")"); do { *((volatile int*)__null) = 2027; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 2028 | ||||
| 2029 | /* | |||
| 2030 | * Get hold of each node's principal | |||
| 2031 | */ | |||
| 2032 | ||||
| 2033 | nsIPrincipal* trustedPrincipal = aTrustedNode->NodePrincipal(); | |||
| 2034 | nsIPrincipal* unTrustedPrincipal = unTrustedNode->NodePrincipal(); | |||
| 2035 | ||||
| 2036 | if (trustedPrincipal == unTrustedPrincipal) { | |||
| 2037 | return NS_OK; | |||
| 2038 | } | |||
| 2039 | ||||
| 2040 | bool equal; | |||
| 2041 | // XXXbz should we actually have a Subsumes() check here instead? Or perhaps | |||
| 2042 | // a separate method for that, with callers using one or the other? | |||
| 2043 | if (NS_FAILED(trustedPrincipal->Equals(unTrustedPrincipal, &equal))((bool)(__builtin_expect(!!(NS_FAILED_impl(trustedPrincipal-> Equals(unTrustedPrincipal, &equal))), 0))) || | |||
| 2044 | !equal) { | |||
| 2045 | return NS_ERROR_DOM_PROP_ACCESS_DENIED; | |||
| 2046 | } | |||
| 2047 | ||||
| 2048 | return NS_OK; | |||
| 2049 | } | |||
| 2050 | ||||
| 2051 | // static | |||
| 2052 | bool nsContentUtils::CanCallerAccess(nsIPrincipal* aSubjectPrincipal, | |||
| 2053 | nsIPrincipal* aPrincipal) { | |||
| 2054 | bool subsumes; | |||
| 2055 | nsresult rv = aSubjectPrincipal->Subsumes(aPrincipal, &subsumes); | |||
| 2056 | 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" , 2056); return false; } } while (false); | |||
| 2057 | ||||
| 2058 | if (subsumes) { | |||
| 2059 | return true; | |||
| 2060 | } | |||
| 2061 | ||||
| 2062 | // The subject doesn't subsume aPrincipal. Allow access only if the subject | |||
| 2063 | // is chrome. | |||
| 2064 | return IsCallerChrome(); | |||
| 2065 | } | |||
| 2066 | ||||
| 2067 | // static | |||
| 2068 | bool nsContentUtils::CanCallerAccess(const nsINode* aNode) { | |||
| 2069 | nsIPrincipal* subject = SubjectPrincipal(); | |||
| 2070 | if (subject->IsSystemPrincipal()) { | |||
| 2071 | return true; | |||
| 2072 | } | |||
| 2073 | ||||
| 2074 | if (aNode->ChromeOnlyAccess()) { | |||
| 2075 | return false; | |||
| 2076 | } | |||
| 2077 | ||||
| 2078 | return CanCallerAccess(subject, aNode->NodePrincipal()); | |||
| 2079 | } | |||
| 2080 | ||||
| 2081 | // static | |||
| 2082 | bool nsContentUtils::CanCallerAccess(nsPIDOMWindowInner* aWindow) { | |||
| 2083 | nsCOMPtr<nsIScriptObjectPrincipal> scriptObject = do_QueryInterface(aWindow); | |||
| 2084 | 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" , 2084); return false; } } while (false); | |||
| 2085 | ||||
| 2086 | return CanCallerAccess(SubjectPrincipal(), scriptObject->GetPrincipal()); | |||
| 2087 | } | |||
| 2088 | ||||
| 2089 | // static | |||
| 2090 | bool nsContentUtils::PrincipalHasPermission(nsIPrincipal& aPrincipal, | |||
| 2091 | const nsAtom* aPerm) { | |||
| 2092 | // Chrome gets access by default. | |||
| 2093 | if (aPrincipal.IsSystemPrincipal()) { | |||
| 2094 | return true; | |||
| 2095 | } | |||
| 2096 | ||||
| 2097 | // Otherwise, only allow if caller is an addon with the permission. | |||
| 2098 | return BasePrincipal::Cast(aPrincipal).AddonHasPermission(aPerm); | |||
| 2099 | } | |||
| 2100 | ||||
| 2101 | // static | |||
| 2102 | bool nsContentUtils::CallerHasPermission(JSContext* aCx, const nsAtom* aPerm) { | |||
| 2103 | return PrincipalHasPermission(*SubjectPrincipal(aCx), aPerm); | |||
| 2104 | } | |||
| 2105 | ||||
| 2106 | // static | |||
| 2107 | nsIPrincipal* nsContentUtils::GetAttrTriggeringPrincipal( | |||
| 2108 | nsIContent* aContent, const nsAString& aAttrValue, | |||
| 2109 | nsIPrincipal* aSubjectPrincipal) { | |||
| 2110 | nsIPrincipal* contentPrin = aContent ? aContent->NodePrincipal() : nullptr; | |||
| 2111 | ||||
| 2112 | // If the subject principal is the same as the content principal, or no | |||
| 2113 | // explicit subject principal was provided, we don't need to do any further | |||
| 2114 | // checks. Just return the content principal. | |||
| 2115 | if (contentPrin == aSubjectPrincipal || !aSubjectPrincipal) { | |||
| 2116 | return contentPrin; | |||
| 2117 | } | |||
| 2118 | ||||
| 2119 | // Only use the subject principal if the URL string we are going to end up | |||
| 2120 | // fetching is under the control of that principal, which is never the case | |||
| 2121 | // for relative URLs. | |||
| 2122 | if (aAttrValue.IsEmpty() || | |||
| 2123 | !IsAbsoluteURL(NS_ConvertUTF16toUTF8(aAttrValue))) { | |||
| 2124 | return contentPrin; | |||
| 2125 | } | |||
| 2126 | ||||
| 2127 | // Only use the subject principal as the attr triggering principal if it | |||
| 2128 | // should override the CSP of the node's principal. | |||
| 2129 | if (BasePrincipal::Cast(aSubjectPrincipal)->OverridesCSP(contentPrin)) { | |||
| 2130 | return aSubjectPrincipal; | |||
| 2131 | } | |||
| 2132 | ||||
| 2133 | return contentPrin; | |||
| 2134 | } | |||
| 2135 | ||||
| 2136 | // static | |||
| 2137 | bool nsContentUtils::IsAbsoluteURL(const nsACString& aURL) { | |||
| 2138 | nsAutoCString scheme; | |||
| 2139 | if (NS_FAILED(net_ExtractURLScheme(aURL, scheme))((bool)(__builtin_expect(!!(NS_FAILED_impl(net_ExtractURLScheme (aURL, scheme))), 0)))) { | |||
| 2140 | // If we can't extract a scheme, it's not an absolute URL. | |||
| 2141 | return false; | |||
| 2142 | } | |||
| 2143 | ||||
| 2144 | // If it parses as an absolute StandardURL, it's definitely an absolute URL, | |||
| 2145 | // so no need to check with the IO service. | |||
| 2146 | if (net_IsAbsoluteURL(aURL)) { | |||
| 2147 | return true; | |||
| 2148 | } | |||
| 2149 | ||||
| 2150 | nsresult rv = NS_OK; | |||
| 2151 | nsCOMPtr<nsIIOService> io = mozilla::components::IO::Service(&rv); | |||
| 2152 | 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" , 2152); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" ")"); do { *((volatile int*)__null) = 2152; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 2153 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 2154 | return false; | |||
| 2155 | } | |||
| 2156 | ||||
| 2157 | uint32_t flags; | |||
| 2158 | if (NS_SUCCEEDED(io->GetProtocolFlags(scheme.get(), &flags))((bool)(__builtin_expect(!!(!NS_FAILED_impl(io->GetProtocolFlags (scheme.get(), &flags))), 1)))) { | |||
| 2159 | return flags & nsIProtocolHandler::URI_NORELATIVE; | |||
| 2160 | } | |||
| 2161 | ||||
| 2162 | return false; | |||
| 2163 | } | |||
| 2164 | ||||
| 2165 | // static | |||
| 2166 | bool nsContentUtils::InProlog(nsINode* aNode) { | |||
| 2167 | 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" , 2167); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNode" ") (" "missing node to nsContentUtils::InProlog" ")"); do { *((volatile int*)__null) = 2167; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 2168 | ||||
| 2169 | nsINode* parent = aNode->GetParentNode(); | |||
| 2170 | if (!parent || !parent->IsDocument()) { | |||
| 2171 | return false; | |||
| 2172 | } | |||
| 2173 | ||||
| 2174 | const Document* doc = parent->AsDocument(); | |||
| 2175 | const nsIContent* root = doc->GetRootElement(); | |||
| 2176 | if (!root) { | |||
| 2177 | return true; | |||
| 2178 | } | |||
| 2179 | const Maybe<uint32_t> indexOfNode = doc->ComputeIndexOf(aNode); | |||
| 2180 | const Maybe<uint32_t> indexOfRoot = doc->ComputeIndexOf(root); | |||
| 2181 | if (MOZ_LIKELY(indexOfNode.isSome() && indexOfRoot.isSome())(__builtin_expect(!!(indexOfNode.isSome() && indexOfRoot .isSome()), 1))) { | |||
| 2182 | return *indexOfNode < *indexOfRoot; | |||
| 2183 | } | |||
| 2184 | // XXX Keep the odd traditional behavior for now. | |||
| 2185 | return indexOfNode.isNothing() && indexOfRoot.isSome(); | |||
| 2186 | } | |||
| 2187 | ||||
| 2188 | bool nsContentUtils::IsCallerChrome() { | |||
| 2189 | 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" , 2189); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 2189; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 2190 | return SubjectPrincipal() == sSystemPrincipal; | |||
| 2191 | } | |||
| 2192 | ||||
| 2193 | #ifdef FUZZING | |||
| 2194 | bool nsContentUtils::IsFuzzingEnabled() { | |||
| 2195 | return StaticPrefs::fuzzing_enabled(); | |||
| 2196 | } | |||
| 2197 | #endif | |||
| 2198 | ||||
| 2199 | /* static */ | |||
| 2200 | bool nsContentUtils::IsCallerChromeOrElementTransformGettersEnabled( | |||
| 2201 | JSContext* aCx, JSObject*) { | |||
| 2202 | return ThreadsafeIsSystemCaller(aCx) || | |||
| 2203 | StaticPrefs::dom_element_transform_getters_enabled(); | |||
| 2204 | } | |||
| 2205 | ||||
| 2206 | // Older Should RFP Functions ---------------------------------- | |||
| 2207 | ||||
| 2208 | /* static */ | |||
| 2209 | bool nsContentUtils::ShouldResistFingerprinting(bool aIsPrivateMode, | |||
| 2210 | RFPTarget aTarget) { | |||
| 2211 | return nsRFPService::IsRFPEnabledFor(aIsPrivateMode, aTarget, Nothing()); | |||
| 2212 | } | |||
| 2213 | ||||
| 2214 | /* static */ | |||
| 2215 | bool nsContentUtils::ShouldResistFingerprinting(nsIGlobalObject* aGlobalObject, | |||
| 2216 | RFPTarget aTarget) { | |||
| 2217 | if (!aGlobalObject) { | |||
| 2218 | return ShouldResistFingerprinting("Null Object", aTarget); | |||
| 2219 | } | |||
| 2220 | return aGlobalObject->ShouldResistFingerprinting(aTarget); | |||
| 2221 | } | |||
| 2222 | ||||
| 2223 | // Newer Should RFP Functions ---------------------------------- | |||
| 2224 | // Utilities --------------------------------------------------- | |||
| 2225 | ||||
| 2226 | inline void LogDomainAndPrefList(const char* urlType, | |||
| 2227 | const char* exemptedDomainsPrefName, | |||
| 2228 | nsAutoCString& url, bool isExemptDomain) { | |||
| 2229 | nsAutoCString list; | |||
| 2230 | Preferences::GetCString(exemptedDomainsPrefName, list); | |||
| 2231 | 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) | |||
| 2232 | ("%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) | |||
| 2233 | 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) | |||
| 2234 | 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); | |||
| 2235 | } | |||
| 2236 | ||||
| 2237 | inline already_AddRefed<nsICookieJarSettings> GetCookieJarSettings( | |||
| 2238 | nsILoadInfo* aLoadInfo) { | |||
| 2239 | nsCOMPtr<nsICookieJarSettings> cookieJarSettings; | |||
| 2240 | nsresult rv = | |||
| 2241 | aLoadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings)); | |||
| 2242 | if (rv == NS_ERROR_NOT_IMPLEMENTED) { | |||
| 2243 | // The TRRLoadInfo in particular does not implement this method | |||
| 2244 | // In that instance. We will return false and let other code decide if | |||
| 2245 | // we shouldRFP for this connection | |||
| 2246 | return nullptr; | |||
| 2247 | } | |||
| 2248 | 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" , 2248)) { | |||
| 2249 | 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) | |||
| 2250 | ("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) | |||
| 2251 | "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); | |||
| 2252 | return nullptr; | |||
| 2253 | } | |||
| 2254 | ||||
| 2255 | 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" , 2255); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cookieJarSettings" ")"); do { *((volatile int*)__null) = 2255; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 2256 | return cookieJarSettings.forget(); | |||
| 2257 | } | |||
| 2258 | ||||
| 2259 | bool ETPSaysShouldNotResistFingerprinting(nsIChannel* aChannel, | |||
| 2260 | nsILoadInfo* aLoadInfo) { | |||
| 2261 | // A positive return from this function should always be obeyed. | |||
| 2262 | // A negative return means we should keep checking things. | |||
| 2263 | ||||
| 2264 | bool isPBM = NS_UsePrivateBrowsing(aChannel); | |||
| 2265 | // We do not want this check to apply to RFP, only to FPP | |||
| 2266 | // There is one problematic combination of prefs; however: | |||
| 2267 | // If RFP is enabled in PBMode only and FPP is enabled globally | |||
| 2268 | // (so, in non-PBM mode) - we need to know if we're in PBMode or not. | |||
| 2269 | // But that's kind of expensive and we'd like to avoid it if we | |||
| 2270 | // don't have to, so special-case that scenario | |||
| 2271 | if (StaticPrefs::privacy_fingerprintingProtection_DoNotUseDirectly() && | |||
| 2272 | !StaticPrefs::privacy_resistFingerprinting_DoNotUseDirectly() && | |||
| 2273 | StaticPrefs::privacy_resistFingerprinting_pbmode_DoNotUseDirectly()) { | |||
| 2274 | if (isPBM) { | |||
| 2275 | // In PBM (where RFP is enabled) do not exempt based on the ETP toggle | |||
| 2276 | return false; | |||
| 2277 | } | |||
| 2278 | } else if (StaticPrefs::privacy_resistFingerprinting_DoNotUseDirectly() || | |||
| 2279 | (isPBM && | |||
| 2280 | StaticPrefs:: | |||
| 2281 | privacy_resistFingerprinting_pbmode_DoNotUseDirectly())) { | |||
| 2282 | // In RFP, never use the ETP toggle to exempt. | |||
| 2283 | // We can safely return false here even if we are not in PBM mode | |||
| 2284 | // and RFP_pbmode is enabled because we will later see that and | |||
| 2285 | // return false from the ShouldRFP function entirely. | |||
| 2286 | return false; | |||
| 2287 | } | |||
| 2288 | ||||
| 2289 | nsCOMPtr<nsICookieJarSettings> cookieJarSettings = | |||
| 2290 | GetCookieJarSettings(aLoadInfo); | |||
| 2291 | if (!cookieJarSettings) { | |||
| 2292 | return false; | |||
| 2293 | } | |||
| 2294 | ||||
| 2295 | return ContentBlockingAllowList::Check(cookieJarSettings); | |||
| 2296 | } | |||
| 2297 | ||||
| 2298 | inline bool CookieJarSettingsSaysShouldResistFingerprinting( | |||
| 2299 | nsILoadInfo* aLoadInfo) { | |||
| 2300 | // A positive return from this function should always be obeyed. | |||
| 2301 | // A negative return means we should keep checking things. | |||
| 2302 | ||||
| 2303 | nsCOMPtr<nsICookieJarSettings> cookieJarSettings = | |||
| 2304 | GetCookieJarSettings(aLoadInfo); | |||
| 2305 | if (!cookieJarSettings) { | |||
| 2306 | return false; | |||
| 2307 | } | |||
| 2308 | return cookieJarSettings->GetShouldResistFingerprinting(); | |||
| 2309 | } | |||
| 2310 | ||||
| 2311 | inline bool SchemeSaysShouldNotResistFingerprinting(nsIURI* aURI) { | |||
| 2312 | return aURI->SchemeIs("chrome") || aURI->SchemeIs("resource") || | |||
| 2313 | aURI->SchemeIs("view-source") || aURI->SchemeIs("moz-extension") || | |||
| 2314 | (aURI->SchemeIs("about") && !NS_IsContentAccessibleAboutURI(aURI)); | |||
| 2315 | } | |||
| 2316 | ||||
| 2317 | inline bool SchemeSaysShouldNotResistFingerprinting(nsIPrincipal* aPrincipal) { | |||
| 2318 | if (aPrincipal->SchemeIs("chrome") || aPrincipal->SchemeIs("resource") || | |||
| 2319 | aPrincipal->SchemeIs("view-source") || | |||
| 2320 | aPrincipal->SchemeIs("moz-extension")) { | |||
| 2321 | return true; | |||
| 2322 | } | |||
| 2323 | ||||
| 2324 | if (!aPrincipal->SchemeIs("about")) { | |||
| 2325 | return false; | |||
| 2326 | } | |||
| 2327 | ||||
| 2328 | bool isContentAccessibleAboutURI; | |||
| 2329 | Unused << aPrincipal->IsContentAccessibleAboutURI( | |||
| 2330 | &isContentAccessibleAboutURI); | |||
| 2331 | return !isContentAccessibleAboutURI; | |||
| 2332 | } | |||
| 2333 | ||||
| 2334 | const char* kExemptedDomainsPrefName = | |||
| 2335 | "privacy.resistFingerprinting.exemptedDomains"; | |||
| 2336 | ||||
| 2337 | inline bool PartionKeyIsAlsoExempted( | |||
| 2338 | const mozilla::OriginAttributes& aOriginAttributes) { | |||
| 2339 | // If we've gotten here we have (probably) passed the CookieJarSettings | |||
| 2340 | // check that would tell us that if we _are_ a subdocument, then we are on | |||
| 2341 | // an exempted top-level domain and we should see if we ourselves are | |||
| 2342 | // exempted. But we may have gotten here because we directly called the | |||
| 2343 | // _dangerous function and we haven't done that check, but we _were_ | |||
| 2344 | // instatiated from a state where we could have been partitioned. | |||
| 2345 | // So perform this last-ditch check for that scenario. | |||
| 2346 | // We arbitrarily use https as the scheme, but it doesn't matter. | |||
| 2347 | nsresult rv = NS_ERROR_NOT_INITIALIZED; | |||
| 2348 | nsCOMPtr<nsIURI> uri; | |||
| 2349 | if (StaticPrefs::privacy_firstparty_isolate() && | |||
| 2350 | !aOriginAttributes.mFirstPartyDomain.IsEmpty()) { | |||
| 2351 | rv = NS_NewURI(getter_AddRefs(uri), | |||
| 2352 | u"https://"_ns + aOriginAttributes.mFirstPartyDomain); | |||
| 2353 | } else if (!aOriginAttributes.mPartitionKey.IsEmpty()) { | |||
| 2354 | rv = NS_NewURI(getter_AddRefs(uri), | |||
| 2355 | u"https://"_ns + aOriginAttributes.mPartitionKey); | |||
| 2356 | } | |||
| 2357 | ||||
| 2358 | if (!NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 2359 | bool isExemptPartitionKey = | |||
| 2360 | nsContentUtils::IsURIInPrefList(uri, kExemptedDomainsPrefName); | |||
| 2361 | if (MOZ_LOG_TEST(nsContentUtils::ResistFingerprintingLog(),(__builtin_expect(!!(mozilla::detail::log_test(nsContentUtils ::ResistFingerprintingLog(), mozilla::LogLevel::Debug)), 0)) | |||
| 2362 | mozilla::LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(nsContentUtils ::ResistFingerprintingLog(), mozilla::LogLevel::Debug)), 0))) { | |||
| 2363 | nsAutoCString url; | |||
| 2364 | uri->GetHost(url); | |||
| 2365 | LogDomainAndPrefList("Partition Key", kExemptedDomainsPrefName, url, | |||
| 2366 | isExemptPartitionKey); | |||
| 2367 | } | |||
| 2368 | return isExemptPartitionKey; | |||
| 2369 | } | |||
| 2370 | return true; | |||
| 2371 | } | |||
| 2372 | ||||
| 2373 | // Functions --------------------------------------------------- | |||
| 2374 | ||||
| 2375 | /* static */ | |||
| 2376 | bool nsContentUtils::ShouldResistFingerprinting(const char* aJustification, | |||
| 2377 | RFPTarget aTarget) { | |||
| 2378 | // See comment in header file for information about usage | |||
| 2379 | // We hardcode PBM to true to be the more restrictive option. | |||
| 2380 | return nsContentUtils::ShouldResistFingerprinting(true, aTarget); | |||
| 2381 | } | |||
| 2382 | ||||
| 2383 | namespace { | |||
| 2384 | ||||
| 2385 | // This function is only called within this file for Positive Return Checks | |||
| 2386 | bool ShouldResistFingerprinting_(const char* aJustification, | |||
| 2387 | bool aIsPrivateMode, RFPTarget aTarget) { | |||
| 2388 | // See comment in header file for information about usage | |||
| 2389 | return nsContentUtils::ShouldResistFingerprinting(aIsPrivateMode, aTarget); | |||
| 2390 | } | |||
| 2391 | ||||
| 2392 | } // namespace | |||
| 2393 | ||||
| 2394 | /* static */ | |||
| 2395 | bool nsContentUtils::ShouldResistFingerprinting(CallerType aCallerType, | |||
| 2396 | nsIGlobalObject* aGlobalObject, | |||
| 2397 | RFPTarget aTarget) { | |||
| 2398 | if (aCallerType == CallerType::System) { | |||
| 2399 | return false; | |||
| 2400 | } | |||
| 2401 | return ShouldResistFingerprinting(aGlobalObject, aTarget); | |||
| 2402 | } | |||
| 2403 | ||||
| 2404 | bool nsContentUtils::ShouldResistFingerprinting(nsIDocShell* aDocShell, | |||
| 2405 | RFPTarget aTarget) { | |||
| 2406 | if (!aDocShell) { | |||
| 2407 | 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) | |||
| 2408 | ("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) | |||
| 2409 | "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); | |||
| 2410 | return ShouldResistFingerprinting("Null Object", aTarget); | |||
| 2411 | } | |||
| 2412 | Document* doc = aDocShell->GetDocument(); | |||
| 2413 | if (!doc) { | |||
| 2414 | 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) | |||
| 2415 | ("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) | |||
| 2416 | "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); | |||
| 2417 | return ShouldResistFingerprinting("Null Object", aTarget); | |||
| 2418 | } | |||
| 2419 | return doc->ShouldResistFingerprinting(aTarget); | |||
| 2420 | } | |||
| 2421 | ||||
| 2422 | /* static */ | |||
| 2423 | bool nsContentUtils::ShouldResistFingerprinting(nsIChannel* aChannel, | |||
| 2424 | RFPTarget aTarget) { | |||
| 2425 | if (!aChannel) { | |||
| 2426 | 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) | |||
| 2427 | ("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) | |||
| 2428 | "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); | |||
| 2429 | return ShouldResistFingerprinting("Null Object", aTarget); | |||
| 2430 | } | |||
| 2431 | ||||
| 2432 | nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); | |||
| 2433 | if (!loadInfo) { | |||
| 2434 | 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) | |||
| 2435 | ("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) | |||
| 2436 | "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); | |||
| 2437 | return ShouldResistFingerprinting("Null Object", aTarget); | |||
| 2438 | } | |||
| 2439 | ||||
| 2440 | // With this check, we can ensure that the prefs and target say yes, so only | |||
| 2441 | // an exemption would cause us to return false. | |||
| 2442 | bool isPBM = NS_UsePrivateBrowsing(aChannel); | |||
| 2443 | if (!ShouldResistFingerprinting_("Positive return check", isPBM, aTarget)) { | |||
| 2444 | 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) | |||
| 2445 | ("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) | |||
| 2446 | " 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) | |||
| 2447 | 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); | |||
| 2448 | return false; | |||
| 2449 | } | |||
| 2450 | ||||
| 2451 | if (ETPSaysShouldNotResistFingerprinting(aChannel, loadInfo)) { | |||
| 2452 | 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) | |||
| 2453 | ("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) | |||
| 2454 | " 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); | |||
| 2455 | return false; | |||
| 2456 | } | |||
| 2457 | ||||
| 2458 | if (CookieJarSettingsSaysShouldResistFingerprinting(loadInfo)) { | |||
| 2459 | 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) | |||
| 2460 | ("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) | |||
| 2461 | " 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); | |||
| 2462 | return true; | |||
| 2463 | } | |||
| 2464 | ||||
| 2465 | // Document types have no loading principal. Subdocument types do have a | |||
| 2466 | // loading principal, but it is the loading principal of the parent | |||
| 2467 | // document; not the subdocument. | |||
| 2468 | auto contentType = loadInfo->GetExternalContentPolicyType(); | |||
| 2469 | // Case 1: Document or Subdocument load | |||
| 2470 | if (contentType == ExtContentPolicy::TYPE_DOCUMENT || | |||
| 2471 | contentType == ExtContentPolicy::TYPE_SUBDOCUMENT) { | |||
| 2472 | nsCOMPtr<nsIURI> channelURI; | |||
| 2473 | nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI)); | |||
| 2474 | 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" , 2477); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" ") (" "Failed to get URI in " "nsContentUtils::ShouldResistFingerprinting(nsIChannel* aChannel)" ")"); do { *((volatile int*)__null) = 2477; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) | |||
| 2475 | 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" , 2477); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" ") (" "Failed to get URI in " "nsContentUtils::ShouldResistFingerprinting(nsIChannel* aChannel)" ")"); do { *((volatile int*)__null) = 2477; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) | |||
| 2476 | "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" , 2477); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" ") (" "Failed to get URI in " "nsContentUtils::ShouldResistFingerprinting(nsIChannel* aChannel)" ")"); do { *((volatile int*)__null) = 2477; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) | |||
| 2477 | "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" , 2477); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" ") (" "Failed to get URI in " "nsContentUtils::ShouldResistFingerprinting(nsIChannel* aChannel)" ")"); do { *((volatile int*)__null) = 2477; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 2478 | // this check is to ensure that we do not crash in non-debug builds. | |||
| 2479 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 2480 | return true; | |||
| 2481 | } | |||
| 2482 | ||||
| 2483 | #if 0 | |||
| 2484 | if (loadInfo->GetExternalContentPolicyType() == ExtContentPolicy::TYPE_SUBDOCUMENT) { | |||
| 2485 | nsCOMPtr<nsIURI> channelURI; | |||
| 2486 | nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI)); | |||
| 2487 | nsAutoCString channelSpec; | |||
| 2488 | channelURI->GetSpec(channelSpec); | |||
| 2489 | ||||
| 2490 | if (!loadInfo->GetLoadingPrincipal()) { | |||
| 2491 | 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) | |||
| 2492 | ("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) | |||
| 2493 | 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); | |||
| 2494 | ||||
| 2495 | } else { | |||
| 2496 | nsAutoCString loadingPrincipalSpec; | |||
| 2497 | loadInfo->GetLoadingPrincipal()->GetOrigin(loadingPrincipalSpec); | |||
| 2498 | ||||
| 2499 | 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) | |||
| 2500 | ("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) | |||
| 2501 | 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); | |||
| 2502 | } | |||
| 2503 | } | |||
| 2504 | ||||
| 2505 | #endif | |||
| 2506 | ||||
| 2507 | return ShouldResistFingerprinting_dangerous( | |||
| 2508 | channelURI, loadInfo->GetOriginAttributes(), "Internal Call", aTarget); | |||
| 2509 | } | |||
| 2510 | ||||
| 2511 | // Case 2: Subresource Load | |||
| 2512 | // Because this code is only used for subresource loads, this | |||
| 2513 | // will check the parent's principal | |||
| 2514 | nsIPrincipal* principal = loadInfo->GetLoadingPrincipal(); | |||
| 2515 | ||||
| 2516 | 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" , 2519); AnnotateMozCrashReason("MOZ_ASSERT" "(" "BasePrincipal::Cast(principal)->OriginAttributesRef() == loadInfo->GetOriginAttributes()" ")"); do { *((volatile int*)__null) = 2519; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false) | |||
| 2517 | !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" , 2519); AnnotateMozCrashReason("MOZ_ASSERT" "(" "BasePrincipal::Cast(principal)->OriginAttributesRef() == loadInfo->GetOriginAttributes()" ")"); do { *((volatile int*)__null) = 2519; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false) | |||
| 2518 | 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" , 2519); AnnotateMozCrashReason("MOZ_ASSERT" "(" "BasePrincipal::Cast(principal)->OriginAttributesRef() == loadInfo->GetOriginAttributes()" ")"); do { *((volatile int*)__null) = 2519; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false) | |||
| 2519 | 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" , 2519); AnnotateMozCrashReason("MOZ_ASSERT" "(" "BasePrincipal::Cast(principal)->OriginAttributesRef() == loadInfo->GetOriginAttributes()" ")"); do { *((volatile int*)__null) = 2519; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); | |||
| 2520 | return ShouldResistFingerprinting_dangerous(principal, "Internal Call", | |||
| 2521 | aTarget); | |||
| 2522 | } | |||
| 2523 | ||||
| 2524 | /* static */ | |||
| 2525 | bool nsContentUtils::ShouldResistFingerprinting_dangerous( | |||
| 2526 | nsIURI* aURI, const mozilla::OriginAttributes& aOriginAttributes, | |||
| 2527 | const char* aJustification, RFPTarget aTarget) { | |||
| 2528 | // With this check, we can ensure that the prefs and target say yes, so only | |||
| 2529 | // an exemption would cause us to return false. | |||
| 2530 | bool isPBM = aOriginAttributes.IsPrivateBrowsing(); | |||
| 2531 | if (!ShouldResistFingerprinting_("Positive return check", isPBM, aTarget)) { | |||
| 2532 | 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) | |||
| 2533 | ("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) | |||
| 2534 | " 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) | |||
| 2535 | 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); | |||
| 2536 | return false; | |||
| 2537 | } | |||
| 2538 | ||||
| 2539 | 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) | |||
| 2540 | ("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) | |||
| 2541 | " 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) | |||
| 2542 | 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); | |||
| 2543 | ||||
| 2544 | if (!StaticPrefs::privacy_resistFingerprinting_DoNotUseDirectly() && | |||
| 2545 | !StaticPrefs::privacy_fingerprintingProtection_DoNotUseDirectly()) { | |||
| 2546 | // If neither of the 'regular' RFP prefs are set, then one (or both) | |||
| 2547 | // of the PBM-Only prefs are set (or we would have failed the | |||
| 2548 | // Positive return check.) Therefore, if we are not in PBM, return false | |||
| 2549 | if (!aOriginAttributes.IsPrivateBrowsing()) { | |||
| 2550 | 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) | |||
| 2551 | ("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) | |||
| 2552 | " 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); | |||
| 2553 | return false; | |||
| 2554 | } | |||
| 2555 | } | |||
| 2556 | ||||
| 2557 | // Exclude internal schemes and web extensions | |||
| 2558 | if (SchemeSaysShouldNotResistFingerprinting(aURI)) { | |||
| 2559 | 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) | |||
| 2560 | ("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) | |||
| 2561 | " 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); | |||
| 2562 | return false; | |||
| 2563 | } | |||
| 2564 | ||||
| 2565 | bool isExemptDomain = false; | |||
| 2566 | nsAutoCString list; | |||
| 2567 | Preferences::GetCString(kExemptedDomainsPrefName, list); | |||
| 2568 | ToLowerCase(list); | |||
| 2569 | isExemptDomain = IsURIInList(aURI, list); | |||
| 2570 | ||||
| 2571 | if (MOZ_LOG_TEST(nsContentUtils::ResistFingerprintingLog(),(__builtin_expect(!!(mozilla::detail::log_test(nsContentUtils ::ResistFingerprintingLog(), mozilla::LogLevel::Debug)), 0)) | |||
| 2572 | mozilla::LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(nsContentUtils ::ResistFingerprintingLog(), mozilla::LogLevel::Debug)), 0))) { | |||
| 2573 | nsAutoCString url; | |||
| 2574 | aURI->GetHost(url); | |||
| 2575 | LogDomainAndPrefList("URI", kExemptedDomainsPrefName, url, isExemptDomain); | |||
| 2576 | } | |||
| 2577 | ||||
| 2578 | if (isExemptDomain) { | |||
| 2579 | isExemptDomain &= PartionKeyIsAlsoExempted(aOriginAttributes); | |||
| 2580 | } | |||
| 2581 | ||||
| 2582 | return !isExemptDomain; | |||
| 2583 | } | |||
| 2584 | ||||
| 2585 | /* static */ | |||
| 2586 | bool nsContentUtils::ShouldResistFingerprinting_dangerous( | |||
| 2587 | nsIPrincipal* aPrincipal, const char* aJustification, RFPTarget aTarget) { | |||
| 2588 | if (!aPrincipal) { | |||
| 2589 | 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) | |||
| 2590 | ("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) | |||
| 2591 | "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); | |||
| 2592 | return ShouldResistFingerprinting("Null object", aTarget); | |||
| 2593 | } | |||
| 2594 | ||||
| 2595 | auto originAttributes = | |||
| 2596 | BasePrincipal::Cast(aPrincipal)->OriginAttributesRef(); | |||
| 2597 | // With this check, we can ensure that the prefs and target say yes, so only | |||
| 2598 | // an exemption would cause us to return false. | |||
| 2599 | bool isPBM = originAttributes.IsPrivateBrowsing(); | |||
| 2600 | if (!ShouldResistFingerprinting_("Positive return check", isPBM, aTarget)) { | |||
| 2601 | 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) | |||
| 2602 | ("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) | |||
| 2603 | "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) | |||
| 2604 | 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); | |||
| 2605 | return false; | |||
| 2606 | } | |||
| 2607 | ||||
| 2608 | if (aPrincipal->IsSystemPrincipal()) { | |||
| 2609 | 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) | |||
| 2610 | ("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) | |||
| 2611 | "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); | |||
| 2612 | return false; | |||
| 2613 | } | |||
| 2614 | ||||
| 2615 | // Exclude internal schemes and web extensions | |||
| 2616 | if (SchemeSaysShouldNotResistFingerprinting(aPrincipal)) { | |||
| 2617 | 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) | |||
| 2618 | ("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) | |||
| 2619 | " 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); | |||
| 2620 | return false; | |||
| 2621 | } | |||
| 2622 | ||||
| 2623 | // Web extension principals are also excluded | |||
| 2624 | if (BasePrincipal::Cast(aPrincipal)->AddonPolicy()) { | |||
| 2625 | 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) | |||
| 2626 | ("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) | |||
| 2627 | " 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); | |||
| 2628 | return false; | |||
| 2629 | } | |||
| 2630 | ||||
| 2631 | bool isExemptDomain = false; | |||
| 2632 | aPrincipal->IsURIInPrefList(kExemptedDomainsPrefName, &isExemptDomain); | |||
| 2633 | ||||
| 2634 | if (MOZ_LOG_TEST(nsContentUtils::ResistFingerprintingLog(),(__builtin_expect(!!(mozilla::detail::log_test(nsContentUtils ::ResistFingerprintingLog(), mozilla::LogLevel::Debug)), 0)) | |||
| 2635 | mozilla::LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(nsContentUtils ::ResistFingerprintingLog(), mozilla::LogLevel::Debug)), 0))) { | |||
| 2636 | nsAutoCString origin; | |||
| 2637 | aPrincipal->GetOrigin(origin); | |||
| 2638 | LogDomainAndPrefList("URI", kExemptedDomainsPrefName, origin, | |||
| 2639 | isExemptDomain); | |||
| 2640 | } | |||
| 2641 | ||||
| 2642 | if (isExemptDomain) { | |||
| 2643 | isExemptDomain &= PartionKeyIsAlsoExempted(originAttributes); | |||
| 2644 | } | |||
| 2645 | ||||
| 2646 | return !isExemptDomain; | |||
| 2647 | } | |||
| 2648 | ||||
| 2649 | // -------------------------------------------------------------------- | |||
| 2650 | ||||
| 2651 | /* static */ | |||
| 2652 | void nsContentUtils::CalcRoundedWindowSizeForResistingFingerprinting( | |||
| 2653 | int32_t aChromeWidth, int32_t aChromeHeight, int32_t aScreenWidth, | |||
| 2654 | int32_t aScreenHeight, int32_t aInputWidth, int32_t aInputHeight, | |||
| 2655 | bool aSetOuterWidth, bool aSetOuterHeight, int32_t* aOutputWidth, | |||
| 2656 | int32_t* aOutputHeight) { | |||
| 2657 | 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" , 2657); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOutputWidth" ")"); do { *((volatile int*)__null) = 2657; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 2658 | 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" , 2658); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOutputHeight" ")"); do { *((volatile int*)__null) = 2658; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 2659 | ||||
| 2660 | int32_t availContentWidth = 0; | |||
| 2661 | int32_t availContentHeight = 0; | |||
| 2662 | ||||
| 2663 | availContentWidth = std::min(StaticPrefs::privacy_window_maxInnerWidth(), | |||
| 2664 | aScreenWidth - aChromeWidth); | |||
| 2665 | #ifdef MOZ_WIDGET_GTK1 | |||
| 2666 | // In the GTK window, it will not report outside system decorations | |||
| 2667 | // when we get available window size, see Bug 581863. So, we leave a | |||
| 2668 | // 40 pixels space for them when calculating the available content | |||
| 2669 | // height. It is not necessary for the width since the content width | |||
| 2670 | // is usually pretty much the same as the chrome width. | |||
| 2671 | availContentHeight = std::min(StaticPrefs::privacy_window_maxInnerHeight(), | |||
| 2672 | (-40 + aScreenHeight) - aChromeHeight); | |||
| 2673 | #else | |||
| 2674 | availContentHeight = std::min(StaticPrefs::privacy_window_maxInnerHeight(), | |||
| 2675 | aScreenHeight - aChromeHeight); | |||
| 2676 | #endif | |||
| 2677 | ||||
| 2678 | // Ideally, we'd like to round window size to 1000x1000, but the | |||
| 2679 | // screen space could be too small to accommodate this size in some | |||
| 2680 | // cases. If it happens, we would round the window size to the nearest | |||
| 2681 | // 200x100. | |||
| 2682 | availContentWidth = availContentWidth - (availContentWidth % 200); | |||
| 2683 | availContentHeight = availContentHeight - (availContentHeight % 100); | |||
| 2684 | ||||
| 2685 | // If aIsOuter is true, we are setting the outer window. So we | |||
| 2686 | // have to consider the chrome UI. | |||
| 2687 | int32_t chromeOffsetWidth = aSetOuterWidth ? aChromeWidth : 0; | |||
| 2688 | int32_t chromeOffsetHeight = aSetOuterHeight ? aChromeHeight : 0; | |||
| 2689 | int32_t resultWidth = 0, resultHeight = 0; | |||
| 2690 | ||||
| 2691 | // if the original size is greater than the maximum available size, we set | |||
| 2692 | // it to the maximum size. And if the original value is less than the | |||
| 2693 | // minimum rounded size, we set it to the minimum 200x100. | |||
| 2694 | if (aInputWidth > (availContentWidth + chromeOffsetWidth)) { | |||
| 2695 | resultWidth = availContentWidth + chromeOffsetWidth; | |||
| 2696 | } else if (aInputWidth < (200 + chromeOffsetWidth)) { | |||
| 2697 | resultWidth = 200 + chromeOffsetWidth; | |||
| 2698 | } else { | |||
| 2699 | // Otherwise, we round the window to the nearest upper rounded 200x100. | |||
| 2700 | resultWidth = NSToIntCeil((aInputWidth - chromeOffsetWidth) / 200.0) * 200 + | |||
| 2701 | chromeOffsetWidth; | |||
| 2702 | } | |||
| 2703 | ||||
| 2704 | if (aInputHeight > (availContentHeight + chromeOffsetHeight)) { | |||
| 2705 | resultHeight = availContentHeight + chromeOffsetHeight; | |||
| 2706 | } else if (aInputHeight < (100 + chromeOffsetHeight)) { | |||
| 2707 | resultHeight = 100 + chromeOffsetHeight; | |||
| 2708 | } else { | |||
| 2709 | resultHeight = | |||
| 2710 | NSToIntCeil((aInputHeight - chromeOffsetHeight) / 100.0) * 100 + | |||
| 2711 | chromeOffsetHeight; | |||
| 2712 | } | |||
| 2713 | ||||
| 2714 | *aOutputWidth = resultWidth; | |||
| 2715 | *aOutputHeight = resultHeight; | |||
| 2716 | } | |||
| 2717 | ||||
| 2718 | bool nsContentUtils::ThreadsafeIsCallerChrome() { | |||
| 2719 | return NS_IsMainThread() ? IsCallerChrome() | |||
| 2720 | : IsCurrentThreadRunningChromeWorker(); | |||
| 2721 | } | |||
| 2722 | ||||
| 2723 | bool nsContentUtils::IsCallerUAWidget() { | |||
| 2724 | JSContext* cx = GetCurrentJSContext(); | |||
| 2725 | if (!cx) { | |||
| 2726 | return false; | |||
| 2727 | } | |||
| 2728 | ||||
| 2729 | JS::Realm* realm = JS::GetCurrentRealmOrNull(cx); | |||
| 2730 | if (!realm) { | |||
| 2731 | return false; | |||
| 2732 | } | |||
| 2733 | ||||
| 2734 | return xpc::IsUAWidgetScope(realm); | |||
| 2735 | } | |||
| 2736 | ||||
| 2737 | bool nsContentUtils::IsSystemCaller(JSContext* aCx) { | |||
| 2738 | // Note that SubjectPrincipal() assumes we are in a compartment here. | |||
| 2739 | return SubjectPrincipal(aCx) == sSystemPrincipal; | |||
| 2740 | } | |||
| 2741 | ||||
| 2742 | bool nsContentUtils::ThreadsafeIsSystemCaller(JSContext* aCx) { | |||
| 2743 | CycleCollectedJSContext* ccjscx = CycleCollectedJSContext::Get(); | |||
| 2744 | 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" , 2744); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ccjscx->Context() == aCx" ")"); do { *((volatile int*)__null) = 2744; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 2745 | ||||
| 2746 | return ccjscx->IsSystemCaller(); | |||
| 2747 | } | |||
| 2748 | ||||
| 2749 | // static | |||
| 2750 | bool nsContentUtils::LookupBindingMember( | |||
| 2751 | JSContext* aCx, nsIContent* aContent, JS::Handle<jsid> aId, | |||
| 2752 | JS::MutableHandle<JS::PropertyDescriptor> aDesc) { | |||
| 2753 | return true; | |||
| 2754 | } | |||
| 2755 | ||||
| 2756 | nsINode* nsContentUtils::GetNearestInProcessCrossDocParentNode( | |||
| 2757 | nsINode* aChild) { | |||
| 2758 | if (aChild->IsDocument()) { | |||
| 2759 | for (BrowsingContext* bc = aChild->AsDocument()->GetBrowsingContext(); bc; | |||
| 2760 | bc = bc->GetParent()) { | |||
| 2761 | if (bc->GetEmbedderElement()) { | |||
| 2762 | return bc->GetEmbedderElement(); | |||
| 2763 | } | |||
| 2764 | } | |||
| 2765 | return nullptr; | |||
| 2766 | } | |||
| 2767 | ||||
| 2768 | nsINode* parent = aChild->GetParentNode(); | |||
| 2769 | if (parent && parent->IsContent() && aChild->IsContent()) { | |||
| 2770 | parent = aChild->AsContent()->GetFlattenedTreeParent(); | |||
| 2771 | } | |||
| 2772 | ||||
| 2773 | return parent; | |||
| 2774 | } | |||
| 2775 | ||||
| 2776 | bool nsContentUtils::ContentIsHostIncludingDescendantOf( | |||
| 2777 | const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor) { | |||
| 2778 | 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" , 2778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPossibleDescendant" ") (" "The possible descendant is null!" ")"); do { *((volatile int*)__null) = 2778; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 2779 | 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" , 2779); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPossibleAncestor" ") (" "The possible ancestor is null!" ")"); do { *((volatile int*)__null) = 2779; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 2780 | ||||
| 2781 | do { | |||
| 2782 | if (aPossibleDescendant == aPossibleAncestor) return true; | |||
| 2783 | if (aPossibleDescendant->IsDocumentFragment()) { | |||
| 2784 | aPossibleDescendant = | |||
| 2785 | aPossibleDescendant->AsDocumentFragment()->GetHost(); | |||
| 2786 | } else { | |||
| 2787 | aPossibleDescendant = aPossibleDescendant->GetParentNode(); | |||
| 2788 | } | |||
| 2789 | } while (aPossibleDescendant); | |||
| 2790 | ||||
| 2791 | return false; | |||
| 2792 | } | |||
| 2793 | ||||
| 2794 | // static | |||
| 2795 | bool nsContentUtils::ContentIsCrossDocDescendantOf(nsINode* aPossibleDescendant, | |||
| 2796 | nsINode* aPossibleAncestor) { | |||
| 2797 | 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" , 2797); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPossibleDescendant" ") (" "The possible descendant is null!" ")"); do { *((volatile int*)__null) = 2797; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 2798 | 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" , 2798); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPossibleAncestor" ") (" "The possible ancestor is null!" ")"); do { *((volatile int*)__null) = 2798; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 2799 | ||||
| 2800 | do { | |||
| 2801 | if (aPossibleDescendant == aPossibleAncestor) { | |||
| 2802 | return true; | |||
| 2803 | } | |||
| 2804 | ||||
| 2805 | aPossibleDescendant = | |||
| 2806 | GetNearestInProcessCrossDocParentNode(aPossibleDescendant); | |||
| 2807 | } while (aPossibleDescendant); | |||
| 2808 | ||||
| 2809 | return false; | |||
| 2810 | } | |||
| 2811 | ||||
| 2812 | // static | |||
| 2813 | bool nsContentUtils::ContentIsFlattenedTreeDescendantOf( | |||
| 2814 | const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor) { | |||
| 2815 | 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" , 2815); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPossibleDescendant" ") (" "The possible descendant is null!" ")"); do { *((volatile int*)__null) = 2815; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 2816 | 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" , 2816); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPossibleAncestor" ") (" "The possible ancestor is null!" ")"); do { *((volatile int*)__null) = 2816; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 2817 | ||||
| 2818 | do { | |||
| 2819 | if (aPossibleDescendant == aPossibleAncestor) { | |||
| 2820 | return true; | |||
| 2821 | } | |||
| 2822 | aPossibleDescendant = aPossibleDescendant->GetFlattenedTreeParentNode(); | |||
| 2823 | } while (aPossibleDescendant); | |||
| 2824 | ||||
| 2825 | return false; | |||
| 2826 | } | |||
| 2827 | ||||
| 2828 | // static | |||
| 2829 | bool nsContentUtils::ContentIsFlattenedTreeDescendantOfForStyle( | |||
| 2830 | const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor) { | |||
| 2831 | 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" , 2831); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPossibleDescendant" ") (" "The possible descendant is null!" ")"); do { *((volatile int*)__null) = 2831; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 2832 | 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" , 2832); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPossibleAncestor" ") (" "The possible ancestor is null!" ")"); do { *((volatile int*)__null) = 2832; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 2833 | ||||
| 2834 | do { | |||
| 2835 | if (aPossibleDescendant == aPossibleAncestor) { | |||
| 2836 | return true; | |||
| 2837 | } | |||
| 2838 | aPossibleDescendant = | |||
| 2839 | aPossibleDescendant->GetFlattenedTreeParentNodeForStyle(); | |||
| 2840 | } while (aPossibleDescendant); | |||
| 2841 | ||||
| 2842 | return false; | |||
| 2843 | } | |||
| 2844 | ||||
| 2845 | // static | |||
| 2846 | nsINode* nsContentUtils::Retarget(nsINode* aTargetA, nsINode* aTargetB) { | |||
| 2847 | while (true && aTargetA) { | |||
| 2848 | // If A's root is not a shadow root... | |||
| 2849 | nsINode* root = aTargetA->SubtreeRoot(); | |||
| 2850 | if (!root->IsShadowRoot()) { | |||
| 2851 | // ...then return A. | |||
| 2852 | return aTargetA; | |||
| 2853 | } | |||
| 2854 | ||||
| 2855 | // or A's root is a shadow-including inclusive ancestor of B... | |||
| 2856 | if (aTargetB->IsShadowIncludingInclusiveDescendantOf(root)) { | |||
| 2857 | // ...then return A. | |||
| 2858 | return aTargetA; | |||
| 2859 | } | |||
| 2860 | ||||
| 2861 | aTargetA = ShadowRoot::FromNode(root)->GetHost(); | |||
| 2862 | } | |||
| 2863 | ||||
| 2864 | return nullptr; | |||
| 2865 | } | |||
| 2866 | ||||
| 2867 | // static | |||
| 2868 | Element* nsContentUtils::GetAnElementForTiming(Element* aTarget, | |||
| 2869 | const Document* aDocument, | |||
| 2870 | nsIGlobalObject* aGlobal) { | |||
| 2871 | if (!aTarget->IsInComposedDoc()) { | |||
| 2872 | return nullptr; | |||
| 2873 | } | |||
| 2874 | ||||
| 2875 | if (!aDocument) { | |||
| 2876 | nsCOMPtr<nsPIDOMWindowInner> inner = do_QueryInterface(aGlobal); | |||
| 2877 | if (!inner) { | |||
| 2878 | return nullptr; | |||
| 2879 | } | |||
| 2880 | aDocument = inner->GetExtantDoc(); | |||
| 2881 | } | |||
| 2882 | ||||
| 2883 | 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" , 2883); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocument" ")" ); do { *((volatile int*)__null) = 2883; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 2884 | ||||
| 2885 | if (aTarget->GetUncomposedDocOrConnectedShadowRoot() != aDocument || | |||
| 2886 | !aDocument->IsCurrentActiveDocument()) { | |||
| 2887 | return nullptr; | |||
| 2888 | } | |||
| 2889 | ||||
| 2890 | return aTarget; | |||
| 2891 | } | |||
| 2892 | ||||
| 2893 | // static | |||
| 2894 | nsresult nsContentUtils::GetInclusiveAncestors(nsINode* aNode, | |||
| 2895 | nsTArray<nsINode*>& aArray) { | |||
| 2896 | while (aNode) { | |||
| 2897 | aArray.AppendElement(aNode); | |||
| 2898 | aNode = aNode->GetParentNode(); | |||
| 2899 | } | |||
| 2900 | return NS_OK; | |||
| 2901 | } | |||
| 2902 | ||||
| 2903 | // static | |||
| 2904 | template <typename GetParentFunc> | |||
| 2905 | nsresult static GetInclusiveAncestorsAndOffsetsHelper( | |||
| 2906 | nsINode* aNode, uint32_t aOffset, nsTArray<nsIContent*>& aAncestorNodes, | |||
| 2907 | nsTArray<Maybe<uint32_t>>& aAncestorOffsets, GetParentFunc aGetParentFunc) { | |||
| 2908 | 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" , 2908); return NS_ERROR_INVALID_POINTER; } } while (false); | |||
| 2909 | ||||
| 2910 | if (!aNode->IsContent()) { | |||
| 2911 | return NS_ERROR_FAILURE; | |||
| 2912 | } | |||
| 2913 | nsIContent* content = aNode->AsContent(); | |||
| 2914 | ||||
| 2915 | if (!aAncestorNodes.IsEmpty()) { | |||
| 2916 | 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" , 2916); | |||
| 2917 | aAncestorNodes.Clear(); | |||
| 2918 | } | |||
| 2919 | ||||
| 2920 | if (!aAncestorOffsets.IsEmpty()) { | |||
| 2921 | 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" , 2921); | |||
| 2922 | aAncestorOffsets.Clear(); | |||
| 2923 | } | |||
| 2924 | ||||
| 2925 | // insert the node itself | |||
| 2926 | aAncestorNodes.AppendElement(content); | |||
| 2927 | aAncestorOffsets.AppendElement(Some(aOffset)); | |||
| 2928 | ||||
| 2929 | // insert all the ancestors | |||
| 2930 | nsIContent* child = content; | |||
| 2931 | nsIContent* parent = aGetParentFunc(child); | |||
| 2932 | while (parent) { | |||
| 2933 | aAncestorNodes.AppendElement(parent->AsContent()); | |||
| 2934 | aAncestorOffsets.AppendElement(parent->ComputeIndexOf(child)); | |||
| 2935 | child = parent; | |||
| 2936 | parent = aGetParentFunc(child); | |||
| 2937 | } | |||
| 2938 | ||||
| 2939 | return NS_OK; | |||
| 2940 | } | |||
| 2941 | ||||
| 2942 | nsresult nsContentUtils::GetInclusiveAncestorsAndOffsets( | |||
| 2943 | nsINode* aNode, uint32_t aOffset, nsTArray<nsIContent*>& aAncestorNodes, | |||
| 2944 | nsTArray<Maybe<uint32_t>>& aAncestorOffsets) { | |||
| 2945 | return GetInclusiveAncestorsAndOffsetsHelper( | |||
| 2946 | aNode, aOffset, aAncestorNodes, aAncestorOffsets, | |||
| 2947 | [](nsIContent* aContent) { return aContent->GetParent(); }); | |||
| 2948 | } | |||
| 2949 | ||||
| 2950 | nsresult nsContentUtils::GetShadowIncludingAncestorsAndOffsets( | |||
| 2951 | nsINode* aNode, uint32_t aOffset, nsTArray<nsIContent*>& aAncestorNodes, | |||
| 2952 | nsTArray<Maybe<uint32_t>>& aAncestorOffsets) { | |||
| 2953 | return GetInclusiveAncestorsAndOffsetsHelper( | |||
| 2954 | aNode, aOffset, aAncestorNodes, aAncestorOffsets, | |||
| 2955 | [](nsIContent* aContent) -> nsIContent* { | |||
| 2956 | return nsIContent::FromNodeOrNull( | |||
| 2957 | aContent->GetParentOrShadowHostNode()); | |||
| 2958 | }); | |||
| 2959 | } | |||
| 2960 | ||||
| 2961 | template <typename Node, typename GetParentFunc> | |||
| 2962 | static Node* GetCommonAncestorInternal(Node* aNode1, Node* aNode2, | |||
| 2963 | GetParentFunc aGetParentFunc) { | |||
| 2964 | 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" , 2964); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNode1 != aNode2" ")"); do { *((volatile int*)__null) = 2964; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 2965 | ||||
| 2966 | // Build the chain of parents | |||
| 2967 | AutoTArray<Node*, 30> parents1, parents2; | |||
| 2968 | do { | |||
| 2969 | parents1.AppendElement(aNode1); | |||
| 2970 | aNode1 = aGetParentFunc(aNode1); | |||
| 2971 | } while (aNode1); | |||
| 2972 | do { | |||
| 2973 | parents2.AppendElement(aNode2); | |||
| 2974 | aNode2 = aGetParentFunc(aNode2); | |||
| 2975 | } while (aNode2); | |||
| 2976 | ||||
| 2977 | // Find where the parent chain differs | |||
| 2978 | uint32_t pos1 = parents1.Length(); | |||
| 2979 | uint32_t pos2 = parents2.Length(); | |||
| 2980 | Node** data1 = parents1.Elements(); | |||
| 2981 | Node** data2 = parents2.Elements(); | |||
| 2982 | Node* parent = nullptr; | |||
| 2983 | uint32_t len; | |||
| 2984 | for (len = std::min(pos1, pos2); len > 0; --len) { | |||
| 2985 | Node* child1 = data1[--pos1]; | |||
| 2986 | Node* child2 = data2[--pos2]; | |||
| 2987 | if (child1 != child2) { | |||
| 2988 | break; | |||
| 2989 | } | |||
| 2990 | parent = child1; | |||
| 2991 | } | |||
| 2992 | ||||
| 2993 | return parent; | |||
| 2994 | } | |||
| 2995 | ||||
| 2996 | /* static */ | |||
| 2997 | nsINode* nsContentUtils::GetCommonAncestorHelper(nsINode* aNode1, | |||
| 2998 | nsINode* aNode2) { | |||
| 2999 | return GetCommonAncestorInternal( | |||
| 3000 | aNode1, aNode2, [](nsINode* aNode) { return aNode->GetParentNode(); }); | |||
| 3001 | } | |||
| 3002 | ||||
| 3003 | /* static */ | |||
| 3004 | nsINode* nsContentUtils::GetClosestCommonShadowIncludingInclusiveAncestor( | |||
| 3005 | nsINode* aNode1, nsINode* aNode2) { | |||
| 3006 | if (aNode1 == aNode2) { | |||
| 3007 | return aNode1; | |||
| 3008 | } | |||
| 3009 | ||||
| 3010 | return GetCommonAncestorInternal(aNode1, aNode2, [](nsINode* aNode) { | |||
| 3011 | return aNode->GetParentOrShadowHostNode(); | |||
| 3012 | }); | |||
| 3013 | } | |||
| 3014 | ||||
| 3015 | /* static */ | |||
| 3016 | nsIContent* nsContentUtils::GetCommonFlattenedTreeAncestorHelper( | |||
| 3017 | nsIContent* aContent1, nsIContent* aContent2) { | |||
| 3018 | return GetCommonAncestorInternal( | |||
| 3019 | aContent1, aContent2, | |||
| 3020 | [](nsIContent* aContent) { return aContent->GetFlattenedTreeParent(); }); | |||
| 3021 | } | |||
| 3022 | ||||
| 3023 | /* static */ | |||
| 3024 | nsIContent* nsContentUtils::GetCommonFlattenedTreeAncestorForSelection( | |||
| 3025 | nsIContent* aContent1, nsIContent* aContent2) { | |||
| 3026 | if (aContent1 == aContent2) { | |||
| 3027 | return aContent1; | |||
| 3028 | } | |||
| 3029 | ||||
| 3030 | return GetCommonAncestorInternal( | |||
| 3031 | aContent1, aContent2, [](nsIContent* aContent) { | |||
| 3032 | return aContent->GetFlattenedTreeParentNodeForSelection(); | |||
| 3033 | }); | |||
| 3034 | } | |||
| 3035 | ||||
| 3036 | /* static */ | |||
| 3037 | Element* nsContentUtils::GetCommonFlattenedTreeAncestorForStyle( | |||
| 3038 | Element* aElement1, Element* aElement2) { | |||
| 3039 | return GetCommonAncestorInternal(aElement1, aElement2, [](Element* aElement) { | |||
| 3040 | return aElement->GetFlattenedTreeParentElementForStyle(); | |||
| 3041 | }); | |||
| 3042 | } | |||
| 3043 | ||||
| 3044 | /* static */ | |||
| 3045 | bool nsContentUtils::PositionIsBefore(nsINode* aNode1, nsINode* aNode2, | |||
| 3046 | Maybe<uint32_t>* aNode1Index, | |||
| 3047 | Maybe<uint32_t>* aNode2Index) { | |||
| 3048 | // Note, CompareDocumentPosition takes the latter params in different order. | |||
| 3049 | return (aNode2->CompareDocumentPosition(*aNode1, aNode2Index, aNode1Index) & | |||
| 3050 | (Node_Binding::DOCUMENT_POSITION_PRECEDING | | |||
| 3051 | Node_Binding::DOCUMENT_POSITION_DISCONNECTED)) == | |||
| 3052 | Node_Binding::DOCUMENT_POSITION_PRECEDING; | |||
| 3053 | } | |||
| 3054 | ||||
| 3055 | /* static */ | |||
| 3056 | Maybe<int32_t> nsContentUtils::ComparePoints(const nsINode* aParent1, | |||
| 3057 | uint32_t aOffset1, | |||
| 3058 | const nsINode* aParent2, | |||
| 3059 | uint32_t aOffset2, | |||
| 3060 | NodeIndexCache* aIndexCache) { | |||
| 3061 | bool disconnected{false}; | |||
| 3062 | ||||
| 3063 | const int32_t order = ComparePoints_Deprecated( | |||
| 3064 | aParent1, aOffset1, aParent2, aOffset2, &disconnected, aIndexCache); | |||
| 3065 | if (disconnected) { | |||
| 3066 | return Nothing(); | |||
| 3067 | } | |||
| 3068 | ||||
| 3069 | return Some(order); | |||
| 3070 | } | |||
| 3071 | ||||
| 3072 | /* static */ | |||
| 3073 | int32_t nsContentUtils::ComparePoints_Deprecated( | |||
| 3074 | const nsINode* aParent1, uint32_t aOffset1, const nsINode* aParent2, | |||
| 3075 | uint32_t aOffset2, bool* aDisconnected, NodeIndexCache* aIndexCache) { | |||
| 3076 | if (aParent1 == aParent2) { | |||
| 3077 | return aOffset1 < aOffset2 ? -1 : aOffset1 > aOffset2 ? 1 : 0; | |||
| 3078 | } | |||
| 3079 | ||||
| 3080 | AutoTArray<const nsINode*, 32> parents1, parents2; | |||
| 3081 | const nsINode* node1 = aParent1; | |||
| 3082 | const nsINode* node2 = aParent2; | |||
| 3083 | do { | |||
| 3084 | parents1.AppendElement(node1); | |||
| 3085 | node1 = node1->GetParentOrShadowHostNode(); | |||
| 3086 | } while (node1); | |||
| 3087 | do { | |||
| 3088 | parents2.AppendElement(node2); | |||
| 3089 | node2 = node2->GetParentOrShadowHostNode(); | |||
| 3090 | } while (node2); | |||
| 3091 | ||||
| 3092 | uint32_t pos1 = parents1.Length() - 1; | |||
| 3093 | uint32_t pos2 = parents2.Length() - 1; | |||
| 3094 | ||||
| 3095 | bool disconnected = parents1.ElementAt(pos1) != parents2.ElementAt(pos2); | |||
| 3096 | if (aDisconnected) { | |||
| 3097 | *aDisconnected = disconnected; | |||
| 3098 | } | |||
| 3099 | if (disconnected) { | |||
| 3100 | 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" , 3100); MOZ_PretendNoReturn(); } } while (0); | |||
| 3101 | return 1; | |||
| 3102 | } | |||
| 3103 | ||||
| 3104 | // Find where the parent chains differ | |||
| 3105 | const nsINode* parent = parents1.ElementAt(pos1); | |||
| 3106 | uint32_t len; | |||
| 3107 | for (len = std::min(pos1, pos2); len > 0; --len) { | |||
| 3108 | const nsINode* child1 = parents1.ElementAt(--pos1); | |||
| 3109 | const nsINode* child2 = parents2.ElementAt(--pos2); | |||
| 3110 | if (child1 != child2) { | |||
| 3111 | if (MOZ_UNLIKELY(child1->IsShadowRoot())(__builtin_expect(!!(child1->IsShadowRoot()), 0))) { | |||
| 3112 | // Shadow roots come before light DOM per | |||
| 3113 | // https://dom.spec.whatwg.org/#concept-shadow-including-tree-order | |||
| 3114 | 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" , 3114); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!child2->IsShadowRoot()" ") (" "Two shadow roots?" ")"); do { *((volatile int*)__null ) = 3114; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); | |||
| 3115 | return -1; | |||
| 3116 | } | |||
| 3117 | if (MOZ_UNLIKELY(child2->IsShadowRoot())(__builtin_expect(!!(child2->IsShadowRoot()), 0))) { | |||
| 3118 | return 1; | |||
| 3119 | } | |||
| 3120 | Maybe<uint32_t> child1Index; | |||
| 3121 | Maybe<uint32_t> child2Index; | |||
| 3122 | if (aIndexCache) { | |||
| 3123 | aIndexCache->ComputeIndicesOf(parent, child1, child2, child1Index, | |||
| 3124 | child2Index); | |||
| 3125 | } else { | |||
| 3126 | child1Index = parent->ComputeIndexOf(child1); | |||
| 3127 | child2Index = parent->ComputeIndexOf(child2); | |||
| 3128 | } | |||
| 3129 | if (MOZ_LIKELY(child1Index.isSome() && child2Index.isSome())(__builtin_expect(!!(child1Index.isSome() && child2Index .isSome()), 1))) { | |||
| 3130 | return *child1Index < *child2Index ? -1 : 1; | |||
| 3131 | } | |||
| 3132 | // XXX Keep the odd traditional behavior for now. | |||
| 3133 | return child1Index.isNothing() && child2Index.isSome() ? -1 : 1; | |||
| 3134 | } | |||
| 3135 | parent = child1; | |||
| 3136 | } | |||
| 3137 | ||||
| 3138 | // The parent chains never differed, so one of the nodes is an ancestor of | |||
| 3139 | // the other | |||
| 3140 | ||||
| 3141 | 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" , 3142); MOZ_PretendNoReturn(); } } while (0) | |||
| 3142 | "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" , 3142); MOZ_PretendNoReturn(); } } while (0); | |||
| 3143 | ||||
| 3144 | if (!pos1) { | |||
| 3145 | const nsINode* child2 = parents2.ElementAt(--pos2); | |||
| 3146 | const Maybe<uint32_t> child2Index = | |||
| 3147 | aIndexCache ? aIndexCache->ComputeIndexOf(parent, child2) | |||
| 3148 | : parent->ComputeIndexOf(child2); | |||
| 3149 | 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" , 3149)), 0))) { | |||
| 3150 | return 1; | |||
| 3151 | } | |||
| 3152 | return aOffset1 <= *child2Index ? -1 : 1; | |||
| 3153 | } | |||
| 3154 | ||||
| 3155 | const nsINode* child1 = parents1.ElementAt(--pos1); | |||
| 3156 | const Maybe<uint32_t> child1Index = | |||
| 3157 | aIndexCache ? aIndexCache->ComputeIndexOf(parent, child1) | |||
| 3158 | : parent->ComputeIndexOf(child1); | |||
| 3159 | 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" , 3159)), 0))) { | |||
| 3160 | return -1; | |||
| 3161 | } | |||
| 3162 | return *child1Index < aOffset2 ? -1 : 1; | |||
| 3163 | } | |||
| 3164 | ||||
| 3165 | /* static */ | |||
| 3166 | BrowserParent* nsContentUtils::GetCommonBrowserParentAncestor( | |||
| 3167 | BrowserParent* aBrowserParent1, BrowserParent* aBrowserParent2) { | |||
| 3168 | return GetCommonAncestorInternal( | |||
| 3169 | aBrowserParent1, aBrowserParent2, [](BrowserParent* aBrowserParent) { | |||
| 3170 | return aBrowserParent->GetBrowserBridgeParent() | |||
| 3171 | ? aBrowserParent->GetBrowserBridgeParent()->Manager() | |||
| 3172 | : nullptr; | |||
| 3173 | }); | |||
| 3174 | } | |||
| 3175 | ||||
| 3176 | /* static */ | |||
| 3177 | Element* nsContentUtils::GetTargetElement(Document* aDocument, | |||
| 3178 | const nsAString& aAnchorName) { | |||
| 3179 | 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" , 3179); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocument" ")" ); do { *((volatile int*)__null) = 3179; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 3180 | ||||
| 3181 | if (aAnchorName.IsEmpty()) { | |||
| 3182 | return nullptr; | |||
| 3183 | } | |||
| 3184 | // 1. If there is an element in the document tree that has an ID equal to | |||
| 3185 | // fragment, then return the first such element in tree order. | |||
| 3186 | if (Element* el = aDocument->GetElementById(aAnchorName)) { | |||
| 3187 | return el; | |||
| 3188 | } | |||
| 3189 | ||||
| 3190 | // 2. If there is an a element in the document tree that has a name | |||
| 3191 | // attribute whose value is equal to fragment, then return the first such | |||
| 3192 | // element in tree order. | |||
| 3193 | // | |||
| 3194 | // FIXME(emilio): Why the different code-paths for HTML and non-HTML docs? | |||
| 3195 | if (aDocument->IsHTMLDocument()) { | |||
| 3196 | nsCOMPtr<nsINodeList> list = aDocument->GetElementsByName(aAnchorName); | |||
| 3197 | // Loop through the named nodes looking for the first anchor | |||
| 3198 | uint32_t length = list->Length(); | |||
| 3199 | for (uint32_t i = 0; i < length; i++) { | |||
| 3200 | nsIContent* node = list->Item(i); | |||
| 3201 | if (node->IsHTMLElement(nsGkAtoms::a)) { | |||
| 3202 | return node->AsElement(); | |||
| 3203 | } | |||
| 3204 | } | |||
| 3205 | } else { | |||
| 3206 | constexpr auto nameSpace = u"http://www.w3.org/1999/xhtml"_ns; | |||
| 3207 | // Get the list of anchor elements | |||
| 3208 | nsCOMPtr<nsINodeList> list = | |||
| 3209 | aDocument->GetElementsByTagNameNS(nameSpace, u"a"_ns); | |||
| 3210 | // Loop through the anchors looking for the first one with the given name. | |||
| 3211 | for (uint32_t i = 0; true; i++) { | |||
| 3212 | nsIContent* node = list->Item(i); | |||
| 3213 | if (!node) { // End of list | |||
| 3214 | break; | |||
| 3215 | } | |||
| 3216 | ||||
| 3217 | // Compare the name attribute | |||
| 3218 | if (node->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, | |||
| 3219 | aAnchorName, eCaseMatters)) { | |||
| 3220 | return node->AsElement(); | |||
| 3221 | } | |||
| 3222 | } | |||
| 3223 | } | |||
| 3224 | ||||
| 3225 | // 3. Return null. | |||
| 3226 | return nullptr; | |||
| 3227 | } | |||
| 3228 | ||||
| 3229 | /* static */ | |||
| 3230 | template <typename FPT, typename FRT, typename SPT, typename SRT> | |||
| 3231 | Maybe<int32_t> nsContentUtils::ComparePoints( | |||
| 3232 | const RangeBoundaryBase<FPT, FRT>& aFirstBoundary, | |||
| 3233 | const RangeBoundaryBase<SPT, SRT>& aSecondBoundary) { | |||
| 3234 | if (!aFirstBoundary.IsSet() || !aSecondBoundary.IsSet()) { | |||
| 3235 | return Nothing{}; | |||
| 3236 | } | |||
| 3237 | ||||
| 3238 | bool disconnected{false}; | |||
| 3239 | const int32_t order = | |||
| 3240 | ComparePoints_Deprecated(aFirstBoundary, aSecondBoundary, &disconnected); | |||
| 3241 | ||||
| 3242 | if (disconnected) { | |||
| 3243 | return Nothing{}; | |||
| 3244 | } | |||
| 3245 | ||||
| 3246 | return Some(order); | |||
| 3247 | } | |||
| 3248 | ||||
| 3249 | /* static */ | |||
| 3250 | template <typename FPT, typename FRT, typename SPT, typename SRT> | |||
| 3251 | int32_t nsContentUtils::ComparePoints_Deprecated( | |||
| 3252 | const RangeBoundaryBase<FPT, FRT>& aFirstBoundary, | |||
| 3253 | const RangeBoundaryBase<SPT, SRT>& aSecondBoundary, bool* aDisconnected) { | |||
| 3254 | 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" , 3254) || | |||
| 3255 | NS_WARN_IF(!aSecondBoundary.IsSet())NS_warn_if_impl(!aSecondBoundary.IsSet(), "!aSecondBoundary.IsSet()" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp" , 3255)) { | |||
| 3256 | return -1; | |||
| 3257 | } | |||
| 3258 | // XXX Re-implement this without calling `Offset()` as far as possible, | |||
| 3259 | // and the other overload should be an alias of this. | |||
| 3260 | return ComparePoints_Deprecated( | |||
| 3261 | aFirstBoundary.Container(), | |||
| 3262 | *aFirstBoundary.Offset( | |||
| 3263 | RangeBoundaryBase<FPT, FRT>::OffsetFilter::kValidOrInvalidOffsets), | |||
| 3264 | aSecondBoundary.Container(), | |||
| 3265 | *aSecondBoundary.Offset( | |||
| 3266 | RangeBoundaryBase<SPT, SRT>::OffsetFilter::kValidOrInvalidOffsets), | |||
| 3267 | aDisconnected); | |||
| 3268 | } | |||
| 3269 | ||||
| 3270 | inline bool IsCharInSet(const char* aSet, const char16_t aChar) { | |||
| 3271 | char16_t ch; | |||
| 3272 | while ((ch = *aSet)) { | |||
| 3273 | if (aChar == char16_t(ch)) { | |||
| 3274 | return true; | |||
| 3275 | } | |||
| 3276 | ++aSet; | |||
| 3277 | } | |||
| 3278 | return false; | |||
| 3279 | } | |||
| 3280 | ||||
| 3281 | /** | |||
| 3282 | * This method strips leading/trailing chars, in given set, from string. | |||
| 3283 | */ | |||
| 3284 | ||||
| 3285 | // static | |||
| 3286 | const nsDependentSubstring nsContentUtils::TrimCharsInSet( | |||
| 3287 | const char* aSet, const nsAString& aValue) { | |||
| 3288 | nsAString::const_iterator valueCurrent, valueEnd; | |||
| 3289 | ||||
| 3290 | aValue.BeginReading(valueCurrent); | |||
| 3291 | aValue.EndReading(valueEnd); | |||
| 3292 | ||||
| 3293 | // Skip characters in the beginning | |||
| 3294 | while (valueCurrent != valueEnd) { | |||
| 3295 | if (!IsCharInSet(aSet, *valueCurrent)) { | |||
| 3296 | break; | |||
| 3297 | } | |||
| 3298 | ++valueCurrent; | |||
| 3299 | } | |||
| 3300 | ||||
| 3301 | if (valueCurrent != valueEnd) { | |||
| 3302 | for (;;) { | |||
| 3303 | --valueEnd; | |||
| 3304 | if (!IsCharInSet(aSet, *valueEnd)) { | |||
| 3305 | break; | |||
| 3306 | } | |||
| 3307 | } | |||
| 3308 | ++valueEnd; // Step beyond the last character we want in the value. | |||
| 3309 | } | |||
| 3310 | ||||
| 3311 | // valueEnd should point to the char after the last to copy | |||
| 3312 | return Substring(valueCurrent, valueEnd); | |||
| 3313 | } | |||
| 3314 | ||||
| 3315 | /** | |||
| 3316 | * This method strips leading and trailing whitespace from a string. | |||
| 3317 | */ | |||
| 3318 | ||||
| 3319 | // static | |||
| 3320 | template <bool IsWhitespace(char16_t)> | |||
| 3321 | const nsDependentSubstring nsContentUtils::TrimWhitespace(const nsAString& aStr, | |||
| 3322 | bool aTrimTrailing) { | |||
| 3323 | nsAString::const_iterator start, end; | |||
| 3324 | ||||
| 3325 | aStr.BeginReading(start); | |||
| 3326 | aStr.EndReading(end); | |||
| 3327 | ||||
| 3328 | // Skip whitespace characters in the beginning | |||
| 3329 | while (start != end && IsWhitespace(*start)) { | |||
| 3330 | ++start; | |||
| 3331 | } | |||
| 3332 | ||||
| 3333 | if (aTrimTrailing) { | |||
| 3334 | // Skip whitespace characters in the end. | |||
| 3335 | while (end != start) { | |||
| 3336 | --end; | |||
| 3337 | ||||
| 3338 | if (!IsWhitespace(*end)) { | |||
| 3339 | // Step back to the last non-whitespace character. | |||
| 3340 | ++end; | |||
| 3341 | ||||
| 3342 | break; | |||
| 3343 | } | |||
| 3344 | } | |||
| 3345 | } | |||
| 3346 | ||||
| 3347 | // Return a substring for the string w/o leading and/or trailing | |||
| 3348 | // whitespace | |||
| 3349 | ||||
| 3350 | return Substring(start, end); | |||
| 3351 | } | |||
| 3352 | ||||
| 3353 | // Declaring the templates we are going to use avoid linking issues without | |||
| 3354 | // inlining the method. Considering there is not so much spaces checking | |||
| 3355 | // methods we can consider this to be better than inlining. | |||
| 3356 | template const nsDependentSubstring | |||
| 3357 | nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(const nsAString&, bool); | |||
| 3358 | template const nsDependentSubstring nsContentUtils::TrimWhitespace< | |||
| 3359 | nsContentUtils::IsHTMLWhitespace>(const nsAString&, bool); | |||
| 3360 | template const nsDependentSubstring nsContentUtils::TrimWhitespace< | |||
| 3361 | nsContentUtils::IsHTMLWhitespaceOrNBSP>(const nsAString&, bool); | |||
| 3362 | ||||
| 3363 | static inline void KeyAppendSep(nsACString& aKey) { | |||
| 3364 | if (!aKey.IsEmpty()) { | |||
| 3365 | aKey.Append('>'); | |||
| 3366 | } | |||
| 3367 | } | |||
| 3368 | ||||
| 3369 | static inline void KeyAppendString(const nsAString& aString, nsACString& aKey) { | |||
| 3370 | KeyAppendSep(aKey); | |||
| 3371 | ||||
| 3372 | // Could escape separator here if collisions happen. > is not a legal char | |||
| 3373 | // for a name or type attribute, so we should be safe avoiding that extra | |||
| 3374 | // work. | |||
| 3375 | ||||
| 3376 | AppendUTF16toUTF8(aString, aKey); | |||
| 3377 | } | |||
| 3378 | ||||
| 3379 | static inline void KeyAppendString(const nsACString& aString, | |||
| 3380 | nsACString& aKey) { | |||
| 3381 | KeyAppendSep(aKey); | |||
| 3382 | ||||
| 3383 | // Could escape separator here if collisions happen. > is not a legal char | |||
| 3384 | // for a name or type attribute, so we should be safe avoiding that extra | |||
| 3385 | // work. | |||
| 3386 | ||||
| 3387 | aKey.Append(aString); | |||
| 3388 | } | |||
| 3389 | ||||
| 3390 | static inline void KeyAppendInt(int32_t aInt, nsACString& aKey) { | |||
| 3391 | KeyAppendSep(aKey); | |||
| 3392 | ||||
| 3393 | aKey.AppendInt(aInt); | |||
| 3394 | } | |||
| 3395 | ||||
| 3396 | static inline bool IsAutocompleteOff(const nsIContent* aContent) { | |||
| 3397 | return aContent->IsElement() && | |||
| 3398 | aContent->AsElement()->AttrValueIs(kNameSpaceID_None, | |||
| 3399 | nsGkAtoms::autocomplete, u"off"_ns, | |||
| 3400 | eIgnoreCase); | |||
| 3401 | } | |||
| 3402 | ||||
| 3403 | /*static*/ | |||
| 3404 | void nsContentUtils::GenerateStateKey(nsIContent* aContent, Document* aDocument, | |||
| 3405 | nsACString& aKey) { | |||
| 3406 | 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" , 3406); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent" ")" ); do { *((volatile int*)__null) = 3406; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 3407 | ||||
| 3408 | aKey.Truncate(); | |||
| 3409 | ||||
| 3410 | uint32_t partID = aDocument ? aDocument->GetPartID() : 0; | |||
| 3411 | ||||
| 3412 | // Don't capture state for anonymous content | |||
| 3413 | if (aContent->IsInNativeAnonymousSubtree()) { | |||
| 3414 | return; | |||
| 3415 | } | |||
| 3416 | ||||
| 3417 | if (IsAutocompleteOff(aContent)) { | |||
| 3418 | return; | |||
| 3419 | } | |||
| 3420 | ||||
| 3421 | RefPtr<Document> doc = aContent->GetUncomposedDoc(); | |||
| 3422 | ||||
| 3423 | KeyAppendInt(partID, aKey); // first append a partID | |||
| 3424 | bool generatedUniqueKey = false; | |||
| 3425 | ||||
| 3426 | if (doc && doc->IsHTMLOrXHTML()) { | |||
| 3427 | nsHTMLDocument* htmlDoc = doc->AsHTMLDocument(); | |||
| 3428 | ||||
| 3429 | // If we have a form control and can calculate form information, use that | |||
| 3430 | // as the key - it is more reliable than just recording position in the | |||
| 3431 | // DOM. | |||
| 3432 | // XXXbz Is it, really? We have bugs on this, I think... | |||
| 3433 | // Important to have a unique key, and tag/type/name may not be. | |||
| 3434 | // | |||
| 3435 | // The format of the key depends on whether the control has a form, | |||
| 3436 | // and whether the element was parser inserted: | |||
| 3437 | // | |||
| 3438 | // [Has Form, Parser Inserted]: | |||
| 3439 | // fp>type>FormNum>IndOfControlInForm>FormName>name | |||
| 3440 | // | |||
| 3441 | // [No Form, Parser Inserted]: | |||
| 3442 | // dp>type>ControlNum>name | |||
| 3443 | // | |||
| 3444 | // [Has Form, Not Parser Inserted]: | |||
| 3445 | // fn>type>IndOfFormInDoc>IndOfControlInForm>FormName>name | |||
| 3446 | // | |||
| 3447 | // [No Form, Not Parser Inserted]: | |||
| 3448 | // dn>type>IndOfControlInDoc>name | |||
| 3449 | // | |||
| 3450 | // XXX We don't need to use index if name is there | |||
| 3451 | // XXXbz We don't? Why not? I don't follow. | |||
| 3452 | // | |||
| 3453 | if (const auto* control = nsIFormControl::FromNode(aContent)) { | |||
| 3454 | // Get the control number if this was a parser inserted element from the | |||
| 3455 | // network. | |||
| 3456 | int32_t controlNumber = | |||
| 3457 | control->GetParserInsertedControlNumberForStateKey(); | |||
| 3458 | bool parserInserted = controlNumber != -1; | |||
| 3459 | ||||
| 3460 | RefPtr<nsContentList> htmlForms; | |||
| 3461 | RefPtr<nsContentList> htmlFormControls; | |||
| 3462 | if (!parserInserted) { | |||
| 3463 | // Getting these lists is expensive, as we need to keep them up to date | |||
| 3464 | // as the document loads, so we avoid it if we don't need them. | |||
| 3465 | htmlDoc->GetFormsAndFormControls(getter_AddRefs(htmlForms), | |||
| 3466 | getter_AddRefs(htmlFormControls)); | |||
| 3467 | } | |||
| 3468 | ||||
| 3469 | // Append the control type | |||
| 3470 | KeyAppendInt(int32_t(control->ControlType()), aKey); | |||
| 3471 | ||||
| 3472 | // If in a form, add form name / index of form / index in form | |||
| 3473 | HTMLFormElement* formElement = control->GetForm(); | |||
| 3474 | if (formElement) { | |||
| 3475 | if (IsAutocompleteOff(formElement)) { | |||
| 3476 | aKey.Truncate(); | |||
| 3477 | return; | |||
| 3478 | } | |||
| 3479 | ||||
| 3480 | // Append the form number, if this is a parser inserted control, or | |||
| 3481 | // the index of the form in the document otherwise. | |||
| 3482 | bool appendedForm = false; | |||
| 3483 | if (parserInserted) { | |||
| 3484 | 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" , 3486); 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) = 3486; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) | |||
| 3485 | "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" , 3486); 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) = 3486; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) | |||
| 3486 | "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" , 3486); 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) = 3486; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 3487 | KeyAppendString("fp"_ns, aKey); | |||
| 3488 | KeyAppendInt(formElement->GetFormNumberForStateKey(), aKey); | |||
| 3489 | appendedForm = true; | |||
| 3490 | } else { | |||
| 3491 | KeyAppendString("fn"_ns, aKey); | |||
| 3492 | int32_t index = htmlForms->IndexOf(formElement, false); | |||
| 3493 | if (index <= -1) { | |||
| 3494 | // | |||
| 3495 | // XXX HACK this uses some state that was dumped into the document | |||
| 3496 | // specifically to fix bug 138892. What we are trying to do is | |||
| 3497 | // *guess* which form this control's state is found in, with the | |||
| 3498 | // highly likely guess that the highest form parsed so far is the | |||
| 3499 | // one. This code should not be on trunk, only branch. | |||
| 3500 | // | |||
| 3501 | index = htmlDoc->GetNumFormsSynchronous() - 1; | |||
| 3502 | } | |||
| 3503 | if (index > -1) { | |||
| 3504 | KeyAppendInt(index, aKey); | |||
| 3505 | appendedForm = true; | |||
| 3506 | } | |||
| 3507 | } | |||
| 3508 | ||||
| 3509 | if (appendedForm) { | |||
| 3510 | // Append the index of the control in the form | |||
| 3511 | int32_t index = formElement->IndexOfContent(aContent); | |||
| 3512 | ||||
| 3513 | if (index > -1) { | |||
| 3514 | KeyAppendInt(index, aKey); | |||
| 3515 | generatedUniqueKey = true; | |||
| 3516 | } | |||
| 3517 | } | |||
| 3518 | ||||
| 3519 | // Append the form name | |||
| 3520 | nsAutoString formName; | |||
| 3521 | formElement->GetAttr(nsGkAtoms::name, formName); | |||
| 3522 | KeyAppendString(formName, aKey); | |||
| 3523 | } else { | |||
| 3524 | // Not in a form. Append the control number, if this is a parser | |||
| 3525 | // inserted control, or the index of the control in the document | |||
| 3526 | // otherwise. | |||
| 3527 | if (parserInserted) { | |||
| 3528 | KeyAppendString("dp"_ns, aKey); | |||
| 3529 | KeyAppendInt(control->GetParserInsertedControlNumberForStateKey(), | |||
| 3530 | aKey); | |||
| 3531 | generatedUniqueKey = true; | |||
| 3532 | } else { | |||
| 3533 | KeyAppendString("dn"_ns, aKey); | |||
| 3534 | int32_t index = htmlFormControls->IndexOf(aContent, true); | |||
| 3535 | if (index > -1) { | |||
| 3536 | KeyAppendInt(index, aKey); | |||
| 3537 | generatedUniqueKey = true; | |||
| 3538 | } | |||
| 3539 | } | |||
| 3540 | ||||
| 3541 | // Append the control name | |||
| 3542 | nsAutoString name; | |||
| 3543 | aContent->AsElement()->GetAttr(nsGkAtoms::name, name); | |||
| 3544 | KeyAppendString(name, aKey); | |||
| 3545 | } | |||
| 3546 | } | |||
| 3547 | } | |||
| 3548 | ||||
| 3549 | if (!generatedUniqueKey) { | |||
| 3550 | // Either we didn't have a form control or we aren't in an HTML document so | |||
| 3551 | // we can't figure out form info. Append the tag name if it's an element | |||
| 3552 | // to avoid restoring state for one type of element on another type. | |||
| 3553 | if (aContent->IsElement()) { | |||
| 3554 | KeyAppendString(nsDependentAtomString(aContent->NodeInfo()->NameAtom()), | |||
| 3555 | aKey); | |||
| 3556 | } else { | |||
| 3557 | // Append a character that is not "d" or "f" to disambiguate from | |||
| 3558 | // the case when we were a form control in an HTML document. | |||
| 3559 | KeyAppendString("o"_ns, aKey); | |||
| 3560 | } | |||
| 3561 | ||||
| 3562 | // Now start at aContent and append the indices of it and all its ancestors | |||
| 3563 | // in their containers. That should at least pin down its position in the | |||
| 3564 | // DOM... | |||
| 3565 | nsINode* parent = aContent->GetParentNode(); | |||
| 3566 | nsINode* content = aContent; | |||
| 3567 | while (parent) { | |||
| 3568 | KeyAppendInt(parent->ComputeIndexOf_Deprecated(content), aKey); | |||
| 3569 | content = parent; | |||
| 3570 | parent = content->GetParentNode(); | |||
| 3571 | } | |||
| 3572 | } | |||
| 3573 | } | |||
| 3574 | ||||
| 3575 | // static | |||
| 3576 | nsIPrincipal* nsContentUtils::SubjectPrincipal(JSContext* aCx) { | |||
| 3577 | 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" , 3577); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 3577; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 3578 | ||||
| 3579 | // As opposed to SubjectPrincipal(), we do in fact assume that | |||
| 3580 | // we're in a realm here; anyone who calls this function in | |||
| 3581 | // situations where that's not the case is doing it wrong. | |||
| 3582 | JS::Realm* realm = js::GetContextRealm(aCx); | |||
| 3583 | 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" , 3583); AnnotateMozCrashReason("MOZ_ASSERT" "(" "realm" ")") ; do { *((volatile int*)__null) = 3583; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 3584 | ||||
| 3585 | JSPrincipals* principals = JS::GetRealmPrincipals(realm); | |||
| 3586 | return nsJSPrincipals::get(principals); | |||
| 3587 | } | |||
| 3588 | ||||
| 3589 | // static | |||
| 3590 | nsIPrincipal* nsContentUtils::SubjectPrincipal() { | |||
| 3591 | 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" , 3591); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsInitialized()" ")"); do { *((volatile int*)__null) = 3591; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 3592 | 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" , 3592); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 3592; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 3593 | JSContext* cx = GetCurrentJSContext(); | |||
| 3594 | if (!cx) { | |||
| 3595 | 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" , 3597); AnnotateMozCrashReason("MOZ_CRASH(" "Accessing the Subject Principal without an AutoJSAPI on the stack is " "forbidden" ")"); do { *((volatile int*)__null) = 3597; __attribute__ ((nomerge)) ::abort(); } while (false); } while (false) | |||
| 3596 | "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" , 3597); AnnotateMozCrashReason("MOZ_CRASH(" "Accessing the Subject Principal without an AutoJSAPI on the stack is " "forbidden" ")"); do { *((volatile int*)__null) = 3597; __attribute__ ((nomerge)) ::abort(); } while (false); } while (false) | |||
| 3597 | "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" , 3597); AnnotateMozCrashReason("MOZ_CRASH(" "Accessing the Subject Principal without an AutoJSAPI on the stack is " "forbidden" ")"); do { *((volatile int*)__null) = 3597; __attribute__ ((nomerge)) ::abort(); } while (false); } while (false); | |||
| 3598 | } | |||
| 3599 | ||||
| 3600 | JS::Realm* realm = js::GetContextRealm(cx); | |||
| 3601 | ||||
| 3602 | // When an AutoJSAPI is instantiated, we are in a null realm until the | |||
| 3603 | // first JSAutoRealm, which is kind of a purgatory as far as permissions | |||
| 3604 | // go. It would be nice to just hard-abort if somebody does a security check | |||
| 3605 | // in this purgatory zone, but that would be too fragile, since it could be | |||
| 3606 | // triggered by random IsCallerChrome() checks 20-levels deep. | |||
| 3607 | // | |||
| 3608 | // So we want to return _something_ here - and definitely not the System | |||
| 3609 | // Principal, since that would make an AutoJSAPI a very dangerous thing to | |||
| 3610 | // instantiate. | |||
| 3611 | // | |||
| 3612 | // The natural thing to return is a null principal. Ideally, we'd return a | |||
| 3613 | // different null principal each time, to avoid any unexpected interactions | |||
| 3614 | // when the principal accidentally gets inherited somewhere. But | |||
| 3615 | // SubjectPrincipal doesn't return strong references, so there's no way to | |||
| 3616 | // sanely manage the lifetime of multiple null principals. | |||
| 3617 | // | |||
| 3618 | // So we use a singleton null principal. To avoid it being accidentally | |||
| 3619 | // inherited and becoming a "real" subject or object principal, we do a | |||
| 3620 | // release-mode assert during realm creation against using this principal on | |||
| 3621 | // an actual global. | |||
| 3622 | if (!realm) { | |||
| 3623 | return sNullSubjectPrincipal; | |||
| 3624 | } | |||
| 3625 | ||||
| 3626 | return SubjectPrincipal(cx); | |||
| 3627 | } | |||
| 3628 | ||||
| 3629 | // static | |||
| 3630 | nsIPrincipal* nsContentUtils::ObjectPrincipal(JSObject* aObj) { | |||
| 3631 | #ifdef DEBUG1 | |||
| 3632 | JS::AssertObjectBelongsToCurrentThread(aObj); | |||
| 3633 | #endif | |||
| 3634 | ||||
| 3635 | 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" , 3635); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!js::IsCrossCompartmentWrapper(aObj)" ")"); do { *((volatile int*)__null) = 3635; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 3636 | ||||
| 3637 | JS::Realm* realm = js::GetNonCCWObjectRealm(aObj); | |||
| 3638 | JSPrincipals* principals = JS::GetRealmPrincipals(realm); | |||
| 3639 | return nsJSPrincipals::get(principals); | |||
| 3640 | } | |||
| 3641 | ||||
| 3642 | // static | |||
| 3643 | nsresult nsContentUtils::NewURIWithDocumentCharset(nsIURI** aResult, | |||
| 3644 | const nsAString& aSpec, | |||
| 3645 | Document* aDocument, | |||
| 3646 | nsIURI* aBaseURI) { | |||
| 3647 | if (aDocument) { | |||
| 3648 | return NS_NewURI(aResult, aSpec, aDocument->GetDocumentCharacterSet(), | |||
| 3649 | aBaseURI); | |||
| 3650 | } | |||
| 3651 | return NS_NewURI(aResult, aSpec, nullptr, aBaseURI); | |||
| 3652 | } | |||
| 3653 | ||||
| 3654 | // static | |||
| 3655 | bool nsContentUtils::ContainsChar(nsAtom* aAtom, char aChar) { | |||
| 3656 | const uint32_t len = aAtom->GetLength(); | |||
| 3657 | if (!len) { | |||
| 3658 | return false; | |||
| 3659 | } | |||
| 3660 | const char16_t* name = aAtom->GetUTF16String(); | |||
| 3661 | uint32_t i = 0; | |||
| 3662 | while (i < len) { | |||
| 3663 | if (name[i] == aChar) { | |||
| 3664 | return true; | |||
| 3665 | } | |||
| 3666 | i++; | |||
| 3667 | } | |||
| 3668 | return false; | |||
| 3669 | } | |||
| 3670 | ||||
| 3671 | // static | |||
| 3672 | bool nsContentUtils::IsNameWithDash(nsAtom* aName) { | |||
| 3673 | // A valid custom element name is a sequence of characters name which | |||
| 3674 | // must match the PotentialCustomElementName production: | |||
| 3675 | // PotentialCustomElementName ::= [a-z] (PCENChar)* '-' (PCENChar)* | |||
| 3676 | const char16_t* name = aName->GetUTF16String(); | |||
| 3677 | uint32_t len = aName->GetLength(); | |||
| 3678 | bool hasDash = false; | |||
| 3679 | ||||
| 3680 | if (!len || name[0] < 'a' || name[0] > 'z') { | |||
| 3681 | return false; | |||
| 3682 | } | |||
| 3683 | ||||
| 3684 | uint32_t i = 1; | |||
| 3685 | while (i < len) { | |||
| 3686 | 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))) { | |||
| 3687 | // Merged two 16-bit surrogate pairs into code point. | |||
| 3688 | 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)); | |||
| 3689 | ||||
| 3690 | if (code < 0x10000 || code > 0xEFFFF) { | |||
| 3691 | return false; | |||
| 3692 | } | |||
| 3693 | ||||
| 3694 | i += 2; | |||
| 3695 | } else { | |||
| 3696 | if (name[i] == '-') { | |||
| 3697 | hasDash = true; | |||
| 3698 | } | |||
| 3699 | ||||
| 3700 | if (name[i] != '-' && name[i] != '.' && name[i] != '_' && | |||
| 3701 | name[i] != 0xB7 && (name[i] < '0' || name[i] > '9') && | |||
| 3702 | (name[i] < 'a' || name[i] > 'z') && | |||
| 3703 | (name[i] < 0xC0 || name[i] > 0xD6) && | |||
| 3704 | (name[i] < 0xF8 || name[i] > 0x37D) && | |||
| 3705 | (name[i] < 0x37F || name[i] > 0x1FFF) && | |||
| 3706 | (name[i] < 0x200C || name[i] > 0x200D) && | |||
| 3707 | (name[i] < 0x203F || name[i] > 0x2040) && | |||
| 3708 | (name[i] < 0x2070 || name[i] > 0x218F) && | |||
| 3709 | (name[i] < 0x2C00 || name[i] > 0x2FEF) && | |||
| 3710 | (name[i] < 0x3001 || name[i] > 0xD7FF) && | |||
| 3711 | (name[i] < 0xF900 || name[i] > 0xFDCF) && | |||
| 3712 | (name[i] < 0xFDF0 || name[i] > 0xFFFD)) { | |||
| 3713 | return false; | |||
| 3714 | } | |||
| 3715 | ||||
| 3716 | i++; | |||
| 3717 | } | |||
| 3718 | } | |||
| 3719 | ||||
| 3720 | return hasDash; | |||
| 3721 | } | |||
| 3722 | ||||
| 3723 | // static | |||
| 3724 | bool nsContentUtils::IsCustomElementName(nsAtom* aName, uint32_t aNameSpaceID) { | |||
| 3725 | // Allow non-dashed names in XUL for XBL to Custom Element migrations. | |||
| 3726 | if (aNameSpaceID == kNameSpaceID_XUL8) { | |||
| 3727 | return true; | |||
| 3728 | } | |||
| 3729 | ||||
| 3730 | bool hasDash = IsNameWithDash(aName); | |||
| 3731 | if (!hasDash) { | |||
| 3732 | return false; | |||
| 3733 | } | |||
| 3734 | ||||
| 3735 | // The custom element name must not be one of the following values: | |||
| 3736 | // annotation-xml | |||
| 3737 | // color-profile | |||
| 3738 | // font-face | |||
| 3739 | // font-face-src | |||
| 3740 | // font-face-uri | |||
| 3741 | // font-face-format | |||
| 3742 | // font-face-name | |||
| 3743 | // missing-glyph | |||
| 3744 | return aName != nsGkAtoms::annotation_xml_ && | |||
| 3745 | aName != nsGkAtoms::colorProfile && aName != nsGkAtoms::font_face && | |||
| 3746 | aName != nsGkAtoms::font_face_src && | |||
| 3747 | aName != nsGkAtoms::font_face_uri && | |||
| 3748 | aName != nsGkAtoms::font_face_format && | |||
| 3749 | aName != nsGkAtoms::font_face_name && aName != nsGkAtoms::missingGlyph; | |||
| 3750 | } | |||
| 3751 | ||||
| 3752 | // static | |||
| 3753 | nsresult nsContentUtils::CheckQName(const nsAString& aQualifiedName, | |||
| 3754 | bool aNamespaceAware, | |||
| 3755 | const char16_t** aColon) { | |||
| 3756 | const char* colon = nullptr; | |||
| 3757 | const char16_t* begin = aQualifiedName.BeginReading(); | |||
| 3758 | const char16_t* end = aQualifiedName.EndReading(); | |||
| 3759 | ||||
| 3760 | int result = MOZ_XMLCheckQName(reinterpret_cast<const char*>(begin), | |||
| 3761 | reinterpret_cast<const char*>(end), | |||
| 3762 | aNamespaceAware, &colon); | |||
| 3763 | ||||
| 3764 | if (!result) { | |||
| 3765 | if (aColon) { | |||
| 3766 | *aColon = reinterpret_cast<const char16_t*>(colon); | |||
| 3767 | } | |||
| 3768 | ||||
| 3769 | return NS_OK; | |||
| 3770 | } | |||
| 3771 | ||||
| 3772 | return NS_ERROR_DOM_INVALID_CHARACTER_ERR; | |||
| 3773 | } | |||
| 3774 | ||||
| 3775 | // static | |||
| 3776 | nsresult nsContentUtils::SplitQName(const nsIContent* aNamespaceResolver, | |||
| 3777 | const nsString& aQName, int32_t* aNamespace, | |||
| 3778 | nsAtom** aLocalName) { | |||
| 3779 | const char16_t* colon; | |||
| 3780 | nsresult rv = nsContentUtils::CheckQName(aQName, true, &colon); | |||
| 3781 | 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" , 3781); return rv; } } while (false); | |||
| 3782 | ||||
| 3783 | if (colon) { | |||
| 3784 | const char16_t* end; | |||
| 3785 | aQName.EndReading(end); | |||
| 3786 | nsAutoString nameSpace; | |||
| 3787 | rv = aNamespaceResolver->LookupNamespaceURIInternal( | |||
| 3788 | Substring(aQName.get(), colon), nameSpace); | |||
| 3789 | 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" , 3789); return rv; } } while (false); | |||
| 3790 | ||||
| 3791 | *aNamespace = nsNameSpaceManager::GetInstance()->GetNameSpaceID( | |||
| 3792 | nameSpace, nsContentUtils::IsChromeDoc(aNamespaceResolver->OwnerDoc())); | |||
| 3793 | if (*aNamespace == kNameSpaceID_Unknown-1) return NS_ERROR_FAILURE; | |||
| 3794 | ||||
| 3795 | *aLocalName = NS_AtomizeMainThread(Substring(colon + 1, end)).take(); | |||
| 3796 | } else { | |||
| 3797 | *aNamespace = kNameSpaceID_None; | |||
| 3798 | *aLocalName = NS_AtomizeMainThread(aQName).take(); | |||
| 3799 | } | |||
| 3800 | 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" , 3800); return NS_ERROR_OUT_OF_MEMORY; } } while (false); | |||
| 3801 | return NS_OK; | |||
| 3802 | } | |||
| 3803 | ||||
| 3804 | // static | |||
| 3805 | nsresult nsContentUtils::GetNodeInfoFromQName( | |||
| 3806 | const nsAString& aNamespaceURI, const nsAString& aQualifiedName, | |||
| 3807 | nsNodeInfoManager* aNodeInfoManager, uint16_t aNodeType, | |||
| 3808 | mozilla::dom::NodeInfo** aNodeInfo) { | |||
| 3809 | const nsString& qName = PromiseFlatStringTPromiseFlatString<char16_t>(aQualifiedName); | |||
| 3810 | const char16_t* colon; | |||
| 3811 | nsresult rv = nsContentUtils::CheckQName(qName, true, &colon); | |||
| 3812 | 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" , 3812); return rv; } } while (false); | |||
| 3813 | ||||
| 3814 | int32_t nsID; | |||
| 3815 | nsNameSpaceManager::GetInstance()->RegisterNameSpace(aNamespaceURI, nsID); | |||
| 3816 | if (colon) { | |||
| 3817 | const char16_t* end; | |||
| 3818 | qName.EndReading(end); | |||
| 3819 | ||||
| 3820 | RefPtr<nsAtom> prefix = NS_AtomizeMainThread(Substring(qName.get(), colon)); | |||
| 3821 | ||||
| 3822 | rv = aNodeInfoManager->GetNodeInfo(Substring(colon + 1, end), prefix, nsID, | |||
| 3823 | aNodeType, aNodeInfo); | |||
| 3824 | } else { | |||
| 3825 | rv = aNodeInfoManager->GetNodeInfo(aQualifiedName, nullptr, nsID, aNodeType, | |||
| 3826 | aNodeInfo); | |||
| 3827 | } | |||
| 3828 | 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" , 3828); return rv; } } while (false); | |||
| 3829 | ||||
| 3830 | return nsContentUtils::IsValidNodeName((*aNodeInfo)->NameAtom(), | |||
| 3831 | (*aNodeInfo)->GetPrefixAtom(), | |||
| 3832 | (*aNodeInfo)->NamespaceID()) | |||
| 3833 | ? NS_OK | |||
| 3834 | : NS_ERROR_DOM_NAMESPACE_ERR; | |||
| 3835 | } | |||
| 3836 | ||||
| 3837 | // static | |||
| 3838 | void nsContentUtils::SplitExpatName(const char16_t* aExpatName, | |||
| 3839 | nsAtom** aPrefix, nsAtom** aLocalName, | |||
| 3840 | int32_t* aNameSpaceID) { | |||
| 3841 | /** | |||
| 3842 | * Expat can send the following: | |||
| 3843 | * localName | |||
| 3844 | * namespaceURI<separator>localName | |||
| 3845 | * namespaceURI<separator>localName<separator>prefix | |||
| 3846 | * | |||
| 3847 | * and we use 0xFFFF for the <separator>. | |||
| 3848 | * | |||
| 3849 | */ | |||
| 3850 | ||||
| 3851 | const char16_t* uriEnd = nullptr; | |||
| 3852 | const char16_t* nameEnd = nullptr; | |||
| 3853 | const char16_t* pos; | |||
| 3854 | for (pos = aExpatName; *pos; ++pos) { | |||
| 3855 | if (*pos == 0xFFFF) { | |||
| 3856 | if (uriEnd) { | |||
| 3857 | nameEnd = pos; | |||
| 3858 | } else { | |||
| 3859 | uriEnd = pos; | |||
| 3860 | } | |||
| 3861 | } | |||
| 3862 | } | |||
| 3863 | ||||
| 3864 | const char16_t* nameStart; | |||
| 3865 | if (uriEnd) { | |||
| 3866 | nsNameSpaceManager::GetInstance()->RegisterNameSpace( | |||
| 3867 | nsDependentSubstring(aExpatName, uriEnd), *aNameSpaceID); | |||
| 3868 | ||||
| 3869 | nameStart = (uriEnd + 1); | |||
| 3870 | if (nameEnd) { | |||
| 3871 | const char16_t* prefixStart = nameEnd + 1; | |||
| 3872 | *aPrefix = NS_AtomizeMainThread(Substring(prefixStart, pos)).take(); | |||
| 3873 | } else { | |||
| 3874 | nameEnd = pos; | |||
| 3875 | *aPrefix = nullptr; | |||
| 3876 | } | |||
| 3877 | } else { | |||
| 3878 | *aNameSpaceID = kNameSpaceID_None; | |||
| 3879 | nameStart = aExpatName; | |||
| 3880 | nameEnd = pos; | |||
| 3881 | *aPrefix = nullptr; | |||
| 3882 | } | |||
| 3883 | *aLocalName = NS_AtomizeMainThread(Substring(nameStart, nameEnd)).take(); | |||
| 3884 | } | |||
| 3885 | ||||
| 3886 | // static | |||
| 3887 | PresShell* nsContentUtils::GetPresShellForContent(const nsIContent* aContent) { | |||
| 3888 | Document* doc = aContent->GetComposedDoc(); | |||
| 3889 | if (!doc) { | |||
| 3890 | return nullptr; | |||
| 3891 | } | |||
| 3892 | return doc->GetPresShell(); | |||
| 3893 | } | |||
| 3894 | ||||
| 3895 | // static | |||
| 3896 | nsPresContext* nsContentUtils::GetContextForContent( | |||
| 3897 | const nsIContent* aContent) { | |||
| 3898 | PresShell* presShell = GetPresShellForContent(aContent); | |||
| 3899 | if (!presShell) { | |||
| 3900 | return nullptr; | |||
| 3901 | } | |||
| 3902 | return presShell->GetPresContext(); | |||
| 3903 | } | |||
| 3904 | ||||
| 3905 | // static | |||
| 3906 | bool nsContentUtils::IsInPrivateBrowsing(nsILoadGroup* aLoadGroup) { | |||
| 3907 | if (!aLoadGroup) { | |||
| 3908 | return false; | |||
| 3909 | } | |||
| 3910 | // See duplicated code in Document::Reset/ResetToURI | |||
| 3911 | bool isPrivate = false; | |||
| 3912 | nsCOMPtr<nsIInterfaceRequestor> callbacks; | |||
| 3913 | aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks)); | |||
| 3914 | if (callbacks) { | |||
| 3915 | nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks); | |||
| 3916 | isPrivate = loadContext && loadContext->UsePrivateBrowsing(); | |||
| 3917 | } | |||
| 3918 | return isPrivate; | |||
| 3919 | } | |||
| 3920 | ||||
| 3921 | // FIXME(emilio): This is (effectively) almost but not quite the same as | |||
| 3922 | // Document::ShouldLoadImages(), which one is right? | |||
| 3923 | bool nsContentUtils::DocumentInactiveForImageLoads(Document* aDocument) { | |||
| 3924 | if (!aDocument) { | |||
| 3925 | return false; | |||
| 3926 | } | |||
| 3927 | if (IsChromeDoc(aDocument) || aDocument->IsResourceDoc() || | |||
| 3928 | aDocument->IsStaticDocument()) { | |||
| 3929 | return false; | |||
| 3930 | } | |||
| 3931 | nsCOMPtr<nsPIDOMWindowInner> win = | |||
| 3932 | do_QueryInterface(aDocument->GetScopeObject()); | |||
| 3933 | return !win || !win->GetDocShell(); | |||
| 3934 | } | |||
| 3935 | ||||
| 3936 | imgLoader* nsContentUtils::GetImgLoaderForDocument(Document* aDoc) { | |||
| 3937 | 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" , 3937); return nullptr; } } while (false); | |||
| 3938 | ||||
| 3939 | if (!aDoc) { | |||
| 3940 | return imgLoader::NormalLoader(); | |||
| 3941 | } | |||
| 3942 | const bool isPrivate = aDoc->IsInPrivateBrowsing(); | |||
| 3943 | return isPrivate ? imgLoader::PrivateBrowsingLoader() | |||
| 3944 | : imgLoader::NormalLoader(); | |||
| 3945 | } | |||
| 3946 | ||||
| 3947 | // static | |||
| 3948 | imgLoader* nsContentUtils::GetImgLoaderForChannel(nsIChannel* aChannel, | |||
| 3949 | Document* aContext) { | |||
| 3950 | 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" , 3950); return nullptr; } } while (false); | |||
| 3951 | ||||
| 3952 | if (!aChannel) { | |||
| 3953 | return imgLoader::NormalLoader(); | |||
| 3954 | } | |||
| 3955 | return NS_UsePrivateBrowsing(aChannel) ? imgLoader::PrivateBrowsingLoader() | |||
| 3956 | : imgLoader::NormalLoader(); | |||
| 3957 | } | |||
| 3958 | ||||
| 3959 | // static | |||
| 3960 | int32_t nsContentUtils::CORSModeToLoadImageFlags(mozilla::CORSMode aMode) { | |||
| 3961 | switch (aMode) { | |||
| 3962 | case CORS_ANONYMOUS: | |||
| 3963 | return imgILoader::LOAD_CORS_ANONYMOUS; | |||
| 3964 | case CORS_USE_CREDENTIALS: | |||
| 3965 | return imgILoader::LOAD_CORS_USE_CREDENTIALS; | |||
| 3966 | default: | |||
| 3967 | return 0; | |||
| 3968 | } | |||
| 3969 | } | |||
| 3970 | ||||
| 3971 | // static | |||
| 3972 | nsresult nsContentUtils::LoadImage( | |||
| 3973 | nsIURI* aURI, nsINode* aContext, Document* aLoadingDocument, | |||
| 3974 | nsIPrincipal* aLoadingPrincipal, uint64_t aRequestContextID, | |||
| 3975 | nsIReferrerInfo* aReferrerInfo, imgINotificationObserver* aObserver, | |||
| 3976 | int32_t aLoadFlags, const nsAString& initiatorType, | |||
| 3977 | imgRequestProxy** aRequest, nsContentPolicyType aContentPolicyType, | |||
| 3978 | bool aUseUrgentStartForChannel, bool aLinkPreload, | |||
| 3979 | uint64_t aEarlyHintPreloaderId, | |||
| 3980 | mozilla::dom::FetchPriority aFetchPriority) { | |||
| 3981 | 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" , 3981); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aURI" ") (" "Must have a URI" ")"); do { *((volatile int*)__null) = 3981 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 3982 | 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" , 3982); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContext" ") (" "Must have a context" ")"); do { *((volatile int*)__null) = 3982 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 3983 | 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" , 3983); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadingDocument" ") (" "Must have a document" ")"); do { *((volatile int*)__null ) = 3983; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); | |||
| 3984 | 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" , 3984); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadingPrincipal" ") (" "Must have a principal" ")"); do { *((volatile int*)__null ) = 3984; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); | |||
| 3985 | 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" , 3985); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRequest" ") (" "Null out param" ")"); do { *((volatile int*)__null) = 3985; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 3986 | ||||
| 3987 | imgLoader* imgLoader = GetImgLoaderForDocument(aLoadingDocument); | |||
| 3988 | if (!imgLoader) { | |||
| 3989 | // nothing we can do here | |||
| 3990 | return NS_ERROR_FAILURE; | |||
| 3991 | } | |||
| 3992 | ||||
| 3993 | nsCOMPtr<nsILoadGroup> loadGroup = aLoadingDocument->GetDocumentLoadGroup(); | |||
| 3994 | ||||
| 3995 | nsIURI* documentURI = aLoadingDocument->GetDocumentURI(); | |||
| 3996 | ||||
| 3997 | 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" , 3998); MOZ_PretendNoReturn(); } } while (0) | |||
| 3998 | "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" , 3998); MOZ_PretendNoReturn(); } } while (0); | |||
| 3999 | ||||
| 4000 | // XXXbz using "documentURI" for the initialDocumentURI is not quite | |||
| 4001 | // right, but the best we can do here... | |||
| 4002 | return imgLoader->LoadImage(aURI, /* uri to load */ | |||
| 4003 | documentURI, /* initialDocumentURI */ | |||
| 4004 | aReferrerInfo, /* referrerInfo */ | |||
| 4005 | aLoadingPrincipal, /* loading principal */ | |||
| 4006 | aRequestContextID, /* request context ID */ | |||
| 4007 | loadGroup, /* loadgroup */ | |||
| 4008 | aObserver, /* imgINotificationObserver */ | |||
| 4009 | aContext, /* loading context */ | |||
| 4010 | aLoadingDocument, /* uniquification key */ | |||
| 4011 | aLoadFlags, /* load flags */ | |||
| 4012 | nullptr, /* cache key */ | |||
| 4013 | aContentPolicyType, /* content policy type */ | |||
| 4014 | initiatorType, /* the load initiator */ | |||
| 4015 | aUseUrgentStartForChannel, /* urgent-start flag */ | |||
| 4016 | aLinkPreload, /* <link preload> initiator */ | |||
| 4017 | aEarlyHintPreloaderId, aFetchPriority, aRequest); | |||
| 4018 | } | |||
| 4019 | ||||
| 4020 | // static | |||
| 4021 | already_AddRefed<imgIContainer> nsContentUtils::GetImageFromContent( | |||
| 4022 | nsIImageLoadingContent* aContent, imgIRequest** aRequest) { | |||
| 4023 | if (aRequest) { | |||
| 4024 | *aRequest = nullptr; | |||
| 4025 | } | |||
| 4026 | ||||
| 4027 | 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" , 4027); return nullptr; } } while (false); | |||
| 4028 | ||||
| 4029 | nsCOMPtr<imgIRequest> imgRequest; | |||
| 4030 | aContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, | |||
| 4031 | getter_AddRefs(imgRequest)); | |||
| 4032 | if (!imgRequest) { | |||
| 4033 | return nullptr; | |||
| 4034 | } | |||
| 4035 | ||||
| 4036 | nsCOMPtr<imgIContainer> imgContainer; | |||
| 4037 | imgRequest->GetImage(getter_AddRefs(imgContainer)); | |||
| 4038 | ||||
| 4039 | if (!imgContainer) { | |||
| 4040 | return nullptr; | |||
| 4041 | } | |||
| 4042 | ||||
| 4043 | if (aRequest) { | |||
| 4044 | // If the consumer wants the request, verify it has actually loaded | |||
| 4045 | // successfully. | |||
| 4046 | uint32_t imgStatus; | |||
| 4047 | imgRequest->GetImageStatus(&imgStatus); | |||
| 4048 | if (imgStatus & imgIRequest::STATUS_FRAME_COMPLETE && | |||
| 4049 | !(imgStatus & imgIRequest::STATUS_ERROR)) { | |||
| 4050 | imgRequest.swap(*aRequest); | |||
| 4051 | } | |||
| 4052 | } | |||
| 4053 | ||||
| 4054 | return imgContainer.forget(); | |||
| 4055 | } | |||
| 4056 | ||||
| 4057 | static bool IsLinkWithURI(const nsIContent& aContent) { | |||
| 4058 | const auto* element = Element::FromNode(aContent); | |||
| 4059 | if (!element || !element->IsLink()) { | |||
| 4060 | return false; | |||
| 4061 | } | |||
| 4062 | nsCOMPtr<nsIURI> absURI = element->GetHrefURI(); | |||
| 4063 | return !!absURI; | |||
| 4064 | } | |||
| 4065 | ||||
| 4066 | static bool HasImageRequest(nsIContent& aContent) { | |||
| 4067 | nsCOMPtr<nsIImageLoadingContent> imageContent(do_QueryInterface(&aContent)); | |||
| 4068 | if (!imageContent) { | |||
| 4069 | return false; | |||
| 4070 | } | |||
| 4071 | ||||
| 4072 | nsCOMPtr<imgIRequest> imgRequest; | |||
| 4073 | imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, | |||
| 4074 | getter_AddRefs(imgRequest)); | |||
| 4075 | ||||
| 4076 | // XXXbz It may be draggable even if the request resulted in an error. Why? | |||
| 4077 | // Not sure; that's what the old nsContentAreaDragDrop/nsFrame code did. | |||
| 4078 | return !!imgRequest; | |||
| 4079 | } | |||
| 4080 | ||||
| 4081 | static Maybe<bool> DraggableOverride(const nsIContent& aContent) { | |||
| 4082 | if (auto* el = nsGenericHTMLElement::FromNode(aContent)) { | |||
| 4083 | if (el->Draggable()) { | |||
| 4084 | return Some(true); | |||
| 4085 | } | |||
| 4086 | ||||
| 4087 | if (el->AttrValueIs(kNameSpaceID_None, nsGkAtoms::draggable, | |||
| 4088 | nsGkAtoms::_false, eIgnoreCase)) { | |||
| 4089 | return Some(false); | |||
| 4090 | } | |||
| 4091 | } | |||
| 4092 | if (aContent.IsSVGElement()) { | |||
| 4093 | return Some(false); | |||
| 4094 | } | |||
| 4095 | return Nothing(); | |||
| 4096 | } | |||
| 4097 | ||||
| 4098 | // static | |||
| 4099 | bool nsContentUtils::ContentIsDraggable(nsIContent* aContent) { | |||
| 4100 | 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" , 4100); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent" ")" ); do { *((volatile int*)__null) = 4100; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 4101 | ||||
| 4102 | if (auto draggable = DraggableOverride(*aContent)) { | |||
| 4103 | return *draggable; | |||
| 4104 | } | |||
| 4105 | ||||
| 4106 | // special handling for content area image and link dragging | |||
| 4107 | return HasImageRequest(*aContent) || IsLinkWithURI(*aContent); | |||
| 4108 | } | |||
| 4109 | ||||
| 4110 | // static | |||
| 4111 | bool nsContentUtils::IsDraggableImage(nsIContent* aContent) { | |||
| 4112 | 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" , 4112); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent" ")" ); do { *((volatile int*)__null) = 4112; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 4113 | return HasImageRequest(*aContent) && | |||
| 4114 | DraggableOverride(*aContent).valueOr(true); | |||
| 4115 | } | |||
| 4116 | ||||
| 4117 | // static | |||
| 4118 | bool nsContentUtils::IsDraggableLink(const nsIContent* aContent) { | |||
| 4119 | 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" , 4119); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent" ")" ); do { *((volatile int*)__null) = 4119; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 4120 | return IsLinkWithURI(*aContent) && DraggableOverride(*aContent).valueOr(true); | |||
| 4121 | } | |||
| 4122 | ||||
| 4123 | // static | |||
| 4124 | nsresult nsContentUtils::QNameChanged(mozilla::dom::NodeInfo* aNodeInfo, | |||
| 4125 | nsAtom* aName, | |||
| 4126 | mozilla::dom::NodeInfo** aResult) { | |||
| 4127 | nsNodeInfoManager* niMgr = aNodeInfo->NodeInfoManager(); | |||
| 4128 | ||||
| 4129 | *aResult = niMgr | |||
| 4130 | ->GetNodeInfo(aName, nullptr, aNodeInfo->NamespaceID(), | |||
| 4131 | aNodeInfo->NodeType(), aNodeInfo->GetExtraName()) | |||
| 4132 | .take(); | |||
| 4133 | return NS_OK; | |||
| 4134 | } | |||
| 4135 | ||||
| 4136 | static bool TestSitePerm(nsIPrincipal* aPrincipal, const nsACString& aType, | |||
| 4137 | uint32_t aPerm, bool aExactHostMatch) { | |||
| 4138 | if (!aPrincipal) { | |||
| 4139 | // We always deny (i.e. don't allow) the permission if we don't have a | |||
| 4140 | // principal. | |||
| 4141 | return aPerm != nsIPermissionManager::ALLOW_ACTION; | |||
| 4142 | } | |||
| 4143 | ||||
| 4144 | nsCOMPtr<nsIPermissionManager> permMgr = | |||
| 4145 | components::PermissionManager::Service(); | |||
| 4146 | 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" , 4146); return false; } } while (false); | |||
| 4147 | ||||
| 4148 | uint32_t perm; | |||
| 4149 | nsresult rv; | |||
| 4150 | if (aExactHostMatch) { | |||
| 4151 | rv = permMgr->TestExactPermissionFromPrincipal(aPrincipal, aType, &perm); | |||
| 4152 | } else { | |||
| 4153 | rv = permMgr->TestPermissionFromPrincipal(aPrincipal, aType, &perm); | |||
| 4154 | } | |||
| 4155 | 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" , 4155); return false; } } while (false); | |||
| 4156 | ||||
| 4157 | return perm == aPerm; | |||
| 4158 | } | |||
| 4159 | ||||
| 4160 | bool nsContentUtils::IsSitePermAllow(nsIPrincipal* aPrincipal, | |||
| 4161 | const nsACString& aType) { | |||
| 4162 | return TestSitePerm(aPrincipal, aType, nsIPermissionManager::ALLOW_ACTION, | |||
| 4163 | false); | |||
| 4164 | } | |||
| 4165 | ||||
| 4166 | bool nsContentUtils::IsSitePermDeny(nsIPrincipal* aPrincipal, | |||
| 4167 | const nsACString& aType) { | |||
| 4168 | return TestSitePerm(aPrincipal, aType, nsIPermissionManager::DENY_ACTION, | |||
| 4169 | false); | |||
| 4170 | } | |||
| 4171 | ||||
| 4172 | bool nsContentUtils::IsExactSitePermAllow(nsIPrincipal* aPrincipal, | |||
| 4173 | const nsACString& aType) { | |||
| 4174 | return TestSitePerm(aPrincipal, aType, nsIPermissionManager::ALLOW_ACTION, | |||
| 4175 | true); | |||
| 4176 | } | |||
| 4177 | ||||
| 4178 | bool nsContentUtils::IsExactSitePermDeny(nsIPrincipal* aPrincipal, | |||
| 4179 | const nsACString& aType) { | |||
| 4180 | return TestSitePerm(aPrincipal, aType, nsIPermissionManager::DENY_ACTION, | |||
| 4181 | true); | |||
| 4182 | } | |||
| 4183 | ||||
| 4184 | bool nsContentUtils::HasSitePerm(nsIPrincipal* aPrincipal, | |||
| 4185 | const nsACString& aType) { | |||
| 4186 | if (!aPrincipal) { | |||
| 4187 | return false; | |||
| 4188 | } | |||
| 4189 | ||||
| 4190 | nsCOMPtr<nsIPermissionManager> permMgr = | |||
| 4191 | components::PermissionManager::Service(); | |||
| 4192 | 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" , 4192); return false; } } while (false); | |||
| 4193 | ||||
| 4194 | uint32_t perm; | |||
| 4195 | nsresult rv = permMgr->TestPermissionFromPrincipal(aPrincipal, aType, &perm); | |||
| 4196 | 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" , 4196); return false; } } while (false); | |||
| 4197 | ||||
| 4198 | return perm != nsIPermissionManager::UNKNOWN_ACTION; | |||
| 4199 | } | |||
| 4200 | ||||
| 4201 | static const char* gEventNames[] = {"event"}; | |||
| 4202 | static const char* gSVGEventNames[] = {"evt"}; | |||
| 4203 | // for b/w compat, the first name to onerror is still 'event', even though it | |||
| 4204 | // is actually the error message | |||
| 4205 | static const char* gOnErrorNames[] = {"event", "source", "lineno", "colno", | |||
| 4206 | "error"}; | |||
| 4207 | ||||
| 4208 | // static | |||
| 4209 | void nsContentUtils::GetEventArgNames(int32_t aNameSpaceID, nsAtom* aEventName, | |||
| 4210 | bool aIsForWindow, uint32_t* aArgCount, | |||
| 4211 | const char*** aArgArray) { | |||
| 4212 | #define SET_EVENT_ARG_NAMES(names)*aArgCount = sizeof(names) / sizeof(names[0]); *aArgArray = names ; \ | |||
| 4213 | *aArgCount = sizeof(names) / sizeof(names[0]); \ | |||
| 4214 | *aArgArray = names; | |||
| 4215 | ||||
| 4216 | // JSEventHandler is what does the arg magic for onerror, and it does | |||
| 4217 | // not seem to take the namespace into account. So we let onerror in all | |||
| 4218 | // namespaces get the 3 arg names. | |||
| 4219 | if (aEventName == nsGkAtoms::onerror && aIsForWindow) { | |||
| 4220 | SET_EVENT_ARG_NAMES(gOnErrorNames)*aArgCount = sizeof(gOnErrorNames) / sizeof(gOnErrorNames[0]) ; *aArgArray = gOnErrorNames;; | |||
| 4221 | } else if (aNameSpaceID == kNameSpaceID_SVG9) { | |||
| 4222 | SET_EVENT_ARG_NAMES(gSVGEventNames)*aArgCount = sizeof(gSVGEventNames) / sizeof(gSVGEventNames[0 ]); *aArgArray = gSVGEventNames;; | |||
| 4223 | } else { | |||
| 4224 | SET_EVENT_ARG_NAMES(gEventNames)*aArgCount = sizeof(gEventNames) / sizeof(gEventNames[0]); *aArgArray = gEventNames;; | |||
| 4225 | } | |||
| 4226 | } | |||
| 4227 | ||||
| 4228 | // Note: The list of content bundles in nsStringBundle.cpp should be updated | |||
| 4229 | // whenever entries are added or removed from this list. | |||
| 4230 | static const char* gPropertiesFiles[nsContentUtils::PropertiesFile_COUNT] = { | |||
| 4231 | // Must line up with the enum values in |PropertiesFile| enum. | |||
| 4232 | "chrome://global/locale/css.properties", | |||
| 4233 | "chrome://global/locale/xul.properties", | |||
| 4234 | "chrome://global/locale/layout_errors.properties", | |||
| 4235 | "chrome://global/locale/layout/HtmlForm.properties", | |||
| 4236 | "chrome://global/locale/printing.properties", | |||
| 4237 | "chrome://global/locale/dom/dom.properties", | |||
| 4238 | "chrome://global/locale/layout/htmlparser.properties", | |||
| 4239 | "chrome://global/locale/svg/svg.properties", | |||
| 4240 | "chrome://branding/locale/brand.properties", | |||
| 4241 | "chrome://global/locale/commonDialogs.properties", | |||
| 4242 | "chrome://global/locale/mathml/mathml.properties", | |||
| 4243 | "chrome://global/locale/security/security.properties", | |||
| 4244 | "chrome://necko/locale/necko.properties", | |||
| 4245 | "resource://gre/res/locale/layout/HtmlForm.properties", | |||
| 4246 | "resource://gre/res/locale/dom/dom.properties"}; | |||
| 4247 | ||||
| 4248 | /* static */ | |||
| 4249 | nsresult nsContentUtils::EnsureStringBundle(PropertiesFile aFile) { | |||
| 4250 | 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" , 4251); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "NS_IsMainThread()" ") (" "Should not create bundles off main thread." ")"); do { *((volatile int*)__null) = 4251; __attribute__((nomerge)) :: abort(); } while (false); } } while (false) | |||
| 4251 | "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" , 4251); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "NS_IsMainThread()" ") (" "Should not create bundles off main thread." ")"); do { *((volatile int*)__null) = 4251; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); | |||
| 4252 | if (!sStringBundles[aFile]) { | |||
| 4253 | if (!sStringBundleService) { | |||
| 4254 | nsresult rv = | |||
| 4255 | CallGetService(NS_STRINGBUNDLE_CONTRACTID"@mozilla.org/intl/stringbundle;1", &sStringBundleService); | |||
| 4256 | 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" , 4256); return rv; } } while (false); | |||
| 4257 | } | |||
| 4258 | RefPtr<nsIStringBundle> bundle; | |||
| 4259 | 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) | |||
| 4260 | 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); | |||
| 4261 | sStringBundles[aFile] = bundle.forget(); | |||
| 4262 | } | |||
| 4263 | return NS_OK; | |||
| 4264 | } | |||
| 4265 | ||||
| 4266 | /* static */ | |||
| 4267 | void nsContentUtils::AsyncPrecreateStringBundles() { | |||
| 4268 | // We only ever want to pre-create bundles in the parent process. | |||
| 4269 | // | |||
| 4270 | // All nsContentUtils bundles are shared between the parent and child | |||
| 4271 | // precesses, and the shared memory regions that back them *must* be created | |||
| 4272 | // in the parent, and then sent to all children. | |||
| 4273 | // | |||
| 4274 | // If we attempt to create a bundle in the child before its memory region is | |||
| 4275 | // available, we need to create a temporary non-shared bundle, and later | |||
| 4276 | // replace that with the shared memory copy. So attempting to pre-load in the | |||
| 4277 | // child is wasteful and unnecessary. | |||
| 4278 | 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" , 4278); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 4278; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 4279 | ||||
| 4280 | for (uint32_t bundleIndex = 0; bundleIndex < PropertiesFile_COUNT; | |||
| 4281 | ++bundleIndex) { | |||
| 4282 | nsresult rv = NS_DispatchToCurrentThreadQueue( | |||
| 4283 | NS_NewRunnableFunction("AsyncPrecreateStringBundles", | |||
| 4284 | [bundleIndex]() { | |||
| 4285 | PropertiesFile file = | |||
| 4286 | static_cast<PropertiesFile>(bundleIndex); | |||
| 4287 | EnsureStringBundle(file); | |||
| 4288 | nsIStringBundle* bundle = sStringBundles[file]; | |||
| 4289 | bundle->AsyncPreload(); | |||
| 4290 | }), | |||
| 4291 | EventQueuePriority::Idle); | |||
| 4292 | 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" , 4292); | |||
| 4293 | } | |||
| 4294 | } | |||
| 4295 | ||||
| 4296 | /* static */ | |||
| 4297 | bool nsContentUtils::SpoofLocaleEnglish() { | |||
| 4298 | // 0 - will prompt | |||
| 4299 | // 1 - don't spoof | |||
| 4300 | // 2 - spoof | |||
| 4301 | return StaticPrefs::privacy_spoof_english() == 2; | |||
| 4302 | } | |||
| 4303 | ||||
| 4304 | /* static */ | |||
| 4305 | bool nsContentUtils::SpoofLocaleEnglish(const Document* aDocument) { | |||
| 4306 | return SpoofLocaleEnglish() && (!aDocument || !aDocument->AllowsL10n()); | |||
| 4307 | } | |||
| 4308 | ||||
| 4309 | static nsContentUtils::PropertiesFile GetMaybeSpoofedPropertiesFile( | |||
| 4310 | nsContentUtils::PropertiesFile aFile, const char* aKey, | |||
| 4311 | Document* aDocument) { | |||
| 4312 | // When we spoof English, use en-US properties in strings that are accessible | |||
| 4313 | // by content. | |||
| 4314 | bool spoofLocale = nsContentUtils::SpoofLocaleEnglish(aDocument); | |||
| 4315 | if (spoofLocale) { | |||
| 4316 | switch (aFile) { | |||
| 4317 | case nsContentUtils::eFORMS_PROPERTIES: | |||
| 4318 | return nsContentUtils::eFORMS_PROPERTIES_en_US; | |||
| 4319 | case nsContentUtils::eDOM_PROPERTIES: | |||
| 4320 | return nsContentUtils::eDOM_PROPERTIES_en_US; | |||
| 4321 | default: | |||
| 4322 | break; | |||
| 4323 | } | |||
| 4324 | } | |||
| 4325 | return aFile; | |||
| 4326 | } | |||
| 4327 | ||||
| 4328 | /* static */ | |||
| 4329 | nsresult nsContentUtils::GetMaybeLocalizedString(PropertiesFile aFile, | |||
| 4330 | const char* aKey, | |||
| 4331 | Document* aDocument, | |||
| 4332 | nsAString& aResult) { | |||
| 4333 | return GetLocalizedString( | |||
| 4334 | GetMaybeSpoofedPropertiesFile(aFile, aKey, aDocument), aKey, aResult); | |||
| 4335 | } | |||
| 4336 | ||||
| 4337 | /* static */ | |||
| 4338 | nsresult nsContentUtils::GetLocalizedString(PropertiesFile aFile, | |||
| 4339 | const char* aKey, | |||
| 4340 | nsAString& aResult) { | |||
| 4341 | return FormatLocalizedString(aFile, aKey, {}, aResult); | |||
| 4342 | } | |||
| 4343 | ||||
| 4344 | /* static */ | |||
| 4345 | nsresult nsContentUtils::FormatMaybeLocalizedString( | |||
| 4346 | PropertiesFile aFile, const char* aKey, Document* aDocument, | |||
| 4347 | const nsTArray<nsString>& aParams, nsAString& aResult) { | |||
| 4348 | return FormatLocalizedString( | |||
| 4349 | GetMaybeSpoofedPropertiesFile(aFile, aKey, aDocument), aKey, aParams, | |||
| 4350 | aResult); | |||
| 4351 | } | |||
| 4352 | ||||
| 4353 | class FormatLocalizedStringRunnable final : public WorkerMainThreadRunnable { | |||
| 4354 | public: | |||
| 4355 | FormatLocalizedStringRunnable(WorkerPrivate* aWorkerPrivate, | |||
| 4356 | nsContentUtils::PropertiesFile aFile, | |||
| 4357 | const char* aKey, | |||
| 4358 | const nsTArray<nsString>& aParams, | |||
| 4359 | nsAString& aLocalizedString) | |||
| 4360 | : WorkerMainThreadRunnable(aWorkerPrivate, | |||
| 4361 | "FormatLocalizedStringRunnable"_ns), | |||
| 4362 | mFile(aFile), | |||
| 4363 | mKey(aKey), | |||
| 4364 | mParams(aParams), | |||
| 4365 | mLocalizedString(aLocalizedString) { | |||
| 4366 | 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" , 4366); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWorkerPrivate" ")"); do { *((volatile int*)__null) = 4366; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 4367 | aWorkerPrivate->AssertIsOnWorkerThread(); | |||
| 4368 | } | |||
| 4369 | ||||
| 4370 | bool MainThreadRun() override { | |||
| 4371 | AssertIsOnMainThread(); | |||
| 4372 | ||||
| 4373 | mResult = nsContentUtils::FormatLocalizedString(mFile, mKey, mParams, | |||
| 4374 | mLocalizedString); | |||
| 4375 | 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" , 4375); | |||
| 4376 | return true; | |||
| 4377 | } | |||
| 4378 | ||||
| 4379 | nsresult GetResult() const { return mResult; } | |||
| 4380 | ||||
| 4381 | private: | |||
| 4382 | const nsContentUtils::PropertiesFile mFile; | |||
| 4383 | const char* mKey; | |||
| 4384 | const nsTArray<nsString>& mParams; | |||
| 4385 | nsresult mResult = NS_ERROR_FAILURE; | |||
| 4386 | nsAString& mLocalizedString; | |||
| 4387 | }; | |||
| 4388 | ||||
| 4389 | /* static */ | |||
| 4390 | nsresult nsContentUtils::FormatLocalizedString( | |||
| 4391 | PropertiesFile aFile, const char* aKey, const nsTArray<nsString>& aParams, | |||
| 4392 | nsAString& aResult) { | |||
| 4393 | if (!NS_IsMainThread()) { | |||
| 4394 | // nsIStringBundle is thread-safe but its creation is not, and in particular | |||
| 4395 | // we don't create and store nsIStringBundle objects in a thread-safe way. | |||
| 4396 | // | |||
| 4397 | // TODO(emilio): Maybe if we already have the right bundle created we could | |||
| 4398 | // just call into it, but we should make sure that Shutdown() doesn't get | |||
| 4399 | // called on the main thread when that happens which is a bit tricky to | |||
| 4400 | // prove? | |||
| 4401 | WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); | |||
| 4402 | if (NS_WARN_IF(!workerPrivate)NS_warn_if_impl(!workerPrivate, "!workerPrivate", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp" , 4402)) { | |||
| 4403 | return NS_ERROR_UNEXPECTED; | |||
| 4404 | } | |||
| 4405 | ||||
| 4406 | auto runnable = MakeRefPtr<FormatLocalizedStringRunnable>( | |||
| 4407 | workerPrivate, aFile, aKey, aParams, aResult); | |||
| 4408 | ||||
| 4409 | runnable->Dispatch(workerPrivate, Canceling, IgnoreErrors()); | |||
| 4410 | return runnable->GetResult(); | |||
| 4411 | } | |||
| 4412 | ||||
| 4413 | MOZ_TRY(EnsureStringBundle(aFile))do { auto mozTryTempResult_ = ::mozilla::ToResult(EnsureStringBundle (aFile)); if ((__builtin_expect(!!(mozTryTempResult_.isErr()) , 0))) { return mozTryTempResult_.propagateErr(); } } while ( 0); | |||
| 4414 | nsIStringBundle* bundle = sStringBundles[aFile]; | |||
| 4415 | if (aParams.IsEmpty()) { | |||
| 4416 | return bundle->GetStringFromName(aKey, aResult); | |||
| 4417 | } | |||
| 4418 | return bundle->FormatStringFromName(aKey, aParams, aResult); | |||
| 4419 | } | |||
| 4420 | ||||
| 4421 | /* static */ | |||
| 4422 | void nsContentUtils::LogSimpleConsoleError(const nsAString& aErrorText, | |||
| 4423 | const nsACString& aCategory, | |||
| 4424 | bool aFromPrivateWindow, | |||
| 4425 | bool aFromChromeContext, | |||
| 4426 | uint32_t aErrorFlags) { | |||
| 4427 | nsCOMPtr<nsIScriptError> scriptError = | |||
| 4428 | do_CreateInstance(NS_SCRIPTERROR_CONTRACTID"@mozilla.org/scripterror;1"); | |||
| 4429 | if (scriptError) { | |||
| 4430 | nsCOMPtr<nsIConsoleService> console = | |||
| 4431 | do_GetService(NS_CONSOLESERVICE_CONTRACTID"@mozilla.org/consoleservice;1"); | |||
| 4432 | if (console && NS_SUCCEEDED(scriptError->Init(((bool)(__builtin_expect(!!(!NS_FAILED_impl(scriptError->Init ( aErrorText, ""_ns, 0, 0, aErrorFlags, aCategory, aFromPrivateWindow , aFromChromeContext))), 1))) | |||
| 4433 | aErrorText, ""_ns, 0, 0, aErrorFlags, aCategory,((bool)(__builtin_expect(!!(!NS_FAILED_impl(scriptError->Init ( aErrorText, ""_ns, 0, 0, aErrorFlags, aCategory, aFromPrivateWindow , aFromChromeContext))), 1))) | |||
| 4434 | aFromPrivateWindow, aFromChromeContext))((bool)(__builtin_expect(!!(!NS_FAILED_impl(scriptError->Init ( aErrorText, ""_ns, 0, 0, aErrorFlags, aCategory, aFromPrivateWindow , aFromChromeContext))), 1)))) { | |||
| 4435 | console->LogMessage(scriptError); | |||
| 4436 | } | |||
| 4437 | } | |||
| 4438 | } | |||
| 4439 | ||||
| 4440 | /* static */ | |||
| 4441 | nsresult nsContentUtils::ReportToConsole( | |||
| 4442 | uint32_t aErrorFlags, const nsACString& aCategory, | |||
| 4443 | const Document* aDocument, PropertiesFile aFile, const char* aMessageName, | |||
| 4444 | const nsTArray<nsString>& aParams, const SourceLocation& aLoc) { | |||
| 4445 | nsresult rv; | |||
| 4446 | nsAutoString errorText; | |||
| 4447 | if (!aParams.IsEmpty()) { | |||
| 4448 | rv = FormatLocalizedString(aFile, aMessageName, aParams, errorText); | |||
| 4449 | } else { | |||
| 4450 | rv = GetLocalizedString(aFile, aMessageName, errorText); | |||
| 4451 | } | |||
| 4452 | 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" , 4452); return rv; } } while (false); | |||
| 4453 | return ReportToConsoleNonLocalized(errorText, aErrorFlags, aCategory, | |||
| 4454 | aDocument, aLoc); | |||
| 4455 | } | |||
| 4456 | ||||
| 4457 | /* static */ | |||
| 4458 | void nsContentUtils::ReportEmptyGetElementByIdArg(const Document* aDoc) { | |||
| 4459 | ReportToConsole(nsIScriptError::warningFlag, "DOM"_ns, aDoc, | |||
| 4460 | nsContentUtils::eDOM_PROPERTIES, "EmptyGetElementByIdParam"); | |||
| 4461 | } | |||
| 4462 | ||||
| 4463 | /* static */ | |||
| 4464 | nsresult nsContentUtils::ReportToConsoleNonLocalized( | |||
| 4465 | const nsAString& aErrorText, uint32_t aErrorFlags, | |||
| 4466 | const nsACString& aCategory, const Document* aDocument, | |||
| 4467 | const SourceLocation& aLoc) { | |||
| 4468 | uint64_t innerWindowID = aDocument ? aDocument->InnerWindowID() : 0; | |||
| 4469 | if (aLoc || !aDocument || !aDocument->GetDocumentURI()) { | |||
| 4470 | return ReportToConsoleByWindowID(aErrorText, aErrorFlags, aCategory, | |||
| 4471 | innerWindowID, aLoc); | |||
| 4472 | } | |||
| 4473 | return ReportToConsoleByWindowID(aErrorText, aErrorFlags, aCategory, | |||
| 4474 | innerWindowID, | |||
| 4475 | SourceLocation(aDocument->GetDocumentURI())); | |||
| 4476 | } | |||
| 4477 | ||||
| 4478 | /* static */ | |||
| 4479 | nsresult nsContentUtils::ReportToConsoleByWindowID( | |||
| 4480 | const nsAString& aErrorText, uint32_t aErrorFlags, | |||
| 4481 | const nsACString& aCategory, uint64_t aInnerWindowID, | |||
| 4482 | const SourceLocation& aLocation) { | |||
| 4483 | nsresult rv; | |||
| 4484 | if (!sConsoleService) { // only need to bother null-checking here | |||
| 4485 | rv = CallGetService(NS_CONSOLESERVICE_CONTRACTID"@mozilla.org/consoleservice;1", &sConsoleService); | |||
| 4486 | 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" , 4486); return rv; } } while (false); | |||
| 4487 | } | |||
| 4488 | ||||
| 4489 | nsCOMPtr<nsIScriptError> errorObject = | |||
| 4490 | do_CreateInstance(NS_SCRIPTERROR_CONTRACTID"@mozilla.org/scripterror;1", &rv); | |||
| 4491 | 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" , 4491); return rv; } } while (false); | |||
| 4492 | ||||
| 4493 | if (aLocation.mResource.is<nsCOMPtr<nsIURI>>()) { | |||
| 4494 | nsIURI* uri = aLocation.mResource.as<nsCOMPtr<nsIURI>>(); | |||
| 4495 | rv = errorObject->InitWithSourceURI(aErrorText, uri, aLocation.mLine, | |||
| 4496 | aLocation.mColumn, aErrorFlags, | |||
| 4497 | aCategory, aInnerWindowID); | |||
| 4498 | } else { | |||
| 4499 | rv = errorObject->InitWithWindowID( | |||
| 4500 | aErrorText, aLocation.mResource.as<nsCString>(), aLocation.mLine, | |||
| 4501 | aLocation.mColumn, aErrorFlags, aCategory, aInnerWindowID); | |||
| 4502 | } | |||
| 4503 | 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" , 4503); return rv; } } while (false); | |||
| 4504 | ||||
| 4505 | return sConsoleService->LogMessage(errorObject); | |||
| 4506 | } | |||
| 4507 | ||||
| 4508 | void nsContentUtils::LogMessageToConsole(const char* aMsg) { | |||
| 4509 | if (!sConsoleService) { // only need to bother null-checking here | |||
| 4510 | CallGetService(NS_CONSOLESERVICE_CONTRACTID"@mozilla.org/consoleservice;1", &sConsoleService); | |||
| 4511 | if (!sConsoleService) { | |||
| 4512 | return; | |||
| 4513 | } | |||
| 4514 | } | |||
| 4515 | sConsoleService->LogStringMessage(NS_ConvertUTF8toUTF16(aMsg).get()); | |||
| 4516 | } | |||
| 4517 | ||||
| 4518 | bool nsContentUtils::IsChromeDoc(const Document* aDocument) { | |||
| 4519 | return aDocument && aDocument->NodePrincipal() == sSystemPrincipal; | |||
| 4520 | } | |||
| 4521 | ||||
| 4522 | bool nsContentUtils::IsAddonDoc(const Document* aDocument) { | |||
| 4523 | return aDocument && | |||
| 4524 | aDocument->NodePrincipal()->GetIsAddonOrExpandedAddonPrincipal(); | |||
| 4525 | } | |||
| 4526 | ||||
| 4527 | bool nsContentUtils::IsChildOfSameType(Document* aDoc) { | |||
| 4528 | if (BrowsingContext* bc = aDoc->GetBrowsingContext()) { | |||
| 4529 | return bc->GetParent(); | |||
| 4530 | } | |||
| 4531 | return false; | |||
| 4532 | } | |||
| 4533 | ||||
| 4534 | static bool IsJSONType(const nsACString& aContentType) { | |||
| 4535 | return aContentType.EqualsLiteral(TEXT_JSON"text/json") || | |||
| 4536 | aContentType.EqualsLiteral(APPLICATION_JSON"application/json"); | |||
| 4537 | } | |||
| 4538 | ||||
| 4539 | static bool IsNonPlainTextType(const nsACString& aContentType) { | |||
| 4540 | // MIME type suffixes which should not be plain text. | |||
| 4541 | static constexpr std::string_view kNonPlainTextTypes[] = { | |||
| 4542 | "html", | |||
| 4543 | "xml", | |||
| 4544 | "xsl", | |||
| 4545 | "calendar", | |||
| 4546 | "x-calendar", | |||
| 4547 | "x-vcalendar", | |||
| 4548 | "vcalendar", | |||
| 4549 | "vcard", | |||
| 4550 | "x-vcard", | |||
| 4551 | "directory", | |||
| 4552 | "ldif", | |||
| 4553 | "qif", | |||
| 4554 | "x-qif", | |||
| 4555 | "x-csv", | |||
| 4556 | "x-vcf", | |||
| 4557 | "rtf", | |||
| 4558 | "comma-separated-values", | |||
| 4559 | "csv", | |||
| 4560 | "tab-separated-values", | |||
| 4561 | "tsv", | |||
| 4562 | "ofx", | |||
| 4563 | "vnd.sun.j2me.app-descriptor", | |||
| 4564 | "x-ms-iqy", | |||
| 4565 | "x-ms-odc", | |||
| 4566 | "x-ms-rqy", | |||
| 4567 | "x-ms-contact"}; | |||
| 4568 | ||||
| 4569 | // Trim off the "text/" prefix for comparison. | |||
| 4570 | 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" , 4570); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StringBeginsWith(aContentType, \"text/\"_ns)" ")"); do { *((volatile int*)__null) = 4570; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 4571 | std::string_view suffix = aContentType; | |||
| 4572 | suffix.remove_prefix(5); | |||
| 4573 | ||||
| 4574 | for (std::string_view type : kNonPlainTextTypes) { | |||
| 4575 | if (type == suffix) { | |||
| 4576 | return true; | |||
| 4577 | } | |||
| 4578 | } | |||
| 4579 | return false; | |||
| 4580 | } | |||
| 4581 | ||||
| 4582 | bool nsContentUtils::IsPlainTextType(const nsACString& aContentType) { | |||
| 4583 | // All `text/*`, any JSON type and any JavaScript type are considered "plain | |||
| 4584 | // text" types for the purposes of how to render them as a document. | |||
| 4585 | return (StringBeginsWith(aContentType, "text/"_ns) && | |||
| 4586 | !IsNonPlainTextType(aContentType)) || | |||
| 4587 | IsJSONType(aContentType) || IsJavascriptMIMEType(aContentType); | |||
| 4588 | } | |||
| 4589 | ||||
| 4590 | bool nsContentUtils::IsUtf8OnlyPlainTextType(const nsACString& aContentType) { | |||
| 4591 | // NOTE: This must be a subset of the list in IsPlainTextType(). | |||
| 4592 | return IsJSONType(aContentType) || | |||
| 4593 | aContentType.EqualsLiteral(TEXT_CACHE_MANIFEST"text/cache-manifest") || | |||
| 4594 | aContentType.EqualsLiteral(TEXT_VTT"text/vtt"); | |||
| 4595 | } | |||
| 4596 | ||||
| 4597 | bool nsContentUtils::IsInChromeDocshell(const Document* aDocument) { | |||
| 4598 | return aDocument && aDocument->IsInChromeDocShell(); | |||
| 4599 | } | |||
| 4600 | ||||
| 4601 | // static | |||
| 4602 | nsIContentPolicy* nsContentUtils::GetContentPolicy() { | |||
| 4603 | if (!sTriedToGetContentPolicy) { | |||
| 4604 | CallGetService(NS_CONTENTPOLICY_CONTRACTID"@mozilla.org/layout/content-policy;1", &sContentPolicyService); | |||
| 4605 | // It's OK to not have a content policy service | |||
| 4606 | sTriedToGetContentPolicy = true; | |||
| 4607 | } | |||
| 4608 | ||||
| 4609 | return sContentPolicyService; | |||
| 4610 | } | |||
| 4611 | ||||
| 4612 | // static | |||
| 4613 | bool nsContentUtils::IsEventAttributeName(nsAtom* aName, int32_t aType) { | |||
| 4614 | const char16_t* name = aName->GetUTF16String(); | |||
| 4615 | if (name[0] != 'o' || name[1] != 'n') { | |||
| 4616 | return false; | |||
| 4617 | } | |||
| 4618 | ||||
| 4619 | EventNameMapping mapping; | |||
| 4620 | return (sAtomEventTable->Get(aName, &mapping) && mapping.mType & aType); | |||
| 4621 | } | |||
| 4622 | ||||
| 4623 | // static | |||
| 4624 | EventMessage nsContentUtils::GetEventMessage(nsAtom* aName) { | |||
| 4625 | 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" , 4625); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ") (" "sAtomEventTable is not threadsafe" ")"); do { *((volatile int*)__null) = 4625; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 4626 | if (aName) { | |||
| 4627 | EventNameMapping mapping; | |||
| 4628 | if (sAtomEventTable->Get(aName, &mapping)) { | |||
| 4629 | return mapping.mMessage; | |||
| 4630 | } | |||
| 4631 | } | |||
| 4632 | ||||
| 4633 | return eUnidentifiedEvent; | |||
| 4634 | } | |||
| 4635 | ||||
| 4636 | // static | |||
| 4637 | mozilla::EventClassID nsContentUtils::GetEventClassID(const nsAString& aName) { | |||
| 4638 | EventNameMapping mapping; | |||
| 4639 | if (sStringEventTable->Get(aName, &mapping)) return mapping.mEventClassID; | |||
| 4640 | ||||
| 4641 | return eBasicEventClass; | |||
| 4642 | } | |||
| 4643 | ||||
| 4644 | nsAtom* nsContentUtils::GetEventMessageAndAtom( | |||
| 4645 | const nsAString& aName, mozilla::EventClassID aEventClassID, | |||
| 4646 | EventMessage* aEventMessage) { | |||
| 4647 | 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" , 4647); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ") (" "Our hashtables are not threadsafe" ")"); do { *((volatile int*)__null) = 4647; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 4648 | EventNameMapping mapping; | |||
| 4649 | if (sStringEventTable->Get(aName, &mapping)) { | |||
| 4650 | *aEventMessage = mapping.mEventClassID == aEventClassID | |||
| 4651 | ? mapping.mMessage | |||
| 4652 | : eUnidentifiedEvent; | |||
| 4653 | return mapping.mAtom; | |||
| 4654 | } | |||
| 4655 | ||||
| 4656 | // If we have cached lots of user defined event names, clear some of them. | |||
| 4657 | if (sUserDefinedEvents->Length() > 127) { | |||
| 4658 | while (sUserDefinedEvents->Length() > 64) { | |||
| 4659 | nsAtom* first = sUserDefinedEvents->ElementAt(0); | |||
| 4660 | sStringEventTable->Remove(Substring(nsDependentAtomString(first), 2)); | |||
| 4661 | sUserDefinedEvents->RemoveElementAt(0); | |||
| 4662 | } | |||
| 4663 | } | |||
| 4664 | ||||
| 4665 | *aEventMessage = eUnidentifiedEvent; | |||
| 4666 | RefPtr<nsAtom> atom = NS_AtomizeMainThread(u"on"_ns + aName); | |||
| 4667 | sUserDefinedEvents->AppendElement(atom); | |||
| 4668 | mapping.mAtom = atom; | |||
| 4669 | mapping.mMessage = eUnidentifiedEvent; | |||
| 4670 | mapping.mType = EventNameType_None; | |||
| 4671 | mapping.mEventClassID = eBasicEventClass; | |||
| 4672 | sStringEventTable->InsertOrUpdate(aName, mapping); | |||
| 4673 | return mapping.mAtom; | |||
| 4674 | } | |||
| 4675 | ||||
| 4676 | // static | |||
| 4677 | EventMessage nsContentUtils::GetEventMessageAndAtomForListener( | |||
| 4678 | const nsAString& aName, nsAtom** aOnName) { | |||
| 4679 | 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" , 4679); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ") (" "Our hashtables are not threadsafe" ")"); do { *((volatile int*)__null) = 4679; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 4680 | ||||
| 4681 | // Check sStringEventTable for a matching entry. This will only fail for | |||
| 4682 | // user-defined event types. | |||
| 4683 | EventNameMapping mapping; | |||
| 4684 | if (sStringEventTable->Get(aName, &mapping)) { | |||
| 4685 | RefPtr<nsAtom> atom = mapping.mAtom; | |||
| 4686 | atom.forget(aOnName); | |||
| 4687 | return mapping.mMessage; | |||
| 4688 | } | |||
| 4689 | ||||
| 4690 | // sStringEventTable did not contain an entry for this event type string. | |||
| 4691 | // Call GetEventMessageAndAtom, which will create an event type atom and | |||
| 4692 | // cache it in sStringEventTable for future calls. | |||
| 4693 | EventMessage msg = eUnidentifiedEvent; | |||
| 4694 | RefPtr<nsAtom> atom = GetEventMessageAndAtom(aName, eBasicEventClass, &msg); | |||
| 4695 | atom.forget(aOnName); | |||
| 4696 | return msg; | |||
| 4697 | } | |||
| 4698 | ||||
| 4699 | static already_AddRefed<Event> GetEventWithTarget( | |||
| 4700 | Document* aDoc, EventTarget* aTarget, const nsAString& aEventName, | |||
| 4701 | CanBubble aCanBubble, Cancelable aCancelable, Composed aComposed, | |||
| 4702 | Trusted aTrusted, ErrorResult& aErrorResult) { | |||
| 4703 | RefPtr<Event> event = | |||
| 4704 | aDoc->CreateEvent(u"Events"_ns, CallerType::System, aErrorResult); | |||
| 4705 | if (aErrorResult.Failed()) { | |||
| 4706 | return nullptr; | |||
| 4707 | } | |||
| 4708 | ||||
| 4709 | event->InitEvent(aEventName, aCanBubble, aCancelable, aComposed); | |||
| 4710 | event->SetTrusted(aTrusted == Trusted::eYes); | |||
| 4711 | ||||
| 4712 | event->SetTarget(aTarget); | |||
| 4713 | ||||
| 4714 | return event.forget(); | |||
| 4715 | } | |||
| 4716 | ||||
| 4717 | // static | |||
| 4718 | nsresult nsContentUtils::DispatchTrustedEvent( | |||
| 4719 | Document* aDoc, EventTarget* aTarget, const nsAString& aEventName, | |||
| 4720 | CanBubble aCanBubble, Cancelable aCancelable, Composed aComposed, | |||
| 4721 | bool* aDefaultAction) { | |||
| 4722 | 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" , 4724); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEventName.EqualsLiteral(\"input\") && !aEventName.EqualsLiteral(\"beforeinput\")" ") (" "Use DispatchInputEvent() instead" ")"); do { *((volatile int*)__null) = 4724; __attribute__((nomerge)) ::abort(); } while (false); } } while (false) | |||
| 4723 | !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" , 4724); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEventName.EqualsLiteral(\"input\") && !aEventName.EqualsLiteral(\"beforeinput\")" ") (" "Use DispatchInputEvent() instead" ")"); do { *((volatile int*)__null) = 4724; __attribute__((nomerge)) ::abort(); } while (false); } } while (false) | |||
| 4724 | "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" , 4724); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEventName.EqualsLiteral(\"input\") && !aEventName.EqualsLiteral(\"beforeinput\")" ") (" "Use DispatchInputEvent() instead" ")"); do { *((volatile int*)__null) = 4724; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 4725 | return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable, | |||
| 4726 | aComposed, Trusted::eYes, aDefaultAction); | |||
| 4727 | } | |||
| 4728 | ||||
| 4729 | // static | |||
| 4730 | nsresult nsContentUtils::DispatchUntrustedEvent( | |||
| 4731 | Document* aDoc, EventTarget* aTarget, const nsAString& aEventName, | |||
| 4732 | CanBubble aCanBubble, Cancelable aCancelable, bool* aDefaultAction) { | |||
| 4733 | return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable, | |||
| 4734 | Composed::eDefault, Trusted::eNo, aDefaultAction); | |||
| 4735 | } | |||
| 4736 | ||||
| 4737 | // static | |||
| 4738 | nsresult nsContentUtils::DispatchEvent(Document* aDoc, EventTarget* aTarget, | |||
| 4739 | const nsAString& aEventName, | |||
| 4740 | CanBubble aCanBubble, | |||
| 4741 | Cancelable aCancelable, | |||
| 4742 | Composed aComposed, Trusted aTrusted, | |||
| 4743 | bool* aDefaultAction, | |||
| 4744 | ChromeOnlyDispatch aOnlyChromeDispatch) { | |||
| 4745 | if (!aDoc || !aTarget) { | |||
| 4746 | return NS_ERROR_INVALID_ARG; | |||
| 4747 | } | |||
| 4748 | ||||
| 4749 | ErrorResult err; | |||
| 4750 | RefPtr<Event> event = | |||
| 4751 | GetEventWithTarget(aDoc, aTarget, aEventName, aCanBubble, aCancelable, | |||
| 4752 | aComposed, aTrusted, err); | |||
| 4753 | if (err.Failed()) { | |||
| 4754 | return err.StealNSResult(); | |||
| 4755 | } | |||
| 4756 | event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = | |||
| 4757 | aOnlyChromeDispatch == ChromeOnlyDispatch::eYes; | |||
| 4758 | ||||
| 4759 | bool doDefault = aTarget->DispatchEvent(*event, CallerType::System, err); | |||
| 4760 | if (aDefaultAction) { | |||
| 4761 | *aDefaultAction = doDefault; | |||
| 4762 | } | |||
| 4763 | return err.StealNSResult(); | |||
| 4764 | } | |||
| 4765 | ||||
| 4766 | // static | |||
| 4767 | nsresult nsContentUtils::DispatchEvent(Document* aDoc, EventTarget* aTarget, | |||
| 4768 | WidgetEvent& aEvent, | |||
| 4769 | EventMessage aEventMessage, | |||
| 4770 | CanBubble aCanBubble, | |||
| 4771 | Cancelable aCancelable, Trusted aTrusted, | |||
| 4772 | bool* aDefaultAction, | |||
| 4773 | ChromeOnlyDispatch aOnlyChromeDispatch) { | |||
| 4774 | 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" , 4775); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTrusted == Trusted::eYes" ")"); do { *((volatile int*)__null) = 4775; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false) | |||
| 4775 | 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" , 4775); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTrusted == Trusted::eYes" ")"); do { *((volatile int*)__null) = 4775; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); | |||
| 4776 | ||||
| 4777 | aEvent.mSpecifiedEventType = GetEventTypeFromMessage(aEventMessage); | |||
| 4778 | aEvent.SetDefaultComposed(); | |||
| 4779 | aEvent.SetDefaultComposedInNativeAnonymousContent(); | |||
| 4780 | ||||
| 4781 | aEvent.mFlags.mBubbles = aCanBubble == CanBubble::eYes; | |||
| 4782 | aEvent.mFlags.mCancelable = aCancelable == Cancelable::eYes; | |||
| 4783 | aEvent.mFlags.mOnlyChromeDispatch = | |||
| 4784 | aOnlyChromeDispatch == ChromeOnlyDispatch::eYes; | |||
| 4785 | ||||
| 4786 | aEvent.mTarget = aTarget; | |||
| 4787 | ||||
| 4788 | nsEventStatus status = nsEventStatus_eIgnore; | |||
| 4789 | nsresult rv = EventDispatcher::DispatchDOMEvent(aTarget, &aEvent, nullptr, | |||
| 4790 | nullptr, &status); | |||
| 4791 | if (aDefaultAction) { | |||
| 4792 | *aDefaultAction = (status != nsEventStatus_eConsumeNoDefault); | |||
| 4793 | } | |||
| 4794 | return rv; | |||
| 4795 | } | |||
| 4796 | ||||
| 4797 | // static | |||
| 4798 | nsresult nsContentUtils::DispatchInputEvent(Element* aEventTarget) { | |||
| 4799 | return DispatchInputEvent(aEventTarget, mozilla::eEditorInput, | |||
| 4800 | mozilla::EditorInputType::eUnknown, nullptr, | |||
| 4801 | InputEventOptions()); | |||
| 4802 | } | |||
| 4803 | ||||
| 4804 | // static | |||
| 4805 | nsresult nsContentUtils::DispatchInputEvent( | |||
| 4806 | Element* aEventTargetElement, EventMessage aEventMessage, | |||
| 4807 | EditorInputType aEditorInputType, EditorBase* aEditorBase, | |||
| 4808 | InputEventOptions&& aOptions, nsEventStatus* aEventStatus /* = nullptr */) { | |||
| 4809 | 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" , 4810); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEventMessage == eEditorInput || aEventMessage == eEditorBeforeInput" ")"); do { *((volatile int*)__null) = 4810; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) | |||
| 4810 | 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" , 4810); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEventMessage == eEditorInput || aEventMessage == eEditorBeforeInput" ")"); do { *((volatile int*)__null) = 4810; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 4811 | ||||
| 4812 | if (NS_WARN_IF(!aEventTargetElement)NS_warn_if_impl(!aEventTargetElement, "!aEventTargetElement", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp" , 4812)) { | |||
| 4813 | return NS_ERROR_INVALID_ARG; | |||
| 4814 | } | |||
| 4815 | ||||
| 4816 | // If this is called from editor, the instance should be set to aEditorBase. | |||
| 4817 | // Otherwise, we need to look for an editor for aEventTargetElement. | |||
| 4818 | // However, we don't need to do it for HTMLEditor since nobody shouldn't | |||
| 4819 | // dispatch "beforeinput" nor "input" event for HTMLEditor except HTMLEditor | |||
| 4820 | // itself. | |||
| 4821 | bool useInputEvent = false; | |||
| 4822 | if (aEditorBase) { | |||
| 4823 | useInputEvent = true; | |||
| 4824 | } else if (HTMLTextAreaElement* textAreaElement = | |||
| 4825 | HTMLTextAreaElement::FromNode(aEventTargetElement)) { | |||
| 4826 | aEditorBase = textAreaElement->GetTextEditorWithoutCreation(); | |||
| 4827 | useInputEvent = true; | |||
| 4828 | } else if (HTMLInputElement* inputElement = | |||
| 4829 | HTMLInputElement::FromNode(aEventTargetElement)) { | |||
| 4830 | if (inputElement->IsInputEventTarget()) { | |||
| 4831 | aEditorBase = inputElement->GetTextEditorWithoutCreation(); | |||
| 4832 | useInputEvent = true; | |||
| 4833 | } | |||
| 4834 | } | |||
| 4835 | #ifdef DEBUG1 | |||
| 4836 | else { | |||
| 4837 | 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" , 4838); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEventTargetElement->IsTextControlElement()" ") (" "The event target may have editor, but we've not known it yet." ")"); do { *((volatile int*)__null) = 4838; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) | |||
| 4838 | "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" , 4838); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEventTargetElement->IsTextControlElement()" ") (" "The event target may have editor, but we've not known it yet." ")"); do { *((volatile int*)__null) = 4838; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 4839 | } | |||
| 4840 | #endif // #ifdef DEBUG | |||
| 4841 | ||||
| 4842 | if (!useInputEvent) { | |||
| 4843 | 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" , 4843); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEventMessage == eEditorInput" ")"); do { *((volatile int*)__null) = 4843; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 4844 | 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" , 4844); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEditorInputType == EditorInputType::eUnknown" ")"); do { *((volatile int*)__null) = 4844; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 4845 | 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" , 4845); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aOptions.mNeverCancelable" ")"); do { *((volatile int*)__null) = 4845; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 4846 | // Dispatch "input" event with Event instance. | |||
| 4847 | WidgetEvent widgetEvent(true, eUnidentifiedEvent); | |||
| 4848 | widgetEvent.mSpecifiedEventType = nsGkAtoms::oninput; | |||
| 4849 | widgetEvent.mFlags.mCancelable = false; | |||
| 4850 | widgetEvent.mFlags.mComposed = true; | |||
| 4851 | return AsyncEventDispatcher::RunDOMEventWhenSafe(*aEventTargetElement, | |||
| 4852 | widgetEvent, aEventStatus); | |||
| 4853 | } | |||
| 4854 | ||||
| 4855 | 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" , 4856); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aOptions.mNeverCancelable" ")"); do { *((volatile int*)__null) = 4856; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false) | |||
| 4856 | !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" , 4856); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aOptions.mNeverCancelable" ")"); do { *((volatile int*)__null) = 4856; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); | |||
| 4857 | 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" , 4859); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEditorInputType == EditorInputType::eInsertReplacementText" ")"); do { *((volatile int*)__null) = 4859; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false) | |||
| 4858 | 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" , 4859); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEditorInputType == EditorInputType::eInsertReplacementText" ")"); do { *((volatile int*)__null) = 4859; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false) | |||
| 4859 | 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" , 4859); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEditorInputType == EditorInputType::eInsertReplacementText" ")"); do { *((volatile int*)__null) = 4859; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); | |||
| 4860 | ||||
| 4861 | nsCOMPtr<nsIWidget> widget; | |||
| 4862 | if (aEditorBase) { | |||
| 4863 | widget = aEditorBase->GetWidget(); | |||
| 4864 | if (NS_WARN_IF(!widget)NS_warn_if_impl(!widget, "!widget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp" , 4864)) { | |||
| 4865 | return NS_ERROR_FAILURE; | |||
| 4866 | } | |||
| 4867 | } else { | |||
| 4868 | Document* document = aEventTargetElement->OwnerDoc(); | |||
| 4869 | if (NS_WARN_IF(!document)NS_warn_if_impl(!document, "!document", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp" , 4869)) { | |||
| 4870 | return NS_ERROR_FAILURE; | |||
| 4871 | } | |||
| 4872 | // If we're running xpcshell tests, we fail to get presShell here. | |||
| 4873 | // Even in such case, we need to dispatch "input" event without widget. | |||
| 4874 | PresShell* presShell = document->GetPresShell(); | |||
| 4875 | if (presShell) { | |||
| 4876 | nsPresContext* presContext = presShell->GetPresContext(); | |||
| 4877 | if (NS_WARN_IF(!presContext)NS_warn_if_impl(!presContext, "!presContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp" , 4877)) { | |||
| 4878 | return NS_ERROR_FAILURE; | |||
| 4879 | } | |||
| 4880 | widget = presContext->GetRootWidget(); | |||
| 4881 | if (NS_WARN_IF(!widget)NS_warn_if_impl(!widget, "!widget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp" , 4881)) { | |||
| 4882 | return NS_ERROR_FAILURE; | |||
| 4883 | } | |||
| 4884 | } | |||
| 4885 | } | |||
| 4886 | ||||
| 4887 | // Dispatch "input" event with InputEvent instance. | |||
| 4888 | InternalEditorInputEvent inputEvent(true, aEventMessage, widget); | |||
| 4889 | ||||
| 4890 | inputEvent.mFlags.mCancelable = | |||
| 4891 | !aOptions.mNeverCancelable && aEventMessage == eEditorBeforeInput && | |||
| 4892 | IsCancelableBeforeInputEvent(aEditorInputType); | |||
| 4893 | 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" , 4893); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inputEvent.mFlags.mCancelable || aEventStatus" ")"); do { *((volatile int*)__null) = 4893; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 4894 | ||||
| 4895 | // If there is an editor, set isComposing to true when it has composition. | |||
| 4896 | // Note that EditorBase::IsIMEComposing() may return false even when we | |||
| 4897 | // need to set it to true. | |||
| 4898 | // Otherwise, i.e., editor hasn't been created for the element yet, | |||
| 4899 | // we should set isComposing to false since the element can never has | |||
| 4900 | // composition without editor. | |||
| 4901 | inputEvent.mIsComposing = aEditorBase && aEditorBase->GetComposition(); | |||
| 4902 | ||||
| 4903 | if (!aEditorBase || aEditorBase->IsTextEditor()) { | |||
| 4904 | if (IsDataAvailableOnTextEditor(aEditorInputType)) { | |||
| 4905 | inputEvent.mData = std::move(aOptions.mData); | |||
| 4906 | 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" , 4907); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inputEvent.mData.IsVoid()" ") (" "inputEvent.mData shouldn't be void" ")"); do { *((volatile int*)__null) = 4907; __attribute__((nomerge)) ::abort(); } while (false); } } while (false) | |||
| 4907 | "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" , 4907); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inputEvent.mData.IsVoid()" ") (" "inputEvent.mData shouldn't be void" ")"); do { *((volatile int*)__null) = 4907; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 4908 | } | |||
| 4909 | #ifdef DEBUG1 | |||
| 4910 | else { | |||
| 4911 | 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" , 4911); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inputEvent.mData.IsVoid()" ") (" "inputEvent.mData should be void" ")"); do { *((volatile int*)__null) = 4911; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 4912 | } | |||
| 4913 | #endif // #ifdef DEBUG | |||
| 4914 | 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" , 4916); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOptions.mTargetRanges.IsEmpty()" ") (" "Target ranges for <input> and <textarea> should always be empty" ")"); do { *((volatile int*)__null) = 4916; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) | |||
| 4915 | 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" , 4916); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOptions.mTargetRanges.IsEmpty()" ") (" "Target ranges for <input> and <textarea> should always be empty" ")"); do { *((volatile int*)__null) = 4916; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) | |||
| 4916 | "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" , 4916); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOptions.mTargetRanges.IsEmpty()" ") (" "Target ranges for <input> and <textarea> should always be empty" ")"); do { *((volatile int*)__null) = 4916; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 4917 | } else { | |||
| 4918 | 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" , 4918); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEditorBase->IsHTMLEditor()" ")"); do { *((volatile int*)__null) = 4918; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 4919 | if (IsDataAvailableOnHTMLEditor(aEditorInputType)) { | |||
| 4920 | inputEvent.mData = std::move(aOptions.mData); | |||
| 4921 | 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" , 4922); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inputEvent.mData.IsVoid()" ") (" "inputEvent.mData shouldn't be void" ")"); do { *((volatile int*)__null) = 4922; __attribute__((nomerge)) ::abort(); } while (false); } } while (false) | |||
| 4922 | "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" , 4922); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inputEvent.mData.IsVoid()" ") (" "inputEvent.mData shouldn't be void" ")"); do { *((volatile int*)__null) = 4922; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 4923 | } else { | |||
| 4924 | 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" , 4924); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inputEvent.mData.IsVoid()" ") (" "inputEvent.mData should be void" ")"); do { *((volatile int*)__null) = 4924; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 4925 | if (IsDataTransferAvailableOnHTMLEditor(aEditorInputType)) { | |||
| 4926 | inputEvent.mDataTransfer = std::move(aOptions.mDataTransfer); | |||
| 4927 | 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" , 4928); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inputEvent.mDataTransfer" ") (" "inputEvent.mDataTransfer shouldn't be nullptr" ")"); do { *((volatile int*)__null) = 4928; __attribute__((nomerge)) :: abort(); } while (false); } } while (false) | |||
| 4928 | "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" , 4928); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inputEvent.mDataTransfer" ") (" "inputEvent.mDataTransfer shouldn't be nullptr" ")"); do { *((volatile int*)__null) = 4928; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); | |||
| 4929 | 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" , 4930); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inputEvent.mDataTransfer->IsReadOnly()" ") (" "inputEvent.mDataTransfer should be read only" ")"); do { *((volatile int*)__null) = 4930; __attribute__((nomerge)) :: abort(); } while (false); } } while (false) | |||
| 4930 | "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" , 4930); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inputEvent.mDataTransfer->IsReadOnly()" ") (" "inputEvent.mDataTransfer should be read only" ")"); do { *((volatile int*)__null) = 4930; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); | |||
| 4931 | } | |||
| 4932 | #ifdef DEBUG1 | |||
| 4933 | else { | |||
| 4934 | 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" , 4935); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inputEvent.mDataTransfer" ") (" "inputEvent.mDataTransfer should be nullptr" ")"); do { *((volatile int*)__null) = 4935; __attribute__((nomerge)) :: abort(); } while (false); } } while (false) | |||
| 4935 | "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" , 4935); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inputEvent.mDataTransfer" ") (" "inputEvent.mDataTransfer should be nullptr" ")"); do { *((volatile int*)__null) = 4935; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); | |||
| 4936 | } | |||
| 4937 | #endif // #ifdef DEBUG | |||
| 4938 | } | |||
| 4939 | if (aEventMessage == eEditorBeforeInput && | |||
| 4940 | MayHaveTargetRangesOnHTMLEditor(aEditorInputType)) { | |||
| 4941 | inputEvent.mTargetRanges = std::move(aOptions.mTargetRanges); | |||
| 4942 | } | |||
| 4943 | #ifdef DEBUG1 | |||
| 4944 | else { | |||
| 4945 | 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" , 4946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOptions.mTargetRanges.IsEmpty()" ") (" "Target ranges shouldn't be set for the dispatching event" ")"); do { *((volatile int*)__null) = 4946; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) | |||
| 4946 | "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" , 4946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOptions.mTargetRanges.IsEmpty()" ") (" "Target ranges shouldn't be set for the dispatching event" ")"); do { *((volatile int*)__null) = 4946; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 4947 | } | |||
| 4948 | #endif // #ifdef DEBUG | |||
| 4949 | } | |||
| 4950 | ||||
| 4951 | inputEvent.mInputType = aEditorInputType; | |||
| 4952 | ||||
| 4953 | // If we cannot dispatch an event right now, we cannot make it cancelable. | |||
| 4954 | if (!nsContentUtils::IsSafeToRunScript()) { | |||
| 4955 | 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" , 4957); MOZ_PretendNoReturn(); } } while (0) | |||
| 4956 | !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" , 4957); MOZ_PretendNoReturn(); } } while (0) | |||
| 4957 | "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" , 4957); MOZ_PretendNoReturn(); } } while (0); | |||
| 4958 | inputEvent.mFlags.mCancelable = false; | |||
| 4959 | } | |||
| 4960 | return AsyncEventDispatcher::RunDOMEventWhenSafe(*aEventTargetElement, | |||
| 4961 | inputEvent, aEventStatus); | |||
| 4962 | } | |||
| 4963 | ||||
| 4964 | nsresult nsContentUtils::DispatchChromeEvent( | |||
| 4965 | Document* aDoc, EventTarget* aTarget, const nsAString& aEventName, | |||
| 4966 | CanBubble aCanBubble, Cancelable aCancelable, bool* aDefaultAction) { | |||
| 4967 | if (!aDoc || !aTarget) { | |||
| 4968 | return NS_ERROR_INVALID_ARG; | |||
| 4969 | } | |||
| 4970 | ||||
| 4971 | if (!aDoc->GetWindow()) { | |||
| 4972 | return NS_ERROR_INVALID_ARG; | |||
| 4973 | } | |||
| 4974 | ||||
| 4975 | EventTarget* piTarget = aDoc->GetWindow()->GetParentTarget(); | |||
| 4976 | if (!piTarget) { | |||
| 4977 | return NS_ERROR_INVALID_ARG; | |||
| 4978 | } | |||
| 4979 | ||||
| 4980 | ErrorResult err; | |||
| 4981 | RefPtr<Event> event = | |||
| 4982 | GetEventWithTarget(aDoc, aTarget, aEventName, aCanBubble, aCancelable, | |||
| 4983 | Composed::eDefault, Trusted::eYes, err); | |||
| 4984 | if (err.Failed()) { | |||
| 4985 | return err.StealNSResult(); | |||
| 4986 | } | |||
| 4987 | ||||
| 4988 | bool defaultActionEnabled = | |||
| 4989 | piTarget->DispatchEvent(*event, CallerType::System, err); | |||
| 4990 | if (aDefaultAction) { | |||
| 4991 | *aDefaultAction = defaultActionEnabled; | |||
| 4992 | } | |||
| 4993 | return err.StealNSResult(); | |||
| 4994 | } | |||
| 4995 | ||||
| 4996 | void nsContentUtils::RequestFrameFocus(Element& aFrameElement, bool aCanRaise, | |||
| 4997 | CallerType aCallerType) { | |||
| 4998 | RefPtr<Element> target = &aFrameElement; | |||
| 4999 | bool defaultAction = true; | |||
| 5000 | if (aCanRaise) { | |||
| 5001 | DispatchEventOnlyToChrome(target->OwnerDoc(), target, | |||
| 5002 | u"framefocusrequested"_ns, CanBubble::eYes, | |||
| 5003 | Cancelable::eYes, &defaultAction); | |||
| 5004 | } | |||
| 5005 | if (!defaultAction) { | |||
| 5006 | return; | |||
| 5007 | } | |||
| 5008 | ||||
| 5009 | RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager(); | |||
| 5010 | if (!fm) { | |||
| 5011 | return; | |||
| 5012 | } | |||
| 5013 | ||||
| 5014 | uint32_t flags = nsIFocusManager::FLAG_NOSCROLL; | |||
| 5015 | if (aCanRaise) { | |||
| 5016 | flags |= nsIFocusManager::FLAG_RAISE; | |||
| 5017 | } | |||
| 5018 | ||||
| 5019 | if (aCallerType == CallerType::NonSystem) { | |||
| 5020 | flags |= nsIFocusManager::FLAG_NONSYSTEMCALLER; | |||
| 5021 | } | |||
| 5022 | ||||
| 5023 | fm->SetFocus(target, flags); | |||
| 5024 | } | |||
| 5025 | ||||
| 5026 | nsresult nsContentUtils::DispatchEventOnlyToChrome( | |||
| 5027 | Document* aDoc, EventTarget* aTarget, const nsAString& aEventName, | |||
| 5028 | CanBubble aCanBubble, Cancelable aCancelable, Composed aComposed, | |||
| 5029 | bool* aDefaultAction) { | |||
| 5030 | return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable, | |||
| 5031 | aComposed, Trusted::eYes, aDefaultAction, | |||
| 5032 | ChromeOnlyDispatch::eYes); | |||
| 5033 | } | |||
| 5034 | ||||
| 5035 | /* static */ | |||
| 5036 | Element* nsContentUtils::MatchElementId(nsIContent* aContent, | |||
| 5037 | const nsAtom* aId) { | |||
| 5038 | for (nsIContent* cur = aContent; cur; cur = cur->GetNextNode(aContent)) { | |||
| 5039 | if (aId == cur->GetID()) { | |||
| 5040 | return cur->AsElement(); | |||
| 5041 | } | |||
| 5042 | } | |||
| 5043 | ||||
| 5044 | return nullptr; | |||
| 5045 | } | |||
| 5046 | ||||
| 5047 | /* static */ | |||
| 5048 | Element* nsContentUtils::MatchElementId(nsIContent* aContent, | |||
| 5049 | const nsAString& aId) { | |||
| 5050 | 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" , 5050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aId.IsEmpty()" ") (" "Will match random elements" ")"); do { *((volatile int *)__null) = 5050; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 5051 | ||||
| 5052 | // ID attrs are generally stored as atoms, so just atomize this up front | |||
| 5053 | RefPtr<nsAtom> id(NS_Atomize(aId)); | |||
| 5054 | if (!id) { | |||
| 5055 | // OOM, so just bail | |||
| 5056 | return nullptr; | |||
| 5057 | } | |||
| 5058 | ||||
| 5059 | return MatchElementId(aContent, id); | |||
| 5060 | } | |||
| 5061 | ||||
| 5062 | /* static */ | |||
| 5063 | void nsContentUtils::RegisterShutdownObserver(nsIObserver* aObserver) { | |||
| 5064 | nsCOMPtr<nsIObserverService> observerService = | |||
| 5065 | mozilla::services::GetObserverService(); | |||
| 5066 | if (observerService) { | |||
| 5067 | observerService->AddObserver(aObserver, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown", | |||
| 5068 | false); | |||
| 5069 | } | |||
| 5070 | } | |||
| 5071 | ||||
| 5072 | /* static */ | |||
| 5073 | void nsContentUtils::UnregisterShutdownObserver(nsIObserver* aObserver) { | |||
| 5074 | nsCOMPtr<nsIObserverService> observerService = | |||
| 5075 | mozilla::services::GetObserverService(); | |||
| 5076 | if (observerService) { | |||
| 5077 | observerService->RemoveObserver(aObserver, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown"); | |||
| 5078 | } | |||
| 5079 | } | |||
| 5080 | ||||
| 5081 | /* static */ | |||
| 5082 | bool nsContentUtils::HasNonEmptyAttr(const nsIContent* aContent, | |||
| 5083 | int32_t aNameSpaceID, nsAtom* aName) { | |||
| 5084 | static AttrArray::AttrValuesArray strings[] = {nsGkAtoms::_empty, nullptr}; | |||
| 5085 | return aContent->IsElement() && | |||
| 5086 | aContent->AsElement()->FindAttrValueIn(aNameSpaceID, aName, strings, | |||
| 5087 | eCaseMatters) == | |||
| 5088 | AttrArray::ATTR_VALUE_NO_MATCH; | |||
| 5089 | } | |||
| 5090 | ||||
| 5091 | /* static */ | |||
| 5092 | bool nsContentUtils::WantMutationEvents(nsINode* aNode, uint32_t aType, | |||
| 5093 | nsINode* aTargetForSubtreeModified) { | |||
| 5094 | Document* doc = aNode->OwnerDoc(); | |||
| 5095 | if (!doc->MutationEventsEnabled()) { | |||
| 5096 | return false; | |||
| 5097 | } | |||
| 5098 | ||||
| 5099 | if (!doc->FireMutationEvents()) { | |||
| 5100 | return false; | |||
| 5101 | } | |||
| 5102 | ||||
| 5103 | // global object will be null for documents that don't have windows. | |||
| 5104 | nsPIDOMWindowInner* window = doc->GetInnerWindow(); | |||
| 5105 | // This relies on EventListenerManager::AddEventListener, which sets | |||
| 5106 | // all mutation bits when there is a listener for DOMSubtreeModified event. | |||
| 5107 | if (window && !window->HasMutationListeners(aType)) { | |||
| 5108 | return false; | |||
| 5109 | } | |||
| 5110 | ||||
| 5111 | if (aNode->ChromeOnlyAccess() || aNode->IsInShadowTree()) { | |||
| 5112 | return false; | |||
| 5113 | } | |||
| 5114 | ||||
| 5115 | doc->MayDispatchMutationEvent(aTargetForSubtreeModified); | |||
| 5116 | ||||
| 5117 | // If we have a window, we can check it for mutation listeners now. | |||
| 5118 | if (aNode->IsInUncomposedDoc()) { | |||
| 5119 | nsCOMPtr<EventTarget> piTarget(do_QueryInterface(window)); | |||
| 5120 | if (piTarget) { | |||
| 5121 | EventListenerManager* manager = piTarget->GetExistingListenerManager(); | |||
| 5122 | if (manager && manager->HasMutationListeners()) { | |||
| 5123 | return true; | |||
| 5124 | } | |||
| 5125 | } | |||
| 5126 | } | |||
| 5127 | ||||
| 5128 | // If we have a window, we know a mutation listener is registered, but it | |||
| 5129 | // might not be in our chain. If we don't have a window, we might have a | |||
| 5130 | // mutation listener. Check quickly to see. | |||
| 5131 | while (aNode) { | |||
| 5132 | EventListenerManager* manager = aNode->GetExistingListenerManager(); | |||
| 5133 | if (manager && manager->HasMutationListeners()) { | |||
| 5134 | return true; | |||
| 5135 | } | |||
| 5136 | ||||
| 5137 | aNode = aNode->GetParentNode(); | |||
| 5138 | } | |||
| 5139 | ||||
| 5140 | return false; | |||
| 5141 | } | |||
| 5142 | ||||
| 5143 | /* static */ | |||
| 5144 | bool nsContentUtils::HasMutationListeners(Document* aDocument, uint32_t aType) { | |||
| 5145 | nsPIDOMWindowInner* window = | |||
| 5146 | aDocument ? aDocument->GetInnerWindow() : nullptr; | |||
| 5147 | ||||
| 5148 | // This relies on EventListenerManager::AddEventListener, which sets | |||
| 5149 | // all mutation bits when there is a listener for DOMSubtreeModified event. | |||
| 5150 | return !window || window->HasMutationListeners(aType); | |||
| 5151 | } | |||
| 5152 | ||||
| 5153 | void nsContentUtils::MaybeFireNodeRemoved(nsINode* aChild, nsINode* aParent) { | |||
| 5154 | 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" , 5154); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild" ") (" "Missing child" ")"); do { *((volatile int*)__null) = 5154; __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 5155 | 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" , 5155); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->GetParentNode() == aParent" ") (" "Wrong parent" ")"); do { *((volatile int*)__null) = 5155 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 5156 | 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" , 5156); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->OwnerDoc() == aParent->OwnerDoc()" ") (" "Wrong owner-doc" ")"); do { *((volatile int*)__null) = 5156; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 5157 | ||||
| 5158 | // Having an explicit check here since it's an easy mistake to fall into, | |||
| 5159 | // and there might be existing code with problems. We'd rather be safe | |||
| 5160 | // than fire DOMNodeRemoved in all corner cases. We also rely on it for | |||
| 5161 | // nsAutoScriptBlockerSuppressNodeRemoved. | |||
| 5162 | if (!IsSafeToRunScript()) { | |||
| 5163 | // This checks that IsSafeToRunScript is true since we don't want to fire | |||
| 5164 | // events when that is false. We can't rely on EventDispatcher to assert | |||
| 5165 | // this in this situation since most of the time there are no mutation | |||
| 5166 | // event listeners, in which case we won't even attempt to dispatch events. | |||
| 5167 | // However this also allows for two exceptions. First off, we don't assert | |||
| 5168 | // if the mutation happens to native anonymous content since we never fire | |||
| 5169 | // mutation events on such content anyway. | |||
| 5170 | // Second, we don't assert if sDOMNodeRemovedSuppressCount is true since | |||
| 5171 | // that is a know case when we'd normally fire a mutation event, but can't | |||
| 5172 | // make that safe and so we suppress it at this time. Ideally this should | |||
| 5173 | // go away eventually. | |||
| 5174 | if (!aChild->IsInNativeAnonymousSubtree() && | |||
| 5175 | !sDOMNodeRemovedSuppressCount) { | |||
| 5176 | 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" , 5176); MOZ_PretendNoReturn(); } while (0); | |||
| 5177 | WarnScriptWasIgnored(aChild->OwnerDoc()); | |||
| 5178 | } | |||
| 5179 | return; | |||
| 5180 | } | |||
| 5181 | ||||
| 5182 | { | |||
| 5183 | Document* doc = aParent->OwnerDoc(); | |||
| 5184 | if (MOZ_UNLIKELY(doc->DevToolsWatchingDOMMutations())(__builtin_expect(!!(doc->DevToolsWatchingDOMMutations()), 0)) && | |||
| 5185 | aChild->IsInComposedDoc() && !aChild->ChromeOnlyAccess()) { | |||
| 5186 | DispatchChromeEvent(doc, aChild, u"devtoolschildremoved"_ns, | |||
| 5187 | CanBubble::eNo, Cancelable::eNo); | |||
| 5188 | } | |||
| 5189 | } | |||
| 5190 | ||||
| 5191 | if (WantMutationEvents(aChild, NS_EVENT_BITS_MUTATION_NODEREMOVED0x04, aParent)) { | |||
| 5192 | InternalMutationEvent mutation(true, eLegacyNodeRemoved); | |||
| 5193 | mutation.mRelatedNode = aParent; | |||
| 5194 | ||||
| 5195 | mozAutoSubtreeModified subtree(aParent->OwnerDoc(), aParent); | |||
| 5196 | EventDispatcher::Dispatch(aChild, nullptr, &mutation); | |||
| 5197 | } | |||
| 5198 | } | |||
| 5199 | ||||
| 5200 | void nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments() { | |||
| 5201 | if (!sEventListenerManagersHash) { | |||
| 5202 | return; | |||
| 5203 | } | |||
| 5204 | ||||
| 5205 | for (auto i = sEventListenerManagersHash->Iter(); !i.Done(); i.Next()) { | |||
| 5206 | auto entry = static_cast<EventListenerManagerMapEntry*>(i.Get()); | |||
| 5207 | nsINode* n = static_cast<nsINode*>(entry->mListenerManager->GetTarget()); | |||
| 5208 | if (n && n->IsInComposedDoc() && | |||
| 5209 | nsCCUncollectableMarker::InGeneration( | |||
| 5210 | n->OwnerDoc()->GetMarkedCCGeneration())) { | |||
| 5211 | entry->mListenerManager->MarkForCC(); | |||
| 5212 | } | |||
| 5213 | } | |||
| 5214 | } | |||
| 5215 | ||||
| 5216 | /* static */ | |||
| 5217 | void nsContentUtils::TraverseListenerManager( | |||
| 5218 | nsINode* aNode, nsCycleCollectionTraversalCallback& cb) { | |||
| 5219 | if (!sEventListenerManagersHash) { | |||
| 5220 | // We're already shut down, just return. | |||
| 5221 | return; | |||
| 5222 | } | |||
| 5223 | ||||
| 5224 | auto entry = static_cast<EventListenerManagerMapEntry*>( | |||
| 5225 | sEventListenerManagersHash->Search(aNode)); | |||
| 5226 | if (entry) { | |||
| 5227 | CycleCollectionNoteChild(cb, entry->mListenerManager.get(), | |||
| 5228 | "[via hash] mListenerManager"); | |||
| 5229 | } | |||
| 5230 | } | |||
| 5231 | ||||
| 5232 | EventListenerManager* nsContentUtils::GetListenerManagerForNode( | |||
| 5233 | nsINode* aNode) { | |||
| 5234 | if (!sEventListenerManagersHash) { | |||
| 5235 | // We're already shut down, don't bother creating an event listener | |||
| 5236 | // manager. | |||
| 5237 | ||||
| 5238 | return nullptr; | |||
| 5239 | } | |||
| 5240 | ||||
| 5241 | auto entry = static_cast<EventListenerManagerMapEntry*>( | |||
| 5242 | sEventListenerManagersHash->Add(aNode, fallible)); | |||
| 5243 | ||||
| 5244 | if (!entry) { | |||
| 5245 | return nullptr; | |||
| 5246 | } | |||
| 5247 | ||||
| 5248 | if (!entry->mListenerManager) { | |||
| 5249 | entry->mListenerManager = new EventListenerManager(aNode); | |||
| 5250 | ||||
| 5251 | aNode->SetFlags(NODE_HAS_LISTENERMANAGER); | |||
| 5252 | } | |||
| 5253 | ||||
| 5254 | return entry->mListenerManager; | |||
| 5255 | } | |||
| 5256 | ||||
| 5257 | EventListenerManager* nsContentUtils::GetExistingListenerManagerForNode( | |||
| 5258 | const nsINode* aNode) { | |||
| 5259 | if (!aNode->HasFlag(NODE_HAS_LISTENERMANAGER)) { | |||
| 5260 | return nullptr; | |||
| 5261 | } | |||
| 5262 | ||||
| 5263 | if (!sEventListenerManagersHash) { | |||
| 5264 | // We're already shut down, don't bother creating an event listener | |||
| 5265 | // manager. | |||
| 5266 | ||||
| 5267 | return nullptr; | |||
| 5268 | } | |||
| 5269 | ||||
| 5270 | auto entry = static_cast<EventListenerManagerMapEntry*>( | |||
| 5271 | sEventListenerManagersHash->Search(aNode)); | |||
| 5272 | if (entry) { | |||
| 5273 | return entry->mListenerManager; | |||
| 5274 | } | |||
| 5275 | ||||
| 5276 | return nullptr; | |||
| 5277 | } | |||
| 5278 | ||||
| 5279 | void nsContentUtils::AddEntryToDOMArenaTable(nsINode* aNode, | |||
| 5280 | DOMArena* aDOMArena) { | |||
| 5281 | 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" , 5281); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::dom_arena_allocator_enabled_AtStartup()" ")"); do { *((volatile int*)__null) = 5281; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 5282 | 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" , 5282); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sDOMArenaHashtable->Contains(aNode)" ")"); do { *((volatile int*)__null) = 5282; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); | |||
| 5283 | 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" , 5283); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aNode->HasFlag(NODE_KEEPS_DOMARENA)" ")"); do { *((volatile int*)__null) = 5283; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 5284 | if (!sDOMArenaHashtable) { | |||
| 5285 | sDOMArenaHashtable = | |||
| 5286 | new nsRefPtrHashtable<nsPtrHashKey<const nsINode>, dom::DOMArena>(); | |||
| 5287 | } | |||
| 5288 | aNode->SetFlags(NODE_KEEPS_DOMARENA); | |||
| 5289 | sDOMArenaHashtable->InsertOrUpdate(aNode, RefPtr<DOMArena>(aDOMArena)); | |||
| 5290 | } | |||
| 5291 | ||||
| 5292 | already_AddRefed<DOMArena> nsContentUtils::TakeEntryFromDOMArenaTable( | |||
| 5293 | const nsINode* aNode) { | |||
| 5294 | 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" , 5294); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sDOMArenaHashtable->Contains(aNode)" ")"); do { *((volatile int*)__null) = 5294; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 5295 | 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" , 5295); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::dom_arena_allocator_enabled_AtStartup()" ")"); do { *((volatile int*)__null) = 5295; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 5296 | RefPtr<DOMArena> arena; | |||
| 5297 | sDOMArenaHashtable->Remove(aNode, getter_AddRefs(arena)); | |||
| 5298 | return arena.forget(); | |||
| 5299 | } | |||
| 5300 | ||||
| 5301 | /* static */ | |||
| 5302 | void nsContentUtils::RemoveListenerManager(nsINode* aNode) { | |||
| 5303 | if (sEventListenerManagersHash) { | |||
| 5304 | auto entry = static_cast<EventListenerManagerMapEntry*>( | |||
| 5305 | sEventListenerManagersHash->Search(aNode)); | |||
| 5306 | if (entry) { | |||
| 5307 | RefPtr<EventListenerManager> listenerManager; | |||
| 5308 | listenerManager.swap(entry->mListenerManager); | |||
| 5309 | // Remove the entry and *then* do operations that could cause further | |||
| 5310 | // modification of sEventListenerManagersHash. See bug 334177. | |||
| 5311 | sEventListenerManagersHash->RawRemove(entry); | |||
| 5312 | if (listenerManager) { | |||
| 5313 | listenerManager->Disconnect(); | |||
| 5314 | } | |||
| 5315 | } | |||
| 5316 | } | |||
| 5317 | } | |||
| 5318 | ||||
| 5319 | /* static */ | |||
| 5320 | bool nsContentUtils::IsValidNodeName(nsAtom* aLocalName, nsAtom* aPrefix, | |||
| 5321 | int32_t aNamespaceID) { | |||
| 5322 | if (aNamespaceID == kNameSpaceID_Unknown-1) { | |||
| 5323 | return false; | |||
| 5324 | } | |||
| 5325 | ||||
| 5326 | if (!aPrefix) { | |||
| 5327 | // If the prefix is null, then either the QName must be xmlns or the | |||
| 5328 | // namespace must not be XMLNS. | |||
| 5329 | return (aLocalName == nsGkAtoms::xmlns) == | |||
| 5330 | (aNamespaceID == kNameSpaceID_XMLNS1); | |||
| 5331 | } | |||
| 5332 | ||||
| 5333 | // If the prefix is non-null then the namespace must not be null. | |||
| 5334 | if (aNamespaceID == kNameSpaceID_None) { | |||
| 5335 | return false; | |||
| 5336 | } | |||
| 5337 | ||||
| 5338 | // If the namespace is the XMLNS namespace then the prefix must be xmlns, | |||
| 5339 | // but the localname must not be xmlns. | |||
| 5340 | if (aNamespaceID == kNameSpaceID_XMLNS1) { | |||
| 5341 | return aPrefix == nsGkAtoms::xmlns && aLocalName != nsGkAtoms::xmlns; | |||
| 5342 | } | |||
| 5343 | ||||
| 5344 | // If the namespace is not the XMLNS namespace then the prefix must not be | |||
| 5345 | // xmlns. | |||
| 5346 | // If the namespace is the XML namespace then the prefix can be anything. | |||
| 5347 | // If the namespace is not the XML namespace then the prefix must not be xml. | |||
| 5348 | return aPrefix != nsGkAtoms::xmlns && | |||
| 5349 | (aNamespaceID == kNameSpaceID_XML2 || aPrefix != nsGkAtoms::xml); | |||
| 5350 | } | |||
| 5351 | ||||
| 5352 | already_AddRefed<DocumentFragment> nsContentUtils::CreateContextualFragment( | |||
| 5353 | nsINode* aContextNode, const nsAString& aFragment, | |||
| 5354 | bool aPreventScriptExecution, ErrorResult& aRv) { | |||
| 5355 | if (!aContextNode) { | |||
| 5356 | aRv.Throw(NS_ERROR_INVALID_ARG); | |||
| 5357 | return nullptr; | |||
| 5358 | } | |||
| 5359 | ||||
| 5360 | // If we don't have a document here, we can't get the right security context | |||
| 5361 | // for compiling event handlers... so just bail out. | |||
| 5362 | RefPtr<Document> document = aContextNode->OwnerDoc(); | |||
| 5363 | bool isHTML = document->IsHTMLDocument(); | |||
| 5364 | ||||
| 5365 | if (isHTML) { | |||
| 5366 | RefPtr<DocumentFragment> frag = new (document->NodeInfoManager()) | |||
| 5367 | DocumentFragment(document->NodeInfoManager()); | |||
| 5368 | ||||
| 5369 | Element* element = aContextNode->GetAsElementOrParentElement(); | |||
| 5370 | if (element && !element->IsHTMLElement(nsGkAtoms::html)) { | |||
| 5371 | aRv = ParseFragmentHTML( | |||
| 5372 | aFragment, frag, element->NodeInfo()->NameAtom(), | |||
| 5373 | element->GetNameSpaceID(), | |||
| 5374 | (document->GetCompatibilityMode() == eCompatibility_NavQuirks), | |||
| 5375 | aPreventScriptExecution); | |||
| 5376 | } else { | |||
| 5377 | aRv = ParseFragmentHTML( | |||
| 5378 | aFragment, frag, nsGkAtoms::body, kNameSpaceID_XHTML3, | |||
| 5379 | (document->GetCompatibilityMode() == eCompatibility_NavQuirks), | |||
| 5380 | aPreventScriptExecution); | |||
| 5381 | } | |||
| 5382 | ||||
| 5383 | return frag.forget(); | |||
| 5384 | } | |||
| 5385 | ||||
| 5386 | AutoTArray<nsString, 32> tagStack; | |||
| 5387 | nsAutoString uriStr, nameStr; | |||
| 5388 | for (Element* element : aContextNode->InclusiveAncestorsOfType<Element>()) { | |||
| 5389 | nsString& tagName = *tagStack.AppendElement(); | |||
| 5390 | // It mostly doesn't actually matter what tag name we use here: XML doesn't | |||
| 5391 | // have parsing that depends on the open tag stack, apart from namespace | |||
| 5392 | // declarations. So this whole tagStack bit is just there to get the right | |||
| 5393 | // namespace declarations to the XML parser. That said, the parser _is_ | |||
| 5394 | // going to create elements with the tag names we provide here, so we need | |||
| 5395 | // to make sure they are not names that can trigger custom element | |||
| 5396 | // constructors. Just make up a name that is never going to be a valid | |||
| 5397 | // custom element name. | |||
| 5398 | // | |||
| 5399 | // The principled way to do this would probably be to add a new FromParser | |||
| 5400 | // value and make sure we use it when creating the context elements, then | |||
| 5401 | // make sure we teach all FromParser consumers (and in particular the custom | |||
| 5402 | // element code) about it as needed. But right now the XML parser never | |||
| 5403 | // actually uses FromParser values other than NOT_FROM_PARSER, and changing | |||
| 5404 | // that is pretty complicated. | |||
| 5405 | tagName.AssignLiteral("notacustomelement"); | |||
| 5406 | ||||
| 5407 | // see if we need to add xmlns declarations | |||
| 5408 | uint32_t count = element->GetAttrCount(); | |||
| 5409 | bool setDefaultNamespace = false; | |||
| 5410 | if (count > 0) { | |||
| 5411 | uint32_t index; | |||
| 5412 | ||||
| 5413 | for (index = 0; index < count; index++) { | |||
| 5414 | const BorrowedAttrInfo info = element->GetAttrInfoAt(index); | |||
| 5415 | const nsAttrName* name = info.mName; | |||
| 5416 | if (name->NamespaceEquals(kNameSpaceID_XMLNS1)) { | |||
| 5417 | info.mValue->ToString(uriStr); | |||
| 5418 | ||||
| 5419 | // really want something like nsXMLContentSerializer::SerializeAttr | |||
| 5420 | tagName.AppendLiteral(" xmlns"); // space important | |||
| 5421 | if (name->GetPrefix()) { | |||
| 5422 | tagName.Append(char16_t(':')); | |||
| 5423 | name->LocalName()->ToString(nameStr); | |||
| 5424 | tagName.Append(nameStr); | |||
| 5425 | } else { | |||
| 5426 | setDefaultNamespace = true; | |||
| 5427 | } | |||
| 5428 | tagName.AppendLiteral(R"(=")"); | |||
| 5429 | tagName.Append(uriStr); | |||
| 5430 | tagName.Append('"'); | |||
| 5431 | } | |||
| 5432 | } | |||
| 5433 | } | |||
| 5434 | ||||
| 5435 | if (!setDefaultNamespace) { | |||
| 5436 | mozilla::dom::NodeInfo* info = element->NodeInfo(); | |||
| 5437 | if (!info->GetPrefixAtom() && info->NamespaceID() != kNameSpaceID_None) { | |||
| 5438 | // We have no namespace prefix, but have a namespace ID. Push | |||
| 5439 | // default namespace attr in, so that our kids will be in our | |||
| 5440 | // namespace. | |||
| 5441 | info->GetNamespaceURI(uriStr); | |||
| 5442 | tagName.AppendLiteral(R"( xmlns=")"); | |||
| 5443 | tagName.Append(uriStr); | |||
| 5444 | tagName.Append('"'); | |||
| 5445 | } | |||
| 5446 | } | |||
| 5447 | } | |||
| 5448 | ||||
| 5449 | RefPtr<DocumentFragment> frag; | |||
| 5450 | aRv = ParseFragmentXML(aFragment, document, tagStack, aPreventScriptExecution, | |||
| 5451 | -1, getter_AddRefs(frag)); | |||
| 5452 | return frag.forget(); | |||
| 5453 | } | |||
| 5454 | ||||
| 5455 | /* static */ | |||
| 5456 | void nsContentUtils::DropFragmentParsers() { | |||
| 5457 | NS_IF_RELEASE(sHTMLFragmentParser)do { if (sHTMLFragmentParser) { (sHTMLFragmentParser)->Release (); (sHTMLFragmentParser) = 0; } } while (0); | |||
| 5458 | NS_IF_RELEASE(sXMLFragmentParser)do { if (sXMLFragmentParser) { (sXMLFragmentParser)->Release (); (sXMLFragmentParser) = 0; } } while (0); | |||
| 5459 | NS_IF_RELEASE(sXMLFragmentSink)do { if (sXMLFragmentSink) { (sXMLFragmentSink)->Release() ; (sXMLFragmentSink) = 0; } } while (0); | |||
| 5460 | } | |||
| 5461 | ||||
| 5462 | /* static */ | |||
| 5463 | void nsContentUtils::XPCOMShutdown() { nsContentUtils::DropFragmentParsers(); } | |||
| 5464 | ||||
| 5465 | /* Helper function to compuate Sanitization Flags for ParseFramentHTML/XML */ | |||
| 5466 | uint32_t computeSanitizationFlags(nsIPrincipal* aPrincipal, int32_t aFlags) { | |||
| 5467 | uint32_t sanitizationFlags = 0; | |||
| 5468 | if (aPrincipal->IsSystemPrincipal()) { | |||
| 5469 | if (aFlags < 0) { | |||
| 5470 | // if this is a chrome-privileged document and no explicit flags | |||
| 5471 | // were passed, then use this sanitization flags. | |||
| 5472 | sanitizationFlags = nsIParserUtils::SanitizerAllowStyle | | |||
| 5473 | nsIParserUtils::SanitizerAllowComments | | |||
| 5474 | nsIParserUtils::SanitizerDropForms | | |||
| 5475 | nsIParserUtils::SanitizerLogRemovals; | |||
| 5476 | } else { | |||
| 5477 | // if the caller explicitly passes flags, then we use those | |||
| 5478 | // flags but additionally drop forms. | |||
| 5479 | sanitizationFlags = aFlags | nsIParserUtils::SanitizerDropForms; | |||
| 5480 | } | |||
| 5481 | } else if (aFlags >= 0) { | |||
| 5482 | // aFlags by default is -1 and is only ever non equal to -1 if the | |||
| 5483 | // caller of ParseFragmentHTML/ParseFragmentXML is | |||
| 5484 | // ParserUtils::ParseFragment(). Only in that case we should use | |||
| 5485 | // the sanitization flags passed within aFlags. | |||
| 5486 | sanitizationFlags = aFlags; | |||
| 5487 | } | |||
| 5488 | return sanitizationFlags; | |||
| 5489 | } | |||
| 5490 | ||||
| 5491 | /* static */ | |||
| 5492 | void nsContentUtils::SetHTMLUnsafe(FragmentOrElement* aTarget, | |||
| 5493 | Element* aContext, | |||
| 5494 | const TrustedHTMLOrString& aSource, | |||
| 5495 | bool aIsShadowRoot, ErrorResult& aError) { | |||
| 5496 | constexpr nsLiteralString elementSink = u"Element setHTMLUnsafe"_ns; | |||
| 5497 | constexpr nsLiteralString shadowRootSink = u"ShadowRoot setHTMLUnsafe"_ns; | |||
| 5498 | Maybe<nsAutoString> compliantStringHolder; | |||
| 5499 | const nsAString* compliantString = | |||
| 5500 | TrustedTypeUtils::GetTrustedTypesCompliantString( | |||
| 5501 | aSource, aIsShadowRoot ? shadowRootSink : elementSink, | |||
| 5502 | kTrustedTypesOnlySinkGroup, *aContext, compliantStringHolder, aError); | |||
| 5503 | if (aError.Failed()) { | |||
| 5504 | return; | |||
| 5505 | } | |||
| 5506 | ||||
| 5507 | RefPtr<DocumentFragment> fragment; | |||
| 5508 | { | |||
| 5509 | 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" , 5510); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sFragmentParsingActive" ") (" "Re-entrant fragment parsing attempted." ")"); do { *( (volatile int*)__null) = 5510; __attribute__((nomerge)) ::abort (); } while (false); } } while (false) | |||
| 5510 | "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" , 5510); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sFragmentParsingActive" ") (" "Re-entrant fragment parsing attempted." ")"); do { *( (volatile int*)__null) = 5510; __attribute__((nomerge)) ::abort (); } while (false); } } while (false); | |||
| 5511 | mozilla::AutoRestore<bool> guard(sFragmentParsingActive); | |||
| 5512 | sFragmentParsingActive = true; | |||
| 5513 | if (!sHTMLFragmentParser) { | |||
| 5514 | NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser())(sHTMLFragmentParser = new nsHtml5StringParser())->AddRef( ); | |||
| 5515 | // Now sHTMLFragmentParser owns the object | |||
| 5516 | } | |||
| 5517 | ||||
| 5518 | nsAtom* contextLocalName = aContext->NodeInfo()->NameAtom(); | |||
| 5519 | int32_t contextNameSpaceID = aContext->GetNameSpaceID(); | |||
| 5520 | ||||
| 5521 | RefPtr<Document> doc = aTarget->OwnerDoc(); | |||
| 5522 | fragment = doc->CreateDocumentFragment(); | |||
| 5523 | ||||
| 5524 | nsresult rv = sHTMLFragmentParser->ParseFragment( | |||
| 5525 | *compliantString, fragment, contextLocalName, contextNameSpaceID, | |||
| 5526 | fragment->OwnerDoc()->GetCompatibilityMode() == | |||
| 5527 | eCompatibility_NavQuirks, | |||
| 5528 | true, true); | |||
| 5529 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 5530 | 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" , 5530); | |||
| 5531 | } | |||
| 5532 | } | |||
| 5533 | ||||
| 5534 | aTarget->ReplaceChildren(fragment, IgnoreErrors()); | |||
| 5535 | } | |||
| 5536 | ||||
| 5537 | /* static */ | |||
| 5538 | nsresult nsContentUtils::ParseFragmentHTML( | |||
| 5539 | const nsAString& aSourceBuffer, nsIContent* aTargetNode, | |||
| 5540 | nsAtom* aContextLocalName, int32_t aContextNamespace, bool aQuirks, | |||
| 5541 | bool aPreventScriptExecution, int32_t aFlags) { | |||
| 5542 | if (nsContentUtils::sFragmentParsingActive) { | |||
| 5543 | 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" , 5543); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "Re-entrant fragment parsing attempted." ")"); do { *((volatile int*)__null) = 5543; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 5544 | return NS_ERROR_DOM_INVALID_STATE_ERR; | |||
| 5545 | } | |||
| 5546 | mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive); | |||
| 5547 | nsContentUtils::sFragmentParsingActive = true; | |||
| 5548 | if (!sHTMLFragmentParser) { | |||
| 5549 | NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser())(sHTMLFragmentParser = new nsHtml5StringParser())->AddRef( ); | |||
| 5550 | // Now sHTMLFragmentParser owns the object | |||
| 5551 | } | |||
| 5552 | ||||
| 5553 | nsCOMPtr<nsIPrincipal> nodePrincipal = aTargetNode->NodePrincipal(); | |||
| 5554 | ||||
| 5555 | #ifdef DEBUG1 | |||
| 5556 | // aFlags should always be -1 unless the caller of ParseFragmentHTML | |||
| 5557 | // is ParserUtils::ParseFragment() which is the only caller that intends | |||
| 5558 | // sanitization. For all other callers we need to ensure to call | |||
| 5559 | // AuditParsingOfHTMLXMLFragments. | |||
| 5560 | if (aFlags < 0) { | |||
| 5561 | DOMSecurityMonitor::AuditParsingOfHTMLXMLFragments(nodePrincipal, | |||
| 5562 | aSourceBuffer); | |||
| 5563 | } | |||
| 5564 | #endif | |||
| 5565 | ||||
| 5566 | nsIContent* target = aTargetNode; | |||
| 5567 | ||||
| 5568 | RefPtr<Document> doc = aTargetNode->OwnerDoc(); | |||
| 5569 | RefPtr<DocumentFragment> fragment; | |||
| 5570 | // We sanitize if the fragment occurs in a system privileged | |||
| 5571 | // context, an about: page, or if there are explicit sanitization flags. | |||
| 5572 | // Please note that about:blank and about:srcdoc inherit the security | |||
| 5573 | // context from the embedding context and hence are not loaded using | |||
| 5574 | // an about: scheme principal. | |||
| 5575 | bool shouldSanitize = nodePrincipal->IsSystemPrincipal() || | |||
| 5576 | nodePrincipal->SchemeIs("about") || aFlags >= 0; | |||
| 5577 | if (shouldSanitize) { | |||
| 5578 | if (!doc->IsLoadedAsData()) { | |||
| 5579 | doc = nsContentUtils::CreateInertHTMLDocument(doc); | |||
| 5580 | if (!doc) { | |||
| 5581 | return NS_ERROR_FAILURE; | |||
| 5582 | } | |||
| 5583 | } | |||
| 5584 | fragment = | |||
| 5585 | new (doc->NodeInfoManager()) DocumentFragment(doc->NodeInfoManager()); | |||
| 5586 | target = fragment; | |||
| 5587 | } | |||
| 5588 | ||||
| 5589 | nsresult rv = sHTMLFragmentParser->ParseFragment( | |||
| 5590 | aSourceBuffer, target, aContextLocalName, aContextNamespace, aQuirks, | |||
| 5591 | aPreventScriptExecution, false); | |||
| 5592 | 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" , 5592); return rv; } } while (false); | |||
| 5593 | ||||
| 5594 | if (fragment) { | |||
| 5595 | uint32_t sanitizationFlags = | |||
| 5596 | computeSanitizationFlags(nodePrincipal, aFlags); | |||
| 5597 | // Don't fire mutation events for nodes removed by the sanitizer. | |||
| 5598 | nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker; | |||
| 5599 | nsTreeSanitizer sanitizer(sanitizationFlags); | |||
| 5600 | sanitizer.Sanitize(fragment); | |||
| 5601 | ||||
| 5602 | ErrorResult error; | |||
| 5603 | aTargetNode->AppendChild(*fragment, error); | |||
| 5604 | rv = error.StealNSResult(); | |||
| 5605 | } | |||
| 5606 | ||||
| 5607 | return rv; | |||
| 5608 | } | |||
| 5609 | ||||
| 5610 | /* static */ | |||
| 5611 | nsresult nsContentUtils::ParseDocumentHTML( | |||
| 5612 | const nsAString& aSourceBuffer, Document* aTargetDocument, | |||
| 5613 | bool aScriptingEnabledForNoscriptParsing) { | |||
| 5614 | if (nsContentUtils::sFragmentParsingActive) { | |||
| 5615 | 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" , 5615); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "Re-entrant fragment parsing attempted." ")"); do { *((volatile int*)__null) = 5615; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 5616 | return NS_ERROR_DOM_INVALID_STATE_ERR; | |||
| 5617 | } | |||
| 5618 | mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive); | |||
| 5619 | nsContentUtils::sFragmentParsingActive = true; | |||
| 5620 | if (!sHTMLFragmentParser) { | |||
| 5621 | NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser())(sHTMLFragmentParser = new nsHtml5StringParser())->AddRef( ); | |||
| 5622 | // Now sHTMLFragmentParser owns the object | |||
| 5623 | } | |||
| 5624 | nsresult rv = sHTMLFragmentParser->ParseDocument( | |||
| 5625 | aSourceBuffer, aTargetDocument, aScriptingEnabledForNoscriptParsing); | |||
| 5626 | return rv; | |||
| 5627 | } | |||
| 5628 | ||||
| 5629 | /* static */ | |||
| 5630 | nsresult nsContentUtils::ParseFragmentXML(const nsAString& aSourceBuffer, | |||
| 5631 | Document* aDocument, | |||
| 5632 | nsTArray<nsString>& aTagStack, | |||
| 5633 | bool aPreventScriptExecution, | |||
| 5634 | int32_t aFlags, | |||
| 5635 | DocumentFragment** aReturn) { | |||
| 5636 | if (nsContentUtils::sFragmentParsingActive) { | |||
| 5637 | 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" , 5637); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "Re-entrant fragment parsing attempted." ")"); do { *((volatile int*)__null) = 5637; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 5638 | return NS_ERROR_DOM_INVALID_STATE_ERR; | |||
| 5639 | } | |||
| 5640 | mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive); | |||
| 5641 | nsContentUtils::sFragmentParsingActive = true; | |||
| 5642 | if (!sXMLFragmentParser) { | |||
| 5643 | RefPtr<nsParser> parser = new nsParser(); | |||
| 5644 | parser.forget(&sXMLFragmentParser); | |||
| 5645 | // sXMLFragmentParser now owns the parser | |||
| 5646 | } | |||
| 5647 | if (!sXMLFragmentSink) { | |||
| 5648 | NS_NewXMLFragmentContentSink(&sXMLFragmentSink); | |||
| 5649 | // sXMLFragmentSink now owns the sink | |||
| 5650 | } | |||
| 5651 | nsCOMPtr<nsIContentSink> contentsink = do_QueryInterface(sXMLFragmentSink); | |||
| 5652 | 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" , 5652); AnnotateMozCrashReason("MOZ_ASSERT" "(" "contentsink" ") (" "Sink doesn't QI to nsIContentSink!" ")"); do { *((volatile int*)__null) = 5652; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 5653 | sXMLFragmentParser->SetContentSink(contentsink); | |||
| 5654 | ||||
| 5655 | RefPtr<Document> doc; | |||
| 5656 | nsCOMPtr<nsIPrincipal> nodePrincipal = aDocument->NodePrincipal(); | |||
| 5657 | ||||
| 5658 | #ifdef DEBUG1 | |||
| 5659 | // aFlags should always be -1 unless the caller of ParseFragmentXML | |||
| 5660 | // is ParserUtils::ParseFragment() which is the only caller that intends | |||
| 5661 | // sanitization. For all other callers we need to ensure to call | |||
| 5662 | // AuditParsingOfHTMLXMLFragments. | |||
| 5663 | if (aFlags < 0) { | |||
| 5664 | DOMSecurityMonitor::AuditParsingOfHTMLXMLFragments(nodePrincipal, | |||
| 5665 | aSourceBuffer); | |||
| 5666 | } | |||
| 5667 | #endif | |||
| 5668 | ||||
| 5669 | // We sanitize if the fragment occurs in a system privileged | |||
| 5670 | // context, an about: page, or if there are explicit sanitization flags. | |||
| 5671 | // Please note that about:blank and about:srcdoc inherit the security | |||
| 5672 | // context from the embedding context and hence are not loaded using | |||
| 5673 | // an about: scheme principal. | |||
| 5674 | bool shouldSanitize = nodePrincipal->IsSystemPrincipal() || | |||
| 5675 | nodePrincipal->SchemeIs("about") || aFlags >= 0; | |||
| 5676 | if (shouldSanitize && !aDocument->IsLoadedAsData()) { | |||
| 5677 | doc = nsContentUtils::CreateInertXMLDocument(aDocument); | |||
| 5678 | } else { | |||
| 5679 | doc = aDocument; | |||
| 5680 | } | |||
| 5681 | ||||
| 5682 | sXMLFragmentSink->SetTargetDocument(doc); | |||
| 5683 | sXMLFragmentSink->SetPreventScriptExecution(aPreventScriptExecution); | |||
| 5684 | ||||
| 5685 | nsresult rv = sXMLFragmentParser->ParseFragment(aSourceBuffer, aTagStack); | |||
| 5686 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 5687 | // Drop the fragment parser and sink that might be in an inconsistent state | |||
| 5688 | NS_IF_RELEASE(sXMLFragmentParser)do { if (sXMLFragmentParser) { (sXMLFragmentParser)->Release (); (sXMLFragmentParser) = 0; } } while (0); | |||
| 5689 | NS_IF_RELEASE(sXMLFragmentSink)do { if (sXMLFragmentSink) { (sXMLFragmentSink)->Release() ; (sXMLFragmentSink) = 0; } } while (0); | |||
| 5690 | return rv; | |||
| 5691 | } | |||
| 5692 | ||||
| 5693 | rv = sXMLFragmentSink->FinishFragmentParsing(aReturn); | |||
| 5694 | ||||
| 5695 | sXMLFragmentParser->Reset(); | |||
| 5696 | 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" , 5696); return rv; } } while (false); | |||
| 5697 | ||||
| 5698 | if (shouldSanitize) { | |||
| 5699 | uint32_t sanitizationFlags = | |||
| 5700 | computeSanitizationFlags(nodePrincipal, aFlags); | |||
| 5701 | // Don't fire mutation events for nodes removed by the sanitizer. | |||
| 5702 | nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker; | |||
| 5703 | nsTreeSanitizer sanitizer(sanitizationFlags); | |||
| 5704 | sanitizer.Sanitize(*aReturn); | |||
| 5705 | } | |||
| 5706 | ||||
| 5707 | return rv; | |||
| 5708 | } | |||
| 5709 | ||||
| 5710 | /* static */ | |||
| 5711 | nsresult nsContentUtils::ConvertToPlainText(const nsAString& aSourceBuffer, | |||
| 5712 | nsAString& aResultBuffer, | |||
| 5713 | uint32_t aFlags, | |||
| 5714 | uint32_t aWrapCol) { | |||
| 5715 | RefPtr<Document> document = nsContentUtils::CreateInertHTMLDocument(nullptr); | |||
| 5716 | if (!document) { | |||
| 5717 | return NS_ERROR_FAILURE; | |||
| 5718 | } | |||
| 5719 | ||||
| 5720 | nsresult rv = nsContentUtils::ParseDocumentHTML( | |||
| 5721 | aSourceBuffer, document, | |||
| 5722 | !(aFlags & nsIDocumentEncoder::OutputNoScriptContent)); | |||
| 5723 | 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" , 5723); return rv; } } while (false); | |||
| 5724 | ||||
| 5725 | nsCOMPtr<nsIDocumentEncoder> encoder = do_createDocumentEncoder("text/plain"); | |||
| 5726 | ||||
| 5727 | rv = encoder->Init(document, u"text/plain"_ns, aFlags); | |||
| 5728 | 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" , 5728); return rv; } } while (false); | |||
| 5729 | ||||
| 5730 | encoder->SetWrapColumn(aWrapCol); | |||
| 5731 | ||||
| 5732 | return encoder->EncodeToString(aResultBuffer); | |||
| 5733 | } | |||
| 5734 | ||||
| 5735 | static already_AddRefed<Document> CreateInertDocument(const Document* aTemplate, | |||
| 5736 | DocumentFlavor aFlavor) { | |||
| 5737 | if (aTemplate) { | |||
| 5738 | bool hasHad = true; | |||
| 5739 | nsIScriptGlobalObject* sgo = aTemplate->GetScriptHandlingObject(hasHad); | |||
| 5740 | 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" , 5740); return nullptr; } } while (false); | |||
| 5741 | ||||
| 5742 | nsCOMPtr<Document> doc; | |||
| 5743 | nsresult rv = NS_NewDOMDocument( | |||
| 5744 | getter_AddRefs(doc), u""_ns, u""_ns, nullptr, | |||
| 5745 | aTemplate->GetDocumentURI(), aTemplate->GetDocBaseURI(), | |||
| 5746 | aTemplate->NodePrincipal(), true, sgo, aFlavor); | |||
| 5747 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 5748 | return nullptr; | |||
| 5749 | } | |||
| 5750 | return doc.forget(); | |||
| 5751 | } | |||
| 5752 | nsCOMPtr<nsIURI> uri; | |||
| 5753 | NS_NewURI(getter_AddRefs(uri), "about:blank"_ns); | |||
| 5754 | if (!uri) { | |||
| 5755 | return nullptr; | |||
| 5756 | } | |||
| 5757 | ||||
| 5758 | RefPtr<NullPrincipal> nullPrincipal = | |||
| 5759 | NullPrincipal::CreateWithoutOriginAttributes(); | |||
| 5760 | if (!nullPrincipal) { | |||
| 5761 | return nullptr; | |||
| 5762 | } | |||
| 5763 | ||||
| 5764 | nsCOMPtr<Document> doc; | |||
| 5765 | nsresult rv = | |||
| 5766 | NS_NewDOMDocument(getter_AddRefs(doc), u""_ns, u""_ns, nullptr, uri, uri, | |||
| 5767 | nullPrincipal, true, nullptr, aFlavor); | |||
| 5768 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 5769 | return nullptr; | |||
| 5770 | } | |||
| 5771 | return doc.forget(); | |||
| 5772 | } | |||
| 5773 | ||||
| 5774 | /* static */ | |||
| 5775 | already_AddRefed<Document> nsContentUtils::CreateInertXMLDocument( | |||
| 5776 | const Document* aTemplate) { | |||
| 5777 | return CreateInertDocument(aTemplate, DocumentFlavorXML); | |||
| 5778 | } | |||
| 5779 | ||||
| 5780 | /* static */ | |||
| 5781 | already_AddRefed<Document> nsContentUtils::CreateInertHTMLDocument( | |||
| 5782 | const Document* aTemplate) { | |||
| 5783 | return CreateInertDocument(aTemplate, DocumentFlavorHTML); | |||
| 5784 | } | |||
| 5785 | ||||
| 5786 | /* static */ | |||
| 5787 | nsresult nsContentUtils::SetNodeTextContent(nsIContent* aContent, | |||
| 5788 | const nsAString& aValue, | |||
| 5789 | bool aTryReuse) { | |||
| 5790 | // Fire DOMNodeRemoved mutation events before we do anything else. | |||
| 5791 | nsCOMPtr<nsIContent> owningContent; | |||
| 5792 | ||||
| 5793 | // Batch possible DOMSubtreeModified events. | |||
| 5794 | mozAutoSubtreeModified subtree(nullptr, nullptr); | |||
| 5795 | ||||
| 5796 | // Scope firing mutation events so that we don't carry any state that | |||
| 5797 | // might be stale | |||
| 5798 | { | |||
| 5799 | // We're relying on mozAutoSubtreeModified to keep a strong reference if | |||
| 5800 | // needed. | |||
| 5801 | Document* doc = aContent->OwnerDoc(); | |||
| 5802 | ||||
| 5803 | // Optimize the common case of there being no observers | |||
| 5804 | if (HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEREMOVED0x04)) { | |||
| 5805 | subtree.UpdateTarget(doc, nullptr); | |||
| 5806 | owningContent = aContent; | |||
| 5807 | nsCOMPtr<nsINode> child; | |||
| 5808 | bool skipFirst = aTryReuse; | |||
| 5809 | for (child = aContent->GetFirstChild(); | |||
| 5810 | child && child->GetParentNode() == aContent; | |||
| 5811 | child = child->GetNextSibling()) { | |||
| 5812 | if (skipFirst && child->IsText()) { | |||
| 5813 | skipFirst = false; | |||
| 5814 | continue; | |||
| 5815 | } | |||
| 5816 | nsContentUtils::MaybeFireNodeRemoved(child, aContent); | |||
| 5817 | } | |||
| 5818 | } | |||
| 5819 | } | |||
| 5820 | ||||
| 5821 | // Might as well stick a batch around this since we're performing several | |||
| 5822 | // mutations. | |||
| 5823 | mozAutoDocUpdate updateBatch(aContent->GetComposedDoc(), true); | |||
| 5824 | nsAutoMutationBatch mb; | |||
| 5825 | ||||
| 5826 | if (aTryReuse && !aValue.IsEmpty()) { | |||
| 5827 | // Let's remove nodes until we find a eTEXT. | |||
| 5828 | while (aContent->HasChildren()) { | |||
| 5829 | nsIContent* child = aContent->GetFirstChild(); | |||
| 5830 | if (child->IsText()) { | |||
| 5831 | break; | |||
| 5832 | } | |||
| 5833 | aContent->RemoveChildNode(child, true); | |||
| 5834 | } | |||
| 5835 | ||||
| 5836 | // If we have a node, it must be a eTEXT and we reuse it. | |||
| 5837 | if (aContent->HasChildren()) { | |||
| 5838 | nsIContent* child = aContent->GetFirstChild(); | |||
| 5839 | nsresult rv = child->AsText()->SetText(aValue, true); | |||
| 5840 | 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" , 5840); return rv; } } while (false); | |||
| 5841 | ||||
| 5842 | // All the following nodes, if they exist, must be deleted. | |||
| 5843 | while (nsIContent* lastChild = aContent->GetLastChild()) { | |||
| 5844 | if (lastChild == child) { | |||
| 5845 | break; | |||
| 5846 | } | |||
| 5847 | aContent->RemoveChildNode(lastChild, true); | |||
| 5848 | } | |||
| 5849 | } | |||
| 5850 | ||||
| 5851 | if (aContent->HasChildren()) { | |||
| 5852 | return NS_OK; | |||
| 5853 | } | |||
| 5854 | } else { | |||
| 5855 | mb.Init(aContent, true, false); | |||
| 5856 | aContent->RemoveAllChildren(true); | |||
| 5857 | } | |||
| 5858 | mb.RemovalDone(); | |||
| 5859 | ||||
| 5860 | if (aValue.IsEmpty()) { | |||
| 5861 | return NS_OK; | |||
| 5862 | } | |||
| 5863 | ||||
| 5864 | RefPtr<nsTextNode> textContent = new (aContent->NodeInfo()->NodeInfoManager()) | |||
| 5865 | nsTextNode(aContent->NodeInfo()->NodeInfoManager()); | |||
| 5866 | ||||
| 5867 | textContent->SetText(aValue, true); | |||
| 5868 | ||||
| 5869 | ErrorResult rv; | |||
| 5870 | aContent->AppendChildTo(textContent, true, rv); | |||
| 5871 | mb.NodesAdded(); | |||
| 5872 | return rv.StealNSResult(); | |||
| 5873 | } | |||
| 5874 | ||||
| 5875 | static bool AppendNodeTextContentsRecurse(const nsINode* aNode, | |||
| 5876 | nsAString& aResult, | |||
| 5877 | const fallible_t& aFallible) { | |||
| 5878 | for (nsIContent* child = aNode->GetFirstChild(); child; | |||
| 5879 | child = child->GetNextSibling()) { | |||
| 5880 | if (child->IsElement()) { | |||
| 5881 | bool ok = AppendNodeTextContentsRecurse(child, aResult, aFallible); | |||
| 5882 | if (!ok) { | |||
| 5883 | return false; | |||
| 5884 | } | |||
| 5885 | } else if (Text* text = child->GetAsText()) { | |||
| 5886 | bool ok = text->AppendTextTo(aResult, aFallible); | |||
| 5887 | if (!ok) { | |||
| 5888 | return false; | |||
| 5889 | } | |||
| 5890 | } | |||
| 5891 | } | |||
| 5892 | ||||
| 5893 | return true; | |||
| 5894 | } | |||
| 5895 | ||||
| 5896 | /* static */ | |||
| 5897 | bool nsContentUtils::AppendNodeTextContent(const nsINode* aNode, bool aDeep, | |||
| 5898 | nsAString& aResult, | |||
| 5899 | const fallible_t& aFallible) { | |||
| 5900 | if (const Text* text = aNode->GetAsText()) { | |||
| 5901 | return text->AppendTextTo(aResult, aFallible); | |||
| 5902 | } | |||
| 5903 | if (aDeep) { | |||
| 5904 | return AppendNodeTextContentsRecurse(aNode, aResult, aFallible); | |||
| 5905 | } | |||
| 5906 | ||||
| 5907 | for (nsIContent* child = aNode->GetFirstChild(); child; | |||
| 5908 | child = child->GetNextSibling()) { | |||
| 5909 | if (Text* text = child->GetAsText()) { | |||
| 5910 | bool ok = text->AppendTextTo(aResult, fallible); | |||
| 5911 | if (!ok) { | |||
| 5912 | return false; | |||
| 5913 | } | |||
| 5914 | } | |||
| 5915 | } | |||
| 5916 | return true; | |||
| 5917 | } | |||
| 5918 | ||||
| 5919 | bool nsContentUtils::HasNonEmptyTextContent( | |||
| 5920 | nsINode* aNode, TextContentDiscoverMode aDiscoverMode) { | |||
| 5921 | for (nsIContent* child = aNode->GetFirstChild(); child; | |||
| 5922 | child = child->GetNextSibling()) { | |||
| 5923 | if (child->IsText() && child->TextLength() > 0) { | |||
| 5924 | return true; | |||
| 5925 | } | |||
| 5926 | ||||
| 5927 | if (aDiscoverMode == eRecurseIntoChildren && | |||
| 5928 | HasNonEmptyTextContent(child, aDiscoverMode)) { | |||
| 5929 | return true; | |||
| 5930 | } | |||
| 5931 | } | |||
| 5932 | ||||
| 5933 | return false; | |||
| 5934 | } | |||
| 5935 | ||||
| 5936 | /* static */ | |||
| 5937 | bool nsContentUtils::IsInSameAnonymousTree(const nsINode* aNode, | |||
| 5938 | const nsINode* aOtherNode) { | |||
| 5939 | 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" , 5939); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNode" ") (" "Must have a node to work with" ")"); do { *((volatile int*) __null) = 5939; __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); | |||
| 5940 | 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" , 5940); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOtherNode" ") (" "Must have a content to work with" ")"); do { *((volatile int*)__null) = 5940; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 5941 | ||||
| 5942 | const bool anon = aNode->IsInNativeAnonymousSubtree(); | |||
| 5943 | if (anon != aOtherNode->IsInNativeAnonymousSubtree()) { | |||
| 5944 | return false; | |||
| 5945 | } | |||
| 5946 | ||||
| 5947 | if (anon) { | |||
| 5948 | return aOtherNode->GetClosestNativeAnonymousSubtreeRoot() == | |||
| 5949 | aNode->GetClosestNativeAnonymousSubtreeRoot(); | |||
| 5950 | } | |||
| 5951 | ||||
| 5952 | // FIXME: This doesn't deal with disconnected nodes whatsoever, but it didn't | |||
| 5953 | // use to either. Maybe that's fine. | |||
| 5954 | return aNode->GetContainingShadow() == aOtherNode->GetContainingShadow(); | |||
| 5955 | } | |||
| 5956 | ||||
| 5957 | /* static */ | |||
| 5958 | bool nsContentUtils::IsInInteractiveHTMLContent(const Element* aElement, | |||
| 5959 | const Element* aStop) { | |||
| 5960 | const Element* element = aElement; | |||
| 5961 | while (element && element != aStop) { | |||
| 5962 | if (element->IsInteractiveHTMLContent()) { | |||
| 5963 | return true; | |||
| 5964 | } | |||
| 5965 | element = element->GetFlattenedTreeParentElement(); | |||
| 5966 | } | |||
| 5967 | return false; | |||
| 5968 | } | |||
| 5969 | ||||
| 5970 | /* static */ | |||
| 5971 | void nsContentUtils::NotifyInstalledMenuKeyboardListener(bool aInstalling) { | |||
| 5972 | IMEStateManager::OnInstalledMenuKeyboardListener(aInstalling); | |||
| 5973 | } | |||
| 5974 | ||||
| 5975 | /* static */ | |||
| 5976 | bool nsContentUtils::SchemeIs(nsIURI* aURI, const char* aScheme) { | |||
| 5977 | nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI); | |||
| 5978 | 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" , 5978); return false; } } while (false); | |||
| 5979 | return baseURI->SchemeIs(aScheme); | |||
| 5980 | } | |||
| 5981 | ||||
| 5982 | bool nsContentUtils::IsExpandedPrincipal(nsIPrincipal* aPrincipal) { | |||
| 5983 | return aPrincipal && aPrincipal->GetIsExpandedPrincipal(); | |||
| 5984 | } | |||
| 5985 | ||||
| 5986 | bool nsContentUtils::IsSystemOrExpandedPrincipal(nsIPrincipal* aPrincipal) { | |||
| 5987 | return (aPrincipal && aPrincipal->IsSystemPrincipal()) || | |||
| 5988 | IsExpandedPrincipal(aPrincipal); | |||
| 5989 | } | |||
| 5990 | ||||
| 5991 | nsIPrincipal* nsContentUtils::GetSystemPrincipal() { | |||
| 5992 | 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" , 5992); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsInitialized()" ")"); do { *((volatile int*)__null) = 5992; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 5993 | return sSystemPrincipal; | |||
| 5994 | } | |||
| 5995 | ||||
| 5996 | bool nsContentUtils::CombineResourcePrincipals( | |||
| 5997 | nsCOMPtr<nsIPrincipal>* aResourcePrincipal, nsIPrincipal* aExtraPrincipal) { | |||
| 5998 | if (!aExtraPrincipal) { | |||
| 5999 | return false; | |||
| 6000 | } | |||
| 6001 | if (!*aResourcePrincipal) { | |||
| 6002 | *aResourcePrincipal = aExtraPrincipal; | |||
| 6003 | return true; | |||
| 6004 | } | |||
| 6005 | if (*aResourcePrincipal == aExtraPrincipal) { | |||
| 6006 | return false; | |||
| 6007 | } | |||
| 6008 | bool subsumes; | |||
| 6009 | if (NS_SUCCEEDED(((bool)(__builtin_expect(!!(!NS_FAILED_impl((*aResourcePrincipal )->Subsumes(aExtraPrincipal, &subsumes))), 1))) | |||
| 6010 | (*aResourcePrincipal)->Subsumes(aExtraPrincipal, &subsumes))((bool)(__builtin_expect(!!(!NS_FAILED_impl((*aResourcePrincipal )->Subsumes(aExtraPrincipal, &subsumes))), 1))) && | |||
| 6011 | subsumes) { | |||
| 6012 | return false; | |||
| 6013 | } | |||
| 6014 | *aResourcePrincipal = sSystemPrincipal; | |||
| 6015 | return true; | |||
| 6016 | } | |||
| 6017 | ||||
| 6018 | /* static */ | |||
| 6019 | void nsContentUtils::TriggerLink(nsIContent* aContent, nsIURI* aLinkURI, | |||
| 6020 | const nsString& aTargetSpec, bool aClick) { | |||
| 6021 | 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" , 6021); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLinkURI" ") (" "No link URI" ")"); do { *((volatile int*)__null) = 6021; __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 6022 | ||||
| 6023 | if (aContent->IsEditable() || !aContent->OwnerDoc()->LinkHandlingEnabled()) { | |||
| 6024 | return; | |||
| 6025 | } | |||
| 6026 | ||||
| 6027 | nsCOMPtr<nsIDocShell> docShell = aContent->OwnerDoc()->GetDocShell(); | |||
| 6028 | if (!docShell) { | |||
| 6029 | return; | |||
| 6030 | } | |||
| 6031 | ||||
| 6032 | if (!aClick) { | |||
| 6033 | nsDocShell::Cast(docShell)->OnOverLink(aContent, aLinkURI, aTargetSpec); | |||
| 6034 | return; | |||
| 6035 | } | |||
| 6036 | ||||
| 6037 | // Check that this page is allowed to load this URI. | |||
| 6038 | nsresult proceed = NS_OK; | |||
| 6039 | ||||
| 6040 | if (sSecurityManager) { | |||
| 6041 | uint32_t flag = static_cast<uint32_t>(nsIScriptSecurityManager::STANDARD); | |||
| 6042 | proceed = sSecurityManager->CheckLoadURIWithPrincipal( | |||
| 6043 | aContent->NodePrincipal(), aLinkURI, flag, | |||
| 6044 | aContent->OwnerDoc()->InnerWindowID()); | |||
| 6045 | } | |||
| 6046 | ||||
| 6047 | // Only pass off the click event if the script security manager says it's ok. | |||
| 6048 | // We need to rest aTargetSpec for forced downloads. | |||
| 6049 | if (NS_SUCCEEDED(proceed)((bool)(__builtin_expect(!!(!NS_FAILED_impl(proceed)), 1)))) { | |||
| 6050 | // A link/area element with a download attribute is allowed to set | |||
| 6051 | // a pseudo Content-Disposition header. | |||
| 6052 | // For security reasons we only allow websites to declare same-origin | |||
| 6053 | // resources as downloadable. If this check fails we will just do the normal | |||
| 6054 | // thing (i.e. navigate to the resource). | |||
| 6055 | nsAutoString fileName; | |||
| 6056 | if ((!aContent->IsHTMLElement(nsGkAtoms::a) && | |||
| 6057 | !aContent->IsHTMLElement(nsGkAtoms::area) && | |||
| 6058 | !aContent->IsSVGElement(nsGkAtoms::a)) || | |||
| 6059 | !aContent->AsElement()->GetAttr(nsGkAtoms::download, fileName) || | |||
| 6060 | NS_FAILED(aContent->NodePrincipal()->CheckMayLoad(aLinkURI, true))((bool)(__builtin_expect(!!(NS_FAILED_impl(aContent->NodePrincipal ()->CheckMayLoad(aLinkURI, true))), 0)))) { | |||
| 6061 | fileName.SetIsVoid(true); // No actionable download attribute was found. | |||
| 6062 | } | |||
| 6063 | ||||
| 6064 | nsCOMPtr<nsIPrincipal> triggeringPrincipal = aContent->NodePrincipal(); | |||
| 6065 | nsCOMPtr<nsIContentSecurityPolicy> csp = aContent->GetCsp(); | |||
| 6066 | ||||
| 6067 | // Sanitize fileNames containing null characters by replacing them with | |||
| 6068 | // underscores. | |||
| 6069 | if (!fileName.IsVoid()) { | |||
| 6070 | fileName.ReplaceChar(char16_t(0), '_'); | |||
| 6071 | } | |||
| 6072 | nsDocShell::Cast(docShell)->OnLinkClick( | |||
| 6073 | aContent, aLinkURI, fileName.IsVoid() ? aTargetSpec : u""_ns, fileName, | |||
| 6074 | nullptr, nullptr, UserActivation::IsHandlingUserInput(), | |||
| 6075 | triggeringPrincipal, csp); | |||
| 6076 | } | |||
| 6077 | } | |||
| 6078 | ||||
| 6079 | /* static */ | |||
| 6080 | void nsContentUtils::GetLinkLocation(Element* aElement, | |||
| 6081 | nsString& aLocationString) { | |||
| 6082 | nsCOMPtr<nsIURI> hrefURI = aElement->GetHrefURI(); | |||
| 6083 | if (hrefURI) { | |||
| 6084 | nsAutoCString specUTF8; | |||
| 6085 | nsresult rv = hrefURI->GetSpec(specUTF8); | |||
| 6086 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) CopyUTF8toUTF16(specUTF8, aLocationString); | |||
| 6087 | } | |||
| 6088 | } | |||
| 6089 | ||||
| 6090 | /* static */ | |||
| 6091 | nsIWidget* nsContentUtils::GetTopLevelWidget(nsIWidget* aWidget) { | |||
| 6092 | if (!aWidget) return nullptr; | |||
| 6093 | ||||
| 6094 | return aWidget->GetTopLevelWidget(); | |||
| 6095 | } | |||
| 6096 | ||||
| 6097 | /* static */ | |||
| 6098 | const nsDependentString nsContentUtils::GetLocalizedEllipsis() { | |||
| 6099 | static char16_t sBuf[4] = {0, 0, 0, 0}; | |||
| 6100 | if (!sBuf[0]) { | |||
| 6101 | if (!SpoofLocaleEnglish()) { | |||
| 6102 | nsAutoString tmp; | |||
| 6103 | Preferences::GetLocalizedString("intl.ellipsis", tmp); | |||
| 6104 | uint32_t len = | |||
| 6105 | std::min(uint32_t(tmp.Length()), uint32_t(std::size(sBuf) - 1)); | |||
| 6106 | CopyUnicodeTo(tmp, 0, sBuf, len); | |||
| 6107 | } | |||
| 6108 | if (!sBuf[0]) sBuf[0] = char16_t(0x2026); | |||
| 6109 | } | |||
| 6110 | return nsDependentString(sBuf); | |||
| 6111 | } | |||
| 6112 | ||||
| 6113 | /* static */ | |||
| 6114 | void nsContentUtils::AddScriptBlocker() { | |||
| 6115 | 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" , 6115); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 6115; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 6116 | if (!sScriptBlockerCount) { | |||
| 6117 | 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" , 6118); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sRunnersCountAtFirstBlocker == 0" ") (" "Should not already have a count" ")"); do { *((volatile int*)__null) = 6118; __attribute__((nomerge)) ::abort(); } while (false); } } while (false) | |||
| 6118 | "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" , 6118); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sRunnersCountAtFirstBlocker == 0" ") (" "Should not already have a count" ")"); do { *((volatile int*)__null) = 6118; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 6119 | sRunnersCountAtFirstBlocker = | |||
| 6120 | sBlockedScriptRunners ? sBlockedScriptRunners->Length() : 0; | |||
| 6121 | } | |||
| 6122 | ++sScriptBlockerCount; | |||
| 6123 | } | |||
| 6124 | ||||
| 6125 | #ifdef DEBUG1 | |||
| 6126 | static bool sRemovingScriptBlockers = false; | |||
| 6127 | #endif | |||
| 6128 | ||||
| 6129 | /* static */ | |||
| 6130 | void nsContentUtils::RemoveScriptBlocker() { | |||
| 6131 | 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" , 6131); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 6131; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 6132 | 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" , 6132); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sRemovingScriptBlockers" ")"); do { *((volatile int*)__null) = 6132; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 6133 | 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" , 6133); MOZ_PretendNoReturn(); } } while (0); | |||
| 6134 | --sScriptBlockerCount; | |||
| 6135 | if (sScriptBlockerCount) { | |||
| 6136 | return; | |||
| 6137 | } | |||
| 6138 | ||||
| 6139 | if (!sBlockedScriptRunners) { | |||
| 6140 | return; | |||
| 6141 | } | |||
| 6142 | ||||
| 6143 | uint32_t firstBlocker = sRunnersCountAtFirstBlocker; | |||
| 6144 | uint32_t lastBlocker = sBlockedScriptRunners->Length(); | |||
| 6145 | uint32_t originalFirstBlocker = firstBlocker; | |||
| 6146 | uint32_t blockersCount = lastBlocker - firstBlocker; | |||
| 6147 | sRunnersCountAtFirstBlocker = 0; | |||
| 6148 | 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" , 6148); MOZ_PretendNoReturn(); } } while (0); | |||
| 6149 | ||||
| 6150 | while (firstBlocker < lastBlocker) { | |||
| 6151 | nsCOMPtr<nsIRunnable> runnable; | |||
| 6152 | runnable.swap((*sBlockedScriptRunners)[firstBlocker]); | |||
| 6153 | ++firstBlocker; | |||
| 6154 | ||||
| 6155 | // Calling the runnable can reenter us | |||
| 6156 | { | |||
| 6157 | AUTO_PROFILE_FOLLOWING_RUNNABLE(runnable)mozilla::Maybe<mozilla::AutoProfileRunnable> raiiRunnableMarker ; if (profiler_thread_is_profiling_runnables()) { raiiRunnableMarker .emplace(runnable); }; | |||
| 6158 | runnable->Run(); | |||
| 6159 | } | |||
| 6160 | // So can dropping the reference to the runnable | |||
| 6161 | runnable = nullptr; | |||
| 6162 | ||||
| 6163 | 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" , 6163); MOZ_PretendNoReturn(); } } while (0); | |||
| 6164 | 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" , 6164); MOZ_PretendNoReturn(); } } while (0); | |||
| 6165 | } | |||
| 6166 | #ifdef DEBUG1 | |||
| 6167 | AutoRestore<bool> removingScriptBlockers(sRemovingScriptBlockers); | |||
| 6168 | sRemovingScriptBlockers = true; | |||
| 6169 | #endif | |||
| 6170 | sBlockedScriptRunners->RemoveElementsAt(originalFirstBlocker, blockersCount); | |||
| 6171 | } | |||
| 6172 | ||||
| 6173 | /* static */ | |||
| 6174 | already_AddRefed<nsPIDOMWindowOuter> | |||
| 6175 | nsContentUtils::GetMostRecentNonPBWindow() { | |||
| 6176 | nsCOMPtr<nsIWindowMediator> wm = do_GetService(NS_WINDOWMEDIATOR_CONTRACTID"@mozilla.org/appshell/window-mediator;1"); | |||
| 6177 | ||||
| 6178 | nsCOMPtr<mozIDOMWindowProxy> window; | |||
| 6179 | wm->GetMostRecentNonPBWindow(u"navigator:browser", getter_AddRefs(window)); | |||
| 6180 | nsCOMPtr<nsPIDOMWindowOuter> pwindow; | |||
| 6181 | pwindow = do_QueryInterface(window); | |||
| 6182 | ||||
| 6183 | return pwindow.forget(); | |||
| 6184 | } | |||
| 6185 | ||||
| 6186 | /* static */ | |||
| 6187 | void nsContentUtils::WarnScriptWasIgnored(Document* aDocument) { | |||
| 6188 | nsAutoString msg; | |||
| 6189 | bool privateBrowsing = false; | |||
| 6190 | bool chromeContext = false; | |||
| 6191 | ||||
| 6192 | if (aDocument) { | |||
| 6193 | nsCOMPtr<nsIURI> uri = aDocument->GetDocumentURI(); | |||
| 6194 | if (uri) { | |||
| 6195 | msg.Append(NS_ConvertUTF8toUTF16(uri->GetSpecOrDefault())); | |||
| 6196 | msg.AppendLiteral(" : "); | |||
| 6197 | } | |||
| 6198 | privateBrowsing = | |||
| 6199 | aDocument->NodePrincipal()->OriginAttributesRef().IsPrivateBrowsing(); | |||
| 6200 | chromeContext = aDocument->NodePrincipal()->IsSystemPrincipal(); | |||
| 6201 | } | |||
| 6202 | ||||
| 6203 | msg.AppendLiteral( | |||
| 6204 | "Unable to run script because scripts are blocked internally."); | |||
| 6205 | LogSimpleConsoleError(msg, "DOM"_ns, privateBrowsing, chromeContext); | |||
| 6206 | } | |||
| 6207 | ||||
| 6208 | /* static */ | |||
| 6209 | void nsContentUtils::AddScriptRunner(already_AddRefed<nsIRunnable> aRunnable) { | |||
| 6210 | nsCOMPtr<nsIRunnable> runnable = aRunnable; | |||
| 6211 | if (!runnable) { | |||
| 6212 | return; | |||
| 6213 | } | |||
| 6214 | ||||
| 6215 | if (sScriptBlockerCount) { | |||
| 6216 | sBlockedScriptRunners->AppendElement(runnable.forget()); | |||
| 6217 | return; | |||
| 6218 | } | |||
| 6219 | ||||
| 6220 | AUTO_PROFILE_FOLLOWING_RUNNABLE(runnable)mozilla::Maybe<mozilla::AutoProfileRunnable> raiiRunnableMarker ; if (profiler_thread_is_profiling_runnables()) { raiiRunnableMarker .emplace(runnable); }; | |||
| 6221 | runnable->Run(); | |||
| 6222 | } | |||
| 6223 | ||||
| 6224 | /* static */ | |||
| 6225 | void nsContentUtils::AddScriptRunner(nsIRunnable* aRunnable) { | |||
| 6226 | nsCOMPtr<nsIRunnable> runnable = aRunnable; | |||
| 6227 | AddScriptRunner(runnable.forget()); | |||
| 6228 | } | |||
| 6229 | ||||
| 6230 | /* static */ bool nsContentUtils::IsSafeToRunScript() { | |||
| 6231 | 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" , 6232); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ") (" "This static variable only makes sense on the main thread!" ")"); do { *((volatile int*)__null) = 6232; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) | |||
| 6232 | "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" , 6232); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ") (" "This static variable only makes sense on the main thread!" ")"); do { *((volatile int*)__null) = 6232; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 6233 | return sScriptBlockerCount == 0; | |||
| 6234 | } | |||
| 6235 | ||||
| 6236 | /* static */ | |||
| 6237 | void nsContentUtils::RunInStableState(already_AddRefed<nsIRunnable> aRunnable) { | |||
| 6238 | 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" , 6238); AnnotateMozCrashReason("MOZ_ASSERT" "(" "CycleCollectedJSContext::Get()" ") (" "Must be on a script thread!" ")"); do { *((volatile int *)__null) = 6238; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 6239 | CycleCollectedJSContext::Get()->RunInStableState(std::move(aRunnable)); | |||
| 6240 | } | |||
| 6241 | ||||
| 6242 | /* static */ | |||
| 6243 | void nsContentUtils::AddPendingIDBTransaction( | |||
| 6244 | already_AddRefed<nsIRunnable> aTransaction) { | |||
| 6245 | 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" , 6245); AnnotateMozCrashReason("MOZ_ASSERT" "(" "CycleCollectedJSContext::Get()" ") (" "Must be on a script thread!" ")"); do { *((volatile int *)__null) = 6245; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 6246 | CycleCollectedJSContext::Get()->AddPendingIDBTransaction( | |||
| 6247 | std::move(aTransaction)); | |||
| 6248 | } | |||
| 6249 | ||||
| 6250 | /* static */ | |||
| 6251 | bool nsContentUtils::IsInStableOrMetaStableState() { | |||
| 6252 | 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" , 6252); AnnotateMozCrashReason("MOZ_ASSERT" "(" "CycleCollectedJSContext::Get()" ") (" "Must be on a script thread!" ")"); do { *((volatile int *)__null) = 6252; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 6253 | return CycleCollectedJSContext::Get()->IsInStableOrMetaStableState(); | |||
| 6254 | } | |||
| 6255 | ||||
| 6256 | /* static */ | |||
| 6257 | void nsContentUtils::HidePopupsInDocument(Document* aDocument) { | |||
| 6258 | RefPtr<nsXULPopupManager> pm = nsXULPopupManager::GetInstance(); | |||
| 6259 | if (!pm || !aDocument) { | |||
| 6260 | return; | |||
| 6261 | } | |||
| 6262 | nsCOMPtr<nsIDocShellTreeItem> docShellToHide = aDocument->GetDocShell(); | |||
| 6263 | if (docShellToHide) { | |||
| 6264 | pm->HidePopupsInDocShell(docShellToHide); | |||
| 6265 | } | |||
| 6266 | } | |||
| 6267 | ||||
| 6268 | /* static */ | |||
| 6269 | already_AddRefed<nsIDragSession> nsContentUtils::GetDragSession( | |||
| 6270 | nsIWidget* aWidget) { | |||
| 6271 | nsCOMPtr<nsIDragSession> dragSession; | |||
| 6272 | nsCOMPtr<nsIDragService> dragService = | |||
| 6273 | do_GetService("@mozilla.org/widget/dragservice;1"); | |||
| 6274 | if (dragService) { | |||
| 6275 | dragSession = dragService->GetCurrentSession(aWidget); | |||
| 6276 | } | |||
| 6277 | return dragSession.forget(); | |||
| 6278 | } | |||
| 6279 | ||||
| 6280 | /* static */ | |||
| 6281 | already_AddRefed<nsIDragSession> nsContentUtils::GetDragSession( | |||
| 6282 | nsPresContext* aPC) { | |||
| 6283 | 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" , 6283); return nullptr; } } while (false); | |||
| 6284 | auto* widget = aPC->GetRootWidget(); | |||
| 6285 | if (!widget) { | |||
| 6286 | return nullptr; | |||
| 6287 | } | |||
| 6288 | return GetDragSession(widget); | |||
| 6289 | } | |||
| 6290 | ||||
| 6291 | /* static */ | |||
| 6292 | nsresult nsContentUtils::SetDataTransferInEvent(WidgetDragEvent* aDragEvent) { | |||
| 6293 | if (aDragEvent->mDataTransfer || !aDragEvent->IsTrusted()) { | |||
| 6294 | return NS_OK; | |||
| 6295 | } | |||
| 6296 | ||||
| 6297 | // For dragstart events, the data transfer object is | |||
| 6298 | // created before the event fires, so it should already be set. For other | |||
| 6299 | // drag events, get the object from the drag session. | |||
| 6300 | 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" , 6301); MOZ_PretendNoReturn(); } } while (0) | |||
| 6301 | "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" , 6301); MOZ_PretendNoReturn(); } } while (0); | |||
| 6302 | ||||
| 6303 | nsCOMPtr<nsIDragSession> dragSession = GetDragSession(aDragEvent->mWidget); | |||
| 6304 | 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" , 6304); return NS_OK; } } while (false); // no drag in progress | |||
| 6305 | ||||
| 6306 | RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer(); | |||
| 6307 | if (!initialDataTransfer) { | |||
| 6308 | // A dataTransfer won't exist when a drag was started by some other | |||
| 6309 | // means, for instance calling the drag service directly, or a drag | |||
| 6310 | // from another application. In either case, a new dataTransfer should | |||
| 6311 | // be created that reflects the data. | |||
| 6312 | initialDataTransfer = new DataTransfer( | |||
| 6313 | aDragEvent->mTarget, aDragEvent->mMessage, true, Nothing()); | |||
| 6314 | ||||
| 6315 | // now set it in the drag session so we don't need to create it again | |||
| 6316 | dragSession->SetDataTransfer(initialDataTransfer); | |||
| 6317 | } | |||
| 6318 | ||||
| 6319 | bool isCrossDomainSubFrameDrop = false; | |||
| 6320 | if (aDragEvent->mMessage == eDrop) { | |||
| 6321 | isCrossDomainSubFrameDrop = CheckForSubFrameDrop(dragSession, aDragEvent); | |||
| 6322 | } | |||
| 6323 | ||||
| 6324 | // each event should use a clone of the original dataTransfer. | |||
| 6325 | initialDataTransfer->Clone( | |||
| 6326 | aDragEvent->mTarget, aDragEvent->mMessage, aDragEvent->mUserCancelled, | |||
| 6327 | isCrossDomainSubFrameDrop, getter_AddRefs(aDragEvent->mDataTransfer)); | |||
| 6328 | 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" , 6328)) { | |||
| 6329 | return NS_ERROR_OUT_OF_MEMORY; | |||
| 6330 | } | |||
| 6331 | ||||
| 6332 | // for the dragenter and dragover events, initialize the drop effect | |||
| 6333 | // from the drop action, which platform specific widget code sets before | |||
| 6334 | // the event is fired based on the keyboard state. | |||
| 6335 | if (aDragEvent->mMessage == eDragEnter || aDragEvent->mMessage == eDragOver) { | |||
| 6336 | uint32_t action; | |||
| 6337 | dragSession->GetDragAction(&action); | |||
| 6338 | uint32_t effectAllowed = aDragEvent->mDataTransfer->EffectAllowedInt(); | |||
| 6339 | aDragEvent->mDataTransfer->SetDropEffectInt( | |||
| 6340 | FilterDropEffect(action, effectAllowed)); | |||
| 6341 | } else if (aDragEvent->mMessage == eDrop || | |||
| 6342 | aDragEvent->mMessage == eDragEnd) { | |||
| 6343 | // For the drop and dragend events, set the drop effect based on the | |||
| 6344 | // last value that the dropEffect had. This will have been set in | |||
| 6345 | // EventStateManager::PostHandleEvent for the last dragenter or | |||
| 6346 | // dragover event. | |||
| 6347 | aDragEvent->mDataTransfer->SetDropEffectInt( | |||
| 6348 | initialDataTransfer->DropEffectInt()); | |||
| 6349 | } | |||
| 6350 | ||||
| 6351 | return NS_OK; | |||
| 6352 | } | |||
| 6353 | ||||
| 6354 | /* static */ | |||
| 6355 | uint32_t nsContentUtils::FilterDropEffect(uint32_t aAction, | |||
| 6356 | uint32_t aEffectAllowed) { | |||
| 6357 | // It is possible for the drag action to include more than one action, but | |||
| 6358 | // the widget code which sets the action from the keyboard state should only | |||
| 6359 | // be including one. If multiple actions were set, we just consider them in | |||
| 6360 | // the following order: | |||
| 6361 | // copy, link, move | |||
| 6362 | if (aAction & nsIDragService::DRAGDROP_ACTION_COPY) | |||
| 6363 | aAction = nsIDragService::DRAGDROP_ACTION_COPY; | |||
| 6364 | else if (aAction & nsIDragService::DRAGDROP_ACTION_LINK) | |||
| 6365 | aAction = nsIDragService::DRAGDROP_ACTION_LINK; | |||
| 6366 | else if (aAction & nsIDragService::DRAGDROP_ACTION_MOVE) | |||
| 6367 | aAction = nsIDragService::DRAGDROP_ACTION_MOVE; | |||
| 6368 | ||||
| 6369 | // Filter the action based on the effectAllowed. If the effectAllowed | |||
| 6370 | // doesn't include the action, then that action cannot be done, so adjust | |||
| 6371 | // the action to something that is allowed. For a copy, adjust to move or | |||
| 6372 | // link. For a move, adjust to copy or link. For a link, adjust to move or | |||
| 6373 | // link. Otherwise, use none. | |||
| 6374 | if (aAction & aEffectAllowed || | |||
| 6375 | aEffectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED) | |||
| 6376 | return aAction; | |||
| 6377 | if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_MOVE) | |||
| 6378 | return nsIDragService::DRAGDROP_ACTION_MOVE; | |||
| 6379 | if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_COPY) | |||
| 6380 | return nsIDragService::DRAGDROP_ACTION_COPY; | |||
| 6381 | if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_LINK) | |||
| 6382 | return nsIDragService::DRAGDROP_ACTION_LINK; | |||
| 6383 | return nsIDragService::DRAGDROP_ACTION_NONE; | |||
| 6384 | } | |||
| 6385 | ||||
| 6386 | /* static */ | |||
| 6387 | bool nsContentUtils::CheckForSubFrameDrop(nsIDragSession* aDragSession, | |||
| 6388 | WidgetDragEvent* aDropEvent) { | |||
| 6389 | nsCOMPtr<nsIContent> target = | |||
| 6390 | nsIContent::FromEventTargetOrNull(aDropEvent->mOriginalTarget); | |||
| 6391 | if (!target) { | |||
| 6392 | return true; | |||
| 6393 | } | |||
| 6394 | ||||
| 6395 | // Always allow dropping onto chrome shells. | |||
| 6396 | BrowsingContext* targetBC = target->OwnerDoc()->GetBrowsingContext(); | |||
| 6397 | if (targetBC->IsChrome()) { | |||
| 6398 | return false; | |||
| 6399 | } | |||
| 6400 | ||||
| 6401 | WindowContext* targetWC = target->OwnerDoc()->GetWindowContext(); | |||
| 6402 | ||||
| 6403 | // If there is no source browsing context, then this is a drag from another | |||
| 6404 | // application, which should be allowed. | |||
| 6405 | RefPtr<WindowContext> sourceWC; | |||
| 6406 | aDragSession->GetSourceWindowContext(getter_AddRefs(sourceWC)); | |||
| 6407 | if (sourceWC) { | |||
| 6408 | // Get each successive parent of the source document and compare it to | |||
| 6409 | // the drop document. If they match, then this is a drag from a child frame. | |||
| 6410 | for (sourceWC = sourceWC->GetParentWindowContext(); sourceWC; | |||
| 6411 | sourceWC = sourceWC->GetParentWindowContext()) { | |||
| 6412 | // If the source and the target match, then the drag started in a | |||
| 6413 | // descendant frame. If the source is discarded, err on the side of | |||
| 6414 | // caution and treat it as a subframe drag. | |||
| 6415 | if (sourceWC == targetWC || sourceWC->IsDiscarded()) { | |||
| 6416 | return true; | |||
| 6417 | } | |||
| 6418 | } | |||
| 6419 | } | |||
| 6420 | ||||
| 6421 | return false; | |||
| 6422 | } | |||
| 6423 | ||||
| 6424 | /* static */ | |||
| 6425 | bool nsContentUtils::URIIsLocalFile(nsIURI* aURI) { | |||
| 6426 | bool isFile; | |||
| 6427 | nsCOMPtr<nsINetUtil> util = mozilla::components::IO::Service(); | |||
| 6428 | ||||
| 6429 | // Important: we do NOT test the entire URI chain here! | |||
| 6430 | return util && | |||
| 6431 | NS_SUCCEEDED(util->ProtocolHasFlags(((bool)(__builtin_expect(!!(!NS_FAILED_impl(util->ProtocolHasFlags ( aURI, nsIProtocolHandler::URI_IS_LOCAL_FILE, &isFile))) , 1))) | |||
| 6432 | aURI, nsIProtocolHandler::URI_IS_LOCAL_FILE, &isFile))((bool)(__builtin_expect(!!(!NS_FAILED_impl(util->ProtocolHasFlags ( aURI, nsIProtocolHandler::URI_IS_LOCAL_FILE, &isFile))) , 1))) && | |||
| 6433 | isFile; | |||
| 6434 | } | |||
| 6435 | ||||
| 6436 | /* static */ | |||
| 6437 | JSContext* nsContentUtils::GetCurrentJSContext() { | |||
| 6438 | 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" , 6438); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsInitialized()" ")"); do { *((volatile int*)__null) = 6438; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 6439 | if (!IsJSAPIActive()) { | |||
| 6440 | return nullptr; | |||
| 6441 | } | |||
| 6442 | return danger::GetJSContext(); | |||
| 6443 | } | |||
| 6444 | ||||
| 6445 | template <typename StringType, typename CharType> | |||
| 6446 | void _ASCIIToLowerInSitu(StringType& aStr) { | |||
| 6447 | CharType* iter = aStr.BeginWriting(); | |||
| 6448 | CharType* end = aStr.EndWriting(); | |||
| 6449 | 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" , 6449); AnnotateMozCrashReason("MOZ_ASSERT" "(" "iter && end" ")"); do { *((volatile int*)__null) = 6449; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 6450 | ||||
| 6451 | while (iter != end) { | |||
| 6452 | CharType c = *iter; | |||
| 6453 | if (c >= 'A' && c <= 'Z') { | |||
| 6454 | *iter = c + ('a' - 'A'); | |||
| 6455 | } | |||
| 6456 | ++iter; | |||
| 6457 | } | |||
| 6458 | } | |||
| 6459 | ||||
| 6460 | /* static */ | |||
| 6461 | void nsContentUtils::ASCIIToLower(nsAString& aStr) { | |||
| 6462 | return _ASCIIToLowerInSitu<nsAString, char16_t>(aStr); | |||
| 6463 | } | |||
| 6464 | ||||
| 6465 | /* static */ | |||
| 6466 | void nsContentUtils::ASCIIToLower(nsACString& aStr) { | |||
| 6467 | return _ASCIIToLowerInSitu<nsACString, char>(aStr); | |||
| 6468 | } | |||
| 6469 | ||||
| 6470 | template <typename StringType, typename CharType> | |||
| 6471 | void _ASCIIToLowerCopy(const StringType& aSource, StringType& aDest) { | |||
| 6472 | uint32_t len = aSource.Length(); | |||
| 6473 | aDest.SetLength(len); | |||
| 6474 | 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" , 6474); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDest.Length() == len" ")"); do { *((volatile int*)__null) = 6474; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 6475 | ||||
| 6476 | CharType* dest = aDest.BeginWriting(); | |||
| 6477 | 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" , 6477); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dest" ")"); do { *((volatile int*)__null) = 6477; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 6478 | ||||
| 6479 | const CharType* iter = aSource.BeginReading(); | |||
| 6480 | const CharType* end = aSource.EndReading(); | |||
| 6481 | while (iter != end) { | |||
| 6482 | CharType c = *iter; | |||
| 6483 | *dest = (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; | |||
| 6484 | ++iter; | |||
| 6485 | ++dest; | |||
| 6486 | } | |||
| 6487 | } | |||
| 6488 | ||||
| 6489 | /* static */ | |||
| 6490 | void nsContentUtils::ASCIIToLower(const nsAString& aSource, nsAString& aDest) { | |||
| 6491 | return _ASCIIToLowerCopy<nsAString, char16_t>(aSource, aDest); | |||
| 6492 | } | |||
| 6493 | ||||
| 6494 | /* static */ | |||
| 6495 | void nsContentUtils::ASCIIToLower(const nsACString& aSource, | |||
| 6496 | nsACString& aDest) { | |||
| 6497 | return _ASCIIToLowerCopy<nsACString, char>(aSource, aDest); | |||
| 6498 | } | |||
| 6499 | ||||
| 6500 | template <typename StringType, typename CharType> | |||
| 6501 | void _ASCIIToUpperInSitu(StringType& aStr) { | |||
| 6502 | CharType* iter = aStr.BeginWriting(); | |||
| 6503 | CharType* end = aStr.EndWriting(); | |||
| 6504 | 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" , 6504); AnnotateMozCrashReason("MOZ_ASSERT" "(" "iter && end" ")"); do { *((volatile int*)__null) = 6504; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 6505 | ||||
| 6506 | while (iter != end) { | |||
| 6507 | CharType c = *iter; | |||
| 6508 | if (c >= 'a' && c <= 'z') { | |||
| 6509 | *iter = c + ('A' - 'a'); | |||
| 6510 | } | |||
| 6511 | ++iter; | |||
| 6512 | } | |||
| 6513 | } | |||
| 6514 | ||||
| 6515 | /* static */ | |||
| 6516 | void nsContentUtils::ASCIIToUpper(nsAString& aStr) { | |||
| 6517 | return _ASCIIToUpperInSitu<nsAString, char16_t>(aStr); | |||
| 6518 | } | |||
| 6519 | ||||
| 6520 | /* static */ | |||
| 6521 | void nsContentUtils::ASCIIToUpper(nsACString& aStr) { | |||
| 6522 | return _ASCIIToUpperInSitu<nsACString, char>(aStr); | |||
| 6523 | } | |||
| 6524 | ||||
| 6525 | template <typename StringType, typename CharType> | |||
| 6526 | void _ASCIIToUpperCopy(const StringType& aSource, StringType& aDest) { | |||
| 6527 | uint32_t len = aSource.Length(); | |||
| 6528 | aDest.SetLength(len); | |||
| 6529 | 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" , 6529); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDest.Length() == len" ")"); do { *((volatile int*)__null) = 6529; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 6530 | ||||
| 6531 | CharType* dest = aDest.BeginWriting(); | |||
| 6532 | 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" , 6532); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dest" ")"); do { *((volatile int*)__null) = 6532; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 6533 | ||||
| 6534 | const CharType* iter = aSource.BeginReading(); | |||
| 6535 | const CharType* end = aSource.EndReading(); | |||
| 6536 | while (iter != end) { | |||
| 6537 | CharType c = *iter; | |||
| 6538 | *dest = (c >= 'a' && c <= 'z') ? c + ('A' - 'a') : c; | |||
| 6539 | ++iter; | |||
| 6540 | ++dest; | |||
| 6541 | } | |||
| 6542 | } | |||
| 6543 | ||||
| 6544 | /* static */ | |||
| 6545 | void nsContentUtils::ASCIIToUpper(const nsAString& aSource, nsAString& aDest) { | |||
| 6546 | return _ASCIIToUpperCopy<nsAString, char16_t>(aSource, aDest); | |||
| 6547 | } | |||
| 6548 | ||||
| 6549 | /* static */ | |||
| 6550 | void nsContentUtils::ASCIIToUpper(const nsACString& aSource, | |||
| 6551 | nsACString& aDest) { | |||
| 6552 | return _ASCIIToUpperCopy<nsACString, char>(aSource, aDest); | |||
| 6553 | } | |||
| 6554 | ||||
| 6555 | /* static */ | |||
| 6556 | bool nsContentUtils::EqualsIgnoreASCIICase(nsAtom* aAtom1, nsAtom* aAtom2) { | |||
| 6557 | if (aAtom1 == aAtom2) { | |||
| 6558 | return true; | |||
| 6559 | } | |||
| 6560 | ||||
| 6561 | // If both are ascii lowercase already, we know that the slow comparison | |||
| 6562 | // below is going to return false. | |||
| 6563 | if (aAtom1->IsAsciiLowercase() && aAtom2->IsAsciiLowercase()) { | |||
| 6564 | return false; | |||
| 6565 | } | |||
| 6566 | ||||
| 6567 | return EqualsIgnoreASCIICase(nsDependentAtomString(aAtom1), | |||
| 6568 | nsDependentAtomString(aAtom2)); | |||
| 6569 | } | |||
| 6570 | ||||
| 6571 | /* static */ | |||
| 6572 | bool nsContentUtils::EqualsIgnoreASCIICase(const nsAString& aStr1, | |||
| 6573 | const nsAString& aStr2) { | |||
| 6574 | uint32_t len = aStr1.Length(); | |||
| 6575 | if (len != aStr2.Length()) { | |||
| 6576 | return false; | |||
| 6577 | } | |||
| 6578 | ||||
| 6579 | const char16_t* str1 = aStr1.BeginReading(); | |||
| 6580 | const char16_t* str2 = aStr2.BeginReading(); | |||
| 6581 | const char16_t* end = str1 + len; | |||
| 6582 | ||||
| 6583 | while (str1 < end) { | |||
| 6584 | char16_t c1 = *str1++; | |||
| 6585 | char16_t c2 = *str2++; | |||
| 6586 | ||||
| 6587 | // First check if any bits other than the 0x0020 differs | |||
| 6588 | if ((c1 ^ c2) & 0xffdf) { | |||
| 6589 | return false; | |||
| 6590 | } | |||
| 6591 | ||||
| 6592 | // We know they can only differ in the 0x0020 bit. | |||
| 6593 | // Likely the two chars are the same, so check that first | |||
| 6594 | if (c1 != c2) { | |||
| 6595 | // They do differ, but since it's only in the 0x0020 bit, check if it's | |||
| 6596 | // the same ascii char, but just differing in case | |||
| 6597 | char16_t c1Upper = c1 & 0xffdf; | |||
| 6598 | if (!('A' <= c1Upper && c1Upper <= 'Z')) { | |||
| 6599 | return false; | |||
| 6600 | } | |||
| 6601 | } | |||
| 6602 | } | |||
| 6603 | ||||
| 6604 | return true; | |||
| 6605 | } | |||
| 6606 | ||||
| 6607 | /* static */ | |||
| 6608 | bool nsContentUtils::StringContainsASCIIUpper(const nsAString& aStr) { | |||
| 6609 | const char16_t* iter = aStr.BeginReading(); | |||
| 6610 | const char16_t* end = aStr.EndReading(); | |||
| 6611 | while (iter != end) { | |||
| 6612 | char16_t c = *iter; | |||
| 6613 | if (c >= 'A' && c <= 'Z') { | |||
| 6614 | return true; | |||
| 6615 | } | |||
| 6616 | ++iter; | |||
| 6617 | } | |||
| 6618 | ||||
| 6619 | return false; | |||
| 6620 | } | |||
| 6621 | ||||
| 6622 | /* static */ | |||
| 6623 | nsIInterfaceRequestor* nsContentUtils::SameOriginChecker() { | |||
| 6624 | if (!sSameOriginChecker) { | |||
| 6625 | sSameOriginChecker = new SameOriginCheckerImpl(); | |||
| 6626 | NS_ADDREF(sSameOriginChecker)(sSameOriginChecker)->AddRef(); | |||
| 6627 | } | |||
| 6628 | return sSameOriginChecker; | |||
| 6629 | } | |||
| 6630 | ||||
| 6631 | /* static */ | |||
| 6632 | nsresult nsContentUtils::CheckSameOrigin(nsIChannel* aOldChannel, | |||
| 6633 | nsIChannel* aNewChannel) { | |||
| 6634 | if (!nsContentUtils::GetSecurityManager()) return NS_ERROR_NOT_AVAILABLE; | |||
| 6635 | ||||
| 6636 | nsCOMPtr<nsIPrincipal> oldPrincipal; | |||
| 6637 | nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal( | |||
| 6638 | aOldChannel, getter_AddRefs(oldPrincipal)); | |||
| 6639 | ||||
| 6640 | nsCOMPtr<nsIURI> newURI; | |||
| 6641 | aNewChannel->GetURI(getter_AddRefs(newURI)); | |||
| 6642 | nsCOMPtr<nsIURI> newOriginalURI; | |||
| 6643 | aNewChannel->GetOriginalURI(getter_AddRefs(newOriginalURI)); | |||
| 6644 | ||||
| 6645 | 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" , 6645); return NS_ERROR_UNEXPECTED; } } while (false); | |||
| 6646 | ||||
| 6647 | nsresult rv = oldPrincipal->CheckMayLoad(newURI, false); | |||
| 6648 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && newOriginalURI != newURI) { | |||
| 6649 | rv = oldPrincipal->CheckMayLoad(newOriginalURI, false); | |||
| 6650 | } | |||
| 6651 | ||||
| 6652 | return rv; | |||
| 6653 | } | |||
| 6654 | ||||
| 6655 | 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" , 6656); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 6656; __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" , 6656); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"SameOriginCheckerImpl\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 6656; __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" , 6656); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 6656 ; __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" , 6656); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"SameOriginCheckerImpl\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 6656; __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" , 6656); 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(std::size(table ) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } | |||
| 6656 | 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" , 6656); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 6656; __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" , 6656); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"SameOriginCheckerImpl\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 6656; __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" , 6656); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 6656 ; __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" , 6656); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"SameOriginCheckerImpl\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 6656; __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" , 6656); 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(std::size(table ) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } | |||
| 6657 | ||||
| 6658 | NS_IMETHODIMPnsresult | |||
| 6659 | SameOriginCheckerImpl::AsyncOnChannelRedirect( | |||
| 6660 | nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aFlags, | |||
| 6661 | nsIAsyncVerifyRedirectCallback* cb) { | |||
| 6662 | 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" , 6662); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewChannel" ") (" "Redirecting to null channel?" ")"); do { *((volatile int *)__null) = 6662; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 6663 | ||||
| 6664 | nsresult rv = nsContentUtils::CheckSameOrigin(aOldChannel, aNewChannel); | |||
| 6665 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { | |||
| 6666 | cb->OnRedirectVerifyCallback(NS_OK); | |||
| 6667 | } | |||
| 6668 | ||||
| 6669 | return rv; | |||
| 6670 | } | |||
| 6671 | ||||
| 6672 | NS_IMETHODIMPnsresult | |||
| 6673 | SameOriginCheckerImpl::GetInterface(const nsIID& aIID, void** aResult) { | |||
| 6674 | return QueryInterface(aIID, aResult); | |||
| 6675 | } | |||
| 6676 | ||||
| 6677 | /* static */ | |||
| 6678 | nsresult nsContentUtils::GetWebExposedOriginSerialization(nsIURI* aURI, | |||
| 6679 | nsACString& aOrigin) { | |||
| 6680 | nsresult rv; | |||
| 6681 | 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" , 6681); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aURI" ") (" "missing uri" ")"); do { *((volatile int*)__null) = 6681; __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 6682 | ||||
| 6683 | // For Blob URI, the path is the URL of the owning page. | |||
| 6684 | if (aURI->SchemeIs(BLOBURI_SCHEME"blob")) { | |||
| 6685 | nsAutoCString path; | |||
| 6686 | rv = aURI->GetPathQueryRef(path); | |||
| 6687 | 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" , 6687); return rv; } } while (false); | |||
| 6688 | ||||
| 6689 | nsCOMPtr<nsIURI> uri; | |||
| 6690 | rv = NS_NewURI(getter_AddRefs(uri), path); | |||
| 6691 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 6692 | aOrigin.AssignLiteral("null"); | |||
| 6693 | return NS_OK; | |||
| 6694 | } | |||
| 6695 | ||||
| 6696 | if ( | |||
| 6697 | // Schemes in spec. https://url.spec.whatwg.org/#origin | |||
| 6698 | !uri->SchemeIs("http") && !uri->SchemeIs("https") && | |||
| 6699 | !uri->SchemeIs("file") && !uri->SchemeIs("resource") && | |||
| 6700 | // Our own schemes. | |||
| 6701 | !uri->SchemeIs("moz-extension")) { | |||
| 6702 | aOrigin.AssignLiteral("null"); | |||
| 6703 | return NS_OK; | |||
| 6704 | } | |||
| 6705 | ||||
| 6706 | return GetWebExposedOriginSerialization(uri, aOrigin); | |||
| 6707 | } | |||
| 6708 | ||||
| 6709 | nsAutoCString scheme; | |||
| 6710 | aURI->GetScheme(scheme); | |||
| 6711 | ||||
| 6712 | // If the protocol doesn't have URI_HAS_WEB_EXPOSED_ORIGIN, then | |||
| 6713 | // return "null" as the origin serialization. | |||
| 6714 | // We make an exception for "ftp" since we don't have a protocol handler | |||
| 6715 | // for this scheme | |||
| 6716 | uint32_t flags = 0; | |||
| 6717 | nsCOMPtr<nsIIOService> io = mozilla::components::IO::Service(&rv); | |||
| 6718 | if (!scheme.Equals("ftp") && NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && | |||
| 6719 | NS_SUCCEEDED(io->GetProtocolFlags(scheme.get(), &flags))((bool)(__builtin_expect(!!(!NS_FAILED_impl(io->GetProtocolFlags (scheme.get(), &flags))), 1)))) { | |||
| 6720 | if (!(flags & nsIProtocolHandler::URI_HAS_WEB_EXPOSED_ORIGIN)) { | |||
| 6721 | aOrigin.AssignLiteral("null"); | |||
| 6722 | return NS_OK; | |||
| 6723 | } | |||
| 6724 | } | |||
| 6725 | ||||
| 6726 | aOrigin.Truncate(); | |||
| 6727 | ||||
| 6728 | nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI); | |||
| 6729 | 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" , 6729); return NS_ERROR_UNEXPECTED; } } while (false); | |||
| 6730 | ||||
| 6731 | nsAutoCString host; | |||
| 6732 | rv = uri->GetAsciiHost(host); | |||
| 6733 | ||||
| 6734 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !host.IsEmpty()) { | |||
| 6735 | nsAutoCString userPass; | |||
| 6736 | uri->GetUserPass(userPass); | |||
| 6737 | ||||
| 6738 | nsAutoCString prePath; | |||
| 6739 | if (!userPass.IsEmpty()) { | |||
| 6740 | rv = NS_MutateURI(uri).SetUserPass(""_ns).Finalize(uri); | |||
| 6741 | 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" , 6741); return rv; } } while (false); | |||
| 6742 | } | |||
| 6743 | ||||
| 6744 | rv = uri->GetPrePath(prePath); | |||
| 6745 | 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" , 6745); return rv; } } while (false); | |||
| 6746 | ||||
| 6747 | aOrigin = prePath; | |||
| 6748 | } else { | |||
| 6749 | aOrigin.AssignLiteral("null"); | |||
| 6750 | } | |||
| 6751 | ||||
| 6752 | return NS_OK; | |||
| 6753 | } | |||
| 6754 | ||||
| 6755 | /* static */ | |||
| 6756 | nsresult nsContentUtils::GetWebExposedOriginSerialization( | |||
| 6757 | nsIPrincipal* aPrincipal, nsAString& aOrigin) { | |||
| 6758 | 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" , 6758); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrincipal" ") (" "missing principal" ")"); do { *((volatile int*)__null ) = 6758; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); | |||
| 6759 | ||||
| 6760 | aOrigin.Truncate(); | |||
| 6761 | nsAutoCString webExposedOriginSerialization; | |||
| 6762 | ||||
| 6763 | nsresult rv = aPrincipal->GetWebExposedOriginSerialization( | |||
| 6764 | webExposedOriginSerialization); | |||
| 6765 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 6766 | webExposedOriginSerialization.AssignLiteral("null"); | |||
| 6767 | } | |||
| 6768 | ||||
| 6769 | CopyUTF8toUTF16(webExposedOriginSerialization, aOrigin); | |||
| 6770 | return NS_OK; | |||
| 6771 | } | |||
| 6772 | ||||
| 6773 | /* static */ | |||
| 6774 | nsresult nsContentUtils::GetWebExposedOriginSerialization(nsIURI* aURI, | |||
| 6775 | nsAString& aOrigin) { | |||
| 6776 | 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" , 6776); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aURI" ") (" "missing uri" ")"); do { *((volatile int*)__null) = 6776; __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 6777 | nsresult rv; | |||
| 6778 | ||||
| 6779 | #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE) | |||
| 6780 | // Check if either URI has a special origin. | |||
| 6781 | nsCOMPtr<nsIURIWithSpecialOrigin> uriWithSpecialOrigin = | |||
| 6782 | do_QueryInterface(aURI); | |||
| 6783 | if (uriWithSpecialOrigin) { | |||
| 6784 | nsCOMPtr<nsIURI> origin; | |||
| 6785 | rv = uriWithSpecialOrigin->GetOrigin(getter_AddRefs(origin)); | |||
| 6786 | 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" , 6786); return rv; } } while (false); | |||
| 6787 | ||||
| 6788 | return GetWebExposedOriginSerialization(origin, aOrigin); | |||
| 6789 | } | |||
| 6790 | #endif | |||
| 6791 | ||||
| 6792 | nsAutoCString webExposedOriginSerialization; | |||
| 6793 | rv = GetWebExposedOriginSerialization(aURI, webExposedOriginSerialization); | |||
| 6794 | 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" , 6794); return rv; } } while (false); | |||
| 6795 | ||||
| 6796 | CopyUTF8toUTF16(webExposedOriginSerialization, aOrigin); | |||
| 6797 | return NS_OK; | |||
| 6798 | } | |||
| 6799 | ||||
| 6800 | /* static */ | |||
| 6801 | bool nsContentUtils::CheckMayLoad(nsIPrincipal* aPrincipal, | |||
| 6802 | nsIChannel* aChannel, | |||
| 6803 | bool aAllowIfInheritsPrincipal) { | |||
| 6804 | nsCOMPtr<nsIURI> channelURI; | |||
| 6805 | nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI)); | |||
| 6806 | 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" , 6806); return false; } } while (false); | |||
| 6807 | ||||
| 6808 | return NS_SUCCEEDED(((bool)(__builtin_expect(!!(!NS_FAILED_impl(aPrincipal->CheckMayLoad (channelURI, aAllowIfInheritsPrincipal))), 1))) | |||
| 6809 | aPrincipal->CheckMayLoad(channelURI, aAllowIfInheritsPrincipal))((bool)(__builtin_expect(!!(!NS_FAILED_impl(aPrincipal->CheckMayLoad (channelURI, aAllowIfInheritsPrincipal))), 1))); | |||
| 6810 | } | |||
| 6811 | ||||
| 6812 | /* static */ | |||
| 6813 | bool nsContentUtils::CanAccessNativeAnon() { | |||
| 6814 | return LegacyIsCallerChromeOrNativeCode(); | |||
| 6815 | } | |||
| 6816 | ||||
| 6817 | /* static */ | |||
| 6818 | nsresult nsContentUtils::DispatchXULCommand(nsIContent* aTarget, bool aTrusted, | |||
| 6819 | Event* aSourceEvent, | |||
| 6820 | PresShell* aPresShell, bool aCtrl, | |||
| 6821 | bool aAlt, bool aShift, bool aMeta, | |||
| 6822 | uint16_t aInputSource, | |||
| 6823 | int16_t aButton) { | |||
| 6824 | 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" , 6824); return NS_ERROR_UNEXPECTED; } } while (false); | |||
| 6825 | Document* doc = aTarget->OwnerDoc(); | |||
| 6826 | nsPresContext* presContext = doc->GetPresContext(); | |||
| 6827 | ||||
| 6828 | RefPtr<XULCommandEvent> xulCommand = | |||
| 6829 | new XULCommandEvent(doc, presContext, nullptr); | |||
| 6830 | xulCommand->InitCommandEvent(u"command"_ns, true, true, | |||
| 6831 | nsGlobalWindowInner::Cast(doc->GetInnerWindow()), | |||
| 6832 | 0, aCtrl, aAlt, aShift, aMeta, aButton, | |||
| 6833 | aSourceEvent, aInputSource, IgnoreErrors()); | |||
| 6834 | ||||
| 6835 | if (aPresShell) { | |||
| 6836 | nsEventStatus status = nsEventStatus_eIgnore; | |||
| 6837 | return aPresShell->HandleDOMEventWithTarget(aTarget, xulCommand, &status); | |||
| 6838 | } | |||
| 6839 | ||||
| 6840 | ErrorResult rv; | |||
| 6841 | aTarget->DispatchEvent(*xulCommand, rv); | |||
| 6842 | return rv.StealNSResult(); | |||
| 6843 | } | |||
| 6844 | ||||
| 6845 | // static | |||
| 6846 | nsresult nsContentUtils::WrapNative(JSContext* cx, nsISupports* native, | |||
| 6847 | nsWrapperCache* cache, const nsIID* aIID, | |||
| 6848 | JS::MutableHandle<JS::Value> vp, | |||
| 6849 | bool aAllowWrapping) { | |||
| 6850 | 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" , 6850); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cx == GetCurrentJSContext()" ")"); do { *((volatile int*)__null) = 6850; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 6851 | ||||
| 6852 | if (!native) { | |||
| 6853 | vp.setNull(); | |||
| 6854 | ||||
| 6855 | return NS_OK; | |||
| 6856 | } | |||
| 6857 | ||||
| 6858 | JSObject* wrapper = xpc_FastGetCachedWrapper(cx, cache, vp); | |||
| 6859 | if (wrapper) { | |||
| 6860 | return NS_OK; | |||
| 6861 | } | |||
| 6862 | ||||
| 6863 | 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" , 6863); return NS_ERROR_UNEXPECTED; } } while (false); | |||
| 6864 | ||||
| 6865 | if (!NS_IsMainThread()) { | |||
| 6866 | MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp" , 6866); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile int*)__null) = 6866; __attribute__((nomerge)) ::abort(); } while (false); } while (false); | |||
| 6867 | } | |||
| 6868 | ||||
| 6869 | JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx)); | |||
| 6870 | nsresult rv = sXPConnect->WrapNativeToJSVal(cx, scope, native, cache, aIID, | |||
| 6871 | aAllowWrapping, vp); | |||
| 6872 | return rv; | |||
| 6873 | } | |||
| 6874 | ||||
| 6875 | void nsContentUtils::StripNullChars(const nsAString& aInStr, | |||
| 6876 | nsAString& aOutStr) { | |||
| 6877 | // In common cases where we don't have nulls in the | |||
| 6878 | // string we can simple simply bypass the checking code. | |||
| 6879 | int32_t firstNullPos = aInStr.FindChar('\0'); | |||
| 6880 | if (firstNullPos == kNotFound) { | |||
| 6881 | aOutStr.Assign(aInStr); | |||
| 6882 | return; | |||
| 6883 | } | |||
| 6884 | ||||
| 6885 | aOutStr.SetCapacity(aInStr.Length() - 1); | |||
| 6886 | nsAString::const_iterator start, end; | |||
| 6887 | aInStr.BeginReading(start); | |||
| 6888 | aInStr.EndReading(end); | |||
| 6889 | while (start != end) { | |||
| 6890 | if (*start != '\0') aOutStr.Append(*start); | |||
| 6891 | ++start; | |||
| 6892 | } | |||
| 6893 | } | |||
| 6894 | ||||
| 6895 | struct ClassMatchingInfo { | |||
| 6896 | AtomArray mClasses; | |||
| 6897 | nsCaseTreatment mCaseTreatment; | |||
| 6898 | }; | |||
| 6899 | ||||
| 6900 | // static | |||
| 6901 | bool nsContentUtils::MatchClassNames(Element* aElement, int32_t aNamespaceID, | |||
| 6902 | nsAtom* aAtom, void* aData) { | |||
| 6903 | // We can't match if there are no class names | |||
| 6904 | const nsAttrValue* classAttr = aElement->GetClasses(); | |||
| 6905 | if (!classAttr) { | |||
| 6906 | return false; | |||
| 6907 | } | |||
| 6908 | ||||
| 6909 | // need to match *all* of the classes | |||
| 6910 | ClassMatchingInfo* info = static_cast<ClassMatchingInfo*>(aData); | |||
| 6911 | uint32_t length = info->mClasses.Length(); | |||
| 6912 | if (!length) { | |||
| 6913 | // If we actually had no classes, don't match. | |||
| 6914 | return false; | |||
| 6915 | } | |||
| 6916 | uint32_t i; | |||
| 6917 | for (i = 0; i < length; ++i) { | |||
| 6918 | if (!classAttr->Contains(info->mClasses[i], info->mCaseTreatment)) { | |||
| 6919 | return false; | |||
| 6920 | } | |||
| 6921 | } | |||
| 6922 | ||||
| 6923 | return true; | |||
| 6924 | } | |||
| 6925 | ||||
| 6926 | // static | |||
| 6927 | void nsContentUtils::DestroyClassNameArray(void* aData) { | |||
| 6928 | ClassMatchingInfo* info = static_cast<ClassMatchingInfo*>(aData); | |||
| 6929 | delete info; | |||
| 6930 | } | |||
| 6931 | ||||
| 6932 | // static | |||
| 6933 | void* nsContentUtils::AllocClassMatchingInfo(nsINode* aRootNode, | |||
| 6934 | const nsString* aClasses) { | |||
| 6935 | nsAttrValue attrValue; | |||
| 6936 | attrValue.ParseAtomArray(*aClasses); | |||
| 6937 | // nsAttrValue::Equals is sensitive to order, so we'll send an array | |||
| 6938 | auto* info = new ClassMatchingInfo; | |||
| 6939 | if (attrValue.Type() == nsAttrValue::eAtomArray) { | |||
| 6940 | info->mClasses = attrValue.GetAtomArrayValue()->mArray.Clone(); | |||
| 6941 | } else if (attrValue.Type() == nsAttrValue::eAtom) { | |||
| 6942 | info->mClasses.AppendElement(attrValue.GetAtomValue()); | |||
| 6943 | } | |||
| 6944 | ||||
| 6945 | info->mCaseTreatment = | |||
| 6946 | aRootNode->OwnerDoc()->GetCompatibilityMode() == eCompatibility_NavQuirks | |||
| 6947 | ? eIgnoreCase | |||
| 6948 | : eCaseMatters; | |||
| 6949 | return info; | |||
| 6950 | } | |||
| 6951 | ||||
| 6952 | void nsContentUtils::FlushLayoutForTree(nsPIDOMWindowOuter* aWindow) { | |||
| 6953 | if (!aWindow) { | |||
| 6954 | return; | |||
| 6955 | } | |||
| 6956 | ||||
| 6957 | // Note that because FlushPendingNotifications flushes parents, this | |||
| 6958 | // is O(N^2) in docshell tree depth. However, the docshell tree is | |||
| 6959 | // usually pretty shallow. | |||
| 6960 | ||||
| 6961 | if (RefPtr<Document> doc = aWindow->GetDoc()) { | |||
| 6962 | doc->FlushPendingNotifications(FlushType::Layout); | |||
| 6963 | } | |||
| 6964 | ||||
| 6965 | if (nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell()) { | |||
| 6966 | int32_t i = 0, i_end; | |||
| 6967 | docShell->GetInProcessChildCount(&i_end); | |||
| 6968 | for (; i < i_end; ++i) { | |||
| 6969 | nsCOMPtr<nsIDocShellTreeItem> item; | |||
| 6970 | if (docShell->GetInProcessChildAt(i, getter_AddRefs(item)) == NS_OK && | |||
| 6971 | item) { | |||
| 6972 | if (nsCOMPtr<nsPIDOMWindowOuter> win = item->GetWindow()) { | |||
| 6973 | FlushLayoutForTree(win); | |||
| 6974 | } | |||
| 6975 | } | |||
| 6976 | } | |||
| 6977 | } | |||
| 6978 | } | |||
| 6979 | ||||
| 6980 | void nsContentUtils::RemoveNewlines(nsString& aString) { aString.StripCRLF(); } | |||
| 6981 | ||||
| 6982 | void nsContentUtils::PlatformToDOMLineBreaks(nsString& aString) { | |||
| 6983 | if (!PlatformToDOMLineBreaks(aString, fallible)) { | |||
| 6984 | aString.AllocFailed(aString.Length()); | |||
| 6985 | } | |||
| 6986 | } | |||
| 6987 | ||||
| 6988 | bool nsContentUtils::PlatformToDOMLineBreaks(nsString& aString, | |||
| 6989 | const fallible_t& aFallible) { | |||
| 6990 | if (aString.FindChar(char16_t('\r')) != -1) { | |||
| 6991 | // Windows linebreaks: Map CRLF to LF: | |||
| 6992 | if (!aString.ReplaceSubstring(u"\r\n", u"\n", aFallible)) { | |||
| 6993 | return false; | |||
| 6994 | } | |||
| 6995 | ||||
| 6996 | // Mac linebreaks: Map any remaining CR to LF: | |||
| 6997 | if (!aString.ReplaceSubstring(u"\r", u"\n", aFallible)) { | |||
| 6998 | return false; | |||
| 6999 | } | |||
| 7000 | } | |||
| 7001 | ||||
| 7002 | return true; | |||
| 7003 | } | |||
| 7004 | ||||
| 7005 | already_AddRefed<nsContentList> nsContentUtils::GetElementsByClassName( | |||
| 7006 | nsINode* aRootNode, const nsAString& aClasses) { | |||
| 7007 | 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" , 7007); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRootNode" ") (" "Must have root node" ")"); do { *((volatile int*)__null) = 7007 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 7008 | ||||
| 7009 | return GetFuncStringContentList<nsCacheableFuncStringHTMLCollection>( | |||
| 7010 | aRootNode, MatchClassNames, DestroyClassNameArray, AllocClassMatchingInfo, | |||
| 7011 | aClasses); | |||
| 7012 | } | |||
| 7013 | ||||
| 7014 | PresShell* nsContentUtils::FindPresShellForDocument(const Document* aDocument) { | |||
| 7015 | const Document* doc = aDocument; | |||
| 7016 | Document* displayDoc = doc->GetDisplayDocument(); | |||
| 7017 | if (displayDoc) { | |||
| 7018 | doc = displayDoc; | |||
| 7019 | } | |||
| 7020 | ||||
| 7021 | PresShell* presShell = doc->GetPresShell(); | |||
| 7022 | if (presShell) { | |||
| 7023 | return presShell; | |||
| 7024 | } | |||
| 7025 | ||||
| 7026 | nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = doc->GetDocShell(); | |||
| 7027 | while (docShellTreeItem) { | |||
| 7028 | // We may be in a display:none subdocument, or we may not have a presshell | |||
| 7029 | // created yet. | |||
| 7030 | // Walk the docshell tree to find the nearest container that has a | |||
| 7031 | // presshell, and return that. | |||
| 7032 | nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(docShellTreeItem); | |||
| 7033 | if (PresShell* presShell = docShell->GetPresShell()) { | |||
| 7034 | return presShell; | |||
| 7035 | } | |||
| 7036 | nsCOMPtr<nsIDocShellTreeItem> parent; | |||
| 7037 | docShellTreeItem->GetInProcessParent(getter_AddRefs(parent)); | |||
| 7038 | docShellTreeItem = parent; | |||
| 7039 | } | |||
| 7040 | ||||
| 7041 | return nullptr; | |||
| 7042 | } | |||
| 7043 | ||||
| 7044 | /* static */ | |||
| 7045 | nsPresContext* nsContentUtils::FindPresContextForDocument( | |||
| 7046 | const Document* aDocument) { | |||
| 7047 | if (PresShell* presShell = FindPresShellForDocument(aDocument)) { | |||
| 7048 | return presShell->GetPresContext(); | |||
| 7049 | } | |||
| 7050 | return nullptr; | |||
| 7051 | } | |||
| 7052 | ||||
| 7053 | nsIWidget* nsContentUtils::WidgetForDocument(const Document* aDocument) { | |||
| 7054 | PresShell* presShell = FindPresShellForDocument(aDocument); | |||
| 7055 | if (!presShell) { | |||
| 7056 | return nullptr; | |||
| 7057 | } | |||
| 7058 | nsViewManager* vm = presShell->GetViewManager(); | |||
| 7059 | if (!vm) { | |||
| 7060 | return nullptr; | |||
| 7061 | } | |||
| 7062 | nsView* rootView = vm->GetRootView(); | |||
| 7063 | if (!rootView) { | |||
| 7064 | return nullptr; | |||
| 7065 | } | |||
| 7066 | nsView* displayRoot = nsViewManager::GetDisplayRootFor(rootView); | |||
| 7067 | if (!displayRoot) { | |||
| 7068 | return nullptr; | |||
| 7069 | } | |||
| 7070 | return displayRoot->GetNearestWidget(nullptr); | |||
| 7071 | } | |||
| 7072 | ||||
| 7073 | nsIWidget* nsContentUtils::WidgetForContent(const nsIContent* aContent) { | |||
| 7074 | nsIFrame* frame = aContent->GetPrimaryFrame(); | |||
| 7075 | if (frame) { | |||
| 7076 | frame = nsLayoutUtils::GetDisplayRootFrame(frame); | |||
| 7077 | ||||
| 7078 | nsView* view = frame->GetView(); | |||
| 7079 | if (view) { | |||
| 7080 | return view->GetWidget(); | |||
| 7081 | } | |||
| 7082 | } | |||
| 7083 | ||||
| 7084 | return nullptr; | |||
| 7085 | } | |||
| 7086 | ||||
| 7087 | WindowRenderer* nsContentUtils::WindowRendererForContent( | |||
| 7088 | const nsIContent* aContent) { | |||
| 7089 | nsIWidget* widget = nsContentUtils::WidgetForContent(aContent); | |||
| 7090 | if (widget) { | |||
| 7091 | return widget->GetWindowRenderer(); | |||
| 7092 | } | |||
| 7093 | ||||
| 7094 | return nullptr; | |||
| 7095 | } | |||
| 7096 | ||||
| 7097 | WindowRenderer* nsContentUtils::WindowRendererForDocument( | |||
| 7098 | const Document* aDoc) { | |||
| 7099 | nsIWidget* widget = nsContentUtils::WidgetForDocument(aDoc); | |||
| 7100 | if (widget) { | |||
| 7101 | return widget->GetWindowRenderer(); | |||
| 7102 | } | |||
| 7103 | ||||
| 7104 | return nullptr; | |||
| 7105 | } | |||
| 7106 | ||||
| 7107 | bool nsContentUtils::AllowXULXBLForPrincipal(nsIPrincipal* aPrincipal) { | |||
| 7108 | if (!aPrincipal) { | |||
| 7109 | return false; | |||
| 7110 | } | |||
| 7111 | ||||
| 7112 | if (aPrincipal->IsSystemPrincipal()) { | |||
| 7113 | return true; | |||
| 7114 | } | |||
| 7115 | ||||
| 7116 | return xpc::IsInAutomation() && IsSitePermAllow(aPrincipal, "allowXULXBL"_ns); | |||
| 7117 | } | |||
| 7118 | ||||
| 7119 | bool nsContentUtils::IsPDFJSEnabled() { | |||
| 7120 | nsCOMPtr<nsIStreamConverter> conv = do_CreateInstance( | |||
| 7121 | "@mozilla.org/streamconv;1?from=application/pdf&to=text/html"); | |||
| 7122 | return conv; | |||
| 7123 | } | |||
| 7124 | ||||
| 7125 | bool nsContentUtils::IsPDFJS(nsIPrincipal* aPrincipal) { | |||
| 7126 | if (!aPrincipal || !aPrincipal->SchemeIs("resource")) { | |||
| 7127 | return false; | |||
| 7128 | } | |||
| 7129 | nsAutoCString spec; | |||
| 7130 | nsresult rv = aPrincipal->GetAsciiSpec(spec); | |||
| 7131 | 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" , 7131); return false; } } while (false); | |||
| 7132 | return spec.EqualsLiteral("resource://pdf.js/web/viewer.html"); | |||
| 7133 | } | |||
| 7134 | ||||
| 7135 | bool nsContentUtils::IsSystemOrPDFJS(JSContext* aCx, JSObject*) { | |||
| 7136 | nsIPrincipal* principal = SubjectPrincipal(aCx); | |||
| 7137 | return principal && (principal->IsSystemPrincipal() || IsPDFJS(principal)); | |||
| 7138 | } | |||
| 7139 | ||||
| 7140 | bool nsContentUtils::IsSecureContextOrWebExtension(JSContext* aCx, | |||
| 7141 | JSObject* aGlobal) { | |||
| 7142 | nsIPrincipal* principal = SubjectPrincipal(aCx); | |||
| 7143 | return mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, | |||
| 7144 | aGlobal) || | |||
| 7145 | (principal && principal->GetIsAddonOrExpandedAddonPrincipal()); | |||
| 7146 | } | |||
| 7147 | ||||
| 7148 | already_AddRefed<nsIDocumentLoaderFactory> | |||
| 7149 | nsContentUtils::FindInternalDocumentViewer(const nsACString& aType, | |||
| 7150 | DocumentViewerType* aLoaderType) { | |||
| 7151 | if (aLoaderType) { | |||
| 7152 | *aLoaderType = TYPE_UNSUPPORTED; | |||
| 7153 | } | |||
| 7154 | ||||
| 7155 | // one helper factory, please | |||
| 7156 | nsCOMPtr<nsICategoryManager> catMan( | |||
| 7157 | do_GetService(NS_CATEGORYMANAGER_CONTRACTID"@mozilla.org/categorymanager;1")); | |||
| 7158 | if (!catMan) return nullptr; | |||
| 7159 | ||||
| 7160 | nsCOMPtr<nsIDocumentLoaderFactory> docFactory; | |||
| 7161 | ||||
| 7162 | nsCString contractID; | |||
| 7163 | nsresult rv = | |||
| 7164 | catMan->GetCategoryEntry("Gecko-Content-Viewers", aType, contractID); | |||
| 7165 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { | |||
| 7166 | docFactory = do_GetService(contractID.get()); | |||
| 7167 | if (docFactory && aLoaderType) { | |||
| 7168 | if (contractID.EqualsLiteral(CONTENT_DLF_CONTRACTID"@mozilla.org/content/document-loader-factory;1")) | |||
| 7169 | *aLoaderType = TYPE_CONTENT; | |||
| 7170 | else if (contractID.EqualsLiteral(PLUGIN_DLF_CONTRACTID"@mozilla.org/content/plugin/document-loader-factory;1")) | |||
| 7171 | *aLoaderType = TYPE_FALLBACK; | |||
| 7172 | else | |||
| 7173 | *aLoaderType = TYPE_UNKNOWN; | |||
| 7174 | } | |||
| 7175 | return docFactory.forget(); | |||
| 7176 | } | |||
| 7177 | ||||
| 7178 | // If the type wasn't registered in `Gecko-Content-Viewers`, check if it's | |||
| 7179 | // another type which we may dynamically support, such as `text/*` types or | |||
| 7180 | // video document types. These types are all backed by the nsContentDLF. | |||
| 7181 | if (IsPlainTextType(aType) || | |||
| 7182 | DecoderTraits::IsSupportedInVideoDocument(aType)) { | |||
| 7183 | docFactory = do_GetService(CONTENT_DLF_CONTRACTID"@mozilla.org/content/document-loader-factory;1"); | |||
| 7184 | if (docFactory && aLoaderType) { | |||
| 7185 | *aLoaderType = TYPE_CONTENT; | |||
| 7186 | } | |||
| 7187 | return docFactory.forget(); | |||
| 7188 | } | |||
| 7189 | ||||
| 7190 | return nullptr; | |||
| 7191 | } | |||
| 7192 | ||||
| 7193 | static void ReportPatternCompileFailure(nsAString& aPattern, | |||
| 7194 | const JS::RegExpFlags& aFlags, | |||
| 7195 | const Document* aDocument, | |||
| 7196 | JS::MutableHandle<JS::Value> error, | |||
| 7197 | JSContext* cx) { | |||
| 7198 | AutoTArray<nsString, 3> strings; | |||
| 7199 | ||||
| 7200 | strings.AppendElement(aPattern); | |||
| 7201 | ||||
| 7202 | std::stringstream flag_ss; | |||
| 7203 | flag_ss << aFlags; | |||
| 7204 | nsString* flagstr = strings.AppendElement(); | |||
| 7205 | AppendUTF8toUTF16(flag_ss.str(), *flagstr); | |||
| 7206 | ||||
| 7207 | JS::AutoSaveExceptionState savedExc(cx); | |||
| 7208 | JS::Rooted<JSObject*> exnObj(cx, &error.toObject()); | |||
| 7209 | JS::Rooted<JS::Value> messageVal(cx); | |||
| 7210 | if (!JS_GetProperty(cx, exnObj, "message", &messageVal)) { | |||
| 7211 | return; | |||
| 7212 | } | |||
| 7213 | JS::Rooted<JSString*> messageStr(cx, messageVal.toString()); | |||
| 7214 | 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" , 7214); AnnotateMozCrashReason("MOZ_ASSERT" "(" "messageStr" ")"); do { *((volatile int*)__null) = 7214; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 7215 | if (!AssignJSString(cx, *strings.AppendElement(), messageStr)) { | |||
| 7216 | return; | |||
| 7217 | } | |||
| 7218 | ||||
| 7219 | nsContentUtils::ReportToConsole(nsIScriptError::errorFlag, "DOM"_ns, | |||
| 7220 | aDocument, nsContentUtils::eDOM_PROPERTIES, | |||
| 7221 | "PatternAttributeCompileFailurev2", strings); | |||
| 7222 | savedExc.drop(); | |||
| 7223 | } | |||
| 7224 | ||||
| 7225 | // static | |||
| 7226 | Maybe<bool> nsContentUtils::IsPatternMatching(const nsAString& aValue, | |||
| 7227 | nsString&& aPattern, | |||
| 7228 | const Document* aDocument, | |||
| 7229 | bool aHasMultiple, | |||
| 7230 | JS::RegExpFlags aFlags) { | |||
| 7231 | 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" , 7231); MOZ_PretendNoReturn(); } } while (0); | |||
| 7232 | ||||
| 7233 | // The fact that we're using a JS regexp under the hood should not be visible | |||
| 7234 | // to things like window onerror handlers, so we don't initialize our JSAPI | |||
| 7235 | // with the document's window (which may not exist anyway). | |||
| 7236 | AutoJSAPI jsapi; | |||
| 7237 | jsapi.Init(); | |||
| 7238 | JSContext* cx = jsapi.cx(); | |||
| 7239 | AutoDisableJSInterruptCallback disabler(cx); | |||
| 7240 | ||||
| 7241 | // We can use the junk scope here, because we're just using it for regexp | |||
| 7242 | // evaluation, not actual script execution, and we disable statics so that the | |||
| 7243 | // evaluation does not interact with the execution global. | |||
| 7244 | JSAutoRealm ar(cx, xpc::PrivilegedJunkScope()); | |||
| 7245 | ||||
| 7246 | // Check if the pattern by itself is valid first, and not that it only becomes | |||
| 7247 | // valid once we add ^(?: and )$. | |||
| 7248 | JS::Rooted<JS::Value> error(cx); | |||
| 7249 | if (!JS::CheckRegExpSyntax(cx, aPattern.BeginReading(), aPattern.Length(), | |||
| 7250 | aFlags, &error)) { | |||
| 7251 | return Nothing(); | |||
| 7252 | } | |||
| 7253 | ||||
| 7254 | if (!error.isUndefined()) { | |||
| 7255 | ReportPatternCompileFailure(aPattern, aFlags, aDocument, &error, cx); | |||
| 7256 | return Some(true); | |||
| 7257 | } | |||
| 7258 | ||||
| 7259 | // The pattern has to match the entire value. | |||
| 7260 | aPattern.InsertLiteral(u"^(?:", 0); | |||
| 7261 | aPattern.AppendLiteral(")$"); | |||
| 7262 | ||||
| 7263 | JS::Rooted<JSObject*> re( | |||
| 7264 | cx, JS::NewUCRegExpObject(cx, aPattern.BeginReading(), aPattern.Length(), | |||
| 7265 | aFlags)); | |||
| 7266 | if (!re) { | |||
| 7267 | return Nothing(); | |||
| 7268 | } | |||
| 7269 | ||||
| 7270 | JS::Rooted<JS::Value> rval(cx, JS::NullValue()); | |||
| 7271 | if (!aHasMultiple) { | |||
| 7272 | size_t idx = 0; | |||
| 7273 | if (!JS::ExecuteRegExpNoStatics(cx, re, aValue.BeginReading(), | |||
| 7274 | aValue.Length(), &idx, true, &rval)) { | |||
| 7275 | return Nothing(); | |||
| 7276 | } | |||
| 7277 | return Some(!rval.isNull()); | |||
| 7278 | } | |||
| 7279 | ||||
| 7280 | HTMLSplitOnSpacesTokenizer tokenizer(aValue, ','); | |||
| 7281 | while (tokenizer.hasMoreTokens()) { | |||
| 7282 | const nsAString& value = tokenizer.nextToken(); | |||
| 7283 | size_t idx = 0; | |||
| 7284 | if (!JS::ExecuteRegExpNoStatics(cx, re, value.BeginReading(), | |||
| 7285 | value.Length(), &idx, true, &rval)) { | |||
| 7286 | return Nothing(); | |||
| 7287 | } | |||
| 7288 | if (rval.isNull()) { | |||
| 7289 | return Some(false); | |||
| 7290 | } | |||
| 7291 | } | |||
| 7292 | return Some(true); | |||
| 7293 | } | |||
| 7294 | ||||
| 7295 | // static | |||
| 7296 | nsresult nsContentUtils::URIInheritsSecurityContext(nsIURI* aURI, | |||
| 7297 | bool* aResult) { | |||
| 7298 | // Note: about:blank URIs do NOT inherit the security context from the | |||
| 7299 | // current document, which is what this function tests for... | |||
| 7300 | return NS_URIChainHasFlags( | |||
| 7301 | aURI, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT, aResult); | |||
| 7302 | } | |||
| 7303 | ||||
| 7304 | // static | |||
| 7305 | bool nsContentUtils::ChannelShouldInheritPrincipal( | |||
| 7306 | nsIPrincipal* aLoadingPrincipal, nsIURI* aURI, bool aInheritForAboutBlank, | |||
| 7307 | bool aForceInherit) { | |||
| 7308 | 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" , 7309); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadingPrincipal" ") (" "Can not check inheritance without a principal" ")"); do { *((volatile int*)__null) = 7309; __attribute__((nomerge)) :: abort(); } while (false); } } while (false) | |||
| 7309 | "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" , 7309); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadingPrincipal" ") (" "Can not check inheritance without a principal" ")"); do { *((volatile int*)__null) = 7309; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); | |||
| 7310 | ||||
| 7311 | // Only tell the channel to inherit if it can't provide its own security | |||
| 7312 | // context. | |||
| 7313 | // | |||
| 7314 | // XXX: If this is ever changed, check all callers for what owners | |||
| 7315 | // they're passing in. In particular, see the code and | |||
| 7316 | // comments in nsDocShell::LoadURI where we fall back on | |||
| 7317 | // inheriting the owner if called from chrome. That would be | |||
| 7318 | // very wrong if this code changed anything but channels that | |||
| 7319 | // can't provide their own security context! | |||
| 7320 | // | |||
| 7321 | // If aForceInherit is true, we will inherit, even for a channel that | |||
| 7322 | // can provide its own security context. This is used for srcdoc loads. | |||
| 7323 | bool inherit = aForceInherit; | |||
| 7324 | if (!inherit) { | |||
| 7325 | bool uriInherits; | |||
| 7326 | // We expect URIInheritsSecurityContext to return success for an | |||
| 7327 | // about:blank URI, so don't call NS_IsAboutBlank() if this call fails. | |||
| 7328 | // This condition needs to match the one in nsDocShell::InternalLoad where | |||
| 7329 | // we're checking for things that will use the owner. | |||
| 7330 | inherit = | |||
| 7331 | (NS_SUCCEEDED(URIInheritsSecurityContext(aURI, &uriInherits))((bool)(__builtin_expect(!!(!NS_FAILED_impl(URIInheritsSecurityContext (aURI, &uriInherits))), 1))) && | |||
| 7332 | (uriInherits || (aInheritForAboutBlank && | |||
| 7333 | NS_IsAboutBlankAllowQueryAndFragment(aURI)))) || | |||
| 7334 | // | |||
| 7335 | // file: uri special-casing | |||
| 7336 | // | |||
| 7337 | // If this is a file: load opened from another file: then it may need | |||
| 7338 | // to inherit the owner from the referrer so they can script each other. | |||
| 7339 | // If we don't set the owner explicitly then each file: gets an owner | |||
| 7340 | // based on its own codebase later. | |||
| 7341 | // | |||
| 7342 | (URIIsLocalFile(aURI) && | |||
| 7343 | NS_SUCCEEDED(aLoadingPrincipal->CheckMayLoad(aURI, false))((bool)(__builtin_expect(!!(!NS_FAILED_impl(aLoadingPrincipal ->CheckMayLoad(aURI, false))), 1))) && | |||
| 7344 | // One more check here. CheckMayLoad will always return true for the | |||
| 7345 | // system principal, but we do NOT want to inherit in that case. | |||
| 7346 | !aLoadingPrincipal->IsSystemPrincipal()); | |||
| 7347 | } | |||
| 7348 | return inherit; | |||
| 7349 | } | |||
| 7350 | ||||
| 7351 | /* static */ | |||
| 7352 | bool nsContentUtils::IsCutCopyAllowed(Document* aDocument, | |||
| 7353 | nsIPrincipal& aSubjectPrincipal) { | |||
| 7354 | if (StaticPrefs::dom_allow_cut_copy() && aDocument && | |||
| 7355 | aDocument->HasValidTransientUserGestureActivation()) { | |||
| 7356 | return true; | |||
| 7357 | } | |||
| 7358 | ||||
| 7359 | return PrincipalHasPermission(aSubjectPrincipal, nsGkAtoms::clipboardWrite); | |||
| 7360 | } | |||
| 7361 | ||||
| 7362 | /* static */ | |||
| 7363 | bool nsContentUtils::HaveEqualPrincipals(Document* aDoc1, Document* aDoc2) { | |||
| 7364 | if (!aDoc1 || !aDoc2) { | |||
| 7365 | return false; | |||
| 7366 | } | |||
| 7367 | bool principalsEqual = false; | |||
| 7368 | aDoc1->NodePrincipal()->Equals(aDoc2->NodePrincipal(), &principalsEqual); | |||
| 7369 | return principalsEqual; | |||
| 7370 | } | |||
| 7371 | ||||
| 7372 | /* static */ | |||
| 7373 | void nsContentUtils::FireMutationEventsForDirectParsing( | |||
| 7374 | Document* aDoc, nsIContent* aDest, int32_t aOldChildCount) { | |||
| 7375 | // Fire mutation events. Optimize for the case when there are no listeners | |||
| 7376 | int32_t newChildCount = aDest->GetChildCount(); | |||
| 7377 | if (newChildCount && nsContentUtils::HasMutationListeners( | |||
| 7378 | aDoc, NS_EVENT_BITS_MUTATION_NODEINSERTED0x02)) { | |||
| 7379 | AutoTArray<nsCOMPtr<nsIContent>, 50> childNodes; | |||
| 7380 | 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" , 7381); MOZ_PretendNoReturn(); } } while (0) | |||
| 7381 | "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" , 7381); MOZ_PretendNoReturn(); } } while (0); | |||
| 7382 | childNodes.SetCapacity(newChildCount - aOldChildCount); | |||
| 7383 | for (nsIContent* child = aDest->GetFirstChild(); child; | |||
| 7384 | child = child->GetNextSibling()) { | |||
| 7385 | childNodes.AppendElement(child); | |||
| 7386 | } | |||
| 7387 | FragmentOrElement::FireNodeInserted(aDoc, aDest, childNodes); | |||
| 7388 | } | |||
| 7389 | } | |||
| 7390 | ||||
| 7391 | /* static */ | |||
| 7392 | const Document* nsContentUtils::GetInProcessSubtreeRootDocument( | |||
| 7393 | const Document* aDoc) { | |||
| 7394 | if (!aDoc) { | |||
| 7395 | return nullptr; | |||
| 7396 | } | |||
| 7397 | const Document* doc = aDoc; | |||
| 7398 | while (doc->GetInProcessParentDocument()) { | |||
| 7399 | doc = doc->GetInProcessParentDocument(); | |||
| 7400 | } | |||
| 7401 | return doc; | |||
| 7402 | } | |||
| 7403 | ||||
| 7404 | // static | |||
| 7405 | int32_t nsContentUtils::GetAdjustedOffsetInTextControl(nsIFrame* aOffsetFrame, | |||
| 7406 | int32_t aOffset) { | |||
| 7407 | // The structure of the anonymous frames within a text control frame is | |||
| 7408 | // an optional block frame, followed by an optional br frame. | |||
| 7409 | ||||
| 7410 | // If the offset frame has a child, then this frame is the block which | |||
| 7411 | // has the text frames (containing the content) as its children. This will | |||
| 7412 | // be the case if we click to the right of any of the text frames, or at the | |||
| 7413 | // bottom of the text area. | |||
| 7414 | nsIFrame* firstChild = aOffsetFrame->PrincipalChildList().FirstChild(); | |||
| 7415 | if (firstChild) { | |||
| 7416 | // In this case, the passed-in offset is incorrect, and we want the length | |||
| 7417 | // of the entire content in the text control frame. | |||
| 7418 | return firstChild->GetContent()->Length(); | |||
| 7419 | } | |||
| 7420 | ||||
| 7421 | if (aOffsetFrame->GetPrevSibling() && !aOffsetFrame->GetNextSibling()) { | |||
| 7422 | // In this case, we're actually within the last frame, which is a br | |||
| 7423 | // frame. Our offset should therefore be the length of the first child of | |||
| 7424 | // our parent. | |||
| 7425 | int32_t aOutOffset = aOffsetFrame->GetParent() | |||
| 7426 | ->PrincipalChildList() | |||
| 7427 | .FirstChild() | |||
| 7428 | ->GetContent() | |||
| 7429 | ->Length(); | |||
| 7430 | return aOutOffset; | |||
| 7431 | } | |||
| 7432 | ||||
| 7433 | // Otherwise, we're within one of the text frames, in which case our offset | |||
| 7434 | // has already been correctly calculated. | |||
| 7435 | return aOffset; | |||
| 7436 | } | |||
| 7437 | ||||
| 7438 | // static | |||
| 7439 | bool nsContentUtils::IsPointInSelection( | |||
| 7440 | const mozilla::dom::Selection& aSelection, const nsINode& aNode, | |||
| 7441 | const uint32_t aOffset, const bool aAllowCrossShadowBoundary) { | |||
| 7442 | const bool selectionIsCollapsed = | |||
| 7443 | !aAllowCrossShadowBoundary | |||
| 7444 | ? aSelection.IsCollapsed() | |||
| 7445 | : aSelection.AreNormalAndCrossShadowBoundaryRangesCollapsed(); | |||
| 7446 | if (selectionIsCollapsed) { | |||
| 7447 | return false; | |||
| 7448 | } | |||
| 7449 | ||||
| 7450 | const uint32_t rangeCount = aSelection.RangeCount(); | |||
| 7451 | for (const uint32_t i : IntegerRange(rangeCount)) { | |||
| 7452 | 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" , 7452); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSelection.RangeCount() == rangeCount" ")"); do { *((volatile int*)__null) = 7452; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 7453 | RefPtr<const nsRange> range = aSelection.GetRangeAt(i); | |||
| 7454 | if (NS_WARN_IF(!range)NS_warn_if_impl(!range, "!range", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp" , 7454)) { | |||
| 7455 | // Don't bail yet, iterate through them all | |||
| 7456 | continue; | |||
| 7457 | } | |||
| 7458 | ||||
| 7459 | // Done when we find a range that we are in | |||
| 7460 | if (range->IsPointInRange(aNode, aOffset, IgnoreErrors(), | |||
| 7461 | aAllowCrossShadowBoundary)) { | |||
| 7462 | return true; | |||
| 7463 | } | |||
| 7464 | } | |||
| 7465 | ||||
| 7466 | return false; | |||
| 7467 | } | |||
| 7468 | ||||
| 7469 | // static | |||
| 7470 | void nsContentUtils::GetSelectionInTextControl(Selection* aSelection, | |||
| 7471 | Element* aRoot, | |||
| 7472 | uint32_t& aOutStartOffset, | |||
| 7473 | uint32_t& aOutEndOffset) { | |||
| 7474 | 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" , 7474); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSelection && aRoot" ")"); do { *((volatile int*)__null) = 7474; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 7475 | ||||
| 7476 | // We don't care which end of this selection is anchor and which is focus. In | |||
| 7477 | // fact, we explicitly want to know which is the _start_ and which is the | |||
| 7478 | // _end_, not anchor vs focus. | |||
| 7479 | const nsRange* range = aSelection->GetAnchorFocusRange(); | |||
| 7480 | if (!range) { | |||
| 7481 | // Nothing selected | |||
| 7482 | aOutStartOffset = aOutEndOffset = 0; | |||
| 7483 | return; | |||
| 7484 | } | |||
| 7485 | ||||
| 7486 | // All the node pointers here are raw pointers for performance. We shouldn't | |||
| 7487 | // be doing anything in this function that invalidates the node tree. | |||
| 7488 | nsINode* startContainer = range->GetStartContainer(); | |||
| 7489 | uint32_t startOffset = range->StartOffset(); | |||
| 7490 | nsINode* endContainer = range->GetEndContainer(); | |||
| 7491 | uint32_t endOffset = range->EndOffset(); | |||
| 7492 | ||||
| 7493 | // We have at most two children, consisting of an optional text node followed | |||
| 7494 | // by an optional <br>. | |||
| 7495 | 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" , 7495); MOZ_PretendNoReturn(); } } while (0); | |||
| 7496 | nsIContent* firstChild = aRoot->GetFirstChild(); | |||
| 7497 | #ifdef DEBUG1 | |||
| 7498 | nsCOMPtr<nsIContent> lastChild = aRoot->GetLastChild(); | |||
| 7499 | 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" , 7501); MOZ_PretendNoReturn(); } } while (0) | |||
| 7500 | 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" , 7501); MOZ_PretendNoReturn(); } } while (0) | |||
| 7501 | "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" , 7501); MOZ_PretendNoReturn(); } } while (0); | |||
| 7502 | 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" , 7504); MOZ_PretendNoReturn(); } } while (0) | |||
| 7503 | 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" , 7504); MOZ_PretendNoReturn(); } } while (0) | |||
| 7504 | "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" , 7504); MOZ_PretendNoReturn(); } } while (0); | |||
| 7505 | // firstChild is either text or a <br> (hence an element). | |||
| 7506 | 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" , 7506); AnnotateMozCrashReason("MOZ_ASSERT" "(" "firstChild->IsText() || firstChild->IsElement()" ")"); do { *((volatile int*)__null) = 7506; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); | |||
| 7507 | #endif | |||
| 7508 | if (!firstChild || firstChild->IsElement()) { | |||
| 7509 | // No text node, so everything is 0 | |||
| 7510 | startOffset = endOffset = 0; | |||
| 7511 | } else { | |||
| 7512 | // First child is text. If the start/end is already in the text node, | |||
| 7513 | // or the start of the root node, no change needed. If it's in the root | |||
| 7514 | // node but not the start, or in the trailing <br>, we need to set the | |||
| 7515 | // offset to the end. | |||
| 7516 | if ((startContainer == aRoot && startOffset != 0) || | |||
| 7517 | (startContainer != aRoot && startContainer != firstChild)) { | |||
| 7518 | startOffset = firstChild->Length(); | |||
| 7519 | } | |||
| 7520 | if ((endContainer == aRoot && endOffset != 0) || | |||
| 7521 | (endContainer != aRoot && endContainer != firstChild)) { | |||
| 7522 | endOffset = firstChild->Length(); | |||
| 7523 | } | |||
| 7524 | } | |||
| 7525 | ||||
| 7526 | 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" , 7526); AnnotateMozCrashReason("MOZ_ASSERT" "(" "startOffset <= endOffset" ")"); do { *((volatile int*)__null) = 7526; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 7527 | aOutStartOffset = startOffset; | |||
| 7528 | aOutEndOffset = endOffset; | |||
| 7529 | } | |||
| 7530 | ||||
| 7531 | // static | |||
| 7532 | HTMLEditor* nsContentUtils::GetHTMLEditor(nsPresContext* aPresContext) { | |||
| 7533 | if (!aPresContext) { | |||
| 7534 | return nullptr; | |||
| 7535 | } | |||
| 7536 | return GetHTMLEditor(aPresContext->GetDocShell()); | |||
| 7537 | } | |||
| 7538 | ||||
| 7539 | // static | |||
| 7540 | HTMLEditor* nsContentUtils::GetHTMLEditor(nsDocShell* aDocShell) { | |||
| 7541 | bool isEditable; | |||
| 7542 | if (!aDocShell || NS_FAILED(aDocShell->GetEditable(&isEditable))((bool)(__builtin_expect(!!(NS_FAILED_impl(aDocShell->GetEditable (&isEditable))), 0))) || | |||
| 7543 | !isEditable) { | |||
| 7544 | return nullptr; | |||
| 7545 | } | |||
| 7546 | return aDocShell->GetHTMLEditor(); | |||
| 7547 | } | |||
| 7548 | ||||
| 7549 | // static | |||
| 7550 | EditorBase* nsContentUtils::GetActiveEditor(nsPresContext* aPresContext) { | |||
| 7551 | if (!aPresContext) { | |||
| 7552 | return nullptr; | |||
| 7553 | } | |||
| 7554 | ||||
| 7555 | return GetActiveEditor(aPresContext->Document()->GetWindow()); | |||
| 7556 | } | |||
| 7557 | ||||
| 7558 | // static | |||
| 7559 | EditorBase* nsContentUtils::GetActiveEditor(nsPIDOMWindowOuter* aWindow) { | |||
| 7560 | if (!aWindow || !aWindow->GetExtantDoc()) { | |||
| 7561 | return nullptr; | |||
| 7562 | } | |||
| 7563 | ||||
| 7564 | // If it's in designMode, nobody can have focus. Therefore, the HTMLEditor | |||
| 7565 | // handles all events. I.e., it's focused editor in this case. | |||
| 7566 | if (aWindow->GetExtantDoc()->IsInDesignMode()) { | |||
| 7567 | return GetHTMLEditor(nsDocShell::Cast(aWindow->GetDocShell())); | |||
| 7568 | } | |||
| 7569 | ||||
| 7570 | // If focused element is associated with TextEditor, it must be <input> | |||
| 7571 | // element or <textarea> element. Let's return it even if it's in a | |||
| 7572 | // contenteditable element. | |||
| 7573 | nsCOMPtr<nsPIDOMWindowOuter> focusedWindow; | |||
| 7574 | if (Element* focusedElement = nsFocusManager::GetFocusedDescendant( | |||
| 7575 | aWindow, nsFocusManager::SearchRange::eOnlyCurrentWindow, | |||
| 7576 | getter_AddRefs(focusedWindow))) { | |||
| 7577 | if (TextEditor* textEditor = focusedElement->GetTextEditorInternal()) { | |||
| 7578 | return textEditor; | |||
| 7579 | } | |||
| 7580 | } | |||
| 7581 | ||||
| 7582 | // Otherwise, HTMLEditor may handle inputs even non-editable element has | |||
| 7583 | // focus or nobody has focus. | |||
| 7584 | return GetHTMLEditor(nsDocShell::Cast(aWindow->GetDocShell())); | |||
| 7585 | } | |||
| 7586 | ||||
| 7587 | // static | |||
| 7588 | TextEditor* nsContentUtils::GetTextEditorFromAnonymousNodeWithoutCreation( | |||
| 7589 | const nsIContent* aAnonymousContent) { | |||
| 7590 | if (!aAnonymousContent) { | |||
| 7591 | return nullptr; | |||
| 7592 | } | |||
| 7593 | nsIContent* parent = aAnonymousContent->FindFirstNonChromeOnlyAccessContent(); | |||
| 7594 | if (!parent || parent == aAnonymousContent) { | |||
| 7595 | return nullptr; | |||
| 7596 | } | |||
| 7597 | if (HTMLInputElement* inputElement = | |||
| 7598 | HTMLInputElement::FromNodeOrNull(parent)) { | |||
| 7599 | return inputElement->GetTextEditorWithoutCreation(); | |||
| 7600 | } | |||
| 7601 | if (HTMLTextAreaElement* textareaElement = | |||
| 7602 | HTMLTextAreaElement::FromNodeOrNull(parent)) { | |||
| 7603 | return textareaElement->GetTextEditorWithoutCreation(); | |||
| 7604 | } | |||
| 7605 | return nullptr; | |||
| 7606 | } | |||
| 7607 | ||||
| 7608 | // static | |||
| 7609 | bool nsContentUtils::IsNodeInEditableRegion(nsINode* aNode) { | |||
| 7610 | while (aNode) { | |||
| 7611 | if (aNode->IsEditable()) { | |||
| 7612 | return true; | |||
| 7613 | } | |||
| 7614 | aNode = aNode->GetParent(); | |||
| 7615 | } | |||
| 7616 | return false; | |||
| 7617 | } | |||
| 7618 | ||||
| 7619 | // static | |||
| 7620 | bool nsContentUtils::IsForbiddenRequestHeader(const nsACString& aHeader, | |||
| 7621 | const nsACString& aValue) { | |||
| 7622 | if (IsForbiddenSystemRequestHeader(aHeader)) { | |||
| 7623 | return true; | |||
| 7624 | } | |||
| 7625 | ||||
| 7626 | if ((nsContentUtils::IsOverrideMethodHeader(aHeader) && | |||
| 7627 | nsContentUtils::ContainsForbiddenMethod(aValue))) { | |||
| 7628 | return true; | |||
| 7629 | } | |||
| 7630 | ||||
| 7631 | if (StringBeginsWith(aHeader, "proxy-"_ns, | |||
| 7632 | nsCaseInsensitiveCStringComparator) || | |||
| 7633 | StringBeginsWith(aHeader, "sec-"_ns, | |||
| 7634 | nsCaseInsensitiveCStringComparator)) { | |||
| 7635 | return true; | |||
| 7636 | } | |||
| 7637 | ||||
| 7638 | return false; | |||
| 7639 | } | |||
| 7640 | ||||
| 7641 | // static | |||
| 7642 | bool nsContentUtils::IsForbiddenSystemRequestHeader(const nsACString& aHeader) { | |||
| 7643 | static const char* kInvalidHeaders[] = {"accept-charset", | |||
| 7644 | "accept-encoding", | |||
| 7645 | "access-control-request-headers", | |||
| 7646 | "access-control-request-method", | |||
| 7647 | "connection", | |||
| 7648 | "content-length", | |||
| 7649 | "cookie", | |||
| 7650 | "cookie2", | |||
| 7651 | "date", | |||
| 7652 | "dnt", | |||
| 7653 | "expect", | |||
| 7654 | "host", | |||
| 7655 | "keep-alive", | |||
| 7656 | "origin", | |||
| 7657 | "referer", | |||
| 7658 | "set-cookie", | |||
| 7659 | "te", | |||
| 7660 | "trailer", | |||
| 7661 | "transfer-encoding", | |||
| 7662 | "upgrade", | |||
| 7663 | "via"}; | |||
| 7664 | for (auto& kInvalidHeader : kInvalidHeaders) { | |||
| 7665 | if (aHeader.LowerCaseEqualsASCII(kInvalidHeader)) { | |||
| 7666 | return true; | |||
| 7667 | } | |||
| 7668 | } | |||
| 7669 | return false; | |||
| 7670 | } | |||
| 7671 | ||||
| 7672 | // static | |||
| 7673 | bool nsContentUtils::IsForbiddenResponseHeader(const nsACString& aHeader) { | |||
| 7674 | return (aHeader.LowerCaseEqualsASCII("set-cookie") || | |||
| 7675 | aHeader.LowerCaseEqualsASCII("set-cookie2")); | |||
| 7676 | } | |||
| 7677 | ||||
| 7678 | // static | |||
| 7679 | bool nsContentUtils::IsOverrideMethodHeader(const nsACString& headerName) { | |||
| 7680 | return headerName.EqualsIgnoreCase("x-http-method-override") || | |||
| 7681 | headerName.EqualsIgnoreCase("x-http-method") || | |||
| 7682 | headerName.EqualsIgnoreCase("x-method-override"); | |||
| 7683 | } | |||
| 7684 | ||||
| 7685 | // static | |||
| 7686 | bool nsContentUtils::ContainsForbiddenMethod(const nsACString& headerValue) { | |||
| 7687 | bool hasInsecureMethod = false; | |||
| 7688 | nsCCharSeparatedTokenizer tokenizer(headerValue, ','); | |||
| 7689 | ||||
| 7690 | while (tokenizer.hasMoreTokens()) { | |||
| 7691 | const nsDependentCSubstring& value = tokenizer.nextToken(); | |||
| 7692 | ||||
| 7693 | if (value.EqualsIgnoreCase("connect") || value.EqualsIgnoreCase("trace") || | |||
| 7694 | value.EqualsIgnoreCase("track")) { | |||
| 7695 | hasInsecureMethod = true; | |||
| 7696 | break; | |||
| 7697 | } | |||
| 7698 | } | |||
| 7699 | ||||
| 7700 | return hasInsecureMethod; | |||
| 7701 | } | |||
| 7702 | ||||
| 7703 | Maybe<nsContentUtils::ParsedRange> nsContentUtils::ParseSingleRangeRequest( | |||
| 7704 | const nsACString& aHeaderValue, bool aAllowWhitespace) { | |||
| 7705 | // See https://fetch.spec.whatwg.org/#simple-range-header-value | |||
| 7706 | mozilla::Tokenizer p(aHeaderValue); | |||
| 7707 | Maybe<uint64_t> rangeStart; | |||
| 7708 | Maybe<uint64_t> rangeEnd; | |||
| 7709 | ||||
| 7710 | // Step 2 and 3 | |||
| 7711 | if (!p.CheckWord("bytes")) { | |||
| 7712 | return Nothing(); | |||
| 7713 | } | |||
| 7714 | ||||
| 7715 | // Step 4 | |||
| 7716 | if (aAllowWhitespace) { | |||
| 7717 | p.SkipWhites(); | |||
| 7718 | } | |||
| 7719 | ||||
| 7720 | // Step 5 and 6 | |||
| 7721 | if (!p.CheckChar('=')) { | |||
| 7722 | return Nothing(); | |||
| 7723 | } | |||
| 7724 | ||||
| 7725 | // Step 7 | |||
| 7726 | if (aAllowWhitespace) { | |||
| 7727 | p.SkipWhites(); | |||
| 7728 | } | |||
| 7729 | ||||
| 7730 | // Step 8 and 9 | |||
| 7731 | uint64_t res; | |||
| 7732 | if (p.ReadInteger(&res)) { | |||
| 7733 | rangeStart = Some(res); | |||
| 7734 | } | |||
| 7735 | ||||
| 7736 | // Step 10 | |||
| 7737 | if (aAllowWhitespace) { | |||
| 7738 | p.SkipWhites(); | |||
| 7739 | } | |||
| 7740 | ||||
| 7741 | // Step 11 | |||
| 7742 | if (!p.CheckChar('-')) { | |||
| 7743 | return Nothing(); | |||
| 7744 | } | |||
| 7745 | ||||
| 7746 | // Step 13 | |||
| 7747 | if (aAllowWhitespace) { | |||
| 7748 | p.SkipWhites(); | |||
| 7749 | } | |||
| 7750 | ||||
| 7751 | // Step 14 and 15 | |||
| 7752 | if (p.ReadInteger(&res)) { | |||
| 7753 | rangeEnd = Some(res); | |||
| 7754 | } | |||
| 7755 | ||||
| 7756 | // Step 16 | |||
| 7757 | if (!p.CheckEOF()) { | |||
| 7758 | return Nothing(); | |||
| 7759 | } | |||
| 7760 | ||||
| 7761 | // Step 17 | |||
| 7762 | if (!rangeStart && !rangeEnd) { | |||
| 7763 | return Nothing(); | |||
| 7764 | } | |||
| 7765 | ||||
| 7766 | // Step 18 | |||
| 7767 | if (rangeStart && rangeEnd && *rangeStart > *rangeEnd) { | |||
| 7768 | return Nothing(); | |||
| 7769 | } | |||
| 7770 | ||||
| 7771 | return Some(ParsedRange(rangeStart, rangeEnd)); | |||
| 7772 | } | |||
| 7773 | ||||
| 7774 | // static | |||
| 7775 | bool nsContentUtils::IsCorsUnsafeRequestHeaderValue( | |||
| 7776 | const nsACString& aHeaderValue) { | |||
| 7777 | const char* cur = aHeaderValue.BeginReading(); | |||
| 7778 | const char* end = aHeaderValue.EndReading(); | |||
| 7779 | ||||
| 7780 | while (cur != end) { | |||
| 7781 | // Implementation of | |||
| 7782 | // https://fetch.spec.whatwg.org/#cors-unsafe-request-header-byte Is less | |||
| 7783 | // than a space but not a horizontal tab | |||
| 7784 | if ((*cur < ' ' && *cur != '\t') || *cur == '"' || *cur == '(' || | |||
| 7785 | *cur == ')' || *cur == ':' || *cur == '<' || *cur == '>' || | |||
| 7786 | *cur == '?' || *cur == '@' || *cur == '[' || *cur == '\\' || | |||
| 7787 | *cur == ']' || *cur == '{' || *cur == '}' || | |||
| 7788 | *cur == 0x7F) { // 0x75 is DEL | |||
| 7789 | return true; | |||
| 7790 | } | |||
| 7791 | cur++; | |||
| 7792 | } | |||
| 7793 | return false; | |||
| 7794 | } | |||
| 7795 | ||||
| 7796 | // static | |||
| 7797 | bool nsContentUtils::IsAllowedNonCorsAccept(const nsACString& aHeaderValue) { | |||
| 7798 | if (IsCorsUnsafeRequestHeaderValue(aHeaderValue)) { | |||
| 7799 | return false; | |||
| 7800 | } | |||
| 7801 | return true; | |||
| 7802 | } | |||
| 7803 | ||||
| 7804 | // static | |||
| 7805 | bool nsContentUtils::IsAllowedNonCorsContentType( | |||
| 7806 | const nsACString& aHeaderValue) { | |||
| 7807 | nsAutoCString contentType; | |||
| 7808 | nsAutoCString unused; | |||
| 7809 | ||||
| 7810 | if (IsCorsUnsafeRequestHeaderValue(aHeaderValue)) { | |||
| 7811 | return false; | |||
| 7812 | } | |||
| 7813 | ||||
| 7814 | nsresult rv = NS_ParseRequestContentType(aHeaderValue, contentType, unused); | |||
| 7815 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 7816 | return false; | |||
| 7817 | } | |||
| 7818 | ||||
| 7819 | return contentType.LowerCaseEqualsLiteral("text/plain") || | |||
| 7820 | contentType.LowerCaseEqualsLiteral( | |||
| 7821 | "application/x-www-form-urlencoded") || | |||
| 7822 | contentType.LowerCaseEqualsLiteral("multipart/form-data"); | |||
| 7823 | } | |||
| 7824 | ||||
| 7825 | // static | |||
| 7826 | bool nsContentUtils::IsAllowedNonCorsLanguage(const nsACString& aHeaderValue) { | |||
| 7827 | const char* cur = aHeaderValue.BeginReading(); | |||
| 7828 | const char* end = aHeaderValue.EndReading(); | |||
| 7829 | ||||
| 7830 | while (cur != end) { | |||
| 7831 | if ((*cur >= '0' && *cur <= '9') || (*cur >= 'A' && *cur <= 'Z') || | |||
| 7832 | (*cur >= 'a' && *cur <= 'z') || *cur == ' ' || *cur == '*' || | |||
| 7833 | *cur == ',' || *cur == '-' || *cur == '.' || *cur == ';' || | |||
| 7834 | *cur == '=') { | |||
| 7835 | cur++; | |||
| 7836 | continue; | |||
| 7837 | } | |||
| 7838 | return false; | |||
| 7839 | } | |||
| 7840 | return true; | |||
| 7841 | } | |||
| 7842 | ||||
| 7843 | bool nsContentUtils::IsAllowedNonCorsRange(const nsACString& aHeaderValue) { | |||
| 7844 | Maybe<ParsedRange> parsedRange = ParseSingleRangeRequest(aHeaderValue, false); | |||
| 7845 | if (!parsedRange) { | |||
| 7846 | return false; | |||
| 7847 | } | |||
| 7848 | ||||
| 7849 | if (!parsedRange->Start()) { | |||
| 7850 | return false; | |||
| 7851 | } | |||
| 7852 | ||||
| 7853 | return true; | |||
| 7854 | } | |||
| 7855 | ||||
| 7856 | // static | |||
| 7857 | bool nsContentUtils::IsCORSSafelistedRequestHeader(const nsACString& aName, | |||
| 7858 | const nsACString& aValue) { | |||
| 7859 | // see https://fetch.spec.whatwg.org/#cors-safelisted-request-header | |||
| 7860 | if (aValue.Length() > 128) { | |||
| 7861 | return false; | |||
| 7862 | } | |||
| 7863 | return (aName.LowerCaseEqualsLiteral("accept") && | |||
| 7864 | nsContentUtils::IsAllowedNonCorsAccept(aValue)) || | |||
| 7865 | (aName.LowerCaseEqualsLiteral("accept-language") && | |||
| 7866 | nsContentUtils::IsAllowedNonCorsLanguage(aValue)) || | |||
| 7867 | (aName.LowerCaseEqualsLiteral("content-language") && | |||
| 7868 | nsContentUtils::IsAllowedNonCorsLanguage(aValue)) || | |||
| 7869 | (aName.LowerCaseEqualsLiteral("content-type") && | |||
| 7870 | nsContentUtils::IsAllowedNonCorsContentType(aValue)) || | |||
| 7871 | (aName.LowerCaseEqualsLiteral("range") && | |||
| 7872 | nsContentUtils::IsAllowedNonCorsRange(aValue)) || | |||
| 7873 | (StaticPrefs::network_http_idempotencyKey_enabled() && | |||
| 7874 | aName.LowerCaseEqualsLiteral("idempotency-key")); | |||
| 7875 | } | |||
| 7876 | ||||
| 7877 | mozilla::LogModule* nsContentUtils::ResistFingerprintingLog() { | |||
| 7878 | return gResistFingerprintingLog; | |||
| 7879 | } | |||
| 7880 | mozilla::LogModule* nsContentUtils::DOMDumpLog() { return sDOMDumpLog; } | |||
| 7881 | ||||
| 7882 | bool nsContentUtils::GetNodeTextContent(const nsINode* aNode, bool aDeep, | |||
| 7883 | nsAString& aResult, | |||
| 7884 | const fallible_t& aFallible) { | |||
| 7885 | aResult.Truncate(); | |||
| 7886 | return AppendNodeTextContent(aNode, aDeep, aResult, aFallible); | |||
| 7887 | } | |||
| 7888 | ||||
| 7889 | void nsContentUtils::GetNodeTextContent(const nsINode* aNode, bool aDeep, | |||
| 7890 | nsAString& aResult) { | |||
| 7891 | if (!GetNodeTextContent(aNode, aDeep, aResult, fallible)) { | |||
| 7892 | NS_ABORT_OOM(0); // Unfortunately we don't know the allocation size | |||
| 7893 | } | |||
| 7894 | } | |||
| 7895 | ||||
| 7896 | void nsContentUtils::DestroyMatchString(void* aData) { | |||
| 7897 | if (aData) { | |||
| 7898 | nsString* matchString = static_cast<nsString*>(aData); | |||
| 7899 | delete matchString; | |||
| 7900 | } | |||
| 7901 | } | |||
| 7902 | ||||
| 7903 | // Table ordered from most to least likely JS MIME types. | |||
| 7904 | static constexpr std::string_view kJavascriptMIMETypes[] = { | |||
| 7905 | "text/javascript", | |||
| 7906 | "text/ecmascript", | |||
| 7907 | "application/javascript", | |||
| 7908 | "application/ecmascript", | |||
| 7909 | "application/x-javascript", | |||
| 7910 | "application/x-ecmascript", | |||
| 7911 | "text/javascript1.0", | |||
| 7912 | "text/javascript1.1", | |||
| 7913 | "text/javascript1.2", | |||
| 7914 | "text/javascript1.3", | |||
| 7915 | "text/javascript1.4", | |||
| 7916 | "text/javascript1.5", | |||
| 7917 | "text/jscript", | |||
| 7918 | "text/livescript", | |||
| 7919 | "text/x-ecmascript", | |||
| 7920 | "text/x-javascript"}; | |||
| 7921 | ||||
| 7922 | bool nsContentUtils::IsJavascriptMIMEType(const nsAString& aMIMEType) { | |||
| 7923 | for (std::string_view type : kJavascriptMIMETypes) { | |||
| 7924 | if (aMIMEType.LowerCaseEqualsASCII(type.data(), type.length())) { | |||
| 7925 | return true; | |||
| 7926 | } | |||
| 7927 | } | |||
| 7928 | return false; | |||
| 7929 | } | |||
| 7930 | ||||
| 7931 | bool nsContentUtils::IsJavascriptMIMEType(const nsACString& aMIMEType) { | |||
| 7932 | for (std::string_view type : kJavascriptMIMETypes) { | |||
| 7933 | if (aMIMEType.LowerCaseEqualsASCII(type.data(), type.length())) { | |||
| 7934 | return true; | |||
| 7935 | } | |||
| 7936 | } | |||
| 7937 | return false; | |||
| 7938 | } | |||
| 7939 | ||||
| 7940 | bool nsContentUtils::IsJsonMimeType(const nsAString& aMimeType) { | |||
| 7941 | // Table ordered from most to least likely JSON MIME types. | |||
| 7942 | static constexpr std::string_view jsonTypes[] = {"application/json", | |||
| 7943 | "text/json"}; | |||
| 7944 | ||||
| 7945 | for (std::string_view type : jsonTypes) { | |||
| 7946 | if (aMimeType.LowerCaseEqualsASCII(type.data(), type.length())) { | |||
| 7947 | return true; | |||
| 7948 | } | |||
| 7949 | } | |||
| 7950 | ||||
| 7951 | return StringEndsWith(aMimeType, u"+json"_ns); | |||
| 7952 | } | |||
| 7953 | ||||
| 7954 | bool nsContentUtils::PrefetchPreloadEnabled(nsIDocShell* aDocShell) { | |||
| 7955 | // | |||
| 7956 | // SECURITY CHECK: disable prefetching and preloading from mailnews! | |||
| 7957 | // | |||
| 7958 | // walk up the docshell tree to see if any containing | |||
| 7959 | // docshell are of type MAIL. | |||
| 7960 | // | |||
| 7961 | ||||
| 7962 | if (!aDocShell) { | |||
| 7963 | return false; | |||
| 7964 | } | |||
| 7965 | ||||
| 7966 | nsCOMPtr<nsIDocShell> docshell = aDocShell; | |||
| 7967 | nsCOMPtr<nsIDocShellTreeItem> parentItem; | |||
| 7968 | ||||
| 7969 | do { | |||
| 7970 | auto appType = docshell->GetAppType(); | |||
| 7971 | if (appType == nsIDocShell::APP_TYPE_MAIL) { | |||
| 7972 | return false; // do not prefetch, preload, preconnect from mailnews | |||
| 7973 | } | |||
| 7974 | ||||
| 7975 | docshell->GetInProcessParent(getter_AddRefs(parentItem)); | |||
| 7976 | if (parentItem) { | |||
| 7977 | docshell = do_QueryInterface(parentItem); | |||
| 7978 | if (!docshell) { | |||
| 7979 | 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" , 7979); MOZ_PretendNoReturn(); } while (0); | |||
| 7980 | return false; | |||
| 7981 | } | |||
| 7982 | } | |||
| 7983 | } while (parentItem); | |||
| 7984 | ||||
| 7985 | return true; | |||
| 7986 | } | |||
| 7987 | ||||
| 7988 | uint64_t nsContentUtils::GetInnerWindowID(nsIRequest* aRequest) { | |||
| 7989 | // can't do anything if there's no nsIRequest! | |||
| 7990 | if (!aRequest) { | |||
| 7991 | return 0; | |||
| 7992 | } | |||
| 7993 | ||||
| 7994 | nsCOMPtr<nsILoadGroup> loadGroup; | |||
| 7995 | nsresult rv = aRequest->GetLoadGroup(getter_AddRefs(loadGroup)); | |||
| 7996 | ||||
| 7997 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !loadGroup) { | |||
| 7998 | return 0; | |||
| 7999 | } | |||
| 8000 | ||||
| 8001 | return GetInnerWindowID(loadGroup); | |||
| 8002 | } | |||
| 8003 | ||||
| 8004 | uint64_t nsContentUtils::GetInnerWindowID(nsILoadGroup* aLoadGroup) { | |||
| 8005 | if (!aLoadGroup) { | |||
| 8006 | return 0; | |||
| 8007 | } | |||
| 8008 | ||||
| 8009 | nsCOMPtr<nsIInterfaceRequestor> callbacks; | |||
| 8010 | nsresult rv = aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks)); | |||
| 8011 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !callbacks) { | |||
| 8012 | return 0; | |||
| 8013 | } | |||
| 8014 | ||||
| 8015 | nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks); | |||
| 8016 | if (!loadContext) { | |||
| 8017 | return 0; | |||
| 8018 | } | |||
| 8019 | ||||
| 8020 | nsCOMPtr<mozIDOMWindowProxy> window; | |||
| 8021 | rv = loadContext->GetAssociatedWindow(getter_AddRefs(window)); | |||
| 8022 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !window) { | |||
| 8023 | return 0; | |||
| 8024 | } | |||
| 8025 | ||||
| 8026 | auto* pwindow = nsPIDOMWindowOuter::From(window); | |||
| 8027 | if (!pwindow) { | |||
| 8028 | return 0; | |||
| 8029 | } | |||
| 8030 | ||||
| 8031 | nsPIDOMWindowInner* inner = pwindow->GetCurrentInnerWindow(); | |||
| 8032 | return inner ? inner->WindowID() : 0; | |||
| 8033 | } | |||
| 8034 | ||||
| 8035 | // static | |||
| 8036 | void nsContentUtils::MaybeFixIPv6Host(nsACString& aHost) { | |||
| 8037 | if (aHost.FindChar(':') != -1) { // Escape IPv6 address | |||
| 8038 | MOZ_ASSERT(!aHost.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!aHost.IsEmpty())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!aHost.IsEmpty()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aHost.IsEmpty()" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp" , 8038); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aHost.IsEmpty()" ")"); do { *((volatile int*)__null) = 8038; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 8039 | if (aHost.Length() >= 2 && aHost[0] != '[' && | |||
| 8040 | aHost[aHost.Length() - 1] != ']') { | |||
| 8041 | aHost.Insert('[', 0); | |||
| 8042 | aHost.Append(']'); | |||
| 8043 | } | |||
| 8044 | } | |||
| 8045 | } | |||
| 8046 | ||||
| 8047 | nsresult nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, | |||
| 8048 | nsACString& aHost) { | |||
| 8049 | aHost.Truncate(); | |||
| 8050 | nsresult rv = aURI->GetHost(aHost); | |||
| 8051 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { // Some URIs do not have a host | |||
| 8052 | return rv; | |||
| 8053 | } | |||
| 8054 | ||||
| 8055 | MaybeFixIPv6Host(aHost); | |||
| 8056 | ||||
| 8057 | return NS_OK; | |||
| 8058 | } | |||
| 8059 | ||||
| 8060 | nsresult nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, | |||
| 8061 | nsAString& aHost) { | |||
| 8062 | nsAutoCString hostname; | |||
| 8063 | nsresult rv = GetHostOrIPv6WithBrackets(aURI, hostname); | |||
| 8064 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 8065 | return rv; | |||
| 8066 | } | |||
| 8067 | CopyUTF8toUTF16(hostname, aHost); | |||
| 8068 | return NS_OK; | |||
| 8069 | } | |||
| 8070 | ||||
| 8071 | nsresult nsContentUtils::GetHostOrIPv6WithBrackets(nsIPrincipal* aPrincipal, | |||
| 8072 | nsACString& aHost) { | |||
| 8073 | nsresult rv = aPrincipal->GetAsciiHost(aHost); | |||
| 8074 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { // Some URIs do not have a host | |||
| 8075 | return rv; | |||
| 8076 | } | |||
| 8077 | ||||
| 8078 | MaybeFixIPv6Host(aHost); | |||
| 8079 | return NS_OK; | |||
| 8080 | } | |||
| 8081 | ||||
| 8082 | CallState nsContentUtils::CallOnAllRemoteChildren( | |||
| 8083 | MessageBroadcaster* aManager, | |||
| 8084 | const std::function<CallState(BrowserParent*)>& aCallback) { | |||
| 8085 | uint32_t browserChildCount = aManager->ChildCount(); | |||
| 8086 | for (uint32_t j = 0; j < browserChildCount; ++j) { | |||
| 8087 | RefPtr<MessageListenerManager> childMM = aManager->GetChildAt(j); | |||
| 8088 | if (!childMM) { | |||
| 8089 | continue; | |||
| 8090 | } | |||
| 8091 | ||||
| 8092 | RefPtr<MessageBroadcaster> nonLeafMM = MessageBroadcaster::From(childMM); | |||
| 8093 | if (nonLeafMM) { | |||
| 8094 | if (CallOnAllRemoteChildren(nonLeafMM, aCallback) == CallState::Stop) { | |||
| 8095 | return CallState::Stop; | |||
| 8096 | } | |||
| 8097 | continue; | |||
| 8098 | } | |||
| 8099 | ||||
| 8100 | mozilla::dom::ipc::MessageManagerCallback* cb = childMM->GetCallback(); | |||
| 8101 | if (cb) { | |||
| 8102 | nsFrameLoader* fl = static_cast<nsFrameLoader*>(cb); | |||
| 8103 | BrowserParent* remote = BrowserParent::GetFrom(fl); | |||
| 8104 | if (remote && aCallback) { | |||
| 8105 | if (aCallback(remote) == CallState::Stop) { | |||
| 8106 | return CallState::Stop; | |||
| 8107 | } | |||
| 8108 | } | |||
| 8109 | } | |||
| 8110 | } | |||
| 8111 | ||||
| 8112 | return CallState::Continue; | |||
| 8113 | } | |||
| 8114 | ||||
| 8115 | void nsContentUtils::CallOnAllRemoteChildren( | |||
| 8116 | nsPIDOMWindowOuter* aWindow, | |||
| 8117 | const std::function<CallState(BrowserParent*)>& aCallback) { | |||
| 8118 | nsGlobalWindowOuter* window = nsGlobalWindowOuter::Cast(aWindow); | |||
| 8119 | if (window->IsChromeWindow()) { | |||
| 8120 | RefPtr<MessageBroadcaster> windowMM = window->GetMessageManager(); | |||
| 8121 | if (windowMM) { | |||
| 8122 | CallOnAllRemoteChildren(windowMM, aCallback); | |||
| 8123 | } | |||
| 8124 | } | |||
| 8125 | } | |||
| 8126 | ||||
| 8127 | bool nsContentUtils::IPCTransferableDataItemHasKnownFlavor( | |||
| 8128 | const IPCTransferableDataItem& aItem) { | |||
| 8129 | // Unknown types are converted to kCustomTypesMime. | |||
| 8130 | if (aItem.flavor().EqualsASCII(kCustomTypesMime"application/x-moz-custom-clipdata")) { | |||
| 8131 | return true; | |||
| 8132 | } | |||
| 8133 | ||||
| 8134 | for (const char* format : DataTransfer::kKnownFormats) { | |||
| 8135 | if (aItem.flavor().EqualsASCII(format)) { | |||
| 8136 | return true; | |||
| 8137 | } | |||
| 8138 | } | |||
| 8139 | ||||
| 8140 | return false; | |||
| 8141 | } | |||
| 8142 | ||||
| 8143 | nsresult nsContentUtils::IPCTransferableDataToTransferable( | |||
| 8144 | const IPCTransferableData& aTransferableData, bool aAddDataFlavor, | |||
| 8145 | nsITransferable* aTransferable, const bool aFilterUnknownFlavors) { | |||
| 8146 | nsresult rv; | |||
| 8147 | const nsTArray<IPCTransferableDataItem>& items = aTransferableData.items(); | |||
| 8148 | for (const auto& item : items) { | |||
| 8149 | if (aFilterUnknownFlavors && !IPCTransferableDataItemHasKnownFlavor(item)) { | |||
| 8150 | 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" , 8152) | |||
| 8151 | "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" , 8152) | |||
| 8152 | "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" , 8152); | |||
| 8153 | continue; | |||
| 8154 | } | |||
| 8155 | ||||
| 8156 | if (aAddDataFlavor) { | |||
| 8157 | aTransferable->AddDataFlavor(item.flavor().get()); | |||
| 8158 | } | |||
| 8159 | ||||
| 8160 | nsCOMPtr<nsISupports> transferData; | |||
| 8161 | switch (item.data().type()) { | |||
| 8162 | case IPCTransferableDataType::TIPCTransferableDataString: { | |||
| 8163 | const auto& data = item.data().get_IPCTransferableDataString(); | |||
| 8164 | nsCOMPtr<nsISupportsString> dataWrapper = | |||
| 8165 | do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID"@mozilla.org/supports-string;1", &rv); | |||
| 8166 | 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" , 8166); return rv; } } while (false); | |||
| 8167 | rv = dataWrapper->SetData(nsDependentSubstring( | |||
| 8168 | reinterpret_cast<const char16_t*>(data.data().Data()), | |||
| 8169 | data.data().Size() / sizeof(char16_t))); | |||
| 8170 | 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" , 8170); return rv; } } while (false); | |||
| 8171 | transferData = dataWrapper; | |||
| 8172 | break; | |||
| 8173 | } | |||
| 8174 | case IPCTransferableDataType::TIPCTransferableDataCString: { | |||
| 8175 | const auto& data = item.data().get_IPCTransferableDataCString(); | |||
| 8176 | nsCOMPtr<nsISupportsCString> dataWrapper = | |||
| 8177 | do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID"@mozilla.org/supports-cstring;1", &rv); | |||
| 8178 | 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" , 8178); return rv; } } while (false); | |||
| 8179 | rv = dataWrapper->SetData(nsDependentCSubstring( | |||
| 8180 | reinterpret_cast<const char*>(data.data().Data()), | |||
| 8181 | data.data().Size())); | |||
| 8182 | 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" , 8182); return rv; } } while (false); | |||
| 8183 | transferData = dataWrapper; | |||
| 8184 | break; | |||
| 8185 | } | |||
| 8186 | case IPCTransferableDataType::TIPCTransferableDataInputStream: { | |||
| 8187 | const auto& data = item.data().get_IPCTransferableDataInputStream(); | |||
| 8188 | nsCOMPtr<nsIInputStream> stream; | |||
| 8189 | rv = NS_NewByteInputStream(getter_AddRefs(stream), | |||
| 8190 | AsChars(data.data().AsSpan()), | |||
| 8191 | NS_ASSIGNMENT_COPY); | |||
| 8192 | 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" , 8192); return rv; } } while (false); | |||
| 8193 | transferData = stream.forget(); | |||
| 8194 | break; | |||
| 8195 | } | |||
| 8196 | case IPCTransferableDataType::TIPCTransferableDataImageContainer: { | |||
| 8197 | const auto& data = item.data().get_IPCTransferableDataImageContainer(); | |||
| 8198 | nsCOMPtr<imgIContainer> container; | |||
| 8199 | rv = DeserializeTransferableDataImageContainer( | |||
| 8200 | data, getter_AddRefs(container)); | |||
| 8201 | 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" , 8201); return rv; } } while (false); | |||
| 8202 | transferData = container; | |||
| 8203 | break; | |||
| 8204 | } | |||
| 8205 | case IPCTransferableDataType::TIPCTransferableDataBlob: { | |||
| 8206 | const auto& data = item.data().get_IPCTransferableDataBlob(); | |||
| 8207 | transferData = IPCBlobUtils::Deserialize(data.blob()); | |||
| 8208 | break; | |||
| 8209 | } | |||
| 8210 | case IPCTransferableDataType::T__None: | |||
| 8211 | 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" , 8211); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " ")"); do { *((volatile int*)__null ) = 8211; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); | |||
| 8212 | return NS_ERROR_FAILURE; | |||
| 8213 | } | |||
| 8214 | ||||
| 8215 | rv = aTransferable->SetTransferData(item.flavor().get(), transferData); | |||
| 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 | } | |||
| 8218 | return NS_OK; | |||
| 8219 | } | |||
| 8220 | ||||
| 8221 | nsresult nsContentUtils::IPCTransferableToTransferable( | |||
| 8222 | const IPCTransferable& aIPCTransferable, bool aAddDataFlavor, | |||
| 8223 | nsITransferable* aTransferable, const bool aFilterUnknownFlavors) { | |||
| 8224 | // Note that we need to set privacy status of transferable before adding any | |||
| 8225 | // data into it. | |||
| 8226 | aTransferable->SetIsPrivateData(aIPCTransferable.isPrivateData()); | |||
| 8227 | ||||
| 8228 | nsresult rv = | |||
| 8229 | IPCTransferableDataToTransferable(aIPCTransferable.data(), aAddDataFlavor, | |||
| 8230 | aTransferable, aFilterUnknownFlavors); | |||
| 8231 | 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" , 8231); return rv; } } while (false); | |||
| 8232 | ||||
| 8233 | if (aIPCTransferable.cookieJarSettings().isSome()) { | |||
| 8234 | nsCOMPtr<nsICookieJarSettings> cookieJarSettings; | |||
| 8235 | net::CookieJarSettings::Deserialize( | |||
| 8236 | aIPCTransferable.cookieJarSettings().ref(), | |||
| 8237 | getter_AddRefs(cookieJarSettings)); | |||
| 8238 | aTransferable->SetCookieJarSettings(cookieJarSettings); | |||
| 8239 | } | |||
| 8240 | aTransferable->SetReferrerInfo(aIPCTransferable.referrerInfo()); | |||
| 8241 | aTransferable->SetDataPrincipal(aIPCTransferable.dataPrincipal()); | |||
| 8242 | aTransferable->SetContentPolicyType(aIPCTransferable.contentPolicyType()); | |||
| 8243 | ||||
| 8244 | return NS_OK; | |||
| 8245 | } | |||
| 8246 | ||||
| 8247 | nsresult nsContentUtils::IPCTransferableDataItemToVariant( | |||
| 8248 | const IPCTransferableDataItem& aItem, nsIWritableVariant* aVariant) { | |||
| 8249 | 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" , 8249); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aVariant" ")" ); do { *((volatile int*)__null) = 8249; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 8250 | ||||
| 8251 | switch (aItem.data().type()) { | |||
| 8252 | case IPCTransferableDataType::TIPCTransferableDataString: { | |||
| 8253 | const auto& data = aItem.data().get_IPCTransferableDataString(); | |||
| 8254 | return aVariant->SetAsAString(nsDependentSubstring( | |||
| 8255 | reinterpret_cast<const char16_t*>(data.data().Data()), | |||
| 8256 | data.data().Size() / sizeof(char16_t))); | |||
| 8257 | } | |||
| 8258 | case IPCTransferableDataType::TIPCTransferableDataCString: { | |||
| 8259 | const auto& data = aItem.data().get_IPCTransferableDataCString(); | |||
| 8260 | return aVariant->SetAsACString(nsDependentCSubstring( | |||
| 8261 | reinterpret_cast<const char*>(data.data().Data()), | |||
| 8262 | data.data().Size())); | |||
| 8263 | } | |||
| 8264 | case IPCTransferableDataType::TIPCTransferableDataInputStream: { | |||
| 8265 | const auto& data = aItem.data().get_IPCTransferableDataInputStream(); | |||
| 8266 | nsCOMPtr<nsIInputStream> stream; | |||
| 8267 | nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream), | |||
| 8268 | AsChars(data.data().AsSpan()), | |||
| 8269 | NS_ASSIGNMENT_COPY); | |||
| 8270 | 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" , 8270); return rv; } } while (false); | |||
| 8271 | return aVariant->SetAsISupports(stream); | |||
| 8272 | } | |||
| 8273 | case IPCTransferableDataType::TIPCTransferableDataImageContainer: { | |||
| 8274 | const auto& data = aItem.data().get_IPCTransferableDataImageContainer(); | |||
| 8275 | nsCOMPtr<imgIContainer> container; | |||
| 8276 | nsresult rv = DeserializeTransferableDataImageContainer( | |||
| 8277 | data, getter_AddRefs(container)); | |||
| 8278 | 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" , 8278); return rv; } } while (false); | |||
| 8279 | return aVariant->SetAsISupports(container); | |||
| 8280 | } | |||
| 8281 | case IPCTransferableDataType::TIPCTransferableDataBlob: { | |||
| 8282 | const auto& data = aItem.data().get_IPCTransferableDataBlob(); | |||
| 8283 | RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(data.blob()); | |||
| 8284 | return aVariant->SetAsISupports(blobImpl); | |||
| 8285 | } | |||
| 8286 | case IPCTransferableDataType::T__None: | |||
| 8287 | break; | |||
| 8288 | } | |||
| 8289 | ||||
| 8290 | 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" , 8290); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " ")"); do { *((volatile int*)__null ) = 8290; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); | |||
| 8291 | return NS_ERROR_UNEXPECTED; | |||
| 8292 | } | |||
| 8293 | ||||
| 8294 | void nsContentUtils::TransferablesToIPCTransferableDatas( | |||
| 8295 | nsIArray* aTransferables, nsTArray<IPCTransferableData>& aIPC, | |||
| 8296 | bool aInSyncMessage, mozilla::dom::ContentParent* aParent) { | |||
| 8297 | aIPC.Clear(); | |||
| 8298 | if (aTransferables) { | |||
| 8299 | uint32_t transferableCount = 0; | |||
| 8300 | aTransferables->GetLength(&transferableCount); | |||
| 8301 | for (uint32_t i = 0; i < transferableCount; ++i) { | |||
| 8302 | IPCTransferableData* dt = aIPC.AppendElement(); | |||
| 8303 | nsCOMPtr<nsITransferable> transferable = | |||
| 8304 | do_QueryElementAt(aTransferables, i); | |||
| 8305 | TransferableToIPCTransferableData(transferable, dt, aInSyncMessage, | |||
| 8306 | aParent); | |||
| 8307 | } | |||
| 8308 | } | |||
| 8309 | } | |||
| 8310 | ||||
| 8311 | nsresult nsContentUtils::CalculateBufferSizeForImage( | |||
| 8312 | const uint32_t& aStride, const IntSize& aImageSize, | |||
| 8313 | const SurfaceFormat& aFormat, size_t* aMaxBufferSize, | |||
| 8314 | size_t* aUsedBufferSize) { | |||
| 8315 | CheckedInt32 requiredBytes = | |||
| 8316 | CheckedInt32(aStride) * CheckedInt32(aImageSize.height); | |||
| 8317 | ||||
| 8318 | CheckedInt32 usedBytes = | |||
| 8319 | requiredBytes - aStride + | |||
| 8320 | (CheckedInt32(aImageSize.width) * BytesPerPixel(aFormat)); | |||
| 8321 | if (!usedBytes.isValid()) { | |||
| 8322 | return NS_ERROR_FAILURE; | |||
| 8323 | } | |||
| 8324 | ||||
| 8325 | 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" , 8325); AnnotateMozCrashReason("MOZ_ASSERT" "(" "requiredBytes.isValid()" ") (" "usedBytes valid but not required?" ")"); do { *((volatile int*)__null) = 8325; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 8326 | *aMaxBufferSize = requiredBytes.value(); | |||
| 8327 | *aUsedBufferSize = usedBytes.value(); | |||
| 8328 | return NS_OK; | |||
| 8329 | } | |||
| 8330 | ||||
| 8331 | static already_AddRefed<DataSourceSurface> BigBufferToDataSurface( | |||
| 8332 | const BigBuffer& aData, uint32_t aStride, const IntSize& aImageSize, | |||
| 8333 | SurfaceFormat aFormat) { | |||
| 8334 | if (!aData.Size() || !aImageSize.width || !aImageSize.height) { | |||
| 8335 | return nullptr; | |||
| 8336 | } | |||
| 8337 | ||||
| 8338 | // Validate shared memory buffer size | |||
| 8339 | size_t imageBufLen = 0; | |||
| 8340 | size_t maxBufLen = 0; | |||
| 8341 | if (NS_FAILED(nsContentUtils::CalculateBufferSizeForImage(((bool)(__builtin_expect(!!(NS_FAILED_impl(nsContentUtils::CalculateBufferSizeForImage ( aStride, aImageSize, aFormat, &maxBufLen, &imageBufLen ))), 0))) | |||
| 8342 | aStride, aImageSize, aFormat, &maxBufLen, &imageBufLen))((bool)(__builtin_expect(!!(NS_FAILED_impl(nsContentUtils::CalculateBufferSizeForImage ( aStride, aImageSize, aFormat, &maxBufLen, &imageBufLen ))), 0)))) { | |||
| 8343 | return nullptr; | |||
| 8344 | } | |||
| 8345 | if (imageBufLen > aData.Size()) { | |||
| 8346 | return nullptr; | |||
| 8347 | } | |||
| 8348 | return CreateDataSourceSurfaceFromData(aImageSize, aFormat, aData.Data(), | |||
| 8349 | aStride); | |||
| 8350 | } | |||
| 8351 | ||||
| 8352 | nsresult nsContentUtils::DeserializeTransferableDataImageContainer( | |||
| 8353 | const IPCTransferableDataImageContainer& aData, | |||
| 8354 | imgIContainer** aContainer) { | |||
| 8355 | RefPtr<DataSourceSurface> surface = IPCImageToSurface(aData.image()); | |||
| 8356 | if (!surface) { | |||
| 8357 | return NS_ERROR_FAILURE; | |||
| 8358 | } | |||
| 8359 | ||||
| 8360 | RefPtr<gfxDrawable> drawable = | |||
| 8361 | new gfxSurfaceDrawable(surface, surface->GetSize()); | |||
| 8362 | nsCOMPtr<imgIContainer> imageContainer = | |||
| 8363 | image::ImageOps::CreateFromDrawable(drawable); | |||
| 8364 | imageContainer.forget(aContainer); | |||
| 8365 | ||||
| 8366 | return NS_OK; | |||
| 8367 | } | |||
| 8368 | ||||
| 8369 | bool nsContentUtils::IsFlavorImage(const nsACString& aFlavor) { | |||
| 8370 | return aFlavor.EqualsLiteral(kNativeImageMime"application/x-moz-nativeimage") || | |||
| 8371 | aFlavor.EqualsLiteral(kJPEGImageMime"image/jpeg") || | |||
| 8372 | aFlavor.EqualsLiteral(kJPGImageMime"image/jpg") || | |||
| 8373 | aFlavor.EqualsLiteral(kPNGImageMime"image/png") || | |||
| 8374 | aFlavor.EqualsLiteral(kGIFImageMime"image/gif"); | |||
| 8375 | } | |||
| 8376 | ||||
| 8377 | // FIXME: This can probably be removed once bug 1783240 lands, as `nsString` | |||
| 8378 | // will be implicitly serialized in shmem when sent over IPDL directly. | |||
| 8379 | static IPCTransferableDataString AsIPCTransferableDataString( | |||
| 8380 | Span<const char16_t> aInput) { | |||
| 8381 | return IPCTransferableDataString{BigBuffer(AsBytes(aInput))}; | |||
| 8382 | } | |||
| 8383 | ||||
| 8384 | // FIXME: This can probably be removed once bug 1783240 lands, as `nsCString` | |||
| 8385 | // will be implicitly serialized in shmem when sent over IPDL directly. | |||
| 8386 | static IPCTransferableDataCString AsIPCTransferableDataCString( | |||
| 8387 | Span<const char> aInput) { | |||
| 8388 | return IPCTransferableDataCString{BigBuffer(AsBytes(aInput))}; | |||
| 8389 | } | |||
| 8390 | ||||
| 8391 | void nsContentUtils::TransferableToIPCTransferableData( | |||
| 8392 | nsITransferable* aTransferable, IPCTransferableData* aTransferableData, | |||
| 8393 | bool aInSyncMessage, mozilla::dom::ContentParent* aParent) { | |||
| 8394 | 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" , 8394); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent" ")" ); do { *((volatile int*)__null) = 8394; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); | |||
| 8395 | ||||
| 8396 | if (aTransferable) { | |||
| 8397 | nsTArray<nsCString> flavorList; | |||
| 8398 | aTransferable->FlavorsTransferableCanExport(flavorList); | |||
| 8399 | ||||
| 8400 | for (uint32_t j = 0; j < flavorList.Length(); ++j) { | |||
| 8401 | nsCString& flavorStr = flavorList[j]; | |||
| 8402 | if (!flavorStr.Length()) { | |||
| 8403 | continue; | |||
| 8404 | } | |||
| 8405 | ||||
| 8406 | nsCOMPtr<nsISupports> data; | |||
| 8407 | nsresult rv = | |||
| 8408 | aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(data)); | |||
| 8409 | ||||
| 8410 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !data) { | |||
| 8411 | if (aInSyncMessage) { | |||
| 8412 | // Can't do anything. | |||
| 8413 | // FIXME: This shouldn't be the case anymore! | |||
| 8414 | continue; | |||
| 8415 | } | |||
| 8416 | ||||
| 8417 | // This is a hack to support kFilePromiseMime. | |||
| 8418 | // On Windows there just needs to be an entry for it, | |||
| 8419 | // and for OSX we need to create | |||
| 8420 | // nsContentAreaDragDropDataProvider as nsIFlavorDataProvider. | |||
| 8421 | if (flavorStr.EqualsLiteral(kFilePromiseMime"application/x-moz-file-promise")) { | |||
| 8422 | IPCTransferableDataItem* item = | |||
| 8423 | aTransferableData->items().AppendElement(); | |||
| 8424 | item->flavor() = flavorStr; | |||
| 8425 | item->data() = | |||
| 8426 | AsIPCTransferableDataString(NS_ConvertUTF8toUTF16(flavorStr)); | |||
| 8427 | continue; | |||
| 8428 | } | |||
| 8429 | ||||
| 8430 | // Empty element, transfer only the flavor | |||
| 8431 | IPCTransferableDataItem* item = | |||
| 8432 | aTransferableData->items().AppendElement(); | |||
| 8433 | item->flavor() = flavorStr; | |||
| 8434 | item->data() = AsIPCTransferableDataString(EmptyString()); | |||
| 8435 | continue; | |||
| 8436 | } | |||
| 8437 | ||||
| 8438 | // We need to handle nsIInputStream before nsISupportsCString, otherwise | |||
| 8439 | // nsStringInputStream would be converted into a wrong type. | |||
| 8440 | if (nsCOMPtr<nsIInputStream> stream = do_QueryInterface(data)) { | |||
| 8441 | IPCTransferableDataItem* item = | |||
| 8442 | aTransferableData->items().AppendElement(); | |||
| 8443 | item->flavor() = flavorStr; | |||
| 8444 | nsCString imageData; | |||
| 8445 | DebugOnly<nsresult> rv = | |||
| 8446 | NS_ConsumeStream(stream, UINT32_MAX(4294967295U), imageData); | |||
| 8447 | 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" , 8449); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rv != NS_BASE_STREAM_WOULD_BLOCK" ") (" "cannot use async input streams in nsITransferable right now" ")"); do { *((volatile int*)__null) = 8449; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) | |||
| 8448 | 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" , 8449); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rv != NS_BASE_STREAM_WOULD_BLOCK" ") (" "cannot use async input streams in nsITransferable right now" ")"); do { *((volatile int*)__null) = 8449; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) | |||
| 8449 | "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" , 8449); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rv != NS_BASE_STREAM_WOULD_BLOCK" ") (" "cannot use async input streams in nsITransferable right now" ")"); do { *((volatile int*)__null) = 8449; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 8450 | // FIXME: This can probably be simplified once bug 1783240 lands, as | |||
| 8451 | // `nsCString` will be implicitly serialized in shmem when sent over | |||
| 8452 | // IPDL directly. | |||
| 8453 | item->data() = | |||
| 8454 | IPCTransferableDataInputStream(BigBuffer(AsBytes(Span(imageData)))); | |||
| 8455 | continue; | |||
| 8456 | } | |||
| 8457 | ||||
| 8458 | if (nsCOMPtr<nsISupportsString> text = do_QueryInterface(data)) { | |||
| 8459 | nsAutoString dataAsString; | |||
| 8460 | MOZ_ALWAYS_SUCCEEDS(text->GetData(dataAsString))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (text->GetData(dataAsString))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(text->GetData(dataAsString))" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp" , 8460); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(text->GetData(dataAsString))" ")"); do { *((volatile int*)__null) = 8460; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ); | |||
| 8461 | ||||
| 8462 | IPCTransferableDataItem* item = | |||
| 8463 | aTransferableData->items().AppendElement(); | |||
| 8464 | item->flavor() = flavorStr; | |||
| 8465 | item->data() = AsIPCTransferableDataString(dataAsString); | |||
| 8466 | continue; | |||
| 8467 | } | |||
| 8468 | ||||
| 8469 | if (nsCOMPtr<nsISupportsCString> ctext = do_QueryInterface(data)) { | |||
| 8470 | nsAutoCString dataAsString; | |||
| 8471 | MOZ_ALWAYS_SUCCEEDS(ctext->GetData(dataAsString))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (ctext->GetData(dataAsString))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(ctext->GetData(dataAsString))" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp" , 8471); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(ctext->GetData(dataAsString))" ")"); do { *((volatile int*)__null) = 8471; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ); | |||
| 8472 | ||||
| 8473 | IPCTransferableDataItem* item = | |||
| 8474 | aTransferableData->items().AppendElement(); | |||
| 8475 | item->flavor() = flavorStr; | |||
| 8476 | item->data() = AsIPCTransferableDataCString(dataAsString); | |||
| 8477 | continue; | |||
| 8478 | } | |||
| 8479 | ||||
| 8480 | if (nsCOMPtr<imgIContainer> image = do_QueryInterface(data)) { | |||
| 8481 | // Images to be placed on the clipboard are imgIContainers. | |||
| 8482 | RefPtr<mozilla::gfx::SourceSurface> surface = image->GetFrame( | |||
| 8483 | imgIContainer::FRAME_CURRENT, | |||
| 8484 | imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY); | |||
| 8485 | if (!surface) { | |||
| 8486 | continue; | |||
| 8487 | } | |||
| 8488 | RefPtr<mozilla::gfx::DataSourceSurface> dataSurface = | |||
| 8489 | surface->GetDataSurface(); | |||
| 8490 | if (!dataSurface) { | |||
| 8491 | continue; | |||
| 8492 | } | |||
| 8493 | ||||
| 8494 | auto imageData = nsContentUtils::SurfaceToIPCImage(*dataSurface); | |||
| 8495 | if (!imageData) { | |||
| 8496 | continue; | |||
| 8497 | } | |||
| 8498 | ||||
| 8499 | IPCTransferableDataItem* item = | |||
| 8500 | aTransferableData->items().AppendElement(); | |||
| 8501 | item->flavor() = flavorStr; | |||
| 8502 | item->data() = IPCTransferableDataImageContainer(std::move(*imageData)); | |||
| 8503 | continue; | |||
| 8504 | } | |||
| 8505 | ||||
| 8506 | // Otherwise, handle this as a file. | |||
| 8507 | nsCOMPtr<BlobImpl> blobImpl; | |||
| 8508 | if (nsCOMPtr<nsIFile> file = do_QueryInterface(data)) { | |||
| 8509 | if (aParent) { | |||
| 8510 | bool isDir = false; | |||
| 8511 | if (NS_SUCCEEDED(file->IsDirectory(&isDir))((bool)(__builtin_expect(!!(!NS_FAILED_impl(file->IsDirectory (&isDir))), 1))) && isDir) { | |||
| 8512 | nsAutoString path; | |||
| 8513 | 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" , 8513)) { | |||
| 8514 | continue; | |||
| 8515 | } | |||
| 8516 | ||||
| 8517 | RefPtr<FileSystemSecurity> fss = FileSystemSecurity::GetOrCreate(); | |||
| 8518 | fss->GrantAccessToContentProcess(aParent->ChildID(), path); | |||
| 8519 | } | |||
| 8520 | } | |||
| 8521 | ||||
| 8522 | blobImpl = new FileBlobImpl(file); | |||
| 8523 | ||||
| 8524 | IgnoredErrorResult rv; | |||
| 8525 | ||||
| 8526 | // Ensure that file data is cached no that the content process | |||
| 8527 | // has this data available to it when passed over: | |||
| 8528 | blobImpl->GetSize(rv); | |||
| 8529 | 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" , 8529)) { | |||
| 8530 | continue; | |||
| 8531 | } | |||
| 8532 | ||||
| 8533 | blobImpl->GetLastModified(rv); | |||
| 8534 | 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" , 8534)) { | |||
| 8535 | continue; | |||
| 8536 | } | |||
| 8537 | } else { | |||
| 8538 | if (aInSyncMessage) { | |||
| 8539 | // Can't do anything. | |||
| 8540 | // FIXME: This shouldn't be the case anymore! | |||
| 8541 | continue; | |||
| 8542 | } | |||
| 8543 | ||||
| 8544 | blobImpl = do_QueryInterface(data); | |||
| 8545 | } | |||
| 8546 | ||||
| 8547 | if (blobImpl) { | |||
| 8548 | // If we failed to create the blob actor, then this blob probably | |||
| 8549 | // can't get the file size for the underlying file, ignore it for | |||
| 8550 | // now. TODO pass this through anyway. | |||
| 8551 | IPCBlob ipcBlob; | |||
| 8552 | nsresult rv = IPCBlobUtils::Serialize(blobImpl, ipcBlob); | |||
| 8553 | 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" , 8553)) { | |||
| 8554 | continue; | |||
| 8555 | } | |||
| 8556 | ||||
| 8557 | IPCTransferableDataItem* item = | |||
| 8558 | aTransferableData->items().AppendElement(); | |||
| 8559 | item->flavor() = flavorStr; | |||
| 8560 | item->data() = IPCTransferableDataBlob(ipcBlob); | |||
| 8561 | } | |||
| 8562 | } | |||
| 8563 | } | |||
| 8564 | } | |||
| 8565 | ||||
| 8566 | void nsContentUtils::TransferableToIPCTransferable( | |||
| 8567 | nsITransferable* aTransferable, IPCTransferable* aIPCTransferable, | |||
| 8568 | bool aInSyncMessage, mozilla::dom::ContentParent* aParent) { | |||
| 8569 | IPCTransferableData ipcTransferableData; | |||
| 8570 | TransferableToIPCTransferableData(aTransferable, &ipcTransferableData, | |||
| 8571 | aInSyncMessage, aParent); | |||
| 8572 | ||||
| 8573 | Maybe<net::CookieJarSettingsArgs> cookieJarSettingsArgs; | |||
| 8574 | if (nsCOMPtr<nsICookieJarSettings> cookieJarSettings = | |||
| 8575 | aTransferable->GetCookieJarSettings()) { | |||
| 8576 | net::CookieJarSettingsArgs args; | |||
| 8577 | net::CookieJarSettings::Cast(cookieJarSettings)->Serialize(args); | |||
| 8578 | cookieJarSettingsArgs = Some(std::move(args)); | |||
| 8579 | } | |||
| 8580 | ||||
| 8581 | aIPCTransferable->data() = std::move(ipcTransferableData); | |||
| 8582 | aIPCTransferable->isPrivateData() = aTransferable->GetIsPrivateData(); | |||
| 8583 | aIPCTransferable->dataPrincipal() = aTransferable->GetDataPrincipal(); | |||
| 8584 | aIPCTransferable->cookieJarSettings() = std::move(cookieJarSettingsArgs); | |||
| 8585 | aIPCTransferable->contentPolicyType() = aTransferable->GetContentPolicyType(); | |||
| 8586 | aIPCTransferable->referrerInfo() = aTransferable->GetReferrerInfo(); | |||
| 8587 | } | |||
| 8588 | ||||
| 8589 | Maybe<BigBuffer> nsContentUtils::GetSurfaceData(DataSourceSurface& aSurface, | |||
| 8590 | size_t* aLength, | |||
| 8591 | int32_t* aStride) { | |||
| 8592 | mozilla::gfx::DataSourceSurface::MappedSurface map; | |||
| 8593 | if (!aSurface.Map(mozilla::gfx::DataSourceSurface::MapType::READ, &map)) { | |||
| 8594 | return Nothing(); | |||
| 8595 | } | |||
| 8596 | ||||
| 8597 | size_t bufLen = 0; | |||
| 8598 | size_t maxBufLen = 0; | |||
| 8599 | nsresult rv = nsContentUtils::CalculateBufferSizeForImage( | |||
| 8600 | map.mStride, aSurface.GetSize(), aSurface.GetFormat(), &maxBufLen, | |||
| 8601 | &bufLen); | |||
| 8602 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 8603 | aSurface.Unmap(); | |||
| 8604 | return Nothing(); | |||
| 8605 | } | |||
| 8606 | ||||
| 8607 | BigBuffer surfaceData(maxBufLen); | |||
| 8608 | memcpy(surfaceData.Data(), map.mData, bufLen); | |||
| 8609 | memset(surfaceData.Data() + bufLen, 0, maxBufLen - bufLen); | |||
| 8610 | ||||
| 8611 | *aLength = maxBufLen; | |||
| 8612 | *aStride = map.mStride; | |||
| 8613 | ||||
| 8614 | aSurface.Unmap(); | |||
| 8615 | return Some(std::move(surfaceData)); | |||
| 8616 | } | |||
| 8617 | ||||
| 8618 | Maybe<IPCImage> nsContentUtils::SurfaceToIPCImage(DataSourceSurface& aSurface) { | |||
| 8619 | size_t len = 0; | |||
| 8620 | int32_t stride = 0; | |||
| 8621 | auto mem = GetSurfaceData(aSurface, &len, &stride); | |||
| 8622 | if (!mem) { | |||
| 8623 | return Nothing(); | |||
| 8624 | } | |||
| 8625 | return Some(IPCImage{std::move(*mem), uint32_t(stride), aSurface.GetFormat(), | |||
| 8626 | ImageIntSize::FromUnknownSize(aSurface.GetSize())}); | |||
| 8627 | } | |||
| 8628 | ||||
| 8629 | already_AddRefed<DataSourceSurface> nsContentUtils::IPCImageToSurface( | |||
| 8630 | const IPCImage& aImage) { | |||
| 8631 | return BigBufferToDataSurface(aImage.data(), aImage.stride(), | |||
| 8632 | aImage.size().ToUnknownSize(), aImage.format()); | |||
| 8633 | } | |||
| 8634 | ||||
| 8635 | Modifiers nsContentUtils::GetWidgetModifiers(int32_t aModifiers) { | |||
| 8636 | Modifiers result = 0; | |||
| 8637 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_SHIFT) { | |||
| 8638 | result |= mozilla::MODIFIER_SHIFT; | |||
| 8639 | } | |||
| 8640 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_CONTROL) { | |||
| 8641 | result |= mozilla::MODIFIER_CONTROL; | |||
| 8642 | } | |||
| 8643 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_ALT) { | |||
| 8644 | result |= mozilla::MODIFIER_ALT; | |||
| 8645 | } | |||
| 8646 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_META) { | |||
| 8647 | result |= mozilla::MODIFIER_META; | |||
| 8648 | } | |||
| 8649 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_ALTGRAPH) { | |||
| 8650 | result |= mozilla::MODIFIER_ALTGRAPH; | |||
| 8651 | } | |||
| 8652 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_CAPSLOCK) { | |||
| 8653 | result |= mozilla::MODIFIER_CAPSLOCK; | |||
| 8654 | } | |||
| 8655 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_FN) { | |||
| 8656 | result |= mozilla::MODIFIER_FN; | |||
| 8657 | } | |||
| 8658 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_FNLOCK) { | |||
| 8659 | result |= mozilla::MODIFIER_FNLOCK; | |||
| 8660 | } | |||
| 8661 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_NUMLOCK) { | |||
| 8662 | result |= mozilla::MODIFIER_NUMLOCK; | |||
| 8663 | } | |||
| 8664 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_SCROLLLOCK) { | |||
| 8665 | result |= mozilla::MODIFIER_SCROLLLOCK; | |||
| 8666 | } | |||
| 8667 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_SYMBOL) { | |||
| 8668 | result |= mozilla::MODIFIER_SYMBOL; | |||
| 8669 | } | |||
| 8670 | if (aModifiers & nsIDOMWindowUtils::MODIFIER_SYMBOLLOCK) { | |||
| 8671 | result |= mozilla::MODIFIER_SYMBOLLOCK; | |||
| 8672 | } | |||
| 8673 | return result; | |||
| 8674 | } | |||
| 8675 | ||||
| 8676 | nsIWidget* nsContentUtils::GetWidget(PresShell* aPresShell, nsPoint* aOffset) { | |||
| 8677 | if (!aPresShell) { | |||
| 8678 | return nullptr; | |||
| 8679 | } | |||
| 8680 | nsIFrame* frame = aPresShell->GetRootFrame(); | |||
| 8681 | if (!frame) { | |||
| 8682 | return nullptr; | |||
| 8683 | } | |||
| 8684 | return frame->GetView()->GetNearestWidget(aOffset); | |||
| 8685 | } | |||
| 8686 | ||||
| 8687 | int16_t nsContentUtils::GetButtonsFlagForButton(int32_t aButton) { | |||
| 8688 | switch (aButton) { | |||
| 8689 | case -1: | |||
| 8690 | return MouseButtonsFlag::eNoButtons; | |||
| 8691 | case MouseButton::ePrimary: | |||
| 8692 | return MouseButtonsFlag::ePrimaryFlag; | |||
| 8693 | case MouseButton::eMiddle: | |||
| 8694 | return MouseButtonsFlag::eMiddleFlag; | |||
| 8695 | case MouseButton::eSecondary: | |||
| 8696 | return MouseButtonsFlag::eSecondaryFlag; | |||
| 8697 | case 3: | |||
| 8698 | return MouseButtonsFlag::e4thFlag; | |||
| 8699 | case 4: | |||
| 8700 | return MouseButtonsFlag::e5thFlag; | |||
| 8701 | case MouseButton::eEraser: | |||
| 8702 | return MouseButtonsFlag::eEraserFlag; | |||
| 8703 | default: | |||
| 8704 | 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" , 8704); MOZ_PretendNoReturn(); } while (0); | |||
| 8705 | return 0; | |||
| 8706 | } | |||
| 8707 | } | |||
| 8708 | ||||
| 8709 | LayoutDeviceIntPoint nsContentUtils::ToWidgetPoint( | |||
| 8710 | const CSSPoint& aPoint, const nsPoint& aOffset, | |||
| 8711 | nsPresContext* aPresContext) { | |||
| 8712 | nsPoint layoutRelative = CSSPoint::ToAppUnits(aPoint) + aOffset; | |||
| 8713 | nsPoint visualRelative = | |||
| 8714 | ViewportUtils::LayoutToVisual(layoutRelative, aPresContext->PresShell()); | |||
| 8715 | return LayoutDeviceIntPoint::FromAppUnitsRounded( | |||
| 8716 | visualRelative, aPresContext->AppUnitsPerDevPixel()); | |||
| 8717 | } | |||
| 8718 | ||||
| 8719 | nsView* nsContentUtils::GetViewToDispatchEvent(nsPresContext* aPresContext, | |||
| 8720 | PresShell** aPresShell) { | |||
| 8721 | if (!aPresContext || !aPresShell) { | |||
| 8722 | return nullptr; | |||
| 8723 | } | |||
| 8724 | RefPtr<PresShell> presShell = aPresContext->PresShell(); | |||
| 8725 | if (NS_WARN_IF(!presShell)NS_warn_if_impl(!presShell, "!presShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp" , 8725)) { | |||
| 8726 | *aPresShell = nullptr; | |||
| 8727 | return nullptr; | |||
| 8728 | } | |||
| 8729 | nsViewManager* viewManager = presShell->GetViewManager(); | |||
| 8730 | if (!viewManager) { | |||
| 8731 | presShell.forget(aPresShell); // XXX Is this intentional? | |||
| 8732 | return nullptr; | |||
| 8733 | } | |||
| 8734 | presShell.forget(aPresShell); | |||
| 8735 | return viewManager->GetRootView(); | |||
| 8736 | } | |||
| 8737 | ||||
| 8738 | nsresult nsContentUtils::SendMouseEvent( | |||
| 8739 | mozilla::PresShell* aPresShell, const nsAString& aType, float aX, float aY, | |||
| 8740 | int32_t aButton, int32_t aButtons, int32_t aClickCount, int32_t aModifiers, | |||
| 8741 | bool aIgnoreRootScrollFrame, float aPressure, | |||
| 8742 | unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, | |||
| 8743 | bool* aPreventDefault, bool aIsDOMEventSynthesized, | |||
| 8744 | bool aIsWidgetEventSynthesized) { | |||
| 8745 | nsPoint offset; | |||
| 8746 | nsCOMPtr<nsIWidget> widget = GetWidget(aPresShell, &offset); | |||
| 8747 | if (!widget) return NS_ERROR_FAILURE; | |||
| 8748 | ||||
| 8749 | EventMessage msg; | |||
| 8750 | Maybe<WidgetMouseEvent::ExitFrom> exitFrom; | |||
| 8751 | bool contextMenuKey = false; | |||
| 8752 | if (aType.EqualsLiteral("mousedown")) { | |||
| 8753 | msg = eMouseDown; | |||
| 8754 | } else if (aType.EqualsLiteral("mouseup")) { | |||
| 8755 | msg = eMouseUp; | |||
| 8756 | } else if (aType.EqualsLiteral("mousemove")) { | |||
| 8757 | msg = eMouseMove; | |||
| 8758 | } else if (aType.EqualsLiteral("mouseover")) { | |||
| 8759 | msg = eMouseEnterIntoWidget; | |||
| 8760 | } else if (aType.EqualsLiteral("mouseout")) { | |||
| 8761 | msg = eMouseExitFromWidget; | |||
| 8762 | exitFrom = Some(WidgetMouseEvent::ePlatformChild); | |||
| 8763 | } else if (aType.EqualsLiteral("mousecancel")) { | |||
| 8764 | msg = eMouseExitFromWidget; | |||
| 8765 | exitFrom = Some(XRE_IsParentProcess() ? WidgetMouseEvent::ePlatformTopLevel | |||
| 8766 | : WidgetMouseEvent::ePuppet); | |||
| 8767 | } else if (aType.EqualsLiteral("mouselongtap")) { | |||
| 8768 | msg = eMouseLongTap; | |||
| 8769 | } else if (aType.EqualsLiteral("contextmenu")) { | |||
| 8770 | msg = eContextMenu; | |||
| 8771 | contextMenuKey = !aButton && aInputSourceArg != | |||
| 8772 | dom::MouseEvent_Binding::MOZ_SOURCE_TOUCH; | |||
| 8773 | } else if (aType.EqualsLiteral("MozMouseHittest")) { | |||
| 8774 | msg = eMouseHitTest; | |||
| 8775 | } else if (aType.EqualsLiteral("MozMouseExploreByTouch")) { | |||
| 8776 | msg = eMouseExploreByTouch; | |||
| 8777 | } else { | |||
| 8778 | return NS_ERROR_FAILURE; | |||
| 8779 | } | |||
| 8780 | ||||
| 8781 | if (aInputSourceArg == MouseEvent_Binding::MOZ_SOURCE_UNKNOWN) { | |||
| 8782 | aInputSourceArg = MouseEvent_Binding::MOZ_SOURCE_MOUSE; | |||
| 8783 | } | |||
| 8784 | ||||
| 8785 | Maybe<WidgetPointerEvent> pointerEvent; | |||
| 8786 | Maybe<WidgetMouseEvent> mouseEvent; | |||
| 8787 | if (IsPointerEventMessage(msg)) { | |||
| 8788 | 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" , 8789); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIsWidgetEventSynthesized" ") (" "The event shouldn't be dispatched as a synthesized event" ")"); do { *((volatile int*)__null) = 8789; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) | |||
| 8789 | "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" , 8789); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIsWidgetEventSynthesized" ") (" "The event shouldn't be dispatched as a synthesized event" ")"); do { *((volatile int*)__null) = 8789; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 8790 | if (MOZ_UNLIKELY(aIsWidgetEventSynthesized)(__builtin_expect(!!(aIsWidgetEventSynthesized), 0))) { | |||
| 8791 | // `click`, `auxclick` nor `contextmenu` should not be dispatched as a | |||
| 8792 | // synthesized event. | |||
| 8793 | return NS_ERROR_INVALID_ARG; | |||
| 8794 | } | |||
| 8795 | pointerEvent.emplace(true, msg, widget, | |||
| 8796 | contextMenuKey ? WidgetMouseEvent::eContextMenuKey | |||
| 8797 | : WidgetMouseEvent::eNormal); | |||
| 8798 | } else { | |||
| 8799 | mouseEvent.emplace(true, msg, widget, | |||
| 8800 | aIsWidgetEventSynthesized | |||
| 8801 | ? WidgetMouseEvent::eSynthesized | |||
| 8802 | : WidgetMouseEvent::eReal, | |||
| 8803 | contextMenuKey ? WidgetMouseEvent::eContextMenuKey | |||
| 8804 | : WidgetMouseEvent::eNormal); | |||
| 8805 | } | |||
| 8806 | WidgetMouseEvent& mouseOrPointerEvent = | |||
| 8807 | pointerEvent.isSome() ? pointerEvent.ref() : mouseEvent.ref(); | |||
| 8808 | mouseOrPointerEvent.pointerId = aIdentifier; | |||
| 8809 | mouseOrPointerEvent.mModifiers = GetWidgetModifiers(aModifiers); | |||
| 8810 | mouseOrPointerEvent.mButton = aButton; | |||
| 8811 | mouseOrPointerEvent.mButtons = | |||
| 8812 | aButtons != nsIDOMWindowUtils::MOUSE_BUTTONS_NOT_SPECIFIED ? aButtons | |||
| 8813 | : msg == eMouseUp ? 0 | |||
| 8814 | : GetButtonsFlagForButton(aButton); | |||
| 8815 | mouseOrPointerEvent.mPressure = aPressure; | |||
| 8816 | mouseOrPointerEvent.mInputSource = aInputSourceArg; | |||
| 8817 | mouseOrPointerEvent.mClickCount = aClickCount; | |||
| 8818 | mouseOrPointerEvent.mFlags.mIsSynthesizedForTests = aIsDOMEventSynthesized; | |||
| 8819 | mouseOrPointerEvent.mExitFrom = exitFrom; | |||
| 8820 | ||||
| 8821 | nsPresContext* presContext = aPresShell->GetPresContext(); | |||
| 8822 | if (!presContext) return NS_ERROR_FAILURE; | |||
| 8823 | ||||
| 8824 | mouseOrPointerEvent.mRefPoint = | |||
| 8825 | ToWidgetPoint(CSSPoint(aX, aY), offset, presContext); | |||
| 8826 | mouseOrPointerEvent.mIgnoreRootScrollFrame = aIgnoreRootScrollFrame; | |||
| 8827 | ||||
| 8828 | nsEventStatus status = nsEventStatus_eIgnore; | |||
| 8829 | if (aToWindow) { | |||
| 8830 | RefPtr<PresShell> presShell; | |||
| 8831 | nsView* view = | |||
| 8832 | GetViewToDispatchEvent(presContext, getter_AddRefs(presShell)); | |||
| 8833 | if (!presShell || !view) { | |||
| 8834 | return NS_ERROR_FAILURE; | |||
| 8835 | } | |||
| 8836 | return presShell->HandleEvent(view->GetFrame(), &mouseOrPointerEvent, false, | |||
| 8837 | &status); | |||
| 8838 | } | |||
| 8839 | if (StaticPrefs::test_events_async_enabled()) { | |||
| 8840 | status = widget->DispatchInputEvent(&mouseOrPointerEvent).mContentStatus; | |||
| 8841 | } else { | |||
| 8842 | nsresult rv = widget->DispatchEvent(&mouseOrPointerEvent, status); | |||
| 8843 | 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" , 8843); return rv; } } while (false); | |||
| 8844 | } | |||
| 8845 | if (aPreventDefault) { | |||
| 8846 | *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault); | |||
| 8847 | } | |||
| 8848 | ||||
| 8849 | return NS_OK; | |||
| 8850 | } | |||
| 8851 | ||||
| 8852 | /* static */ | |||
| 8853 | void nsContentUtils::FirePageHideEventForFrameLoaderSwap( | |||
| 8854 | nsIDocShellTreeItem* aItem, EventTarget* aChromeEventHandler, | |||
| 8855 | bool aOnlySystemGroup) { | |||
| 8856 | 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" , 8856); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aItem" ")"); do { *((volatile int*)__null) = 8856; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 8857 | 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" , 8857); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aChromeEventHandler" ")"); do { *((volatile int*)__null) = 8857; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 8858 | ||||
| 8859 | if (RefPtr<Document> doc = aItem->GetDocument()) { | |||
| 8860 | doc->OnPageHide(true, aChromeEventHandler, aOnlySystemGroup); | |||
| 8861 | } | |||
| 8862 | ||||
| 8863 | int32_t childCount = 0; | |||
| 8864 | aItem->GetInProcessChildCount(&childCount); | |||
| 8865 | AutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> kids; | |||
| 8866 | kids.AppendElements(childCount); | |||
| 8867 | for (int32_t i = 0; i < childCount; ++i) { | |||
| 8868 | aItem->GetInProcessChildAt(i, getter_AddRefs(kids[i])); | |||
| 8869 | } | |||
| 8870 | ||||
| 8871 | for (uint32_t i = 0; i < kids.Length(); ++i) { | |||
| 8872 | if (kids[i]) { | |||
| 8873 | FirePageHideEventForFrameLoaderSwap(kids[i], aChromeEventHandler, | |||
| 8874 | aOnlySystemGroup); | |||
| 8875 | } | |||
| 8876 | } | |||
| 8877 | } | |||
| 8878 | ||||
| 8879 | // The pageshow event is fired for a given document only if IsShowing() returns | |||
| 8880 | // the same thing as aFireIfShowing. This gives us a way to fire pageshow only | |||
| 8881 | // on documents that are still loading or only on documents that are already | |||
| 8882 | // loaded. | |||
| 8883 | /* static */ | |||
| 8884 | void nsContentUtils::FirePageShowEventForFrameLoaderSwap( | |||
| 8885 | nsIDocShellTreeItem* aItem, EventTarget* aChromeEventHandler, | |||
| 8886 | bool aFireIfShowing, bool aOnlySystemGroup) { | |||
| 8887 | int32_t childCount = 0; | |||
| 8888 | aItem->GetInProcessChildCount(&childCount); | |||
| 8889 | AutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> kids; | |||
| 8890 | kids.AppendElements(childCount); | |||
| 8891 | for (int32_t i = 0; i < childCount; ++i) { | |||
| 8892 | aItem->GetInProcessChildAt(i, getter_AddRefs(kids[i])); | |||
| 8893 | } | |||
| 8894 | ||||
| 8895 | for (uint32_t i = 0; i < kids.Length(); ++i) { | |||
| 8896 | if (kids[i]) { | |||
| 8897 | FirePageShowEventForFrameLoaderSwap(kids[i], aChromeEventHandler, | |||
| 8898 | aFireIfShowing, aOnlySystemGroup); | |||
| 8899 | } | |||
| 8900 | } | |||
| 8901 | ||||
| 8902 | RefPtr<Document> doc = aItem->GetDocument(); | |||
| 8903 | if (doc && doc->IsShowing() == aFireIfShowing) { | |||
| 8904 | doc->OnPageShow(true, aChromeEventHandler, aOnlySystemGroup); | |||
| 8905 | } | |||
| 8906 | } | |||
| 8907 | ||||
| 8908 | /* static */ | |||
| 8909 | already_AddRefed<nsPIWindowRoot> nsContentUtils::GetWindowRoot(Document* aDoc) { | |||
| 8910 | if (aDoc) { | |||
| 8911 | if (nsPIDOMWindowOuter* win = aDoc->GetWindow()) { | |||
| 8912 | return win->GetTopWindowRoot(); | |||
| 8913 | } | |||
| 8914 | } | |||
| 8915 | return nullptr; | |||
| 8916 | } | |||
| 8917 | ||||
| 8918 | /* static */ | |||
| 8919 | bool nsContentUtils::LinkContextIsURI(const nsAString& aAnchor, | |||
| 8920 | nsIURI* aDocURI) { | |||
| 8921 | if (aAnchor.IsEmpty()) { | |||
| 8922 | // anchor parameter not present or empty -> same document reference | |||
| 8923 | return true; | |||
| 8924 | } | |||
| 8925 | ||||
| 8926 | // the document URI might contain a fragment identifier ("#...') | |||
| 8927 | // we want to ignore that because it's invisible to the server | |||
| 8928 | // and just affects the local interpretation in the recipient | |||
| 8929 | nsCOMPtr<nsIURI> contextUri; | |||
| 8930 | nsresult rv = NS_GetURIWithoutRef(aDocURI, getter_AddRefs(contextUri)); | |||
| 8931 | ||||
| 8932 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 8933 | // copying failed | |||
| 8934 | return false; | |||
| 8935 | } | |||
| 8936 | ||||
| 8937 | // resolve anchor against context | |||
| 8938 | nsCOMPtr<nsIURI> resolvedUri; | |||
| 8939 | rv = NS_NewURI(getter_AddRefs(resolvedUri), aAnchor, nullptr, contextUri); | |||
| 8940 | ||||
| 8941 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 8942 | // resolving failed | |||
| 8943 | return false; | |||
| 8944 | } | |||
| 8945 | ||||
| 8946 | bool same; | |||
| 8947 | rv = contextUri->Equals(resolvedUri, &same); | |||
| 8948 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 8949 | // comparison failed | |||
| 8950 | return false; | |||
| 8951 | } | |||
| 8952 | ||||
| 8953 | return same; | |||
| 8954 | } | |||
| 8955 | ||||
| 8956 | /* static */ | |||
| 8957 | bool nsContentUtils::IsPreloadType(nsContentPolicyType aType) { | |||
| 8958 | return (aType == nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD || | |||
| 8959 | aType == nsIContentPolicy::TYPE_INTERNAL_MODULE_PRELOAD || | |||
| 8960 | aType == nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD || | |||
| 8961 | aType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD || | |||
| 8962 | aType == nsIContentPolicy::TYPE_INTERNAL_FONT_PRELOAD || | |||
| 8963 | aType == nsIContentPolicy::TYPE_INTERNAL_JSON_PRELOAD || | |||
| 8964 | aType == nsIContentPolicy::TYPE_INTERNAL_FETCH_PRELOAD); | |||
| 8965 | } | |||
| 8966 | ||||
| 8967 | // static | |||
| 8968 | ReferrerPolicy nsContentUtils::GetReferrerPolicyFromChannel( | |||
| 8969 | nsIChannel* aChannel) { | |||
| 8970 | nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel); | |||
| 8971 | if (!httpChannel) { | |||
| 8972 | return ReferrerPolicy::_empty; | |||
| 8973 | } | |||
| 8974 | ||||
| 8975 | nsresult rv; | |||
| 8976 | nsAutoCString headerValue; | |||
| 8977 | rv = httpChannel->GetResponseHeader("referrer-policy"_ns, headerValue); | |||
| 8978 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || headerValue.IsEmpty()) { | |||
| 8979 | return ReferrerPolicy::_empty; | |||
| 8980 | } | |||
| 8981 | ||||
| 8982 | return ReferrerInfo::ReferrerPolicyFromHeaderString( | |||
| 8983 | NS_ConvertUTF8toUTF16(headerValue)); | |||
| 8984 | } | |||
| 8985 | ||||
| 8986 | // static | |||
| 8987 | bool nsContentUtils::IsNonSubresourceRequest(nsIChannel* aChannel) { | |||
| 8988 | nsLoadFlags loadFlags = 0; | |||
| 8989 | aChannel->GetLoadFlags(&loadFlags); | |||
| 8990 | if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI) { | |||
| 8991 | return true; | |||
| 8992 | } | |||
| 8993 | ||||
| 8994 | nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); | |||
| 8995 | nsContentPolicyType type = loadInfo->InternalContentPolicyType(); | |||
| 8996 | return IsNonSubresourceInternalPolicyType(type); | |||
| 8997 | } | |||
| 8998 | ||||
| 8999 | // static | |||
| 9000 | bool nsContentUtils::IsNonSubresourceInternalPolicyType( | |||
| 9001 | nsContentPolicyType aType) { | |||
| 9002 | return aType == nsIContentPolicy::TYPE_DOCUMENT || | |||
| 9003 | aType == nsIContentPolicy::TYPE_INTERNAL_IFRAME || | |||
| 9004 | aType == nsIContentPolicy::TYPE_INTERNAL_FRAME || | |||
| 9005 | aType == nsIContentPolicy::TYPE_INTERNAL_WORKER || | |||
| 9006 | aType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER; | |||
| 9007 | } | |||
| 9008 | ||||
| 9009 | // static public | |||
| 9010 | bool nsContentUtils::IsThirdPartyTrackingResourceWindow( | |||
| 9011 | nsPIDOMWindowInner* aWindow) { | |||
| 9012 | 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" , 9012); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow" ")" ); do { *((volatile int*)__null) = 9012; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 9013 | ||||
| 9014 | Document* document = aWindow->GetExtantDoc(); | |||
| 9015 | if (!document) { | |||
| 9016 | return false; | |||
| 9017 | } | |||
| 9018 | ||||
| 9019 | nsCOMPtr<nsIClassifiedChannel> classifiedChannel = | |||
| 9020 | do_QueryInterface(document->GetChannel()); | |||
| 9021 | if (!classifiedChannel) { | |||
| 9022 | return false; | |||
| 9023 | } | |||
| 9024 | ||||
| 9025 | return classifiedChannel->IsThirdPartyTrackingResource(); | |||
| 9026 | } | |||
| 9027 | ||||
| 9028 | // static public | |||
| 9029 | bool nsContentUtils::IsFirstPartyTrackingResourceWindow( | |||
| 9030 | nsPIDOMWindowInner* aWindow) { | |||
| 9031 | 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" , 9031); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow" ")" ); do { *((volatile int*)__null) = 9031; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 9032 | ||||
| 9033 | Document* document = aWindow->GetExtantDoc(); | |||
| 9034 | if (!document) { | |||
| 9035 | return false; | |||
| 9036 | } | |||
| 9037 | ||||
| 9038 | nsCOMPtr<nsIClassifiedChannel> classifiedChannel = | |||
| 9039 | do_QueryInterface(document->GetChannel()); | |||
| 9040 | if (!classifiedChannel) { | |||
| 9041 | return false; | |||
| 9042 | } | |||
| 9043 | ||||
| 9044 | uint32_t classificationFlags = | |||
| 9045 | classifiedChannel->GetFirstPartyClassificationFlags(); | |||
| 9046 | ||||
| 9047 | return mozilla::net::UrlClassifierCommon::IsTrackingClassificationFlag( | |||
| 9048 | classificationFlags, NS_UsePrivateBrowsing(document->GetChannel())); | |||
| 9049 | } | |||
| 9050 | ||||
| 9051 | namespace { | |||
| 9052 | ||||
| 9053 | // We put StringBuilder in the anonymous namespace to prevent anything outside | |||
| 9054 | // this file from accidentally being linked against it. | |||
| 9055 | class BulkAppender { | |||
| 9056 | using size_type = typename nsAString::size_type; | |||
| 9057 | ||||
| 9058 | public: | |||
| 9059 | explicit BulkAppender(BulkWriteHandle<char16_t>&& aHandle) | |||
| 9060 | : mHandle(std::move(aHandle)), mPosition(0) {} | |||
| 9061 | ~BulkAppender() = default; | |||
| 9062 | ||||
| 9063 | template <int N> | |||
| 9064 | void AppendLiteral(const char16_t (&aStr)[N]) { | |||
| 9065 | size_t len = N - 1; | |||
| 9066 | 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" , 9066); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPosition + len <= mHandle.Length()" ")"); do { *((volatile int*)__null) = 9066; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 9067 | memcpy(mHandle.Elements() + mPosition, aStr, len * sizeof(char16_t)); | |||
| 9068 | mPosition += len; | |||
| 9069 | } | |||
| 9070 | ||||
| 9071 | void Append(Span<const char16_t> aStr) { | |||
| 9072 | size_t len = aStr.Length(); | |||
| 9073 | 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" , 9073); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPosition + len <= mHandle.Length()" ")"); do { *((volatile int*)__null) = 9073; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 9074 | // Both mHandle.Elements() and aStr.Elements() are guaranteed | |||
| 9075 | // to be non-null (by the string implementation and by Span, | |||
| 9076 | // respectively), so not checking the pointers for null before | |||
| 9077 | // memcpy does not lead to UB even if len was zero. | |||
| 9078 | memcpy(mHandle.Elements() + mPosition, aStr.Elements(), | |||
| 9079 | len * sizeof(char16_t)); | |||
| 9080 | mPosition += len; | |||
| 9081 | } | |||
| 9082 | ||||
| 9083 | void Append(Span<const char> aStr) { | |||
| 9084 | size_t len = aStr.Length(); | |||
| 9085 | 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" , 9085); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPosition + len <= mHandle.Length()" ")"); do { *((volatile int*)__null) = 9085; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 9086 | ConvertLatin1toUtf16(aStr, mHandle.AsSpan().From(mPosition)); | |||
| 9087 | mPosition += len; | |||
| 9088 | } | |||
| 9089 | ||||
| 9090 | void Finish() { mHandle.Finish(mPosition, false); } | |||
| 9091 | ||||
| 9092 | private: | |||
| 9093 | BulkWriteHandle<char16_t> mHandle; | |||
| 9094 | size_type mPosition; | |||
| 9095 | }; | |||
| 9096 | ||||
| 9097 | class StringBuilder { | |||
| 9098 | private: | |||
| 9099 | class Unit { | |||
| 9100 | public: | |||
| 9101 | 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); } | |||
| 9102 | ~Unit() { | |||
| 9103 | if (mType == Type::String || mType == Type::StringWithEncode) { | |||
| 9104 | mString.~nsString(); | |||
| 9105 | } | |||
| 9106 | 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); | |||
| 9107 | } | |||
| 9108 | ||||
| 9109 | enum class Type : uint8_t { | |||
| 9110 | Unknown, | |||
| 9111 | Atom, | |||
| 9112 | String, | |||
| 9113 | StringWithEncode, | |||
| 9114 | Literal, | |||
| 9115 | TextFragment, | |||
| 9116 | TextFragmentWithEncode, | |||
| 9117 | }; | |||
| 9118 | ||||
| 9119 | struct LiteralSpan { | |||
| 9120 | const char16_t* mData; | |||
| 9121 | uint32_t mLength; | |||
| 9122 | ||||
| 9123 | Span<const char16_t> AsSpan() { return Span(mData, mLength); } | |||
| 9124 | }; | |||
| 9125 | ||||
| 9126 | union { | |||
| 9127 | nsAtom* mAtom; | |||
| 9128 | LiteralSpan mLiteral; | |||
| 9129 | nsString mString; | |||
| 9130 | const nsTextFragment* mTextFragment; | |||
| 9131 | }; | |||
| 9132 | Type mType = Type::Unknown; | |||
| 9133 | }; | |||
| 9134 | ||||
| 9135 | static_assert(sizeof(void*) != 8 || sizeof(Unit) <= 3 * sizeof(void*), | |||
| 9136 | "Unit should remain small"); | |||
| 9137 | ||||
| 9138 | public: | |||
| 9139 | // Try to keep the size of StringBuilder close to a jemalloc bucket size (the | |||
| 9140 | // 16kb one in this case). | |||
| 9141 | static constexpr uint32_t TARGET_SIZE = 16 * 1024; | |||
| 9142 | ||||
| 9143 | // The number of units we need to remove from the inline buffer so that the | |||
| 9144 | // rest of the builder members fit. A more precise approach would be to | |||
| 9145 | // calculate that extra size and use (TARGET_SIZE - OTHER_SIZE) / sizeof(Unit) | |||
| 9146 | // or so, but this is simpler. | |||
| 9147 | static constexpr uint32_t PADDING_UNITS = sizeof(void*) == 8 ? 1 : 2; | |||
| 9148 | ||||
| 9149 | static constexpr uint32_t STRING_BUFFER_UNITS = | |||
| 9150 | TARGET_SIZE / sizeof(Unit) - PADDING_UNITS; | |||
| 9151 | ||||
| 9152 | 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); } | |||
| 9153 | ||||
| 9154 | 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); } | |||
| 9155 | ||||
| 9156 | void Append(nsAtom* aAtom) { | |||
| 9157 | Unit* u = AddUnit(); | |||
| 9158 | u->mAtom = aAtom; | |||
| 9159 | u->mType = Unit::Type::Atom; | |||
| 9160 | uint32_t len = aAtom->GetLength(); | |||
| 9161 | mLength += len; | |||
| 9162 | } | |||
| 9163 | ||||
| 9164 | template <int N> | |||
| 9165 | void Append(const char16_t (&aLiteral)[N]) { | |||
| 9166 | constexpr uint32_t len = N - 1; | |||
| 9167 | Unit* u = AddUnit(); | |||
| 9168 | u->mLiteral = {aLiteral, len}; | |||
| 9169 | u->mType = Unit::Type::Literal; | |||
| 9170 | mLength += len; | |||
| 9171 | } | |||
| 9172 | ||||
| 9173 | void Append(nsString&& aString) { | |||
| 9174 | Unit* u = AddUnit(); | |||
| 9175 | uint32_t len = aString.Length(); | |||
| 9176 | new (&u->mString) nsString(std::move(aString)); | |||
| 9177 | u->mType = Unit::Type::String; | |||
| 9178 | mLength += len; | |||
| 9179 | } | |||
| 9180 | ||||
| 9181 | // aLen can be !isValid(), which will get propagated into mLength. | |||
| 9182 | void AppendWithAttrEncode(nsString&& aString, CheckedInt<uint32_t> aLen) { | |||
| 9183 | Unit* u = AddUnit(); | |||
| 9184 | new (&u->mString) nsString(std::move(aString)); | |||
| 9185 | u->mType = Unit::Type::StringWithEncode; | |||
| 9186 | mLength += aLen; | |||
| 9187 | } | |||
| 9188 | ||||
| 9189 | void Append(const nsTextFragment* aTextFragment) { | |||
| 9190 | Unit* u = AddUnit(); | |||
| 9191 | u->mTextFragment = aTextFragment; | |||
| 9192 | u->mType = Unit::Type::TextFragment; | |||
| 9193 | uint32_t len = aTextFragment->GetLength(); | |||
| 9194 | mLength += len; | |||
| 9195 | } | |||
| 9196 | ||||
| 9197 | // aLen can be !isValid(), which will get propagated into mLength. | |||
| 9198 | void AppendWithEncode(const nsTextFragment* aTextFragment, | |||
| 9199 | CheckedInt<uint32_t> aLen) { | |||
| 9200 | Unit* u = AddUnit(); | |||
| 9201 | u->mTextFragment = aTextFragment; | |||
| 9202 | u->mType = Unit::Type::TextFragmentWithEncode; | |||
| 9203 | mLength += aLen; | |||
| 9204 | } | |||
| 9205 | ||||
| 9206 | bool ToString(nsAString& aOut) { | |||
| 9207 | if (!mLength.isValid()) { | |||
| 9208 | return false; | |||
| 9209 | } | |||
| 9210 | auto appenderOrErr = aOut.BulkWrite(mLength.value(), 0, true); | |||
| 9211 | if (appenderOrErr.isErr()) { | |||
| 9212 | return false; | |||
| 9213 | } | |||
| 9214 | ||||
| 9215 | BulkAppender appender{appenderOrErr.unwrap()}; | |||
| 9216 | ||||
| 9217 | for (StringBuilder* current = this; current; | |||
| 9218 | current = current->mNext.get()) { | |||
| 9219 | uint32_t len = current->mUnits.Length(); | |||
| 9220 | for (uint32_t i = 0; i < len; ++i) { | |||
| 9221 | Unit& u = current->mUnits[i]; | |||
| 9222 | switch (u.mType) { | |||
| 9223 | case Unit::Type::Atom: | |||
| 9224 | appender.Append(*(u.mAtom)); | |||
| 9225 | break; | |||
| 9226 | case Unit::Type::String: | |||
| 9227 | appender.Append(u.mString); | |||
| 9228 | break; | |||
| 9229 | case Unit::Type::StringWithEncode: | |||
| 9230 | EncodeAttrString(u.mString, appender); | |||
| 9231 | break; | |||
| 9232 | case Unit::Type::Literal: | |||
| 9233 | appender.Append(u.mLiteral.AsSpan()); | |||
| 9234 | break; | |||
| 9235 | case Unit::Type::TextFragment: | |||
| 9236 | if (u.mTextFragment->Is2b()) { | |||
| 9237 | appender.Append( | |||
| 9238 | Span(u.mTextFragment->Get2b(), u.mTextFragment->GetLength())); | |||
| 9239 | } else { | |||
| 9240 | appender.Append( | |||
| 9241 | Span(u.mTextFragment->Get1b(), u.mTextFragment->GetLength())); | |||
| 9242 | } | |||
| 9243 | break; | |||
| 9244 | case Unit::Type::TextFragmentWithEncode: | |||
| 9245 | if (u.mTextFragment->Is2b()) { | |||
| 9246 | EncodeTextFragment( | |||
| 9247 | Span(u.mTextFragment->Get2b(), u.mTextFragment->GetLength()), | |||
| 9248 | appender); | |||
| 9249 | } else { | |||
| 9250 | EncodeTextFragment( | |||
| 9251 | Span(u.mTextFragment->Get1b(), u.mTextFragment->GetLength()), | |||
| 9252 | appender); | |||
| 9253 | } | |||
| 9254 | break; | |||
| 9255 | default: | |||
| 9256 | 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" , 9256); AnnotateMozCrashReason("MOZ_CRASH(" "Unknown unit type?" ")"); do { *((volatile int*)__null) = 9256; __attribute__((nomerge )) ::abort(); } while (false); } while (false); | |||
| 9257 | } | |||
| 9258 | } | |||
| 9259 | } | |||
| 9260 | appender.Finish(); | |||
| 9261 | return true; | |||
| 9262 | } | |||
| 9263 | ||||
| 9264 | private: | |||
| 9265 | Unit* AddUnit() { | |||
| 9266 | if (mLast->mUnits.Length() == STRING_BUFFER_UNITS) { | |||
| 9267 | new StringBuilder(this); | |||
| 9268 | } | |||
| 9269 | return mLast->mUnits.AppendElement(); | |||
| 9270 | } | |||
| 9271 | ||||
| 9272 | explicit StringBuilder(StringBuilder* aFirst) : mLast(nullptr), mLength(0) { | |||
| 9273 | 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); | |||
| 9274 | aFirst->mLast->mNext = WrapUnique(this); | |||
| 9275 | aFirst->mLast = this; | |||
| 9276 | } | |||
| 9277 | ||||
| 9278 | void EncodeAttrString(Span<const char16_t> aStr, BulkAppender& aAppender) { | |||
| 9279 | size_t flushedUntil = 0; | |||
| 9280 | size_t currentPosition = 0; | |||
| 9281 | for (char16_t c : aStr) { | |||
| 9282 | switch (c) { | |||
| 9283 | case '"': | |||
| 9284 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); | |||
| 9285 | aAppender.AppendLiteral(u"""); | |||
| 9286 | flushedUntil = currentPosition + 1; | |||
| 9287 | break; | |||
| 9288 | case '&': | |||
| 9289 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); | |||
| 9290 | aAppender.AppendLiteral(u"&"); | |||
| 9291 | flushedUntil = currentPosition + 1; | |||
| 9292 | break; | |||
| 9293 | case 0x00A0: | |||
| 9294 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); | |||
| 9295 | aAppender.AppendLiteral(u" "); | |||
| 9296 | flushedUntil = currentPosition + 1; | |||
| 9297 | break; | |||
| 9298 | default: | |||
| 9299 | break; | |||
| 9300 | } | |||
| 9301 | currentPosition++; | |||
| 9302 | } | |||
| 9303 | if (currentPosition > flushedUntil) { | |||
| 9304 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); | |||
| 9305 | } | |||
| 9306 | } | |||
| 9307 | ||||
| 9308 | template <class T> | |||
| 9309 | void EncodeTextFragment(Span<const T> aStr, BulkAppender& aAppender) { | |||
| 9310 | size_t flushedUntil = 0; | |||
| 9311 | size_t currentPosition = 0; | |||
| 9312 | for (T c : aStr) { | |||
| 9313 | switch (c) { | |||
| 9314 | case '<': | |||
| 9315 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); | |||
| 9316 | aAppender.AppendLiteral(u"<"); | |||
| 9317 | flushedUntil = currentPosition + 1; | |||
| 9318 | break; | |||
| 9319 | case '>': | |||
| 9320 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); | |||
| 9321 | aAppender.AppendLiteral(u">"); | |||
| 9322 | flushedUntil = currentPosition + 1; | |||
| 9323 | break; | |||
| 9324 | case '&': | |||
| 9325 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); | |||
| 9326 | aAppender.AppendLiteral(u"&"); | |||
| 9327 | flushedUntil = currentPosition + 1; | |||
| 9328 | break; | |||
| 9329 | case T(0xA0): | |||
| 9330 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); | |||
| 9331 | aAppender.AppendLiteral(u" "); | |||
| 9332 | flushedUntil = currentPosition + 1; | |||
| 9333 | break; | |||
| 9334 | default: | |||
| 9335 | break; | |||
| 9336 | } | |||
| 9337 | currentPosition++; | |||
| 9338 | } | |||
| 9339 | if (currentPosition > flushedUntil) { | |||
| 9340 | aAppender.Append(aStr.FromTo(flushedUntil, currentPosition)); | |||
| 9341 | } | |||
| 9342 | } | |||
| 9343 | ||||
| 9344 | AutoTArray<Unit, STRING_BUFFER_UNITS> mUnits; | |||
| 9345 | UniquePtr<StringBuilder> mNext; | |||
| 9346 | StringBuilder* mLast; | |||
| 9347 | // mLength is used only in the first StringBuilder object in the linked list. | |||
| 9348 | CheckedInt<uint32_t> mLength; | |||
| 9349 | }; | |||
| 9350 | ||||
| 9351 | static_assert(sizeof(StringBuilder) <= StringBuilder::TARGET_SIZE, | |||
| 9352 | "StringBuilder should fit in the target bucket"); | |||
| 9353 | ||||
| 9354 | } // namespace | |||
| 9355 | ||||
| 9356 | static void AppendEncodedCharacters(const nsTextFragment* aText, | |||
| 9357 | StringBuilder& aBuilder) { | |||
| 9358 | uint32_t numEncodedChars = 0; | |||
| 9359 | uint32_t len = aText->GetLength(); | |||
| 9360 | if (aText->Is2b()) { | |||
| 9361 | const char16_t* data = aText->Get2b(); | |||
| 9362 | for (uint32_t i = 0; i < len; ++i) { | |||
| 9363 | const char16_t c = data[i]; | |||
| 9364 | switch (c) { | |||
| 9365 | case '<': | |||
| 9366 | case '>': | |||
| 9367 | case '&': | |||
| 9368 | case 0x00A0: | |||
| 9369 | ++numEncodedChars; | |||
| 9370 | break; | |||
| 9371 | default: | |||
| 9372 | break; | |||
| 9373 | } | |||
| 9374 | } | |||
| 9375 | } else { | |||
| 9376 | const char* data = aText->Get1b(); | |||
| 9377 | for (uint32_t i = 0; i < len; ++i) { | |||
| 9378 | const unsigned char c = data[i]; | |||
| 9379 | switch (c) { | |||
| 9380 | case '<': | |||
| 9381 | case '>': | |||
| 9382 | case '&': | |||
| 9383 | case 0x00A0: | |||
| 9384 | ++numEncodedChars; | |||
| 9385 | break; | |||
| 9386 | default: | |||
| 9387 | break; | |||
| 9388 | } | |||
| 9389 | } | |||
| 9390 | } | |||
| 9391 | ||||
| 9392 | if (numEncodedChars) { | |||
| 9393 | // For simplicity, conservatively estimate the size of the string after | |||
| 9394 | // encoding. This will result in reserving more memory than we actually | |||
| 9395 | // need, but that should be fine unless the string has an enormous number of | |||
| 9396 | // eg < in it. We subtract 1 for the null terminator, then 1 more for the | |||
| 9397 | // existing character that will be replaced. | |||
| 9398 | constexpr uint32_t maxCharExtraSpace = | |||
| 9399 | std::max({std::size("<"), std::size(">"), std::size("&"), | |||
| 9400 | std::size(" ")}) - | |||
| 9401 | 2; | |||
| 9402 | static_assert(maxCharExtraSpace < 100, "Possible underflow"); | |||
| 9403 | CheckedInt<uint32_t> maxExtraSpace = | |||
| 9404 | CheckedInt<uint32_t>(numEncodedChars) * maxCharExtraSpace; | |||
| 9405 | aBuilder.AppendWithEncode(aText, maxExtraSpace + len); | |||
| 9406 | } else { | |||
| 9407 | aBuilder.Append(aText); | |||
| 9408 | } | |||
| 9409 | } | |||
| 9410 | ||||
| 9411 | static CheckedInt<uint32_t> ExtraSpaceNeededForAttrEncoding( | |||
| 9412 | const nsAString& aValue) { | |||
| 9413 | const char16_t* c = aValue.BeginReading(); | |||
| 9414 | const char16_t* end = aValue.EndReading(); | |||
| 9415 | ||||
| 9416 | uint32_t numEncodedChars = 0; | |||
| 9417 | while (c < end) { | |||
| 9418 | switch (*c) { | |||
| 9419 | case '"': | |||
| 9420 | case '&': | |||
| 9421 | case 0x00A0: | |||
| 9422 | ++numEncodedChars; | |||
| 9423 | break; | |||
| 9424 | default: | |||
| 9425 | break; | |||
| 9426 | } | |||
| 9427 | ++c; | |||
| 9428 | } | |||
| 9429 | ||||
| 9430 | if (!numEncodedChars) { | |||
| 9431 | return 0; | |||
| 9432 | } | |||
| 9433 | ||||
| 9434 | // For simplicity, conservatively estimate the size of the string after | |||
| 9435 | // encoding. This will result in reserving more memory than we actually | |||
| 9436 | // need, but that should be fine unless the string has an enormous number of | |||
| 9437 | // & in it. We subtract 1 for the null terminator, then 1 more for the | |||
| 9438 | // existing character that will be replaced. | |||
| 9439 | constexpr uint32_t maxCharExtraSpace = | |||
| 9440 | std::max({std::size("""), std::size("&"), std::size(" ")}) - | |||
| 9441 | 2; | |||
| 9442 | static_assert(maxCharExtraSpace < 100, "Possible underflow"); | |||
| 9443 | return CheckedInt<uint32_t>(numEncodedChars) * maxCharExtraSpace; | |||
| 9444 | } | |||
| 9445 | ||||
| 9446 | static void AppendEncodedAttributeValue(const nsAttrValue& aValue, | |||
| 9447 | StringBuilder& aBuilder) { | |||
| 9448 | if (nsAtom* atom = aValue.GetStoredAtom()) { | |||
| 9449 | nsDependentAtomString atomStr(atom); | |||
| 9450 | auto space = ExtraSpaceNeededForAttrEncoding(atomStr); | |||
| 9451 | if (space.isValid() && !space.value()) { | |||
| 9452 | aBuilder.Append(atom); | |||
| 9453 | } else { | |||
| 9454 | aBuilder.AppendWithAttrEncode(nsString(atomStr), | |||
| 9455 | space + atomStr.Length()); | |||
| 9456 | } | |||
| 9457 | return; | |||
| 9458 | } | |||
| 9459 | // NOTE(emilio): In most cases this will just be a reference to the stored | |||
| 9460 | // nsStringBuffer. | |||
| 9461 | nsString str; | |||
| 9462 | aValue.ToString(str); | |||
| 9463 | auto space = ExtraSpaceNeededForAttrEncoding(str); | |||
| 9464 | if (!space.isValid() || space.value()) { | |||
| 9465 | aBuilder.AppendWithAttrEncode(std::move(str), space + str.Length()); | |||
| 9466 | } else { | |||
| 9467 | aBuilder.Append(std::move(str)); | |||
| 9468 | } | |||
| 9469 | } | |||
| 9470 | ||||
| 9471 | static void StartElement(Element* aElement, StringBuilder& aBuilder) { | |||
| 9472 | nsAtom* localName = aElement->NodeInfo()->NameAtom(); | |||
| 9473 | const int32_t tagNS = aElement->GetNameSpaceID(); | |||
| 9474 | ||||
| 9475 | aBuilder.Append(u"<"); | |||
| 9476 | if (tagNS == kNameSpaceID_XHTML3 || tagNS == kNameSpaceID_SVG9 || | |||
| 9477 | tagNS == kNameSpaceID_MathML6) { | |||
| 9478 | aBuilder.Append(localName); | |||
| 9479 | } else { | |||
| 9480 | aBuilder.Append(nsString(aElement->NodeName())); | |||
| 9481 | } | |||
| 9482 | ||||
| 9483 | if (CustomElementData* ceData = aElement->GetCustomElementData()) { | |||
| 9484 | nsAtom* isAttr = ceData->GetIs(aElement); | |||
| 9485 | if (isAttr && !aElement->HasAttr(nsGkAtoms::is)) { | |||
| 9486 | aBuilder.Append(uR"( is=")"); | |||
| 9487 | aBuilder.Append(isAttr); | |||
| 9488 | aBuilder.Append(uR"(")"); | |||
| 9489 | } | |||
| 9490 | } | |||
| 9491 | ||||
| 9492 | uint32_t i = 0; | |||
| 9493 | while (BorrowedAttrInfo info = aElement->GetAttrInfoAt(i++)) { | |||
| 9494 | const nsAttrName* name = info.mName; | |||
| 9495 | ||||
| 9496 | int32_t attNs = name->NamespaceID(); | |||
| 9497 | nsAtom* attName = name->LocalName(); | |||
| 9498 | ||||
| 9499 | // Filter out any attribute starting with [-|_]moz | |||
| 9500 | // FIXME(emilio): Do we still need this? | |||
| 9501 | nsDependentAtomString attrNameStr(attName); | |||
| 9502 | if (StringBeginsWith(attrNameStr, u"_moz"_ns) || | |||
| 9503 | StringBeginsWith(attrNameStr, u"-moz"_ns)) { | |||
| 9504 | continue; | |||
| 9505 | } | |||
| 9506 | ||||
| 9507 | aBuilder.Append(u" "); | |||
| 9508 | ||||
| 9509 | if (MOZ_LIKELY(attNs == kNameSpaceID_None)(__builtin_expect(!!(attNs == kNameSpaceID_None), 1)) || | |||
| 9510 | (attNs == kNameSpaceID_XMLNS1 && attName == nsGkAtoms::xmlns)) { | |||
| 9511 | // Nothing else required | |||
| 9512 | } else if (attNs == kNameSpaceID_XML2) { | |||
| 9513 | aBuilder.Append(u"xml:"); | |||
| 9514 | } else if (attNs == kNameSpaceID_XMLNS1) { | |||
| 9515 | aBuilder.Append(u"xmlns:"); | |||
| 9516 | } else if (attNs == kNameSpaceID_XLink4) { | |||
| 9517 | aBuilder.Append(u"xlink:"); | |||
| 9518 | } else if (nsAtom* prefix = name->GetPrefix()) { | |||
| 9519 | aBuilder.Append(prefix); | |||
| 9520 | aBuilder.Append(u":"); | |||
| 9521 | } | |||
| 9522 | ||||
| 9523 | aBuilder.Append(attName); | |||
| 9524 | aBuilder.Append(uR"(=")"); | |||
| 9525 | AppendEncodedAttributeValue(*info.mValue, aBuilder); | |||
| 9526 | aBuilder.Append(uR"(")"); | |||
| 9527 | } | |||
| 9528 | ||||
| 9529 | aBuilder.Append(u">"); | |||
| 9530 | ||||
| 9531 | /* | |||
| 9532 | // Per HTML spec we should append one \n if the first child of | |||
| 9533 | // pre/textarea/listing is a textnode and starts with a \n. | |||
| 9534 | // But because browsers haven't traditionally had that behavior, | |||
| 9535 | // we're not changing our behavior either - yet. | |||
| 9536 | if (aContent->IsHTMLElement()) { | |||
| 9537 | if (localName == nsGkAtoms::pre || localName == nsGkAtoms::textarea || | |||
| 9538 | localName == nsGkAtoms::listing) { | |||
| 9539 | nsIContent* fc = aContent->GetFirstChild(); | |||
| 9540 | if (fc && | |||
| 9541 | (fc->NodeType() == nsINode::TEXT_NODE || | |||
| 9542 | fc->NodeType() == nsINode::CDATA_SECTION_NODE)) { | |||
| 9543 | const nsTextFragment* text = fc->GetText(); | |||
| 9544 | if (text && text->GetLength() && text->CharAt(0) == char16_t('\n')) { | |||
| 9545 | aBuilder.Append("\n"); | |||
| 9546 | } | |||
| 9547 | } | |||
| 9548 | } | |||
| 9549 | }*/ | |||
| 9550 | } | |||
| 9551 | ||||
| 9552 | static inline bool ShouldEscape(nsIContent* aParent) { | |||
| 9553 | if (!aParent || !aParent->IsHTMLElement()) { | |||
| 9554 | return true; | |||
| 9555 | } | |||
| 9556 | ||||
| 9557 | static const nsAtom* nonEscapingElements[] = { | |||
| 9558 | nsGkAtoms::style, nsGkAtoms::script, nsGkAtoms::xmp, | |||
| 9559 | nsGkAtoms::iframe, nsGkAtoms::noembed, nsGkAtoms::noframes, | |||
| 9560 | nsGkAtoms::plaintext, nsGkAtoms::noscript}; | |||
| 9561 | static mozilla::BitBloomFilter<12, nsAtom> sFilter; | |||
| 9562 | static bool sInitialized = false; | |||
| 9563 | if (!sInitialized) { | |||
| 9564 | sInitialized = true; | |||
| 9565 | for (auto& nonEscapingElement : nonEscapingElements) { | |||
| 9566 | sFilter.add(nonEscapingElement); | |||
| 9567 | } | |||
| 9568 | } | |||
| 9569 | ||||
| 9570 | nsAtom* tag = aParent->NodeInfo()->NameAtom(); | |||
| 9571 | if (sFilter.mightContain(tag)) { | |||
| 9572 | for (auto& nonEscapingElement : nonEscapingElements) { | |||
| 9573 | if (tag == nonEscapingElement) { | |||
| 9574 | if (MOZ_UNLIKELY(tag == nsGkAtoms::noscript)(__builtin_expect(!!(tag == nsGkAtoms::noscript), 0)) && | |||
| 9575 | MOZ_UNLIKELY(!aParent->OwnerDoc()->IsScriptEnabled())(__builtin_expect(!!(!aParent->OwnerDoc()->IsScriptEnabled ()), 0))) { | |||
| 9576 | return true; | |||
| 9577 | } | |||
| 9578 | return false; | |||
| 9579 | } | |||
| 9580 | } | |||
| 9581 | } | |||
| 9582 | return true; | |||
| 9583 | } | |||
| 9584 | ||||
| 9585 | static inline bool IsVoidTag(Element* aElement) { | |||
| 9586 | if (!aElement->IsHTMLElement()) { | |||
| 9587 | return false; | |||
| 9588 | } | |||
| 9589 | return FragmentOrElement::IsHTMLVoid(aElement->NodeInfo()->NameAtom()); | |||
| 9590 | } | |||
| 9591 | ||||
| 9592 | static bool StartSerializingShadowDOM( | |||
| 9593 | nsINode* aNode, StringBuilder& aBuilder, bool aSerializableShadowRoots, | |||
| 9594 | const Sequence<OwningNonNull<ShadowRoot>>& aShadowRoots) { | |||
| 9595 | ShadowRoot* shadow = aNode->GetShadowRoot(); | |||
| 9596 | if (!shadow || ((!aSerializableShadowRoots || !shadow->Serializable()) && | |||
| 9597 | !aShadowRoots.Contains(shadow))) { | |||
| 9598 | return false; | |||
| 9599 | } | |||
| 9600 | ||||
| 9601 | aBuilder.Append(u"<template shadowrootmode=\""); | |||
| 9602 | if (shadow->IsClosed()) { | |||
| 9603 | aBuilder.Append(u"closed\""); | |||
| 9604 | } else { | |||
| 9605 | aBuilder.Append(u"open\""); | |||
| 9606 | } | |||
| 9607 | ||||
| 9608 | if (shadow->DelegatesFocus()) { | |||
| 9609 | aBuilder.Append(u" shadowrootdelegatesfocus=\"\""); | |||
| 9610 | } | |||
| 9611 | if (shadow->Serializable()) { | |||
| 9612 | aBuilder.Append(u" shadowrootserializable=\"\""); | |||
| 9613 | } | |||
| 9614 | if (shadow->Clonable()) { | |||
| 9615 | aBuilder.Append(u" shadowrootclonable=\"\""); | |||
| 9616 | } | |||
| 9617 | ||||
| 9618 | aBuilder.Append(u">"); | |||
| 9619 | ||||
| 9620 | if (!shadow->HasChildren()) { | |||
| 9621 | aBuilder.Append(u"</template>"); | |||
| 9622 | return false; | |||
| 9623 | } | |||
| 9624 | return true; | |||
| 9625 | } | |||
| 9626 | ||||
| 9627 | template <SerializeShadowRoots ShouldSerializeShadowRoots> | |||
| 9628 | static void SerializeNodeToMarkupInternal( | |||
| 9629 | nsINode* aRoot, bool aDescendantsOnly, StringBuilder& aBuilder, | |||
| 9630 | bool aSerializableShadowRoots, | |||
| 9631 | const Sequence<OwningNonNull<ShadowRoot>>& aShadowRoots) { | |||
| 9632 | nsINode* current = | |||
| 9633 | aDescendantsOnly ? aRoot->GetFirstChildOfTemplateOrNode() : aRoot; | |||
| 9634 | if (!current) { | |||
| 9635 | return; | |||
| 9636 | } | |||
| 9637 | ||||
| 9638 | nsIContent* next; | |||
| 9639 | while (true) { | |||
| 9640 | bool isVoid = false; | |||
| 9641 | switch (current->NodeType()) { | |||
| 9642 | case nsINode::ELEMENT_NODE: { | |||
| 9643 | Element* elem = current->AsElement(); | |||
| 9644 | StartElement(elem, aBuilder); | |||
| 9645 | ||||
| 9646 | if constexpr (ShouldSerializeShadowRoots == SerializeShadowRoots::Yes) { | |||
| 9647 | if (StartSerializingShadowDOM( | |||
| 9648 | current, aBuilder, aSerializableShadowRoots, aShadowRoots)) { | |||
| 9649 | current = current->GetShadowRoot()->GetFirstChild(); | |||
| 9650 | continue; | |||
| 9651 | } | |||
| 9652 | } | |||
| 9653 | ||||
| 9654 | isVoid = IsVoidTag(elem); | |||
| 9655 | if (!isVoid && (next = current->GetFirstChildOfTemplateOrNode())) { | |||
| 9656 | current = next; | |||
| 9657 | continue; | |||
| 9658 | } | |||
| 9659 | break; | |||
| 9660 | } | |||
| 9661 | ||||
| 9662 | case nsINode::TEXT_NODE: | |||
| 9663 | case nsINode::CDATA_SECTION_NODE: { | |||
| 9664 | const nsTextFragment* text = ¤t->AsText()->TextFragment(); | |||
| 9665 | nsIContent* parent = current->GetParent(); | |||
| 9666 | if (ShouldEscape(parent)) { | |||
| 9667 | AppendEncodedCharacters(text, aBuilder); | |||
| 9668 | } else { | |||
| 9669 | aBuilder.Append(text); | |||
| 9670 | } | |||
| 9671 | break; | |||
| 9672 | } | |||
| 9673 | ||||
| 9674 | case nsINode::COMMENT_NODE: { | |||
| 9675 | aBuilder.Append(u"<!--"); | |||
| 9676 | aBuilder.Append(static_cast<nsIContent*>(current)->GetText()); | |||
| 9677 | aBuilder.Append(u"-->"); | |||
| 9678 | break; | |||
| 9679 | } | |||
| 9680 | ||||
| 9681 | case nsINode::DOCUMENT_TYPE_NODE: { | |||
| 9682 | aBuilder.Append(u"<!DOCTYPE "); | |||
| 9683 | aBuilder.Append(nsString(current->NodeName())); | |||
| 9684 | aBuilder.Append(u">"); | |||
| 9685 | break; | |||
| 9686 | } | |||
| 9687 | ||||
| 9688 | case nsINode::PROCESSING_INSTRUCTION_NODE: { | |||
| 9689 | aBuilder.Append(u"<?"); | |||
| 9690 | aBuilder.Append(nsString(current->NodeName())); | |||
| 9691 | aBuilder.Append(u" "); | |||
| 9692 | aBuilder.Append(static_cast<nsIContent*>(current)->GetText()); | |||
| 9693 | aBuilder.Append(u">"); | |||
| 9694 | break; | |||
| 9695 | } | |||
| 9696 | } | |||
| 9697 | ||||
| 9698 | while (true) { | |||
| 9699 | if (!isVoid && current->NodeType() == nsINode::ELEMENT_NODE) { | |||
| 9700 | aBuilder.Append(u"</"); | |||
| 9701 | nsIContent* elem = static_cast<nsIContent*>(current); | |||
| 9702 | if (elem->IsHTMLElement() || elem->IsSVGElement() || | |||
| 9703 | elem->IsMathMLElement()) { | |||
| 9704 | aBuilder.Append(elem->NodeInfo()->NameAtom()); | |||
| 9705 | } else { | |||
| 9706 | aBuilder.Append(nsString(current->NodeName())); | |||
| 9707 | } | |||
| 9708 | aBuilder.Append(u">"); | |||
| 9709 | } | |||
| 9710 | isVoid = false; | |||
| 9711 | ||||
| 9712 | if (current == aRoot) { | |||
| 9713 | return; | |||
| 9714 | } | |||
| 9715 | ||||
| 9716 | if ((next = current->GetNextSibling())) { | |||
| 9717 | current = next; | |||
| 9718 | break; | |||
| 9719 | } | |||
| 9720 | ||||
| 9721 | if constexpr (ShouldSerializeShadowRoots == SerializeShadowRoots::Yes) { | |||
| 9722 | // If the current node is a shadow root, then we must go to its host. | |||
| 9723 | // Since shadow DOMs are serialized declaratively as template elements, | |||
| 9724 | // we serialize the end tag of the template before going back to | |||
| 9725 | // serializing the shadow host. | |||
| 9726 | if (current->IsShadowRoot()) { | |||
| 9727 | current = current->GetContainingShadowHost(); | |||
| 9728 | aBuilder.Append(u"</template>"); | |||
| 9729 | ||||
| 9730 | if (current->HasChildren()) { | |||
| 9731 | current = current->GetFirstChildOfTemplateOrNode(); | |||
| 9732 | break; | |||
| 9733 | } | |||
| 9734 | continue; | |||
| 9735 | } | |||
| 9736 | } | |||
| 9737 | ||||
| 9738 | current = current->GetParentNode(); | |||
| 9739 | ||||
| 9740 | // Handle template element. If the parent is a template's content, | |||
| 9741 | // then adjust the parent to be the template element. | |||
| 9742 | if (current != aRoot && | |||
| 9743 | current->NodeType() == nsINode::DOCUMENT_FRAGMENT_NODE) { | |||
| 9744 | DocumentFragment* frag = static_cast<DocumentFragment*>(current); | |||
| 9745 | nsIContent* fragHost = frag->GetHost(); | |||
| 9746 | if (fragHost && fragHost->IsTemplateElement()) { | |||
| 9747 | current = fragHost; | |||
| 9748 | } | |||
| 9749 | } | |||
| 9750 | ||||
| 9751 | if (aDescendantsOnly && current == aRoot) { | |||
| 9752 | return; | |||
| 9753 | } | |||
| 9754 | } | |||
| 9755 | } | |||
| 9756 | } | |||
| 9757 | ||||
| 9758 | template <SerializeShadowRoots ShouldSerializeShadowRoots> | |||
| 9759 | bool nsContentUtils::SerializeNodeToMarkup( | |||
| 9760 | nsINode* aRoot, bool aDescendantsOnly, nsAString& aOut, | |||
| 9761 | bool aSerializableShadowRoots, | |||
| 9762 | const Sequence<OwningNonNull<ShadowRoot>>& aShadowRoots) { | |||
| 9763 | // If you pass in a DOCUMENT_NODE, you must pass aDescendentsOnly as true | |||
| 9764 | 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" , 9764); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDescendantsOnly || aRoot->NodeType() != nsINode::DOCUMENT_NODE" ")"); do { *((volatile int*)__null) = 9764; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 9765 | ||||
| 9766 | StringBuilder builder; | |||
| 9767 | if constexpr (ShouldSerializeShadowRoots == SerializeShadowRoots::Yes) { | |||
| 9768 | if (aDescendantsOnly && | |||
| 9769 | StartSerializingShadowDOM(aRoot, builder, aSerializableShadowRoots, | |||
| 9770 | aShadowRoots)) { | |||
| 9771 | SerializeNodeToMarkupInternal<SerializeShadowRoots::Yes>( | |||
| 9772 | aRoot->GetShadowRoot()->GetFirstChild(), false, builder, | |||
| 9773 | aSerializableShadowRoots, aShadowRoots); | |||
| 9774 | // The template tag is opened in StartSerializingShadowDOM, so we need | |||
| 9775 | // to close it here before serializing any children of aRoot. | |||
| 9776 | builder.Append(u"</template>"); | |||
| 9777 | } | |||
| 9778 | } | |||
| 9779 | ||||
| 9780 | SerializeNodeToMarkupInternal<ShouldSerializeShadowRoots>( | |||
| 9781 | aRoot, aDescendantsOnly, builder, aSerializableShadowRoots, aShadowRoots); | |||
| 9782 | return builder.ToString(aOut); | |||
| 9783 | } | |||
| 9784 | ||||
| 9785 | template bool nsContentUtils::SerializeNodeToMarkup<SerializeShadowRoots::No>( | |||
| 9786 | nsINode* aRoot, bool aDescendantsOnly, nsAString& aOut, | |||
| 9787 | bool aSerializableShadowRoots, | |||
| 9788 | const Sequence<OwningNonNull<ShadowRoot>>& aShadowRoots); | |||
| 9789 | template bool nsContentUtils::SerializeNodeToMarkup<SerializeShadowRoots::Yes>( | |||
| 9790 | nsINode* aRoot, bool aDescendantsOnly, nsAString& aOut, | |||
| 9791 | bool aSerializableShadowRoots, | |||
| 9792 | const Sequence<OwningNonNull<ShadowRoot>>& aShadowRoots); | |||
| 9793 | ||||
| 9794 | bool nsContentUtils::IsSpecificAboutPage(JSObject* aGlobal, const char* aUri) { | |||
| 9795 | // aUri must start with about: or this isn't the right function to be using. | |||
| 9796 | 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" , 9796); AnnotateMozCrashReason("MOZ_ASSERT" "(" "strncmp(aUri, \"about:\", 6) == 0" ")"); do { *((volatile int*)__null) = 9796; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 9797 | ||||
| 9798 | // Make sure the global is a window | |||
| 9799 | 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" , 9799); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "JS_IsGlobalObject(aGlobal)" ")"); do { *((volatile int*)__null) = 9799; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 9800 | nsGlobalWindowInner* win = xpc::WindowOrNull(aGlobal); | |||
| 9801 | if (!win) { | |||
| 9802 | return false; | |||
| 9803 | } | |||
| 9804 | ||||
| 9805 | nsCOMPtr<nsIPrincipal> principal = win->GetPrincipal(); | |||
| 9806 | 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" , 9806); return false; } } while (false); | |||
| 9807 | ||||
| 9808 | // First check the scheme to avoid getting long specs in the common case. | |||
| 9809 | if (!principal->SchemeIs("about")) { | |||
| 9810 | return false; | |||
| 9811 | } | |||
| 9812 | ||||
| 9813 | nsAutoCString spec; | |||
| 9814 | principal->GetAsciiSpec(spec); | |||
| 9815 | ||||
| 9816 | return spec.EqualsASCII(aUri); | |||
| 9817 | } | |||
| 9818 | ||||
| 9819 | /* static */ | |||
| 9820 | void nsContentUtils::SetScrollbarsVisibility(nsIDocShell* aDocShell, | |||
| 9821 | bool aVisible) { | |||
| 9822 | if (!aDocShell) { | |||
| 9823 | return; | |||
| 9824 | } | |||
| 9825 | auto pref = aVisible ? ScrollbarPreference::Auto : ScrollbarPreference::Never; | |||
| 9826 | nsDocShell::Cast(aDocShell)->SetScrollbarPreference(pref); | |||
| 9827 | } | |||
| 9828 | ||||
| 9829 | /* static */ | |||
| 9830 | nsIDocShell* nsContentUtils::GetDocShellForEventTarget(EventTarget* aTarget) { | |||
| 9831 | if (!aTarget) { | |||
| 9832 | return nullptr; | |||
| 9833 | } | |||
| 9834 | ||||
| 9835 | nsCOMPtr<nsPIDOMWindowInner> innerWindow; | |||
| 9836 | if (nsCOMPtr<nsINode> node = nsINode::FromEventTarget(aTarget)) { | |||
| 9837 | bool ignore; | |||
| 9838 | innerWindow = | |||
| 9839 | do_QueryInterface(node->OwnerDoc()->GetScriptHandlingObject(ignore)); | |||
| 9840 | } else if ((innerWindow = nsPIDOMWindowInner::FromEventTarget(aTarget))) { | |||
| 9841 | // Nothing else to do | |||
| 9842 | } else if (nsCOMPtr<DOMEventTargetHelper> helper = | |||
| 9843 | do_QueryInterface(aTarget)) { | |||
| 9844 | innerWindow = helper->GetOwnerWindow(); | |||
| 9845 | } | |||
| 9846 | ||||
| 9847 | if (innerWindow) { | |||
| 9848 | return innerWindow->GetDocShell(); | |||
| 9849 | } | |||
| 9850 | ||||
| 9851 | return nullptr; | |||
| 9852 | } | |||
| 9853 | ||||
| 9854 | /* | |||
| 9855 | * Note: this function only relates to figuring out HTTPS state, which is an | |||
| 9856 | * input to the Secure Context algorithm. We are not actually implementing any | |||
| 9857 | * part of the Secure Context algorithm itself here. | |||
| 9858 | * | |||
| 9859 | * This is a bit of a hack. Ideally we'd propagate HTTPS state through | |||
| 9860 | * nsIChannel as described in the Fetch and HTML specs, but making channels | |||
| 9861 | * know about whether they should inherit HTTPS state, propagating information | |||
| 9862 | * about who the channel's "client" is, exposing GetHttpsState API on channels | |||
| 9863 | * and modifying the various cache implementations to store and retrieve HTTPS | |||
| 9864 | * state involves a huge amount of code (see bug 1220687). We avoid that for | |||
| 9865 | * now using this function. | |||
| 9866 | * | |||
| 9867 | * This function takes advantage of the observation that we can return true if | |||
| 9868 | * nsIContentSecurityManager::IsOriginPotentiallyTrustworthy returns true for | |||
| 9869 | * the document's origin (e.g. the origin has a scheme of 'https' or host | |||
| 9870 | * 'localhost' etc.). Since we generally propagate a creator document's origin | |||
| 9871 | * onto data:, blob:, etc. documents, this works for them too. | |||
| 9872 | * | |||
| 9873 | * The scenario where this observation breaks down is sandboxing without the | |||
| 9874 | * 'allow-same-origin' flag, since in this case a document is given a unique | |||
| 9875 | * origin (IsOriginPotentiallyTrustworthy would return false). We handle that | |||
| 9876 | * by using the origin that the document would have had had it not been | |||
| 9877 | * sandboxed. | |||
| 9878 | * | |||
| 9879 | * DEFICIENCIES: Note that this function uses nsIScriptSecurityManager's | |||
| 9880 | * getChannelResultPrincipalIfNotSandboxed, and that method's ignoring of | |||
| 9881 | * sandboxing is limited to the immediate sandbox. In the case that aDocument | |||
| 9882 | * should inherit its origin (e.g. data: URI) but its parent has ended up | |||
| 9883 | * with a unique origin due to sandboxing further up the parent chain we may | |||
| 9884 | * end up returning false when we would ideally return true (since we will | |||
| 9885 | * examine the parent's origin for 'https' and not finding it.) This means | |||
| 9886 | * that we may restrict the privileges of some pages unnecessarily in this | |||
| 9887 | * edge case. | |||
| 9888 | */ | |||
| 9889 | /* static */ | |||
| 9890 | bool nsContentUtils::HttpsStateIsModern(Document* aDocument) { | |||
| 9891 | if (!aDocument) { | |||
| 9892 | return false; | |||
| 9893 | } | |||
| 9894 | ||||
| 9895 | nsCOMPtr<nsIPrincipal> principal = aDocument->NodePrincipal(); | |||
| 9896 | ||||
| 9897 | if (principal->IsSystemPrincipal()) { | |||
| 9898 | return true; | |||
| 9899 | } | |||
| 9900 | ||||
| 9901 | // If aDocument is sandboxed, try and get the principal that it would have | |||
| 9902 | // been given had it not been sandboxed: | |||
| 9903 | if (principal->GetIsNullPrincipal() && | |||
| 9904 | (aDocument->GetSandboxFlags() & SANDBOXED_ORIGIN)) { | |||
| 9905 | nsIChannel* channel = aDocument->GetChannel(); | |||
| 9906 | if (channel) { | |||
| 9907 | nsCOMPtr<nsIScriptSecurityManager> ssm = | |||
| 9908 | nsContentUtils::GetSecurityManager(); | |||
| 9909 | nsresult rv = ssm->GetChannelResultPrincipalIfNotSandboxed( | |||
| 9910 | channel, getter_AddRefs(principal)); | |||
| 9911 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 9912 | return false; | |||
| 9913 | } | |||
| 9914 | if (principal->IsSystemPrincipal()) { | |||
| 9915 | // If a document with the system principal is sandboxing a subdocument | |||
| 9916 | // that would normally inherit the embedding element's principal (e.g. | |||
| 9917 | // a srcdoc document) then the embedding document does not trust the | |||
| 9918 | // content that is written to the embedded document. Unlike when the | |||
| 9919 | // embedding document is https, in this case we have no indication as | |||
| 9920 | // to whether the embedded document's contents are delivered securely | |||
| 9921 | // or not, and the sandboxing would possibly indicate that they were | |||
| 9922 | // not. To play it safe we return false here. (See bug 1162772 | |||
| 9923 | // comment 73-80.) | |||
| 9924 | return false; | |||
| 9925 | } | |||
| 9926 | } | |||
| 9927 | } | |||
| 9928 | ||||
| 9929 | if (principal->GetIsNullPrincipal()) { | |||
| 9930 | return false; | |||
| 9931 | } | |||
| 9932 | ||||
| 9933 | 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" , 9933); AnnotateMozCrashReason("MOZ_ASSERT" "(" "principal->GetIsContentPrincipal()" ")"); do { *((volatile int*)__null) = 9933; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 9934 | ||||
| 9935 | return principal->GetIsOriginPotentiallyTrustworthy(); | |||
| 9936 | } | |||
| 9937 | ||||
| 9938 | /* static */ | |||
| 9939 | bool nsContentUtils::ComputeIsSecureContext(nsIChannel* aChannel) { | |||
| 9940 | 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" , 9940); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChannel" ")" ); do { *((volatile int*)__null) = 9940; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 9941 | ||||
| 9942 | nsCOMPtr<nsIScriptSecurityManager> ssm = nsContentUtils::GetSecurityManager(); | |||
| 9943 | nsCOMPtr<nsIPrincipal> principal; | |||
| 9944 | nsresult rv = ssm->GetChannelResultPrincipalIfNotSandboxed( | |||
| 9945 | aChannel, getter_AddRefs(principal)); | |||
| 9946 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 9947 | return false; | |||
| 9948 | } | |||
| 9949 | ||||
| 9950 | const RefPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); | |||
| 9951 | ||||
| 9952 | if (principal->IsSystemPrincipal()) { | |||
| 9953 | // If the load would've been sandboxed, treat this load as an untrusted | |||
| 9954 | // load, as system code considers sandboxed resources insecure. | |||
| 9955 | return !loadInfo->GetLoadingSandboxed(); | |||
| 9956 | } | |||
| 9957 | ||||
| 9958 | if (principal->GetIsNullPrincipal()) { | |||
| 9959 | return false; | |||
| 9960 | } | |||
| 9961 | ||||
| 9962 | if (const RefPtr<WindowContext> windowContext = | |||
| 9963 | WindowContext::GetById(loadInfo->GetInnerWindowID())) { | |||
| 9964 | if (!windowContext->GetIsSecureContext()) { | |||
| 9965 | return false; | |||
| 9966 | } | |||
| 9967 | } | |||
| 9968 | ||||
| 9969 | return principal->GetIsOriginPotentiallyTrustworthy(); | |||
| 9970 | } | |||
| 9971 | ||||
| 9972 | /* static */ | |||
| 9973 | void nsContentUtils::TryToUpgradeElement(Element* aElement) { | |||
| 9974 | NodeInfo* nodeInfo = aElement->NodeInfo(); | |||
| 9975 | RefPtr<nsAtom> typeAtom = | |||
| 9976 | aElement->GetCustomElementData()->GetCustomElementType(); | |||
| 9977 | ||||
| 9978 | 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" , 9978); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nodeInfo->NameAtom()->Equals(nodeInfo->LocalName())" ")"); do { *((volatile int*)__null) = 9978; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 9979 | CustomElementDefinition* definition = | |||
| 9980 | nsContentUtils::LookupCustomElementDefinition( | |||
| 9981 | nodeInfo->GetDocument(), nodeInfo->NameAtom(), | |||
| 9982 | nodeInfo->NamespaceID(), typeAtom); | |||
| 9983 | if (definition) { | |||
| 9984 | nsContentUtils::EnqueueUpgradeReaction(aElement, definition); | |||
| 9985 | } else { | |||
| 9986 | // Add an unresolved custom element that is a candidate for upgrade when a | |||
| 9987 | // custom element is connected to the document. | |||
| 9988 | nsContentUtils::RegisterUnresolvedElement(aElement, typeAtom); | |||
| 9989 | } | |||
| 9990 | } | |||
| 9991 | ||||
| 9992 | MOZ_CAN_RUN_SCRIPT | |||
| 9993 | static void DoCustomElementCreate(Element** aElement, JSContext* aCx, | |||
| 9994 | Document* aDoc, NodeInfo* aNodeInfo, | |||
| 9995 | CustomElementConstructor* aConstructor, | |||
| 9996 | ErrorResult& aRv, FromParser aFromParser) { | |||
| 9997 | JS::Rooted<JS::Value> constructResult(aCx); | |||
| 9998 | aConstructor->Construct(&constructResult, aRv, "Custom Element Create", | |||
| 9999 | CallbackFunction::eRethrowExceptions); | |||
| 10000 | if (aRv.Failed()) { | |||
| 10001 | return; | |||
| 10002 | } | |||
| 10003 | ||||
| 10004 | RefPtr<Element> element; | |||
| 10005 | // constructResult is an ObjectValue because construction with a callback | |||
| 10006 | // always forms the return value from a JSObject. | |||
| 10007 | UNWRAP_OBJECT(Element, &constructResult, element)mozilla::dom::binding_detail::UnwrapObjectWithCrossOriginAsserts < mozilla::dom::prototypes::id::Element, mozilla::dom::Element_Binding ::NativeType>(&constructResult, element); | |||
| 10008 | if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML3)) { | |||
| 10009 | if (!element || !element->IsHTMLElement()) { | |||
| 10010 | aRv.ThrowTypeError<MSG_DOES_NOT_IMPLEMENT_INTERFACE>("\"this\"", | |||
| 10011 | "HTMLElement"); | |||
| 10012 | return; | |||
| 10013 | } | |||
| 10014 | } else { | |||
| 10015 | if (!element || !element->IsXULElement()) { | |||
| 10016 | aRv.ThrowTypeError<MSG_DOES_NOT_IMPLEMENT_INTERFACE>("\"this\"", | |||
| 10017 | "XULElement"); | |||
| 10018 | return; | |||
| 10019 | } | |||
| 10020 | } | |||
| 10021 | ||||
| 10022 | nsAtom* localName = aNodeInfo->NameAtom(); | |||
| 10023 | ||||
| 10024 | if (aDoc != element->OwnerDoc() || element->GetParentNode() || | |||
| 10025 | element->HasChildren() || element->GetAttrCount() || | |||
| 10026 | element->NodeInfo()->NameAtom() != localName) { | |||
| 10027 | aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); | |||
| 10028 | return; | |||
| 10029 | } | |||
| 10030 | ||||
| 10031 | if (element->IsHTMLElement()) { | |||
| 10032 | static_cast<HTMLElement*>(&*element)->InhibitRestoration( | |||
| 10033 | !(aFromParser & FROM_PARSER_NETWORK)); | |||
| 10034 | } | |||
| 10035 | ||||
| 10036 | element.forget(aElement); | |||
| 10037 | } | |||
| 10038 | ||||
| 10039 | /* static */ | |||
| 10040 | nsresult nsContentUtils::NewXULOrHTMLElement( | |||
| 10041 | Element** aResult, mozilla::dom::NodeInfo* aNodeInfo, | |||
| 10042 | FromParser aFromParser, nsAtom* aIsAtom, | |||
| 10043 | mozilla::dom::CustomElementDefinition* aDefinition) { | |||
| 10044 | RefPtr<mozilla::dom::NodeInfo> nodeInfo = aNodeInfo; | |||
| 10045 | 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" , 10047); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nodeInfo->NamespaceEquals(3) || nodeInfo->NamespaceEquals(8)" ") (" "Can only create XUL or XHTML elements." ")"); do { *( (volatile int*)__null) = 10047; __attribute__((nomerge)) ::abort (); } while (false); } } while (false) | |||
| ||||
| 10046 | 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" , 10047); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nodeInfo->NamespaceEquals(3) || nodeInfo->NamespaceEquals(8)" ") (" "Can only create XUL or XHTML elements." ")"); do { *( (volatile int*)__null) = 10047; __attribute__((nomerge)) ::abort (); } while (false); } } while (false) | |||
| 10047 | "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" , 10047); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nodeInfo->NamespaceEquals(3) || nodeInfo->NamespaceEquals(8)" ") (" "Can only create XUL or XHTML elements." ")"); do { *( (volatile int*)__null) = 10047; __attribute__((nomerge)) ::abort (); } while (false); } } while (false); | |||
| 10048 | ||||
| 10049 | nsAtom* name = nodeInfo->NameAtom(); | |||
| 10050 | int32_t tag = eHTMLTag_unknown; | |||
| 10051 | bool isCustomElementName = false; | |||
| 10052 | if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML3)) { | |||
| 10053 | tag = nsHTMLTags::CaseSensitiveAtomTagToId(name); | |||
| 10054 | isCustomElementName = | |||
| 10055 | (tag == eHTMLTag_userdefined && | |||
| 10056 | nsContentUtils::IsCustomElementName(name, kNameSpaceID_XHTML3)); | |||
| 10057 | } else { // kNameSpaceID_XUL | |||
| 10058 | if (aIsAtom) { | |||
| 10059 | // Make sure the customized built-in element to be constructed confirms | |||
| 10060 | // to our naming requirement, i.e. [is] must be a dashed name and | |||
| 10061 | // the tag name must not. | |||
| 10062 | // if so, set isCustomElementName to false to kick off all the logics | |||
| 10063 | // that pick up aIsAtom. | |||
| 10064 | if (nsContentUtils::IsNameWithDash(aIsAtom) && | |||
| 10065 | !nsContentUtils::IsNameWithDash(name)) { | |||
| 10066 | isCustomElementName = false; | |||
| 10067 | } else { | |||
| 10068 | isCustomElementName = | |||
| 10069 | nsContentUtils::IsCustomElementName(name, kNameSpaceID_XUL8); | |||
| 10070 | } | |||
| 10071 | } else { | |||
| 10072 | isCustomElementName = | |||
| 10073 | nsContentUtils::IsCustomElementName(name, kNameSpaceID_XUL8); | |||
| 10074 | } | |||
| 10075 | } | |||
| 10076 | ||||
| 10077 | nsAtom* tagAtom = nodeInfo->NameAtom(); | |||
| 10078 | nsAtom* typeAtom = nullptr; | |||
| 10079 | bool isCustomElement = isCustomElementName
| |||
| 10080 | if (isCustomElement
| |||
| 10081 | typeAtom = isCustomElementName
| |||
| 10082 | } | |||
| 10083 | ||||
| 10084 | 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" , 10084); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isCustomElement" ")"); do { *((volatile int*)__null) = 10084; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); } } while (false); | |||
| 10085 | ||||
| 10086 | // https://dom.spec.whatwg.org/#concept-create-element | |||
| 10087 | // We only handle the "synchronous custom elements flag is set" now. | |||
| 10088 | // For the unset case (e.g. cloning a node), see bug 1319342 for that. | |||
| 10089 | // Step 4. | |||
| 10090 | RefPtr<CustomElementDefinition> definition = aDefinition; | |||
| 10091 | if (isCustomElement
| |||
| 10092 | 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" , 10092); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nodeInfo->NameAtom()->Equals(nodeInfo->LocalName())" ")"); do { *((volatile int*)__null) = 10092; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 10093 | definition = nsContentUtils::LookupCustomElementDefinition( | |||
| 10094 | nodeInfo->GetDocument(), nodeInfo->NameAtom(), nodeInfo->NamespaceID(), | |||
| 10095 | typeAtom); | |||
| 10096 | } | |||
| 10097 | ||||
| 10098 | // It might be a problem that parser synchronously calls constructor, so filed | |||
| 10099 | // bug 1378079 to figure out what we should do for parser case. | |||
| 10100 | if (definition) { | |||
| 10101 | /* | |||
| 10102 | * Synchronous custom elements flag is determined by 3 places in spec, | |||
| 10103 | * 1) create an element for a token, the flag is determined by | |||
| 10104 | * "will execute script" which is not originally created | |||
| 10105 | * for the HTML fragment parsing algorithm. | |||
| 10106 | * 2) createElement and createElementNS, the flag is the same as | |||
| 10107 | * NOT_FROM_PARSER. | |||
| 10108 | * 3) clone a node, our implementation will not go into this function. | |||
| 10109 | * For the unset case which is non-synchronous only applied for | |||
| 10110 | * inner/outerHTML. | |||
| 10111 | */ | |||
| 10112 | bool synchronousCustomElements = aFromParser != dom::FROM_PARSER_FRAGMENT; | |||
| 10113 | // Per discussion in https://github.com/w3c/webcomponents/issues/635, | |||
| 10114 | // use entry global in those places that are called from JS APIs and use the | |||
| 10115 | // node document's global object if it is called from parser. | |||
| 10116 | nsIGlobalObject* global; | |||
| 10117 | if (aFromParser == dom::NOT_FROM_PARSER) { | |||
| 10118 | global = GetEntryGlobal(); | |||
| 10119 | ||||
| 10120 | // Documents created from the PrototypeDocumentSink always use | |||
| 10121 | // NOT_FROM_PARSER for non-XUL elements. We can get the global from the | |||
| 10122 | // document in that case. | |||
| 10123 | if (!global) { | |||
| 10124 | Document* doc = nodeInfo->GetDocument(); | |||
| 10125 | if (doc && doc->LoadedFromPrototype()) { | |||
| 10126 | global = doc->GetScopeObject(); | |||
| 10127 | } | |||
| 10128 | } | |||
| 10129 | } else { | |||
| 10130 | global = nodeInfo->GetDocument()->GetScopeObject(); | |||
| 10131 | } | |||
| 10132 | if (!global
| |||
| 10133 | // In browser chrome code, one may have access to a document which doesn't | |||
| 10134 | // have scope object anymore. | |||
| 10135 | return NS_ERROR_FAILURE; | |||
| 10136 | } | |||
| 10137 | ||||
| 10138 | AutoAllowLegacyScriptExecution exemption; | |||
| 10139 | AutoEntryScript aes(global, "create custom elements"); | |||
| 10140 | JSContext* cx = aes.cx(); | |||
| 10141 | ErrorResult rv; | |||
| 10142 | ||||
| 10143 | // Step 5. | |||
| 10144 | if (definition->IsCustomBuiltIn()) { | |||
| 10145 | // SetupCustomElement() should be called with an element that don't have | |||
| 10146 | // CustomElementData setup, if not we will hit the assertion in | |||
| 10147 | // SetCustomElementData(). | |||
| 10148 | // Built-in element | |||
| 10149 | if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML3)) { | |||
| 10150 | *aResult = | |||
| 10151 | CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take(); | |||
| 10152 | } else { | |||
| 10153 | NS_IF_ADDREF(*aResult = nsXULElement::Construct(nodeInfo.forget()))ns_if_addref(*aResult = nsXULElement::Construct(nodeInfo.forget ())); | |||
| 10154 | } | |||
| 10155 | (*aResult)->SetCustomElementData(MakeUnique<CustomElementData>(typeAtom)); | |||
| ||||
| 10156 | if (synchronousCustomElements) { | |||
| 10157 | CustomElementRegistry::Upgrade(*aResult, definition, rv); | |||
| 10158 | if (rv.MaybeSetPendingException(cx)) { | |||
| 10159 | aes.ReportException(); | |||
| 10160 | } | |||
| 10161 | } else { | |||
| 10162 | nsContentUtils::EnqueueUpgradeReaction(*aResult, definition); | |||
| 10163 | } | |||
| 10164 | ||||
| 10165 | return NS_OK; | |||
| 10166 | } | |||
| 10167 | ||||
| 10168 | // Step 6.1. | |||
| 10169 | if (synchronousCustomElements) { | |||
| 10170 | definition->mPrefixStack.AppendElement(nodeInfo->GetPrefixAtom()); | |||
| 10171 | RefPtr<Document> doc = nodeInfo->GetDocument(); | |||
| 10172 | DoCustomElementCreate(aResult, cx, doc, nodeInfo, | |||
| 10173 | MOZ_KnownLive(definition->mConstructor)(definition->mConstructor), rv, | |||
| 10174 | aFromParser); | |||
| 10175 | if (rv.MaybeSetPendingException(cx)) { | |||
| 10176 | if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML3)) { | |||
| 10177 | NS_IF_ADDREF(*aResult = NS_NewHTMLUnknownElement(nodeInfo.forget(),ns_if_addref(*aResult = NS_NewHTMLUnknownElement(nodeInfo.forget (), aFromParser)) | |||
| 10178 | aFromParser))ns_if_addref(*aResult = NS_NewHTMLUnknownElement(nodeInfo.forget (), aFromParser)); | |||
| 10179 | } else { | |||
| 10180 | NS_IF_ADDREF(*aResult = nsXULElement::Construct(nodeInfo.forget()))ns_if_addref(*aResult = nsXULElement::Construct(nodeInfo.forget ())); | |||
| 10181 | } | |||
| 10182 | (*aResult)->SetDefined(false); | |||
| 10183 | } | |||
| 10184 | definition->mPrefixStack.RemoveLastElement(); | |||
| 10185 | return NS_OK; | |||
| 10186 | } | |||
| 10187 | ||||
| 10188 | // Step 6.2. | |||
| 10189 | if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML3)) { | |||
| 10190 | NS_IF_ADDREF(*aResult =ns_if_addref(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser )) | |||
| 10191 | NS_NewHTMLElement(nodeInfo.forget(), aFromParser))ns_if_addref(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser )); | |||
| 10192 | } else { | |||
| 10193 | NS_IF_ADDREF(*aResult = nsXULElement::Construct(nodeInfo.forget()))ns_if_addref(*aResult = nsXULElement::Construct(nodeInfo.forget ())); | |||
| 10194 | } | |||
| 10195 | (*aResult)->SetCustomElementData( | |||
| 10196 | MakeUnique<CustomElementData>(definition->mType)); | |||
| 10197 | nsContentUtils::EnqueueUpgradeReaction(*aResult, definition); | |||
| 10198 | return NS_OK; | |||
| 10199 | } | |||
| 10200 | ||||
| 10201 | if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML3)) { | |||
| 10202 | // Per the Custom Element specification, unknown tags that are valid custom | |||
| 10203 | // element names should be HTMLElement instead of HTMLUnknownElement. | |||
| 10204 | if (isCustomElementName) { | |||
| 10205 | NS_IF_ADDREF(*aResult =ns_if_addref(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser )) | |||
| 10206 | NS_NewHTMLElement(nodeInfo.forget(), aFromParser))ns_if_addref(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser )); | |||
| 10207 | } else { | |||
| 10208 | *aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take(); | |||
| 10209 | } | |||
| 10210 | } else { | |||
| 10211 | NS_IF_ADDREF(*aResult = nsXULElement::Construct(nodeInfo.forget()))ns_if_addref(*aResult = nsXULElement::Construct(nodeInfo.forget ())); | |||
| 10212 | } | |||
| 10213 | ||||
| 10214 | if (!*aResult) { | |||
| 10215 | return NS_ERROR_OUT_OF_MEMORY; | |||
| 10216 | } | |||
| 10217 | ||||
| 10218 | if (isCustomElement) { | |||
| 10219 | (*aResult)->SetCustomElementData(MakeUnique<CustomElementData>(typeAtom)); | |||
| 10220 | nsContentUtils::RegisterCallbackUpgradeElement(*aResult, typeAtom); | |||
| 10221 | } | |||
| 10222 | ||||
| 10223 | return NS_OK; | |||
| 10224 | } | |||
| 10225 | ||||
| 10226 | CustomElementRegistry* nsContentUtils::GetCustomElementRegistry( | |||
| 10227 | Document* aDoc) { | |||
| 10228 | 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" , 10228); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDoc" ")") ; do { *((volatile int*)__null) = 10228; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 10229 | ||||
| 10230 | if (!aDoc->GetDocShell()) { | |||
| 10231 | return nullptr; | |||
| 10232 | } | |||
| 10233 | ||||
| 10234 | nsPIDOMWindowInner* window = aDoc->GetInnerWindow(); | |||
| 10235 | if (!window) { | |||
| 10236 | return nullptr; | |||
| 10237 | } | |||
| 10238 | ||||
| 10239 | return window->CustomElements(); | |||
| 10240 | } | |||
| 10241 | ||||
| 10242 | /* static */ | |||
| 10243 | CustomElementDefinition* nsContentUtils::LookupCustomElementDefinition( | |||
| 10244 | Document* aDoc, nsAtom* aNameAtom, uint32_t aNameSpaceID, | |||
| 10245 | nsAtom* aTypeAtom) { | |||
| 10246 | if (aNameSpaceID != kNameSpaceID_XUL8 && aNameSpaceID != kNameSpaceID_XHTML3) { | |||
| 10247 | return nullptr; | |||
| 10248 | } | |||
| 10249 | ||||
| 10250 | RefPtr<CustomElementRegistry> registry = GetCustomElementRegistry(aDoc); | |||
| 10251 | if (!registry) { | |||
| 10252 | return nullptr; | |||
| 10253 | } | |||
| 10254 | ||||
| 10255 | return registry->LookupCustomElementDefinition(aNameAtom, aNameSpaceID, | |||
| 10256 | aTypeAtom); | |||
| 10257 | } | |||
| 10258 | ||||
| 10259 | /* static */ | |||
| 10260 | void nsContentUtils::RegisterCallbackUpgradeElement(Element* aElement, | |||
| 10261 | nsAtom* aTypeName) { | |||
| 10262 | 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" , 10262); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElement" ")" ); do { *((volatile int*)__null) = 10262; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 10263 | ||||
| 10264 | Document* doc = aElement->OwnerDoc(); | |||
| 10265 | CustomElementRegistry* registry = GetCustomElementRegistry(doc); | |||
| 10266 | if (registry) { | |||
| 10267 | registry->RegisterCallbackUpgradeElement(aElement, aTypeName); | |||
| 10268 | } | |||
| 10269 | } | |||
| 10270 | ||||
| 10271 | /* static */ | |||
| 10272 | void nsContentUtils::RegisterUnresolvedElement(Element* aElement, | |||
| 10273 | nsAtom* aTypeName) { | |||
| 10274 | 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" , 10274); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElement" ")" ); do { *((volatile int*)__null) = 10274; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 10275 | ||||
| 10276 | Document* doc = aElement->OwnerDoc(); | |||
| 10277 | CustomElementRegistry* registry = GetCustomElementRegistry(doc); | |||
| 10278 | if (registry) { | |||
| 10279 | registry->RegisterUnresolvedElement(aElement, aTypeName); | |||
| 10280 | } | |||
| 10281 | } | |||
| 10282 | ||||
| 10283 | /* static */ | |||
| 10284 | void nsContentUtils::UnregisterUnresolvedElement(Element* aElement) { | |||
| 10285 | 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" , 10285); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElement" ")" ); do { *((volatile int*)__null) = 10285; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 10286 | ||||
| 10287 | nsAtom* typeAtom = aElement->GetCustomElementData()->GetCustomElementType(); | |||
| 10288 | Document* doc = aElement->OwnerDoc(); | |||
| 10289 | CustomElementRegistry* registry = GetCustomElementRegistry(doc); | |||
| 10290 | if (registry) { | |||
| 10291 | registry->UnregisterUnresolvedElement(aElement, typeAtom); | |||
| 10292 | } | |||
| 10293 | } | |||
| 10294 | ||||
| 10295 | /* static */ | |||
| 10296 | void nsContentUtils::EnqueueUpgradeReaction( | |||
| 10297 | Element* aElement, CustomElementDefinition* aDefinition) { | |||
| 10298 | 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" , 10298); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElement" ")" ); do { *((volatile int*)__null) = 10298; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 10299 | ||||
| 10300 | Document* doc = aElement->OwnerDoc(); | |||
| 10301 | ||||
| 10302 | // No DocGroup means no custom element reactions stack. | |||
| 10303 | if (!doc->GetDocGroup()) { | |||
| 10304 | return; | |||
| 10305 | } | |||
| 10306 | ||||
| 10307 | CustomElementReactionsStack* stack = | |||
| 10308 | doc->GetDocGroup()->CustomElementReactionsStack(); | |||
| 10309 | stack->EnqueueUpgradeReaction(aElement, aDefinition); | |||
| 10310 | } | |||
| 10311 | ||||
| 10312 | /* static */ | |||
| 10313 | void nsContentUtils::EnqueueLifecycleCallback( | |||
| 10314 | ElementCallbackType aType, Element* aCustomElement, | |||
| 10315 | const LifecycleCallbackArgs& aArgs, CustomElementDefinition* aDefinition) { | |||
| 10316 | // No DocGroup means no custom element reactions stack. | |||
| 10317 | if (!aCustomElement->OwnerDoc()->GetDocGroup()) { | |||
| 10318 | return; | |||
| 10319 | } | |||
| 10320 | ||||
| 10321 | CustomElementRegistry::EnqueueLifecycleCallback(aType, aCustomElement, aArgs, | |||
| 10322 | aDefinition); | |||
| 10323 | } | |||
| 10324 | ||||
| 10325 | /* static */ | |||
| 10326 | CustomElementFormValue nsContentUtils::ConvertToCustomElementFormValue( | |||
| 10327 | const Nullable<OwningFileOrUSVStringOrFormData>& aState) { | |||
| 10328 | if (aState.IsNull()) { | |||
| 10329 | return void_t{}; | |||
| 10330 | } | |||
| 10331 | const auto& state = aState.Value(); | |||
| 10332 | if (state.IsFile()) { | |||
| 10333 | RefPtr<BlobImpl> impl = state.GetAsFile()->Impl(); | |||
| 10334 | return {std::move(impl)}; | |||
| 10335 | } | |||
| 10336 | if (state.IsUSVString()) { | |||
| 10337 | return state.GetAsUSVString(); | |||
| 10338 | } | |||
| 10339 | return state.GetAsFormData()->ConvertToCustomElementFormValue(); | |||
| 10340 | } | |||
| 10341 | ||||
| 10342 | /* static */ | |||
| 10343 | Nullable<OwningFileOrUSVStringOrFormData> | |||
| 10344 | nsContentUtils::ExtractFormAssociatedCustomElementValue( | |||
| 10345 | nsIGlobalObject* aGlobal, | |||
| 10346 | const mozilla::dom::CustomElementFormValue& aCEValue) { | |||
| 10347 | 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" , 10347); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGlobal" ")" ); do { *((volatile int*)__null) = 10347; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 10348 | ||||
| 10349 | OwningFileOrUSVStringOrFormData value; | |||
| 10350 | switch (aCEValue.type()) { | |||
| 10351 | case CustomElementFormValue::TBlobImpl: { | |||
| 10352 | RefPtr<File> file = File::Create(aGlobal, aCEValue.get_BlobImpl()); | |||
| 10353 | if (NS_WARN_IF(!file)NS_warn_if_impl(!file, "!file", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp" , 10353)) { | |||
| 10354 | return {}; | |||
| 10355 | } | |||
| 10356 | value.SetAsFile() = file; | |||
| 10357 | } break; | |||
| 10358 | ||||
| 10359 | case CustomElementFormValue::TnsString: | |||
| 10360 | value.SetAsUSVString() = aCEValue.get_nsString(); | |||
| 10361 | break; | |||
| 10362 | ||||
| 10363 | case CustomElementFormValue::TArrayOfFormDataTuple: { | |||
| 10364 | const auto& array = aCEValue.get_ArrayOfFormDataTuple(); | |||
| 10365 | auto formData = MakeRefPtr<FormData>(); | |||
| 10366 | ||||
| 10367 | for (auto i = 0ul; i < array.Length(); ++i) { | |||
| 10368 | const auto& item = array.ElementAt(i); | |||
| 10369 | switch (item.value().type()) { | |||
| 10370 | case FormDataValue::TnsString: | |||
| 10371 | formData->AddNameValuePair(item.name(), | |||
| 10372 | item.value().get_nsString()); | |||
| 10373 | break; | |||
| 10374 | ||||
| 10375 | case FormDataValue::TBlobImpl: { | |||
| 10376 | auto blobImpl = item.value().get_BlobImpl(); | |||
| 10377 | auto* blob = Blob::Create(aGlobal, blobImpl); | |||
| 10378 | formData->AddNameBlobPair(item.name(), blob); | |||
| 10379 | } break; | |||
| 10380 | ||||
| 10381 | default: | |||
| 10382 | continue; | |||
| 10383 | } | |||
| 10384 | } | |||
| 10385 | ||||
| 10386 | value.SetAsFormData() = formData; | |||
| 10387 | } break; | |||
| 10388 | case CustomElementFormValue::Tvoid_t: | |||
| 10389 | return {}; | |||
| 10390 | default: | |||
| 10391 | 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" , 10391); | |||
| 10392 | return {}; | |||
| 10393 | } | |||
| 10394 | return value; | |||
| 10395 | } | |||
| 10396 | ||||
| 10397 | /* static */ | |||
| 10398 | void nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo( | |||
| 10399 | Document* aDocument, nsTArray<nsIContent*>& aElements) { | |||
| 10400 | 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" , 10400); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocument" ")"); do { *((volatile int*)__null) = 10400; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 10401 | #ifdef DEBUG1 | |||
| 10402 | size_t oldLength = aElements.Length(); | |||
| 10403 | #endif | |||
| 10404 | ||||
| 10405 | if (PresShell* presShell = aDocument->GetPresShell()) { | |||
| 10406 | if (ScrollContainerFrame* rootScrollContainerFrame = | |||
| 10407 | presShell->GetRootScrollContainerFrame()) { | |||
| 10408 | rootScrollContainerFrame->AppendAnonymousContentTo(aElements, 0); | |||
| 10409 | } | |||
| 10410 | if (nsCanvasFrame* canvasFrame = presShell->GetCanvasFrame()) { | |||
| 10411 | canvasFrame->AppendAnonymousContentTo(aElements, 0); | |||
| 10412 | } | |||
| 10413 | } | |||
| 10414 | ||||
| 10415 | #ifdef DEBUG1 | |||
| 10416 | for (size_t i = oldLength; i < aElements.Length(); i++) { | |||
| 10417 | 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" , 10419); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElements[i]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent)" ") (" "Someone here has lied, or missed to flag the node" ")" ); do { *((volatile int*)__null) = 10419; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) | |||
| 10418 | 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" , 10419); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElements[i]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent)" ") (" "Someone here has lied, or missed to flag the node" ")" ); do { *((volatile int*)__null) = 10419; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) | |||
| 10419 | "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" , 10419); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElements[i]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent)" ") (" "Someone here has lied, or missed to flag the node" ")" ); do { *((volatile int*)__null) = 10419; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 10420 | } | |||
| 10421 | #endif | |||
| 10422 | } | |||
| 10423 | ||||
| 10424 | static void AppendNativeAnonymousChildrenFromFrame(nsIFrame* aFrame, | |||
| 10425 | nsTArray<nsIContent*>& aKids, | |||
| 10426 | uint32_t aFlags) { | |||
| 10427 | if (nsIAnonymousContentCreator* ac = do_QueryFrame(aFrame)) { | |||
| 10428 | ac->AppendAnonymousContentTo(aKids, aFlags); | |||
| 10429 | } | |||
| 10430 | } | |||
| 10431 | ||||
| 10432 | /* static */ | |||
| 10433 | void nsContentUtils::AppendNativeAnonymousChildren(const nsIContent* aContent, | |||
| 10434 | nsTArray<nsIContent*>& aKids, | |||
| 10435 | uint32_t aFlags) { | |||
| 10436 | if (aContent->MayHaveAnonymousChildren()) { | |||
| 10437 | if (nsIFrame* primaryFrame = aContent->GetPrimaryFrame()) { | |||
| 10438 | // NAC created by the element's primary frame. | |||
| 10439 | AppendNativeAnonymousChildrenFromFrame(primaryFrame, aKids, aFlags); | |||
| 10440 | ||||
| 10441 | // NAC created by any other non-primary frames for the element. | |||
| 10442 | AutoTArray<nsIFrame::OwnedAnonBox, 8> ownedAnonBoxes; | |||
| 10443 | primaryFrame->AppendOwnedAnonBoxes(ownedAnonBoxes); | |||
| 10444 | for (nsIFrame::OwnedAnonBox& box : ownedAnonBoxes) { | |||
| 10445 | 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" , 10445); AnnotateMozCrashReason("MOZ_ASSERT" "(" "box.mAnonBoxFrame->GetContent() == aContent" ")"); do { *((volatile int*)__null) = 10445; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 10446 | AppendNativeAnonymousChildrenFromFrame(box.mAnonBoxFrame, aKids, | |||
| 10447 | aFlags); | |||
| 10448 | } | |||
| 10449 | } | |||
| 10450 | ||||
| 10451 | // View transition pseudos. | |||
| 10452 | if (aContent->IsRootElement()) { | |||
| 10453 | if (auto* vt = aContent->OwnerDoc()->GetActiveViewTransition()) { | |||
| 10454 | if (auto* root = vt->GetRoot()) { | |||
| 10455 | aKids.AppendElement(root); | |||
| 10456 | } | |||
| 10457 | } | |||
| 10458 | } | |||
| 10459 | ||||
| 10460 | // Get manually created NAC (editor resize handles, etc.). | |||
| 10461 | if (auto nac = static_cast<ManualNACArray*>( | |||
| 10462 | aContent->GetProperty(nsGkAtoms::manualNACProperty))) { | |||
| 10463 | aKids.AppendElements(*nac); | |||
| 10464 | } | |||
| 10465 | } | |||
| 10466 | ||||
| 10467 | // The root scroll frame is not the primary frame of the root element. | |||
| 10468 | // Detect and handle this case. | |||
| 10469 | if (!(aFlags & nsIContent::eSkipDocumentLevelNativeAnonymousContent) && | |||
| 10470 | aContent->IsRootElement()) { | |||
| 10471 | AppendDocumentLevelNativeAnonymousContentTo(aContent->OwnerDoc(), aKids); | |||
| 10472 | } | |||
| 10473 | } | |||
| 10474 | ||||
| 10475 | bool nsContentUtils::IsImageAvailable(nsIContent* aLoadingNode, nsIURI* aURI, | |||
| 10476 | nsIPrincipal* aDefaultTriggeringPrincipal, | |||
| 10477 | CORSMode aCORSMode) { | |||
| 10478 | nsCOMPtr<nsIPrincipal> triggeringPrincipal; | |||
| 10479 | QueryTriggeringPrincipal(aLoadingNode, aDefaultTriggeringPrincipal, | |||
| 10480 | getter_AddRefs(triggeringPrincipal)); | |||
| 10481 | 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" , 10481); AnnotateMozCrashReason("MOZ_ASSERT" "(" "triggeringPrincipal" ")"); do { *((volatile int*)__null) = 10481; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 10482 | ||||
| 10483 | Document* doc = aLoadingNode->OwnerDoc(); | |||
| 10484 | return IsImageAvailable(aURI, triggeringPrincipal, aCORSMode, doc); | |||
| 10485 | } | |||
| 10486 | ||||
| 10487 | bool nsContentUtils::IsImageAvailable(nsIURI* aURI, | |||
| 10488 | nsIPrincipal* aTriggeringPrincipal, | |||
| 10489 | CORSMode aCORSMode, Document* aDoc) { | |||
| 10490 | imgLoader* imgLoader = GetImgLoaderForDocument(aDoc); | |||
| 10491 | return imgLoader->IsImageAvailable(aURI, aTriggeringPrincipal, aCORSMode, | |||
| 10492 | aDoc); | |||
| 10493 | } | |||
| 10494 | ||||
| 10495 | /* static */ | |||
| 10496 | bool nsContentUtils::QueryTriggeringPrincipal( | |||
| 10497 | nsIContent* aLoadingNode, nsIPrincipal* aDefaultPrincipal, | |||
| 10498 | nsIPrincipal** aTriggeringPrincipal) { | |||
| 10499 | 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" , 10499); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLoadingNode" ")"); do { *((volatile int*)__null) = 10499; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 10500 | 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" , 10500); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTriggeringPrincipal" ")"); do { *((volatile int*)__null) = 10500; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 10501 | ||||
| 10502 | bool result = false; | |||
| 10503 | nsCOMPtr<nsIPrincipal> loadingPrincipal = aDefaultPrincipal; | |||
| 10504 | if (!loadingPrincipal) { | |||
| 10505 | loadingPrincipal = aLoadingNode->NodePrincipal(); | |||
| 10506 | } | |||
| 10507 | ||||
| 10508 | // If aLoadingNode is content, bail out early. | |||
| 10509 | if (!aLoadingNode->NodePrincipal()->IsSystemPrincipal()) { | |||
| 10510 | loadingPrincipal.forget(aTriggeringPrincipal); | |||
| 10511 | return result; | |||
| 10512 | } | |||
| 10513 | ||||
| 10514 | nsAutoString loadingStr; | |||
| 10515 | if (aLoadingNode->IsElement()) { | |||
| 10516 | aLoadingNode->AsElement()->GetAttr( | |||
| 10517 | kNameSpaceID_None, nsGkAtoms::triggeringprincipal, loadingStr); | |||
| 10518 | } | |||
| 10519 | ||||
| 10520 | // Fall back if 'triggeringprincipal' isn't specified, | |||
| 10521 | if (loadingStr.IsEmpty()) { | |||
| 10522 | loadingPrincipal.forget(aTriggeringPrincipal); | |||
| 10523 | return result; | |||
| 10524 | } | |||
| 10525 | ||||
| 10526 | nsCString binary; | |||
| 10527 | nsCOMPtr<nsIPrincipal> serializedPrin = | |||
| 10528 | BasePrincipal::FromJSON(NS_ConvertUTF16toUTF8(loadingStr)); | |||
| 10529 | if (serializedPrin) { | |||
| 10530 | result = true; | |||
| 10531 | serializedPrin.forget(aTriggeringPrincipal); | |||
| 10532 | } | |||
| 10533 | ||||
| 10534 | if (!result) { | |||
| 10535 | // Fallback if the deserialization is failed. | |||
| 10536 | loadingPrincipal.forget(aTriggeringPrincipal); | |||
| 10537 | } | |||
| 10538 | ||||
| 10539 | return result; | |||
| 10540 | } | |||
| 10541 | ||||
| 10542 | /* static */ | |||
| 10543 | void nsContentUtils::GetContentPolicyTypeForUIImageLoading( | |||
| 10544 | nsIContent* aLoadingNode, nsIPrincipal** aTriggeringPrincipal, | |||
| 10545 | nsContentPolicyType& aContentPolicyType, uint64_t* aRequestContextID) { | |||
| 10546 | 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" , 10546); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRequestContextID" ")"); do { *((volatile int*)__null) = 10546; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 10547 | ||||
| 10548 | bool result = QueryTriggeringPrincipal(aLoadingNode, aTriggeringPrincipal); | |||
| 10549 | if (result) { | |||
| 10550 | // Set the content policy type to TYPE_INTERNAL_IMAGE_FAVICON for | |||
| 10551 | // indicating it's a favicon loading. | |||
| 10552 | aContentPolicyType = nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON; | |||
| 10553 | ||||
| 10554 | nsAutoString requestContextID; | |||
| 10555 | if (aLoadingNode->IsElement()) { | |||
| 10556 | aLoadingNode->AsElement()->GetAttr( | |||
| 10557 | kNameSpaceID_None, nsGkAtoms::requestcontextid, requestContextID); | |||
| 10558 | } | |||
| 10559 | nsresult rv; | |||
| 10560 | int64_t val = requestContextID.ToInteger64(&rv); | |||
| 10561 | *aRequestContextID = NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) ? val : 0; | |||
| 10562 | } else { | |||
| 10563 | aContentPolicyType = nsIContentPolicy::TYPE_INTERNAL_IMAGE; | |||
| 10564 | } | |||
| 10565 | } | |||
| 10566 | ||||
| 10567 | /* static */ | |||
| 10568 | nsresult nsContentUtils::CreateJSValueFromSequenceOfObject( | |||
| 10569 | JSContext* aCx, const Sequence<JSObject*>& aTransfer, | |||
| 10570 | JS::MutableHandle<JS::Value> aValue) { | |||
| 10571 | if (aTransfer.IsEmpty()) { | |||
| 10572 | return NS_OK; | |||
| 10573 | } | |||
| 10574 | ||||
| 10575 | JS::Rooted<JSObject*> array(aCx, JS::NewArrayObject(aCx, aTransfer.Length())); | |||
| 10576 | if (!array) { | |||
| 10577 | return NS_ERROR_OUT_OF_MEMORY; | |||
| 10578 | } | |||
| 10579 | ||||
| 10580 | for (uint32_t i = 0; i < aTransfer.Length(); ++i) { | |||
| 10581 | JS::Rooted<JSObject*> object(aCx, aTransfer[i]); | |||
| 10582 | if (!object) { | |||
| 10583 | continue; | |||
| 10584 | } | |||
| 10585 | ||||
| 10586 | 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" , 10587) | |||
| 10587 | !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" , 10587)) { | |||
| 10588 | return NS_ERROR_OUT_OF_MEMORY; | |||
| 10589 | } | |||
| 10590 | } | |||
| 10591 | ||||
| 10592 | aValue.setObject(*array); | |||
| 10593 | return NS_OK; | |||
| 10594 | } | |||
| 10595 | ||||
| 10596 | /* static */ | |||
| 10597 | void nsContentUtils::StructuredClone(JSContext* aCx, nsIGlobalObject* aGlobal, | |||
| 10598 | JS::Handle<JS::Value> aValue, | |||
| 10599 | const StructuredSerializeOptions& aOptions, | |||
| 10600 | JS::MutableHandle<JS::Value> aRetval, | |||
| 10601 | ErrorResult& aError) { | |||
| 10602 | JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue()); | |||
| 10603 | aError = nsContentUtils::CreateJSValueFromSequenceOfObject( | |||
| 10604 | aCx, aOptions.mTransfer, &transferArray); | |||
| 10605 | 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" , 10605)) { | |||
| 10606 | return; | |||
| 10607 | } | |||
| 10608 | ||||
| 10609 | JS::CloneDataPolicy clonePolicy; | |||
| 10610 | // We are definitely staying in the same agent cluster. | |||
| 10611 | clonePolicy.allowIntraClusterClonableSharedObjects(); | |||
| 10612 | if (aGlobal->IsSharedMemoryAllowed()) { | |||
| 10613 | clonePolicy.allowSharedMemoryObjects(); | |||
| 10614 | } | |||
| 10615 | ||||
| 10616 | StructuredCloneHolder holder(StructuredCloneHolder::CloningSupported, | |||
| 10617 | StructuredCloneHolder::TransferringSupported, | |||
| 10618 | JS::StructuredCloneScope::SameProcess); | |||
| 10619 | holder.Write(aCx, aValue, transferArray, clonePolicy, aError); | |||
| 10620 | 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" , 10620)) { | |||
| 10621 | return; | |||
| 10622 | } | |||
| 10623 | ||||
| 10624 | holder.Read(aGlobal, aCx, aRetval, clonePolicy, aError); | |||
| 10625 | 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" , 10625)) { | |||
| 10626 | return; | |||
| 10627 | } | |||
| 10628 | ||||
| 10629 | nsTArray<RefPtr<MessagePort>> ports = holder.TakeTransferredPorts(); | |||
| 10630 | Unused << ports; | |||
| 10631 | } | |||
| 10632 | ||||
| 10633 | /* static */ | |||
| 10634 | bool nsContentUtils::ShouldBlockReservedKeys(WidgetKeyboardEvent* aKeyEvent) { | |||
| 10635 | nsCOMPtr<nsIPrincipal> principal; | |||
| 10636 | RefPtr<Element> targetElement = | |||
| 10637 | Element::FromEventTargetOrNull(aKeyEvent->mOriginalTarget); | |||
| 10638 | nsCOMPtr<nsIBrowser> targetBrowser; | |||
| 10639 | if (targetElement) { | |||
| 10640 | targetBrowser = targetElement->AsBrowser(); | |||
| 10641 | } | |||
| 10642 | bool isRemoteBrowser = false; | |||
| 10643 | if (targetBrowser) { | |||
| 10644 | targetBrowser->GetIsRemoteBrowser(&isRemoteBrowser); | |||
| 10645 | } | |||
| 10646 | ||||
| 10647 | if (isRemoteBrowser) { | |||
| 10648 | targetBrowser->GetContentPrincipal(getter_AddRefs(principal)); | |||
| 10649 | return principal ? nsContentUtils::IsSitePermDeny(principal, "shortcuts"_ns) | |||
| 10650 | : false; | |||
| 10651 | } | |||
| 10652 | ||||
| 10653 | if (targetElement) { | |||
| 10654 | Document* doc = targetElement->GetUncomposedDoc(); | |||
| 10655 | if (doc) { | |||
| 10656 | RefPtr<WindowContext> wc = doc->GetWindowContext(); | |||
| 10657 | if (wc) { | |||
| 10658 | return wc->TopWindowContext()->GetShortcutsPermission() == | |||
| 10659 | nsIPermissionManager::DENY_ACTION; | |||
| 10660 | } | |||
| 10661 | } | |||
| 10662 | } | |||
| 10663 | ||||
| 10664 | return false; | |||
| 10665 | } | |||
| 10666 | ||||
| 10667 | /** | |||
| 10668 | * Checks whether the given type is a supported document type for | |||
| 10669 | * loading within the nsObjectLoadingContent specified by aContent. | |||
| 10670 | * | |||
| 10671 | * NOTE Helper method for nsContentUtils::HtmlObjectContentTypeForMIMEType. | |||
| 10672 | * NOTE Does not take content policy or capabilities into account | |||
| 10673 | */ | |||
| 10674 | static bool HtmlObjectContentSupportsDocument(const nsCString& aMimeType) { | |||
| 10675 | nsCOMPtr<nsIWebNavigationInfo> info( | |||
| 10676 | do_GetService(NS_WEBNAVIGATION_INFO_CONTRACTID"@mozilla.org/webnavigation-info;1")); | |||
| 10677 | if (!info) { | |||
| 10678 | return false; | |||
| 10679 | } | |||
| 10680 | ||||
| 10681 | uint32_t supported; | |||
| 10682 | nsresult rv = info->IsTypeSupported(aMimeType, &supported); | |||
| 10683 | ||||
| 10684 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 10685 | return false; | |||
| 10686 | } | |||
| 10687 | ||||
| 10688 | if (supported != nsIWebNavigationInfo::UNSUPPORTED) { | |||
| 10689 | // Don't want to support plugins as documents | |||
| 10690 | return supported != nsIWebNavigationInfo::FALLBACK; | |||
| 10691 | } | |||
| 10692 | ||||
| 10693 | // Try a stream converter | |||
| 10694 | // NOTE: We treat any type we can convert from as a supported type. If a | |||
| 10695 | // type is not actually supported, the URI loader will detect that and | |||
| 10696 | // return an error, and we'll fallback. | |||
| 10697 | nsCOMPtr<nsIStreamConverterService> convServ = | |||
| 10698 | do_GetService("@mozilla.org/streamConverters;1"); | |||
| 10699 | bool canConvert = false; | |||
| 10700 | if (convServ) { | |||
| 10701 | rv = convServ->CanConvert(aMimeType.get(), "*/*", &canConvert); | |||
| 10702 | } | |||
| 10703 | return NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && canConvert; | |||
| 10704 | } | |||
| 10705 | ||||
| 10706 | /* static */ | |||
| 10707 | uint32_t nsContentUtils::HtmlObjectContentTypeForMIMEType( | |||
| 10708 | const nsCString& aMIMEType, bool aIsSandboxed) { | |||
| 10709 | if (aMIMEType.IsEmpty()) { | |||
| 10710 | return nsIObjectLoadingContent::TYPE_FALLBACK; | |||
| 10711 | } | |||
| 10712 | ||||
| 10713 | if (imgLoader::SupportImageWithMimeType(aMIMEType)) { | |||
| 10714 | return nsIObjectLoadingContent::TYPE_DOCUMENT; | |||
| 10715 | } | |||
| 10716 | ||||
| 10717 | // Faking support of the PDF content as a document for EMBED tags | |||
| 10718 | // when internal PDF viewer is enabled. | |||
| 10719 | if (aMIMEType.LowerCaseEqualsLiteral(APPLICATION_PDF"application/pdf") && IsPDFJSEnabled()) { | |||
| 10720 | // Sandboxed iframes are just never allowed to display plugins. In the | |||
| 10721 | // modern world, this just means "application/pdf". | |||
| 10722 | return aIsSandboxed ? nsIObjectLoadingContent::TYPE_FALLBACK | |||
| 10723 | : nsIObjectLoadingContent::TYPE_DOCUMENT; | |||
| 10724 | } | |||
| 10725 | ||||
| 10726 | if (HtmlObjectContentSupportsDocument(aMIMEType)) { | |||
| 10727 | return nsIObjectLoadingContent::TYPE_DOCUMENT; | |||
| 10728 | } | |||
| 10729 | ||||
| 10730 | return nsIObjectLoadingContent::TYPE_FALLBACK; | |||
| 10731 | } | |||
| 10732 | ||||
| 10733 | /* static */ | |||
| 10734 | bool nsContentUtils::IsLocalRefURL(const nsAString& aString) { | |||
| 10735 | return !aString.IsEmpty() && aString[0] == '#'; | |||
| 10736 | } | |||
| 10737 | ||||
| 10738 | // We use only 53 bits for the ID so that it can be converted to and from a JS | |||
| 10739 | // value without loss of precision. The upper bits of the ID hold the process | |||
| 10740 | // ID. The lower bits identify the object itself. | |||
| 10741 | static constexpr uint64_t kIdTotalBits = 53; | |||
| 10742 | static constexpr uint64_t kIdProcessBits = 22; | |||
| 10743 | static constexpr uint64_t kIdBits = kIdTotalBits - kIdProcessBits; | |||
| 10744 | ||||
| 10745 | /* static */ | |||
| 10746 | uint64_t nsContentUtils::GenerateProcessSpecificId(uint64_t aId) { | |||
| 10747 | uint64_t processId = 0; | |||
| 10748 | if (XRE_IsContentProcess()) { | |||
| 10749 | ContentChild* cc = ContentChild::GetSingleton(); | |||
| 10750 | processId = cc->GetID(); | |||
| 10751 | } | |||
| 10752 | ||||
| 10753 | 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" , 10753); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "processId < (uint64_t(1) << kIdProcessBits)" ")"); do { *((volatile int*)__null) = 10753; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 10754 | uint64_t processBits = processId & ((uint64_t(1) << kIdProcessBits) - 1); | |||
| 10755 | ||||
| 10756 | uint64_t id = aId; | |||
| 10757 | 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" , 10757); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "id < (uint64_t(1) << kIdBits)" ")"); do { *((volatile int*)__null) = 10757; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 10758 | uint64_t bits = id & ((uint64_t(1) << kIdBits) - 1); | |||
| 10759 | ||||
| 10760 | return (processBits << kIdBits) | bits; | |||
| 10761 | } | |||
| 10762 | ||||
| 10763 | /* static */ | |||
| 10764 | std::tuple<uint64_t, uint64_t> nsContentUtils::SplitProcessSpecificId( | |||
| 10765 | uint64_t aId) { | |||
| 10766 | return {aId >> kIdBits, aId & ((uint64_t(1) << kIdBits) - 1)}; | |||
| 10767 | } | |||
| 10768 | ||||
| 10769 | // Next process-local Tab ID. | |||
| 10770 | static uint64_t gNextTabId = 0; | |||
| 10771 | ||||
| 10772 | /* static */ | |||
| 10773 | uint64_t nsContentUtils::GenerateTabId() { | |||
| 10774 | return GenerateProcessSpecificId(++gNextTabId); | |||
| 10775 | } | |||
| 10776 | ||||
| 10777 | // Next process-local Browser ID. | |||
| 10778 | static uint64_t gNextBrowserId = 0; | |||
| 10779 | ||||
| 10780 | /* static */ | |||
| 10781 | uint64_t nsContentUtils::GenerateBrowserId() { | |||
| 10782 | return GenerateProcessSpecificId(++gNextBrowserId); | |||
| 10783 | } | |||
| 10784 | ||||
| 10785 | // Next process-local Browsing Context ID. | |||
| 10786 | static uint64_t gNextBrowsingContextId = 0; | |||
| 10787 | ||||
| 10788 | /* static */ | |||
| 10789 | uint64_t nsContentUtils::GenerateBrowsingContextId() { | |||
| 10790 | return GenerateProcessSpecificId(++gNextBrowsingContextId); | |||
| 10791 | } | |||
| 10792 | ||||
| 10793 | // Next process-local Window ID. | |||
| 10794 | static uint64_t gNextWindowId = 0; | |||
| 10795 | ||||
| 10796 | /* static */ | |||
| 10797 | uint64_t nsContentUtils::GenerateWindowId() { | |||
| 10798 | return GenerateProcessSpecificId(++gNextWindowId); | |||
| 10799 | } | |||
| 10800 | ||||
| 10801 | // Next process-local load. | |||
| 10802 | static Atomic<uint64_t> gNextLoadIdentifier(0); | |||
| 10803 | ||||
| 10804 | /* static */ | |||
| 10805 | uint64_t nsContentUtils::GenerateLoadIdentifier() { | |||
| 10806 | return GenerateProcessSpecificId(++gNextLoadIdentifier); | |||
| 10807 | } | |||
| 10808 | ||||
| 10809 | /* static */ | |||
| 10810 | bool nsContentUtils::GetUserIsInteracting() { | |||
| 10811 | return UserInteractionObserver::sUserActive; | |||
| 10812 | } | |||
| 10813 | ||||
| 10814 | /* static */ | |||
| 10815 | bool nsContentUtils::GetSourceMapURL(nsIHttpChannel* aChannel, | |||
| 10816 | nsACString& aResult) { | |||
| 10817 | nsresult rv = aChannel->GetResponseHeader("SourceMap"_ns, aResult); | |||
| 10818 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 10819 | rv = aChannel->GetResponseHeader("X-SourceMap"_ns, aResult); | |||
| 10820 | } | |||
| 10821 | return NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))); | |||
| 10822 | } | |||
| 10823 | ||||
| 10824 | /* static */ | |||
| 10825 | bool nsContentUtils::IsMessageInputEvent(const IPC::Message& aMsg) { | |||
| 10826 | if ((aMsg.type() & mozilla::dom::PBrowser::PBrowserStart) == | |||
| 10827 | mozilla::dom::PBrowser::PBrowserStart) { | |||
| 10828 | switch (aMsg.type()) { | |||
| 10829 | case mozilla::dom::PBrowser::Msg_RealMouseMoveEvent__ID: | |||
| 10830 | case mozilla::dom::PBrowser::Msg_RealMouseButtonEvent__ID: | |||
| 10831 | case mozilla::dom::PBrowser::Msg_RealMouseEnterExitWidgetEvent__ID: | |||
| 10832 | case mozilla::dom::PBrowser::Msg_RealKeyEvent__ID: | |||
| 10833 | case mozilla::dom::PBrowser::Msg_MouseWheelEvent__ID: | |||
| 10834 | case mozilla::dom::PBrowser::Msg_RealTouchEvent__ID: | |||
| 10835 | case mozilla::dom::PBrowser::Msg_RealTouchMoveEvent__ID: | |||
| 10836 | case mozilla::dom::PBrowser::Msg_RealDragEvent__ID: | |||
| 10837 | case mozilla::dom::PBrowser::Msg_UpdateDimensions__ID: | |||
| 10838 | return true; | |||
| 10839 | } | |||
| 10840 | } | |||
| 10841 | return false; | |||
| 10842 | } | |||
| 10843 | ||||
| 10844 | /* static */ | |||
| 10845 | bool nsContentUtils::IsMessageCriticalInputEvent(const IPC::Message& aMsg) { | |||
| 10846 | if ((aMsg.type() & mozilla::dom::PBrowser::PBrowserStart) == | |||
| 10847 | mozilla::dom::PBrowser::PBrowserStart) { | |||
| 10848 | switch (aMsg.type()) { | |||
| 10849 | case mozilla::dom::PBrowser::Msg_RealMouseButtonEvent__ID: | |||
| 10850 | case mozilla::dom::PBrowser::Msg_RealKeyEvent__ID: | |||
| 10851 | case mozilla::dom::PBrowser::Msg_MouseWheelEvent__ID: | |||
| 10852 | case mozilla::dom::PBrowser::Msg_RealTouchEvent__ID: | |||
| 10853 | case mozilla::dom::PBrowser::Msg_RealDragEvent__ID: | |||
| 10854 | return true; | |||
| 10855 | } | |||
| 10856 | } | |||
| 10857 | return false; | |||
| 10858 | } | |||
| 10859 | ||||
| 10860 | static const char* kUserInteractionInactive = "user-interaction-inactive"; | |||
| 10861 | static const char* kUserInteractionActive = "user-interaction-active"; | |||
| 10862 | ||||
| 10863 | void nsContentUtils::UserInteractionObserver::Init() { | |||
| 10864 | // Listen for the observer messages from EventStateManager which are telling | |||
| 10865 | // us whether or not the user is interacting. | |||
| 10866 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); | |||
| 10867 | obs->AddObserver(this, kUserInteractionInactive, false); | |||
| 10868 | obs->AddObserver(this, kUserInteractionActive, false); | |||
| 10869 | ||||
| 10870 | // We can't register ourselves as an annotator yet, as the | |||
| 10871 | // BackgroundHangMonitor hasn't started yet. It will have started by the | |||
| 10872 | // time we have the chance to spin the event loop. | |||
| 10873 | RefPtr<UserInteractionObserver> self = this; | |||
| 10874 | NS_DispatchToMainThread(NS_NewRunnableFunction( | |||
| 10875 | "nsContentUtils::UserInteractionObserver::Init", | |||
| 10876 | [=]() { BackgroundHangMonitor::RegisterAnnotator(*self); })); | |||
| 10877 | } | |||
| 10878 | ||||
| 10879 | void nsContentUtils::UserInteractionObserver::Shutdown() { | |||
| 10880 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); | |||
| 10881 | if (obs) { | |||
| 10882 | obs->RemoveObserver(this, kUserInteractionInactive); | |||
| 10883 | obs->RemoveObserver(this, kUserInteractionActive); | |||
| 10884 | } | |||
| 10885 | ||||
| 10886 | BackgroundHangMonitor::UnregisterAnnotator(*this); | |||
| 10887 | } | |||
| 10888 | ||||
| 10889 | /** | |||
| 10890 | * NB: This function is always called by the BackgroundHangMonitor thread. | |||
| 10891 | * Plan accordingly | |||
| 10892 | */ | |||
| 10893 | void nsContentUtils::UserInteractionObserver::AnnotateHang( | |||
| 10894 | BackgroundHangAnnotations& aAnnotations) { | |||
| 10895 | // NOTE: Only annotate the hang report if the user is known to be interacting. | |||
| 10896 | if (sUserActive) { | |||
| 10897 | aAnnotations.AddAnnotation(u"UserInteracting"_ns, true); | |||
| 10898 | } | |||
| 10899 | } | |||
| 10900 | ||||
| 10901 | NS_IMETHODIMPnsresult | |||
| 10902 | nsContentUtils::UserInteractionObserver::Observe(nsISupports* aSubject, | |||
| 10903 | const char* aTopic, | |||
| 10904 | const char16_t* aData) { | |||
| 10905 | if (!strcmp(aTopic, kUserInteractionInactive)) { | |||
| 10906 | if (sUserActive && XRE_IsParentProcess()) { | |||
| 10907 | glean::RecordPowerMetrics(); | |||
| 10908 | } | |||
| 10909 | sUserActive = false; | |||
| 10910 | } else if (!strcmp(aTopic, kUserInteractionActive)) { | |||
| 10911 | if (!sUserActive && XRE_IsParentProcess()) { | |||
| 10912 | glean::RecordPowerMetrics(); | |||
| 10913 | ||||
| 10914 | nsCOMPtr<nsIUserIdleServiceInternal> idleService = | |||
| 10915 | do_GetService("@mozilla.org/widget/useridleservice;1"); | |||
| 10916 | if (idleService) { | |||
| 10917 | idleService->ResetIdleTimeOut(0); | |||
| 10918 | } | |||
| 10919 | } | |||
| 10920 | ||||
| 10921 | sUserActive = true; | |||
| 10922 | } else { | |||
| 10923 | 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" , 10923); | |||
| 10924 | } | |||
| 10925 | return NS_OK; | |||
| 10926 | } | |||
| 10927 | ||||
| 10928 | Atomic<bool> nsContentUtils::UserInteractionObserver::sUserActive(false); | |||
| 10929 | 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" , 10929); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 10929; __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" , 10929); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsContentUtils::UserInteractionObserver\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 10929; __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" , 10929); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 10929 ; __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" , 10929); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsContentUtils::UserInteractionObserver\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 10929; __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" , 10929); 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(std::size(table ) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } | |||
| 10930 | ||||
| 10931 | /* static */ | |||
| 10932 | bool nsContentUtils::IsSpecialName(const nsAString& aName) { | |||
| 10933 | return aName.LowerCaseEqualsLiteral("_blank") || | |||
| 10934 | aName.LowerCaseEqualsLiteral("_top") || | |||
| 10935 | aName.LowerCaseEqualsLiteral("_parent") || | |||
| 10936 | aName.LowerCaseEqualsLiteral("_self"); | |||
| 10937 | } | |||
| 10938 | ||||
| 10939 | /* static */ | |||
| 10940 | bool nsContentUtils::IsOverridingWindowName(const nsAString& aName) { | |||
| 10941 | return !aName.IsEmpty() && !IsSpecialName(aName); | |||
| 10942 | } | |||
| 10943 | ||||
| 10944 | // Unfortunately, we can't unwrap an IDL object using only a concrete type. | |||
| 10945 | // We need to calculate type data based on the IDL typename. Which means | |||
| 10946 | // wrapping our templated function in a macro. | |||
| 10947 | #define EXTRACT_EXN_VALUES(T, ...) \ | |||
| 10948 | ExtractExceptionValues<mozilla::dom::prototypes::id::T, \ | |||
| 10949 | T##_Binding::NativeType, T>(__VA_ARGS__) \ | |||
| 10950 | .isOk() | |||
| 10951 | ||||
| 10952 | template <prototypes::ID PrototypeID, class NativeType, typename T> | |||
| 10953 | static Result<Ok, nsresult> ExtractExceptionValues( | |||
| 10954 | JSContext* aCx, JS::Handle<JSObject*> aObj, nsACString& aSourceSpecOut, | |||
| 10955 | uint32_t* aLineOut, uint32_t* aColumnOut, nsString& aMessageOut) { | |||
| 10956 | AssertStaticUnwrapOK<PrototypeID>(); | |||
| 10957 | RefPtr<T> exn; | |||
| 10958 | 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); | |||
| 10959 | ||||
| 10960 | exn->GetFilename(aCx, aSourceSpecOut); | |||
| 10961 | if (!aSourceSpecOut.IsEmpty()) { | |||
| 10962 | *aLineOut = exn->LineNumber(aCx); | |||
| 10963 | *aColumnOut = exn->ColumnNumber(); | |||
| 10964 | } | |||
| 10965 | ||||
| 10966 | exn->GetName(aMessageOut); | |||
| 10967 | aMessageOut.AppendLiteral(": "); | |||
| 10968 | ||||
| 10969 | nsAutoString message; | |||
| 10970 | exn->GetMessageMoz(message); | |||
| 10971 | aMessageOut.Append(message); | |||
| 10972 | return Ok(); | |||
| 10973 | } | |||
| 10974 | ||||
| 10975 | /* static */ | |||
| 10976 | void nsContentUtils::ExtractErrorValues( | |||
| 10977 | JSContext* aCx, JS::Handle<JS::Value> aValue, nsACString& aSourceSpecOut, | |||
| 10978 | uint32_t* aLineOut, uint32_t* aColumnOut, nsString& aMessageOut) { | |||
| 10979 | 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" , 10979); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLineOut" ")" ); do { *((volatile int*)__null) = 10979; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 10980 | 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" , 10980); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aColumnOut" ")"); do { *((volatile int*)__null) = 10980; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 10981 | ||||
| 10982 | if (aValue.isObject()) { | |||
| 10983 | JS::Rooted<JSObject*> obj(aCx, &aValue.toObject()); | |||
| 10984 | ||||
| 10985 | // Try to process as an Error object. Use the file/line/column values | |||
| 10986 | // from the Error as they will be more specific to the root cause of | |||
| 10987 | // the problem. | |||
| 10988 | JSErrorReport* err = obj ? JS_ErrorFromException(aCx, obj) : nullptr; | |||
| 10989 | if (err) { | |||
| 10990 | // Use xpc to extract the error message only. We don't actually send | |||
| 10991 | // this report anywhere. | |||
| 10992 | RefPtr<xpc::ErrorReport> report = new xpc::ErrorReport(); | |||
| 10993 | report->Init(err, | |||
| 10994 | nullptr, // toString result | |||
| 10995 | false, // chrome | |||
| 10996 | 0); // window ID | |||
| 10997 | ||||
| 10998 | if (!report->mFileName.IsEmpty()) { | |||
| 10999 | aSourceSpecOut = report->mFileName; | |||
| 11000 | *aLineOut = report->mLineNumber; | |||
| 11001 | *aColumnOut = report->mColumn; | |||
| 11002 | } | |||
| 11003 | aMessageOut.Assign(report->mErrorMsg); | |||
| 11004 | } | |||
| 11005 | ||||
| 11006 | // Next, try to unwrap the rejection value as a DOMException. | |||
| 11007 | else if (EXTRACT_EXN_VALUES(DOMException, aCx, obj, aSourceSpecOut, | |||
| 11008 | aLineOut, aColumnOut, aMessageOut)) { | |||
| 11009 | return; | |||
| 11010 | } | |||
| 11011 | ||||
| 11012 | // Next, try to unwrap the rejection value as an XPC Exception. | |||
| 11013 | else if (EXTRACT_EXN_VALUES(Exception, aCx, obj, aSourceSpecOut, aLineOut, | |||
| 11014 | aColumnOut, aMessageOut)) { | |||
| 11015 | return; | |||
| 11016 | } | |||
| 11017 | } | |||
| 11018 | ||||
| 11019 | // If we could not unwrap a specific error type, then perform default safe | |||
| 11020 | // string conversions on primitives. Objects will result in "[Object]" | |||
| 11021 | // unfortunately. | |||
| 11022 | if (aMessageOut.IsEmpty()) { | |||
| 11023 | nsAutoJSString jsString; | |||
| 11024 | if (jsString.init(aCx, aValue)) { | |||
| 11025 | aMessageOut = jsString; | |||
| 11026 | } else { | |||
| 11027 | JS_ClearPendingException(aCx); | |||
| 11028 | } | |||
| 11029 | } | |||
| 11030 | } | |||
| 11031 | ||||
| 11032 | #undef EXTRACT_EXN_VALUES | |||
| 11033 | ||||
| 11034 | /* static */ | |||
| 11035 | bool nsContentUtils::ContentIsLink(nsIContent* aContent) { | |||
| 11036 | if (!aContent || !aContent->IsElement()) { | |||
| 11037 | return false; | |||
| 11038 | } | |||
| 11039 | ||||
| 11040 | if (aContent->IsHTMLElement(nsGkAtoms::a)) { | |||
| 11041 | return true; | |||
| 11042 | } | |||
| 11043 | ||||
| 11044 | return aContent->AsElement()->AttrValueIs(kNameSpaceID_XLink4, nsGkAtoms::type, | |||
| 11045 | nsGkAtoms::simple, eCaseMatters); | |||
| 11046 | } | |||
| 11047 | ||||
| 11048 | /* static */ | |||
| 11049 | already_AddRefed<ContentFrameMessageManager> | |||
| 11050 | nsContentUtils::TryGetBrowserChildGlobal(nsISupports* aFrom) { | |||
| 11051 | RefPtr<nsFrameLoaderOwner> frameLoaderOwner = do_QueryObject(aFrom); | |||
| 11052 | if (!frameLoaderOwner) { | |||
| 11053 | return nullptr; | |||
| 11054 | } | |||
| 11055 | ||||
| 11056 | RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader(); | |||
| 11057 | if (!frameLoader) { | |||
| 11058 | return nullptr; | |||
| 11059 | } | |||
| 11060 | ||||
| 11061 | RefPtr<ContentFrameMessageManager> manager = | |||
| 11062 | frameLoader->GetBrowserChildMessageManager(); | |||
| 11063 | return manager.forget(); | |||
| 11064 | } | |||
| 11065 | ||||
| 11066 | /* static */ | |||
| 11067 | uint32_t nsContentUtils::InnerOrOuterWindowCreated() { | |||
| 11068 | 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" , 11068); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 11068; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 11069 | ++sInnerOrOuterWindowCount; | |||
| 11070 | return ++sInnerOrOuterWindowSerialCounter; | |||
| 11071 | } | |||
| 11072 | ||||
| 11073 | /* static */ | |||
| 11074 | void nsContentUtils::InnerOrOuterWindowDestroyed() { | |||
| 11075 | 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" , 11075); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 11075; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 11076 | 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" , 11076); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sInnerOrOuterWindowCount > 0" ")"); do { *((volatile int*)__null) = 11076; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 11077 | --sInnerOrOuterWindowCount; | |||
| 11078 | } | |||
| 11079 | ||||
| 11080 | /* static */ | |||
| 11081 | nsresult nsContentUtils::AnonymizeURI(nsIURI* aURI, nsCString& aAnonymizedURI) { | |||
| 11082 | 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" , 11082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aURI" ")") ; do { *((volatile int*)__null) = 11082; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 11083 | ||||
| 11084 | if (aURI->SchemeIs("data")) { | |||
| 11085 | aAnonymizedURI.Assign("data:..."_ns); | |||
| 11086 | return NS_OK; | |||
| 11087 | } | |||
| 11088 | // Anonymize the URL. | |||
| 11089 | // Strip the URL of any possible username/password and make it ready to be | |||
| 11090 | // presented in the UI. | |||
| 11091 | nsCOMPtr<nsIURI> exposableURI = net::nsIOService::CreateExposableURI(aURI); | |||
| 11092 | return exposableURI->GetSpec(aAnonymizedURI); | |||
| 11093 | } | |||
| 11094 | ||||
| 11095 | static bool JSONCreator(const char16_t* aBuf, uint32_t aLen, void* aData) { | |||
| 11096 | nsAString* result = static_cast<nsAString*>(aData); | |||
| 11097 | return result->Append(aBuf, aLen, fallible); | |||
| 11098 | } | |||
| 11099 | ||||
| 11100 | /* static */ | |||
| 11101 | bool nsContentUtils::StringifyJSON(JSContext* aCx, JS::Handle<JS::Value> aValue, | |||
| 11102 | nsAString& aOutStr, JSONBehavior aBehavior) { | |||
| 11103 | 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" , 11103); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCx" ")"); do { *((volatile int*)__null) = 11103; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 11104 | switch (aBehavior) { | |||
| 11105 | case UndefinedIsNullStringLiteral: { | |||
| 11106 | aOutStr.Truncate(); | |||
| 11107 | JS::Rooted<JS::Value> value(aCx, aValue); | |||
| 11108 | return JS_Stringify(aCx, &value, nullptr, JS::NullHandleValue, | |||
| 11109 | JSONCreator, &aOutStr); | |||
| 11110 | } | |||
| 11111 | case UndefinedIsVoidString: { | |||
| 11112 | aOutStr.SetIsVoid(true); | |||
| 11113 | return JS::ToJSON(aCx, aValue, nullptr, JS::NullHandleValue, JSONCreator, | |||
| 11114 | &aOutStr); | |||
| 11115 | } | |||
| 11116 | default: | |||
| 11117 | 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" , 11117); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "Invalid value for aBehavior" ")" ); do { *((volatile int*)__null) = 11117; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 11118 | return false; | |||
| 11119 | } | |||
| 11120 | } | |||
| 11121 | ||||
| 11122 | /* static */ | |||
| 11123 | bool nsContentUtils:: | |||
| 11124 | HighPriorityEventPendingForTopLevelDocumentBeforeContentfulPaint( | |||
| 11125 | Document* aDocument) { | |||
| 11126 | 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" , 11127); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsContentProcess()" ") (" "This function only makes sense in content processes" ")" ); do { *((volatile int*)__null) = 11127; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) | |||
| 11127 | "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" , 11127); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsContentProcess()" ") (" "This function only makes sense in content processes" ")" ); do { *((volatile int*)__null) = 11127; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 11128 | ||||
| 11129 | if (aDocument && !aDocument->IsLoadedAsData()) { | |||
| 11130 | if (nsPresContext* presContext = FindPresContextForDocument(aDocument)) { | |||
| 11131 | 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" , 11132); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!presContext->IsChrome()" ") (" "Should never have a chrome PresContext in a content process" ")"); do { *((volatile int*)__null) = 11132; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) | |||
| 11132 | "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" , 11132); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!presContext->IsChrome()" ") (" "Should never have a chrome PresContext in a content process" ")"); do { *((volatile int*)__null) = 11132; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 11133 | ||||
| 11134 | return !presContext->GetInProcessRootContentDocumentPresContext() | |||
| 11135 | ->HadFirstContentfulPaint() && | |||
| 11136 | nsThreadManager::MainThreadHasPendingHighPriorityEvents(); | |||
| 11137 | } | |||
| 11138 | } | |||
| 11139 | return false; | |||
| 11140 | } | |||
| 11141 | ||||
| 11142 | static nsGlobalWindowInner* GetInnerWindowForGlobal(nsIGlobalObject* aGlobal) { | |||
| 11143 | 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" , 11143); return nullptr; } } while (false); | |||
| 11144 | ||||
| 11145 | if (auto* window = aGlobal->GetAsInnerWindow()) { | |||
| 11146 | return nsGlobalWindowInner::Cast(window); | |||
| 11147 | } | |||
| 11148 | ||||
| 11149 | // When Extensions run content scripts inside a sandbox, it uses | |||
| 11150 | // sandboxPrototype to make them appear as though they're running in the | |||
| 11151 | // scope of the page. So when a content script invokes postMessage, it expects | |||
| 11152 | // the |source| of the received message to be the window set as the | |||
| 11153 | // sandboxPrototype. This used to work incidentally for unrelated reasons, but | |||
| 11154 | // now we need to do some special handling to support it. | |||
| 11155 | JS::Rooted<JSObject*> scope(RootingCx(), aGlobal->GetGlobalJSObject()); | |||
| 11156 | 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" , 11156); return nullptr; } } while (false); | |||
| 11157 | ||||
| 11158 | if (xpc::IsSandbox(scope)) { | |||
| 11159 | AutoJSAPI jsapi; | |||
| 11160 | MOZ_ALWAYS_TRUE(jsapi.Init(scope))do { if ((__builtin_expect(!!(jsapi.Init(scope)), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "jsapi.Init(scope)" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp" , 11160); AnnotateMozCrashReason("MOZ_CRASH(" "jsapi.Init(scope)" ")"); do { *((volatile int*)__null) = 11160; __attribute__(( nomerge)) ::abort(); } while (false); } while (false); } } while (false); | |||
| 11161 | JSContext* cx = jsapi.cx(); | |||
| 11162 | // Our current Realm on aCx is the sandbox. Using that for unwrapping | |||
| 11163 | // makes sense: if the sandbox can unwrap the window, we can use it. | |||
| 11164 | return xpc::SandboxWindowOrNull(scope, cx); | |||
| 11165 | } | |||
| 11166 | ||||
| 11167 | // The calling window must be holding a reference, so we can return a weak | |||
| 11168 | // pointer. | |||
| 11169 | return nsGlobalWindowInner::Cast(aGlobal->GetAsInnerWindow()); | |||
| 11170 | } | |||
| 11171 | ||||
| 11172 | /* static */ | |||
| 11173 | nsGlobalWindowInner* nsContentUtils::IncumbentInnerWindow() { | |||
| 11174 | return GetInnerWindowForGlobal(GetIncumbentGlobal()); | |||
| 11175 | } | |||
| 11176 | ||||
| 11177 | /* static */ | |||
| 11178 | nsGlobalWindowInner* nsContentUtils::EntryInnerWindow() { | |||
| 11179 | return GetInnerWindowForGlobal(GetEntryGlobal()); | |||
| 11180 | } | |||
| 11181 | ||||
| 11182 | /* static */ | |||
| 11183 | bool nsContentUtils::IsURIInPrefList(nsIURI* aURI, const char* aPrefName) { | |||
| 11184 | 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" , 11184); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrefName" ")"); do { *((volatile int*)__null) = 11184; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 11185 | ||||
| 11186 | nsAutoCString list; | |||
| 11187 | Preferences::GetCString(aPrefName, list); | |||
| 11188 | ToLowerCase(list); | |||
| 11189 | return IsURIInList(aURI, list); | |||
| 11190 | } | |||
| 11191 | ||||
| 11192 | /* static */ | |||
| 11193 | bool nsContentUtils::IsURIInList(nsIURI* aURI, const nsCString& aList) { | |||
| 11194 | #ifdef DEBUG1 | |||
| 11195 | nsAutoCString listLowerCase(aList); | |||
| 11196 | ToLowerCase(listLowerCase); | |||
| 11197 | 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" , 11198); AnnotateMozCrashReason("MOZ_ASSERT" "(" "listLowerCase.Equals(aList)" ") (" "The aList argument should be lower-case" ")"); do { * ((volatile int*)__null) = 11198; __attribute__((nomerge)) ::abort (); } while (false); } } while (false) | |||
| 11198 | "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" , 11198); AnnotateMozCrashReason("MOZ_ASSERT" "(" "listLowerCase.Equals(aList)" ") (" "The aList argument should be lower-case" ")"); do { * ((volatile int*)__null) = 11198; __attribute__((nomerge)) ::abort (); } while (false); } } while (false); | |||
| 11199 | #endif | |||
| 11200 | ||||
| 11201 | if (!aURI) { | |||
| 11202 | return false; | |||
| 11203 | } | |||
| 11204 | ||||
| 11205 | if (aList.IsEmpty()) { | |||
| 11206 | return false; | |||
| 11207 | } | |||
| 11208 | ||||
| 11209 | nsAutoCString scheme; | |||
| 11210 | aURI->GetScheme(scheme); | |||
| 11211 | if (!scheme.EqualsLiteral("http") && !scheme.EqualsLiteral("https")) { | |||
| 11212 | return false; | |||
| 11213 | } | |||
| 11214 | ||||
| 11215 | // The list is comma separated domain list. Each item may start with "*.". | |||
| 11216 | // If starts with "*.", it matches any sub-domains. | |||
| 11217 | ||||
| 11218 | nsCCharSeparatedTokenizer tokenizer(aList, ','); | |||
| 11219 | while (tokenizer.hasMoreTokens()) { | |||
| 11220 | const nsCString token(tokenizer.nextToken()); | |||
| 11221 | ||||
| 11222 | nsAutoCString host; | |||
| 11223 | aURI->GetHost(host); | |||
| 11224 | if (host.IsEmpty()) { | |||
| 11225 | return false; | |||
| 11226 | } | |||
| 11227 | ToLowerCase(host); | |||
| 11228 | ||||
| 11229 | for (;;) { | |||
| 11230 | int32_t index = token.Find(host); | |||
| 11231 | if (index >= 0 && | |||
| 11232 | static_cast<uint32_t>(index) + host.Length() <= token.Length()) { | |||
| 11233 | // If we found a full match, return true. | |||
| 11234 | size_t indexAfterHost = index + host.Length(); | |||
| 11235 | if (index == 0 && indexAfterHost == token.Length()) { | |||
| 11236 | return true; | |||
| 11237 | } | |||
| 11238 | // If next character is '/', we need to check the path too. | |||
| 11239 | // We assume the path in the list means "/foo" + "*". | |||
| 11240 | if (token[indexAfterHost] == '/') { | |||
| 11241 | nsDependentCSubstring pathInList( | |||
| 11242 | token, indexAfterHost, | |||
| 11243 | static_cast<nsDependentCSubstring::size_type>(-1)); | |||
| 11244 | nsAutoCString filePath; | |||
| 11245 | aURI->GetFilePath(filePath); | |||
| 11246 | ToLowerCase(filePath); | |||
| 11247 | if (StringBeginsWith(filePath, pathInList) && | |||
| 11248 | (filePath.Length() == pathInList.Length() || | |||
| 11249 | pathInList.EqualsLiteral("/") || | |||
| 11250 | filePath[pathInList.Length() - 1] == '/' || | |||
| 11251 | filePath[pathInList.Length() - 1] == '?' || | |||
| 11252 | filePath[pathInList.Length() - 1] == '#')) { | |||
| 11253 | return true; | |||
| 11254 | } | |||
| 11255 | } | |||
| 11256 | } | |||
| 11257 | int32_t startIndexOfCurrentLevel = host[0] == '*' ? 1 : 0; | |||
| 11258 | int32_t startIndexOfNextLevel = | |||
| 11259 | host.Find(".", startIndexOfCurrentLevel + 1); | |||
| 11260 | if (startIndexOfNextLevel <= 0) { | |||
| 11261 | break; | |||
| 11262 | } | |||
| 11263 | host.ReplaceLiteral(0, startIndexOfNextLevel, "*"); | |||
| 11264 | } | |||
| 11265 | } | |||
| 11266 | ||||
| 11267 | return false; | |||
| 11268 | } | |||
| 11269 | ||||
| 11270 | /* static */ | |||
| 11271 | LayoutDeviceIntMargin nsContentUtils::GetWindowSafeAreaInsets( | |||
| 11272 | nsIScreen* aScreen, const LayoutDeviceIntMargin& aSafeAreaInsets, | |||
| 11273 | const LayoutDeviceIntRect& aWindowRect) { | |||
| 11274 | // This calculates safe area insets of window from screen rectangle, window | |||
| 11275 | // rectangle and safe area insets of screen. | |||
| 11276 | // | |||
| 11277 | // +----------------------------------------+ <-- screen | |||
| 11278 | // | +-------------------------------+ <------- window | |||
| 11279 | // | | window's safe area inset top) | | | |||
| 11280 | // +--+-------------------------------+--+ | | |||
| 11281 | // | | | |<------ safe area rectangle of | |||
| 11282 | // | | | | | screen | |||
| 11283 | // +--+-------------------------------+--+ | | |||
| 11284 | // | |window's safe area inset bottom| | | |||
| 11285 | // | +-------------------------------+ | | |||
| 11286 | // +----------------------------------------+ | |||
| 11287 | // | |||
| 11288 | LayoutDeviceIntMargin windowSafeAreaInsets; | |||
| 11289 | if (windowSafeAreaInsets == aSafeAreaInsets) { | |||
| 11290 | // no safe area insets. | |||
| 11291 | return windowSafeAreaInsets; | |||
| 11292 | } | |||
| 11293 | ||||
| 11294 | const LayoutDeviceIntRect screenRect = aScreen->GetRect(); | |||
| 11295 | LayoutDeviceIntRect safeAreaRect = screenRect; | |||
| 11296 | safeAreaRect.Deflate(aSafeAreaInsets); | |||
| 11297 | ||||
| 11298 | // FIXME(bug 1754323): This can trigger because the screen rect is not | |||
| 11299 | // orientation-aware. | |||
| 11300 | // MOZ_ASSERT(screenRect.Contains(windowRect), | |||
| 11301 | // "Screen doesn't contain window rect? Something seems off"); | |||
| 11302 | ||||
| 11303 | // window's rect of safe area | |||
| 11304 | safeAreaRect = safeAreaRect.Intersect(aWindowRect); | |||
| 11305 | ||||
| 11306 | windowSafeAreaInsets.top = safeAreaRect.y - aWindowRect.y; | |||
| 11307 | windowSafeAreaInsets.left = safeAreaRect.x - aWindowRect.x; | |||
| 11308 | windowSafeAreaInsets.right = | |||
| 11309 | aWindowRect.x + aWindowRect.width - (safeAreaRect.x + safeAreaRect.width); | |||
| 11310 | windowSafeAreaInsets.bottom = aWindowRect.y + aWindowRect.height - | |||
| 11311 | (safeAreaRect.y + safeAreaRect.height); | |||
| 11312 | ||||
| 11313 | windowSafeAreaInsets.EnsureAtLeast(LayoutDeviceIntMargin()); | |||
| 11314 | // This shouldn't be needed, but it wallpapers orientation issues, see bug | |||
| 11315 | // 1754323. | |||
| 11316 | windowSafeAreaInsets.EnsureAtMost(aSafeAreaInsets); | |||
| 11317 | ||||
| 11318 | return windowSafeAreaInsets; | |||
| 11319 | } | |||
| 11320 | ||||
| 11321 | /* static */ | |||
| 11322 | nsContentUtils::SubresourceCacheValidationInfo | |||
| 11323 | nsContentUtils::GetSubresourceCacheValidationInfo(nsIRequest* aRequest, | |||
| 11324 | nsIURI* aURI) { | |||
| 11325 | SubresourceCacheValidationInfo info; | |||
| 11326 | if (nsCOMPtr<nsICacheInfoChannel> cache = do_QueryInterface(aRequest)) { | |||
| 11327 | uint32_t value = 0; | |||
| 11328 | if (NS_SUCCEEDED(cache->GetCacheTokenExpirationTime(&value))((bool)(__builtin_expect(!!(!NS_FAILED_impl(cache->GetCacheTokenExpirationTime (&value))), 1)))) { | |||
| 11329 | // NOTE: If the cache doesn't expire, the value should be | |||
| 11330 | // nsICacheEntry::NO_EXPIRATION_TIME. | |||
| 11331 | info.mExpirationTime.emplace(CacheExpirationTime::ExpireAt(value)); | |||
| 11332 | } | |||
| 11333 | } | |||
| 11334 | ||||
| 11335 | // Determine whether the cache entry must be revalidated when we try to use | |||
| 11336 | // it. Currently, only HTTP specifies this information... | |||
| 11337 | if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest)) { | |||
| 11338 | Unused << httpChannel->IsNoStoreResponse(&info.mMustRevalidate); | |||
| 11339 | ||||
| 11340 | if (!info.mMustRevalidate) { | |||
| 11341 | Unused << httpChannel->IsNoCacheResponse(&info.mMustRevalidate); | |||
| 11342 | } | |||
| 11343 | } | |||
| 11344 | ||||
| 11345 | // data: URIs are safe to cache across documents under any circumstance, so we | |||
| 11346 | // special-case them here even though the channel itself doesn't have any | |||
| 11347 | // caching policy. Same for chrome:// uris. | |||
| 11348 | // | |||
| 11349 | // TODO(emilio): Figure out which other schemes that don't have caching | |||
| 11350 | // policies are safe to cache. Blobs should be... | |||
| 11351 | const bool knownCacheable = [&] { | |||
| 11352 | if (!aURI) { | |||
| 11353 | return false; | |||
| 11354 | } | |||
| 11355 | if (aURI->SchemeIs("data") || aURI->SchemeIs("moz-page-thumb") || | |||
| 11356 | aURI->SchemeIs("moz-extension")) { | |||
| 11357 | return true; | |||
| 11358 | } | |||
| 11359 | if (aURI->SchemeIs("chrome") || aURI->SchemeIs("resource")) { | |||
| 11360 | return !StaticPrefs::nglayout_debug_disable_xul_cache(); | |||
| 11361 | } | |||
| 11362 | return false; | |||
| 11363 | }(); | |||
| 11364 | ||||
| 11365 | if (knownCacheable) { | |||
| 11366 | 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" , 11366); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!info.mExpirationTime" ")"); do { *((volatile int*)__null) = 11366; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 11367 | 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" , 11367); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!info.mMustRevalidate" ")"); do { *((volatile int*)__null) = 11367; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 11368 | info.mExpirationTime = Some(CacheExpirationTime::Never()); | |||
| 11369 | } | |||
| 11370 | ||||
| 11371 | return info; | |||
| 11372 | } | |||
| 11373 | ||||
| 11374 | CacheExpirationTime nsContentUtils::GetSubresourceCacheExpirationTime( | |||
| 11375 | nsIRequest* aRequest, nsIURI* aURI) { | |||
| 11376 | auto info = GetSubresourceCacheValidationInfo(aRequest, aURI); | |||
| 11377 | ||||
| 11378 | // For now, we never cache entries that we have to revalidate, or whose | |||
| 11379 | // channel don't support caching. | |||
| 11380 | if (info.mMustRevalidate || !info.mExpirationTime) { | |||
| 11381 | return CacheExpirationTime::AlreadyExpired(); | |||
| 11382 | } | |||
| 11383 | return *info.mExpirationTime; | |||
| 11384 | } | |||
| 11385 | ||||
| 11386 | /* static */ | |||
| 11387 | bool nsContentUtils::ShouldBypassSubResourceCache(Document* aDoc) { | |||
| 11388 | RefPtr<nsILoadGroup> lg = aDoc->GetDocumentLoadGroup(); | |||
| 11389 | if (!lg) { | |||
| 11390 | return false; | |||
| 11391 | } | |||
| 11392 | nsLoadFlags flags; | |||
| 11393 | if (NS_FAILED(lg->GetLoadFlags(&flags))((bool)(__builtin_expect(!!(NS_FAILED_impl(lg->GetLoadFlags (&flags))), 0)))) { | |||
| 11394 | return false; | |||
| 11395 | } | |||
| 11396 | return flags & (nsIRequest::LOAD_BYPASS_CACHE | | |||
| 11397 | nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE); | |||
| 11398 | } | |||
| 11399 | ||||
| 11400 | nsCString nsContentUtils::TruncatedURLForDisplay(nsIURI* aURL, size_t aMaxLen) { | |||
| 11401 | nsCString spec; | |||
| 11402 | if (aURL) { | |||
| 11403 | aURL->GetSpec(spec); | |||
| 11404 | spec.Truncate(std::min(aMaxLen, spec.Length())); | |||
| 11405 | } | |||
| 11406 | return spec; | |||
| 11407 | } | |||
| 11408 | ||||
| 11409 | /* static */ | |||
| 11410 | nsresult nsContentUtils::AnonymizeId(nsAString& aId, | |||
| 11411 | const nsACString& aOriginKey, | |||
| 11412 | OriginFormat aFormat) { | |||
| 11413 | 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" , 11413); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 11413; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 11414 | ||||
| 11415 | nsresult rv; | |||
| 11416 | nsCString rawKey; | |||
| 11417 | if (aFormat == OriginFormat::Base64) { | |||
| 11418 | rv = Base64Decode(aOriginKey, rawKey); | |||
| 11419 | 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" , 11419); return rv; } } while (false); | |||
| 11420 | } else { | |||
| 11421 | rawKey = aOriginKey; | |||
| 11422 | } | |||
| 11423 | ||||
| 11424 | HMAC hmac; | |||
| 11425 | rv = hmac.Begin( | |||
| 11426 | SEC_OID_SHA256, | |||
| 11427 | Span(reinterpret_cast<const uint8_t*>(rawKey.get()), rawKey.Length())); | |||
| 11428 | 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" , 11428); return rv; } } while (false); | |||
| 11429 | ||||
| 11430 | NS_ConvertUTF16toUTF8 id(aId); | |||
| 11431 | rv = hmac.Update(reinterpret_cast<const uint8_t*>(id.get()), id.Length()); | |||
| 11432 | 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" , 11432); return rv; } } while (false); | |||
| 11433 | ||||
| 11434 | nsTArray<uint8_t> macBytes; | |||
| 11435 | rv = hmac.End(macBytes); | |||
| 11436 | 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" , 11436); return rv; } } while (false); | |||
| 11437 | ||||
| 11438 | nsCString macBase64; | |||
| 11439 | rv = Base64Encode( | |||
| 11440 | nsDependentCSubstring(reinterpret_cast<const char*>(macBytes.Elements()), | |||
| 11441 | macBytes.Length()), | |||
| 11442 | macBase64); | |||
| 11443 | 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" , 11443); return rv; } } while (false); | |||
| 11444 | ||||
| 11445 | CopyUTF8toUTF16(macBase64, aId); | |||
| 11446 | return NS_OK; | |||
| 11447 | } | |||
| 11448 | ||||
| 11449 | void nsContentUtils::RequestGeckoTaskBurst() { | |||
| 11450 | nsCOMPtr<nsIAppShell> appShell = do_GetService(NS_APPSHELL_CID{ 0x2d96b3df, 0xc051, 0x11d1, { 0xa8, 0x27, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9 } }); | |||
| 11451 | if (appShell) { | |||
| 11452 | appShell->GeckoTaskBurst(); | |||
| 11453 | } | |||
| 11454 | } | |||
| 11455 | ||||
| 11456 | nsIContent* nsContentUtils::GetClosestLinkInFlatTree(nsIContent* aContent) { | |||
| 11457 | for (nsIContent* content = aContent; content; | |||
| 11458 | content = content->GetFlattenedTreeParent()) { | |||
| 11459 | if (nsContentUtils::IsDraggableLink(content)) { | |||
| 11460 | return content; | |||
| 11461 | } | |||
| 11462 | } | |||
| 11463 | return nullptr; | |||
| 11464 | } | |||
| 11465 | ||||
| 11466 | template <TreeKind aKind> | |||
| 11467 | MOZ_ALWAYS_INLINEinline const nsINode* GetParent(const nsINode* aNode) { | |||
| 11468 | if constexpr (aKind == TreeKind::DOM) { | |||
| 11469 | return aNode->GetParentNode(); | |||
| 11470 | } else { | |||
| 11471 | return aNode->GetFlattenedTreeParentNode(); | |||
| 11472 | } | |||
| 11473 | } | |||
| 11474 | ||||
| 11475 | template <TreeKind aKind> | |||
| 11476 | MOZ_ALWAYS_INLINEinline Maybe<uint32_t> GetIndexInParent(const nsINode* aParent, | |||
| 11477 | const nsINode* aNode) { | |||
| 11478 | if constexpr (aKind == TreeKind::DOM) { | |||
| 11479 | return aParent->ComputeIndexOf(aNode); | |||
| 11480 | } else { | |||
| 11481 | return aParent->ComputeFlatTreeIndexOf(aNode); | |||
| 11482 | } | |||
| 11483 | } | |||
| 11484 | ||||
| 11485 | template <TreeKind aTreeKind> | |||
| 11486 | int32_t nsContentUtils::CompareTreePosition(const nsINode* aNode1, | |||
| 11487 | const nsINode* aNode2, | |||
| 11488 | const nsINode* aCommonAncestor) { | |||
| 11489 | 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" , 11489); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNode1" ") (" "aNode1 must not be null" ")"); do { *((volatile int*)__null ) = 11489; __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); | |||
| 11490 | 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" , 11490); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNode2" ") (" "aNode2 must not be null" ")"); do { *((volatile int*)__null ) = 11490; __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); | |||
| 11491 | ||||
| 11492 | 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" , 11492)) { | |||
| 11493 | return 0; | |||
| 11494 | } | |||
| 11495 | ||||
| 11496 | AutoTArray<const nsINode*, 32> node1Ancestors; | |||
| 11497 | const nsINode* c1; | |||
| 11498 | for (c1 = aNode1; c1 && c1 != aCommonAncestor; | |||
| 11499 | c1 = GetParent<aTreeKind>(c1)) { | |||
| 11500 | node1Ancestors.AppendElement(c1); | |||
| 11501 | } | |||
| 11502 | if (!c1 && aCommonAncestor) { | |||
| 11503 | // So, it turns out aCommonAncestor was not an ancestor of c1. Oops. | |||
| 11504 | // Never mind. We can continue as if aCommonAncestor was null. | |||
| 11505 | aCommonAncestor = nullptr; | |||
| 11506 | } | |||
| 11507 | ||||
| 11508 | AutoTArray<const nsINode*, 32> node2Ancestors; | |||
| 11509 | const nsINode* c2; | |||
| 11510 | for (c2 = aNode2; c2 && c2 != aCommonAncestor; | |||
| 11511 | c2 = GetParent<aTreeKind>(c2)) { | |||
| 11512 | node2Ancestors.AppendElement(c2); | |||
| 11513 | } | |||
| 11514 | if (!c2 && aCommonAncestor) { | |||
| 11515 | // So, it turns out aCommonAncestor was not an ancestor of c2. | |||
| 11516 | // We need to retry with no common ancestor hint. | |||
| 11517 | return CompareTreePosition<aTreeKind>(aNode1, aNode2, nullptr); | |||
| 11518 | } | |||
| 11519 | ||||
| 11520 | int last1 = node1Ancestors.Length() - 1; | |||
| 11521 | int last2 = node2Ancestors.Length() - 1; | |||
| 11522 | const nsINode* node1Ancestor = nullptr; | |||
| 11523 | const nsINode* node2Ancestor = nullptr; | |||
| 11524 | while (last1 >= 0 && last2 >= 0 && | |||
| 11525 | ((node1Ancestor = node1Ancestors.ElementAt(last1)) == | |||
| 11526 | (node2Ancestor = node2Ancestors.ElementAt(last2)))) { | |||
| 11527 | last1--; | |||
| 11528 | last2--; | |||
| 11529 | } | |||
| 11530 | ||||
| 11531 | if (last1 < 0) { | |||
| 11532 | if (last2 < 0) { | |||
| 11533 | 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" , 11533); MOZ_PretendNoReturn(); } } while (0); | |||
| 11534 | return 0; | |||
| 11535 | } | |||
| 11536 | // aContent1 is an ancestor of aContent2 | |||
| 11537 | return -1; | |||
| 11538 | } | |||
| 11539 | ||||
| 11540 | if (last2 < 0) { | |||
| 11541 | // aContent2 is an ancestor of aContent1 | |||
| 11542 | return 1; | |||
| 11543 | } | |||
| 11544 | ||||
| 11545 | // node1Ancestor != node2Ancestor, so they must be siblings with the | |||
| 11546 | // same parent | |||
| 11547 | const nsINode* parent = GetParent<aTreeKind>(node1Ancestor); | |||
| 11548 | if (NS_WARN_IF(!parent)NS_warn_if_impl(!parent, "!parent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsContentUtils.cpp" , 11548)) { // different documents?? | |||
| 11549 | return 0; | |||
| 11550 | } | |||
| 11551 | ||||
| 11552 | const Maybe<uint32_t> index1 = | |||
| 11553 | GetIndexInParent<aTreeKind>(parent, node1Ancestor); | |||
| 11554 | const Maybe<uint32_t> index2 = | |||
| 11555 | GetIndexInParent<aTreeKind>(parent, node2Ancestor); | |||
| 11556 | ||||
| 11557 | // None of the nodes are anonymous, just do a regular comparison. | |||
| 11558 | if (index1.isSome() && index2.isSome()) { | |||
| 11559 | return static_cast<int32_t>(static_cast<int64_t>(*index1) - *index2); | |||
| 11560 | } | |||
| 11561 | ||||
| 11562 | // Otherwise handle pseudo-element and anonymous node ordering. | |||
| 11563 | // ::marker -> ::before -> anon siblings -> regular siblings -> ::after | |||
| 11564 | auto PseudoIndex = [](const nsINode* aNode, | |||
| 11565 | const Maybe<uint32_t>& aNodeIndex) -> int32_t { | |||
| 11566 | if (aNodeIndex.isSome()) { | |||
| 11567 | return 1; // Not a pseudo. | |||
| 11568 | } | |||
| 11569 | if (aNode->IsGeneratedContentContainerForMarker()) { | |||
| 11570 | return -2; | |||
| 11571 | } | |||
| 11572 | if (aNode->IsGeneratedContentContainerForBefore()) { | |||
| 11573 | return -1; | |||
| 11574 | } | |||
| 11575 | if (aNode->IsGeneratedContentContainerForAfter()) { | |||
| 11576 | return 2; | |||
| 11577 | } | |||
| 11578 | return 0; | |||
| 11579 | }; | |||
| 11580 | ||||
| 11581 | return PseudoIndex(node1Ancestor, index1) - | |||
| 11582 | PseudoIndex(node2Ancestor, index2); | |||
| 11583 | } | |||
| 11584 | ||||
| 11585 | nsIContent* nsContentUtils::AttachDeclarativeShadowRoot(nsIContent* aHost, | |||
| 11586 | ShadowRootMode aMode, | |||
| 11587 | bool aIsClonable, | |||
| 11588 | bool aIsSerializable, | |||
| 11589 | bool aDelegatesFocus) { | |||
| 11590 | RefPtr<Element> host = mozilla::dom::Element::FromNodeOrNull(aHost); | |||
| 11591 | if (!host || host->GetShadowRoot()) { | |||
| 11592 | // https://html.spec.whatwg.org/#parsing-main-inhead:shadow-host | |||
| 11593 | return nullptr; | |||
| 11594 | } | |||
| 11595 | ||||
| 11596 | ShadowRootInit init; | |||
| 11597 | init.mMode = aMode; | |||
| 11598 | init.mDelegatesFocus = aDelegatesFocus; | |||
| 11599 | init.mSlotAssignment = SlotAssignmentMode::Named; | |||
| 11600 | init.mClonable = aIsClonable; | |||
| 11601 | init.mSerializable = aIsSerializable; | |||
| 11602 | ||||
| 11603 | RefPtr shadowRoot = host->AttachShadow(init, IgnoreErrors()); | |||
| 11604 | if (shadowRoot) { | |||
| 11605 | shadowRoot->SetIsDeclarative( | |||
| 11606 | nsGenericHTMLFormControlElement::ShadowRootDeclarative::Yes); | |||
| 11607 | // https://html.spec.whatwg.org/#parsing-main-inhead:available-to-element-internals | |||
| 11608 | shadowRoot->SetAvailableToElementInternals(); | |||
| 11609 | } | |||
| 11610 | return shadowRoot; | |||
| 11611 | } | |||
| 11612 | ||||
| 11613 | template int32_t nsContentUtils::CompareTreePosition<TreeKind::DOM>( | |||
| 11614 | const nsINode*, const nsINode*, const nsINode*); | |||
| 11615 | template int32_t nsContentUtils::CompareTreePosition<TreeKind::Flat>( | |||
| 11616 | const nsINode*, const nsINode*, const nsINode*); |